前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >解析envoy处理http请求(上):filter架构

解析envoy处理http请求(上):filter架构

作者头像
灵雀云
发布2019-07-30 16:48:02
3.7K0
发布2019-07-30 16:48:02
举报

Envoy是istio的核心组件之一,以sidecar的方式与服务运行在一起,对服务的流量进行拦截转发。 具有路由,流量控制等等强大特性。

Envoy利用libevent实现了基于事件触发的异步架构,所有的网络阻塞操作包括 accept,read, connect, write 都是由eventloop进行callback触发。

本文以istio1.1所对应的Envoy版本进行源码流程分析。

名词解释:

  • 下游: 发送请求给Envoy的服务,client
  • 上游:接收Envoy发送的请求,并返回响应的服务, server

Filter流程图

下面的流程图为istio架构下,访问80端口的http服务的流程。

1. Client向Envoy的15001 port建立连接,被转到80 port的Listener

2.Client发送请求给Envoy,Envoy经过路由后找到上游Server,并发送请求

3.上游Server返回响应给Envoy,Envoy利用event_active立即返回响应给下游的client

4. Client主动断开下游到Envoy的连接

5. Server主动断开Envoy到上游的连接

Filter分类

1. ListenerFilter

listener.listener_filters

用于接收到下游新连接的时候回调

接口:

  • onAccept(callback)

内置类型:

  • envoy.listener.original_dst (istio中的15001端口常用) 根据iptables转换之前的dst port,查找到真实的Listener,查找到Listener会根据新的Listener的配置继续处理
  • envoy.listener.tls_inspector 注册read callback,识别tls和进行tls握手,握手结束后会进行下一步的filterChain的处

注册filter:

2. ReadFilter

listener.filter_chains.filters

  1. 用于接受到下游新连接的时候回调
  2. 上游或者下游连接上有数据可以读取的时候的回调,一般用于协议的解析

接口:

  • onNewConnection()
  • onData(data, end_stream) ...

内置类型:

  • Envoy::Http::CodecClient 只在向上游的连接用到,且向上游的连接只有这个filter,用于读取响应
  • envoy.http_connection_manager 处理http请求的主要filter
  • envoy.tcp_proxy
  • envoy.redis_proxy ...

注册filter:

3. WriteFilter

listener.filter_chains.filters

用于向上游的连接写入数据的时候回调(目前内置的writeFilter没有http相关的)

接口:

  • onWrite(data, end_stream)

内置类型:

  • envoy.filters.network.dubbo_proxy
  • envoy.mongo_proxy
  • envoy.filters.network.mysql_proxy
  • envoy.filters.network.zookeeper_proxy

注册filter:

4. StreamDecodeFilter ( envoy.http_connection_manager下独有的filter)

listener.filter_chains.filters[envoy.http_connection_manager].http_filters

用于解析http请求各个部分的时候回调执行

接口:

  • decodeHeaders(headers, end_stream)
  • decodeData(data, end_stream)
  • decodeTrailers(HeaderMaps& trailers)
  • decodeComplete()

...

内置类型:

  • envoy.cors
  • envoy.fault
  • envoy.router

...

注册filter:

5. StreamEncodeFilter

(envoy.http_connection_manager 下独有的filter)

listener.filter_chains.filters[envoy.http_connection_manager].http_filters

发送响应各个部分给下游client的时候执行

接口:

  • encode100ContinueHeaders(headers)
  • encodeHeaders(headers, end_stream)
  • encodeData(data, end_stream)
  • encodeTrailers(HeaderMap& trailers)
  • encodeMetadata(metadata_map)
  • encodeComplete()

...

内置类型:

  • envoy.cors
  • envoy.fault
  • envoy.lua

...

注册filter:

6. PerFilterConfig (并不是filter,只是为4,5中的http_filter提供route级别的配置数据)

route.virtual_hosts.per_filter_config

位于route上的字段,只有当对应Listener上http_connection_manager包含对应httpfilter的时候才有用,结构为 map<string, Struct> 用法由filter自己实现

7.ConnectionCallbacks

listener.filter_chains.filters

接口:

  • onEvent(event)

事件分为 RemoteClose, LocalClose, Connected 会在各个阶段调用

  • onAboveWriteBufferHighWatermark()
  • onBelowWriteBufferLowWatermark()
  • route.virtual_hosts.per_filter_config

类型:

  • Envoy::Http::CodeClient只在向上游的连接用到,且向上游的连接只有这个filter,用于检测上游连接断开
  • envoy.http_connection_manager
  • envoy.tcp_proxy
  • envoy.redis_proxy

注册filter:

8. access_log_handlers

接口:

  • log(request_headers, response_headers, response_trailers, stream_info)

类型:

  • Envoy::Http::Mixer::Filter istio为Envoy添加的Filter,在AccessLogHandlers这边主要用于Report
  • Envoy::Extensions::AccessLoggers::File::FileAccessLog
  • Envoy::Extensions::HttpGrpc::File::HttpGrpcAccessLog
  • Envoy::Extensions::HttpFilters::TapFilter::Filter

Filter流程中关键步骤解析

1. findActiveListenerByAddress 根据socket的localaddress和port选择合适的Listener处理

1.利用syscall找到iptables转化之前的dst port (如果有envoy.listener.original_dst) os_syscalls.getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, &orig_addr, &addr_len)

2.先匹配address和port和socket都一致的Listener,如果没找到再找port一致,address==0.0.0.0的Listener

2. 匹配request选择route和cluster

在构造RouteMatcher的时候会遍历virtual_hosts 下的domains,并根据通配符的位置和domain的长度分为4个 map<domain_len, std::unordered_map<domain, virtualHost>, std::greater<int64_t>>

  • default_virtual_host_ domain就是一个通配符(只允许存在一个)
  • wildcard_virtual_host_suffixes_ domain中通配符在开头
  • wildcard_virtual_host_prefixes_ domain中通配符在结尾
  • virtual_hosts_ 不包含通配符

2. 按照 virtual_hosts_ => wildcard_virtual_host_suffixes_ => wildcard_virtual_host_prefixes_ => default_virtual_host_ 的顺序查找

同时按照map的迭代顺序(domain len降序)查找最先除去通配符后能匹配到的virtualhost,如果没有直接返回 404

3.在一个virtualhost上查找对应route和cluster

  • 在通过domain匹配到virtualhost,会在那个virtualhost上匹配查找cluster,如果没匹配上,会直接返回404
  • match可以根据配置分为 prefix, regex, path 三种route进行匹配
  • 如果存在weighted_clusters ,会根据stream_id , 和clusters的weight进行分发,stream_id 本身是每个请求独立随机生成,所以weighted_clusters 的权重分发可以视为随机分发

3.负载均衡策略选择endpoint 1.在上一步查找到了clusterName, 对于clusterEntry,都是从ThreadLocalClusterManagerImpl 中取出,每个worker都一份自己的数据

2.对于ThreadLocalClusterManagerImpl , 维护了多份根据类型和协议区分的map

其中http协议才用的是host_http_conn_pool_map_ 这个map,大致的结构为 map<host, map<protocol, connpool>> , 因为http分为 Http10, Http11, Http2 不同协议的connpool都是独立的

对于http请求,会从 host_http_conn_pool_map_ 中查到对应的connpool,每个worker都维护了一份自己独有的threadlocal connpool

Mixer

mixerclient是istio基于Envoy,添加filter进行check和report的模块

注册到Envoy

注册到Envoy主要就是两行

第一行注册了 StreamDecodeFilter 和 StreamEncodeFilter, Http::Mixer::Filter 在decodeHeader 这个hook中实现了Check,发送attributes给mixerserver进行检查 第二行注册了 AccessLogHandler ,这个会在 一个请求结束的时候执行

在Mixer filter的log method中,会进行report操作

可以看到Mixer虽然是每个请求结束都会调用log,但实际的上报mixer是批量发送(累计一定大小或者到达一定时间间隔)。

总结

1.可以在Envoy处理请求的各个阶段加入filter来定制化功能,可以自己编写c++的filter,用REGISTER_FACTORY 注册到对应的Factory map中。

2. istio通过mixer filter实现了check和report功能。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生技术社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Filter分类
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档