写在前面
上篇探索文章分析了 Envoy 本身是如何启动、线程模型以及线程间如何实现通信。本文将继续深入探索以 DubboFilter 为例,看看在 Envoy 上如何实现各自定义的七层 Filter。
源码分析
本文代码是以 Envoy master 分支 f09ed3646b88fae777a060be37f3224dfa67f428 commit 为基准做的源码分析。
dubboFilter 注册
Envoy 本身是事件触发模型构成,第一步肯定是将对应的 Filter 要完成注册,后续才会收到对应的回调。
可以从源码中看到在读取完配置后,回调函数会调用 filter_manager.addReadFilter
方法。
通过静态方法实现 dubboFilter 的注释。
处理 downstream 数据
当有流量经过时在 libevent 事件通知下,FilterManagerImpl
会调用到 onRead 方法。
里面的关键代码在 filter_->onData
方法,对应的实现方法如下:
此时四层获取的数据流将交给七层做编解码,对应的方法是
DubboFilter 本身的编结码是通过状态机实现(并非每个自定义Filter均以该方式实现)
从源码上可以看到状态转移也不复杂,非别需要处理 header/body 的数据。处理请求头的代码如下:
请求体的代码
在反序列化后,会传递给 ActiveStream::onStreamDecoded 和 ActiveMessage::onStreamDecoded
其中的核心方法是 filter->onMessageDecoded
,对应的代码实现如下。
route 内部的实现逻辑就很清晰了,主题逻辑如下:
1)callbacks_route()
:先做路由匹配,如果找不到对应接口则异常退出。
2)route_->routeEntry()
:找到路由实例以及TLS内的 cluster 详情。
3)cluster->tcpConnPool
:由 cluster 获取或者创建upstream的连接池
4)upstream_request_->start()
:完成 upstream 请求的构建并发起请求
处理 upstream 数据
其中核心方法是 callback_->startUpstreamResponse()
和 callback_->upstreamData(data)
之后的逻辑与上文类似由状态机做编解码,最后由 ActiveResponseDecoder::onStreamDecoded
处理完后写回 response_connection_ 完成最终的处理。