【云驻共创】华为云云原生钻石课程13:Istio数据面架构(Envoy)深度解析
声明:本文参考自《云原生王者之路集训营》,是华为云云原生团队精心打磨的云原生学习技术公开课,分为黄金、钻石、王者三个阶段,帮助广大技术爱好者快速掌握云原生相关技能本课程为钻石课程的第十三课,由华为云容器网格数据面技术专家Sam Zhang主讲,深度解析Istio数据面(Envoy)架构
前言
本文分为5个章节进行介绍:
第1章 服务网格数据面Envoy介绍
第2章 Envoy原理及总体架构
第3章 Envoy启动配置及xDS
第4章 Envoy网络及线程模型、过滤器架构、HTTP请求流程
第5章 Envoy问题分析方法
希望本文可以对涉及Kubernetes、Istio等技术的应用开发者或者其他的云原生技术兴趣爱好者提供帮助,如有问题可在评论下方进行交流
一、Envoy介绍
- Envoy采用C++ 实现,本身为四层及七层代理,可以根据用户应用请求内的数据进行高级服务治理能力,包括服务发现、路由、高级负载均衡、动态配置、链路安全及证书更新、目标健康检查完整的可观测性等
- 且前常见数据面主要有三种:Envoy、Linkerd、TraeficEnvoy由于高性能和扩展能力在数据面遥遥领先
- Iptables使Pod间出入应用的流量均由Envoy代理,所以对应用来说完全透明支持主要常用网路协议 Http1/Http2/Tls/gRPC/Tcp等
从下图可以看出 Envoy 主要通过透明的插入代理来拦截服务的进出流量,并且Envoy 之间打通了数据链路,,代理了服务的请求
二、Envoy原理及总体架构
1.Envoy原理及总体架构-启动
可以修改全局注入参数作用于所有目标空间的 pod
2.Envoy原理及总体架构-说明
1.启动阶段
- istiod拦截pod创建请求,识别为指定popsace则根据configmap配置生成带有Envoy两个容器的创建POD请求,修改过的创建请求被kubelet接收,并在节点创建POD
- istio-init容器添加用于配置容器网络内iptables规则
- istio-proxy容器启动pilot-agent进程,使用UID=1337GID=1337创建Envoy启动命令行与配置文件
- 可以通过自定义deployment内istio注解istio.io/inject:“false”跳过自动注入过程,或修改部分启动参数
- istio.io/config:"{concurrency:6}”#修改工作线程数,默认2
- istio.io/proxylmage:"istio/proxyv2new:1.9.0"#修改默认注入镜像
2.控制面通信
- Pilot-agent进程本身创建UDS接收Envoy连接,用于证书更新下发并且与istiod建立证书更新通道
- Envoy通过pilot-agent转发机制与istiod建立长连接,通过xDS协议接收系统下发的监听器、路由、集群节点等更新信息
3.数据面通信
- 客户端请求进入容器网络,并被iptables规则拦截,经过DNAT后进入EnvoyvirtualOutbound监听器
- virtualOutbound经过监听过滤器恢复用于原始目标服务,并找到后端处理器处理新连接
- 后端处理器在配置中指定处理协议,根据协议相关的网络过滤器处理读取到的数据
- 如果为http协议,再经过请求过滤器处理http协议头部,如路由选择等功能并创建上游连接池
- 将修改及编码后的http消息通过网络发送到对端Envoy的容器网络
- lptables识别为入流量则进入virtuallnbound端口
- 类似恢复原始目标后,根据virtuallnbound配置的监听过滤器找到对应的本地服务器地址,并发起localhost的请求
- 请求进入本地服务器内进行处理并返回响应
- Envoy原理及总体架构-流量拦截
三、Envoy启动配置及xDS
1.Envoy启动配置及xDS
2.Envoy启动配置及xDS-cont' (实操)
- 分为static resources及dynamic resources两种配置,两种方式查看Envoy配置
- pilot-agent:访问Envoy15000端口,指定url获取:
- kubectl exec-it $podname -c istio-proxy -- pilot-agent request GET /config_dump > config.json
- istioctl需要根据Istio不同版本下载:
https://github.com/istio/istio/releases/download/1.9.5/istioct1-1.9.5-linux-amd64.tar.gz
- istioctl pc listener $podname #输出LDS
- istioctl pc route $podname #输出RDS
- istioctl pc cluster $podname #输出CDS
- istioctl pc endpoint $podname #输出EDS
- istioctl pc secret $podname #输出SDS
3.Envoy常用部署方式
四、Envoy网络以及线程模型
1.分为Envoy主线程及worker线程:
主线程:
- 负责初始化Envoy并读取解析配置文件
- 启动gRPC监听器,并启动xDS变化监听
- 启动日志写入线程,每个目标日志文件有独立线程负责输出
- 启动admin RESTful监听,处理运行状态输出,prometheus收集等请求
- 定期将工作线程内监控数据stat进行合并
- 定期刷新DNS信息,加速域名解析
- 目标cluster内主机列表健康状态判断
worker线程:
- 通过启动配置参数concurrency指定,不支持动态调整
- 启动virtualoutbound/virtualinbound网络监听,每个工作线程都对此监听端口进每个工作线程都对此监听端口进行监听,由内核随机挑选监听线程处理新连接
- 进行连接负载均衡处理后,选择最终的业务监听器处理新连接
- 之后对于此连接的所有处理都在此线程进行,包括下游数据集解码,路由选择、上游数据编码发送等
- 同时此工作线程还要处理定期观测信息与主线程同步(通过异步加回调)、线程内配置及集群管理器状态更新等工作
- 请求完成后延迟释放内存,解决本次事件处理中回调所引用对象可以被安全访问,并在下次处理中安全删除
2.Envoy网络及线程模型-共享数据同步
- 调度器通过epoll监控文件事件(网络)及定时器事件进行排队任务处理
- 线程间通信通过post接口发送任务,此任务通过定时器事件激活
- 线程间数据交换通过post更新TLS,这样每个线程内代码都不需要加锁处理
- 每个线程的TLS对象本身只保存真实对象的共享指针进行读操作,减少内存消耗
- 全局对象更新只发生在主线程,并通过COW方式通知工作线程进行指针修改
- 每个TLS slot通过allocateSlot分配,在使用前通过set在每个线程中创建一个拷贝并保存
7.在主线程中调用此slot的runOnAllThreads在所有线程中延迟执行回调,回调内更新每个线程内拷贝对象状态
3.Envoy网络及线程模型-集群信息更新
- Envoy需要在运行中支持添加集群并监控每个集群内目标主机列表变化
- 监控到目标主机健康状态变化时,需要通知到工作线程内主机可用状态
- 当收到节点变化EDS消息时,需要通知到工作线程内新上线、下线主机
- Envoy使用前面提到的TLS方式实现集群状态更新,集群管理器保存一个TLS slot,类型为ThreadLocalClusterManagerimpl当节点变化,,,DNs解析更新,健康状态变化时,将调用集群管理器的postThreadLocalClusterUpdate方法
- 此方法将延迟调用所有线程内ThreadLocalClusterManagerlmplslot的回调函数
- 此函数内将保存新clusterEntry对象的引用
- 下一轮请求解析时将从头TLS中获取到更新后的集群可用状态
4.Envoy网络及线程模型-网络处理
- Envoy启动时创建的Listener与工作线程绑定并启动监听(向libevent注册Read回调onSocketEvent),并进入阻塞运行状态,直到进程退出
- 当新连接到达时,内核网络协议栈调用回调并创建新连接的Socket
- 通过ConnectionHandler调用监听过滤器获得真实访问目标地址
- 根据目标地址匹配得到业务监听器后创建Connection连接对象
- 之后Connection对象再次向libevent 注册Read/Write回调onFileEvent,并作为L4层过滤管理器处理onNewConnection,onData数据接收
- 对于HTTP协议,将继续经过L7层编解码处理后向上游发送请求
- 当请求处理完毕后,将调用deferredDelete删除请求对象
- 使用I/0方式发送网络数据,降低对线程内其他操作的阻塞
4. Envoy过滤器架构
根据位置及作用类型,分为:
监听过滤器(Network::ListenerFilter)
- onAccept接收新连接,判断协议类型,TLS握手,HTTP协议自动识别、提取连接地址信息
L4网络过滤器
- HTTP、Mysql、Dubbo协议处理、元数据交换,四层限流,开发调试支持等 onNewConnection新连接建立,可以决定是否拒绝
- onData处理连接数据到达 onWrite处理连接数据发送
L7HTTP过滤器
- 售留等P请求头,限流处理,Lua扩展、WASM扩展、开发调试支持、压缩、元数据交换
- decodeHeaders处理HTTP请求头部 decodeData处理HTTP请求数据
- decodeTrailers处理HTTP请求结束位置 encodeHeaders发送请求前编码头部 encodeData发送请求前编码数据 encodeTrailers消息发送前编码处理
- 过滤器中可以获取连接对象并直接发送响应数据,同时可以返回Stoplteration结束过滤器迭代
- 实际使用过滤器根据Envoy静态及动态配置注册,并可以在运行中通过EnvoyFilter动态添加或删除
5. Envoy过滤器架构-常用过滤器
6. Envoy过滤器架构-相关代码
lstio项目中Envoy代码分为两部分
- Envoy原始项目的clone,在
https://github.com/istio/envoy.git
- Istio中适配所使用的的插件
https://github.com/istio/proxy.git
- 编译时由proxy项目作为入口,自动引用envoy项目
- 主要框架代码位于envoy项目包含进程启动,线程及网络、主要过滤器框架,观测数据处理等
- 启动入口点位于envoy项目source/exe目录下
- proxy项目中主要提供metadata_exchange,stats等必要WASM扩展
- envoy项目中过滤器插件主要位于source/extensions/filters,listener目录包含监听过滤器,network目录包含L4层网络过滤器,http目录包含L7层HTTP过滤器
7. EnvoyHttp请求流程
- APP发出的请求被iptables拦截,并根据源信息判断为outbound被DNAT后拦截进入Envoy 15001端口
- 15001上监听器通过ORIGINAL_DST获取原始目标地址(服务的clusterlp),匹配业务监听器(不真正监听网络)地址并传递新建下游连接
- 下游连接过滤器判断TLS,ALPN(业务协议名称),HTTP版本后匹配到L4层http_connection_manager网络过滤器
- http_connection_manager使用http codec解码http协议header/body/tailer等并触发回调函数
- http header/body处理回调中将调用L7层HTTP过滤器处理(可修改http原始请求等)最后调用Router过滤器
- Router过滤器负责根据配置中路由部分及请求内url等进行匹配并找到目标cluster
- 根据cluster的负载均衡策略及当前可用POD实例信息,选择最适合的目标POD地址,并创建此目标地址的连接池
- 根据连接池配置的最大可用连接数及允许的最大等待连接数等信息将下游请求与上游连接进行关联
- 当连接准备好后对下游请求使用codec进行HTTP编码,并发送到上游连接的L4层网络过滤器
- 上游连接的L4层网络过滤器使用metadata exchange传输本Envoy内保存的与App相关的元数据信息,包括POD名称、用户空间、cluster id等信息,之后将待发送请求通过Socket发送到网络,经过iptables时判断发送者为Envoy则不再拦截
- 目标POD收到从网络进入的流量,通过iptables拦截后判断为inbound并DNAT处理后,进入Envoy的15006端口
- 由于inbound方向流量的目标地址一定为本POD地址,无需再提取后转到不同业务监听器,因此virtualinbound负责TLS、ALPN及HTTP协议版本判断
- http_connection manager网络过滤器 htpcottmetadata exchate首先解析请求中包含的源POD元数据信息,并同时发送回本Envoy代理POD的元数据信息之后进入L4层 http_connection_manager网络过滤器
- L7层处理流程同outbound方向,区别为inbound通过Router匹配后的目标cluster所指向的上游地址为0.0.1
- 之后创建与本POD内业务容器的服务端口的Socket连接并完成请求发送
- 由于请求方向在建立时会保存下游与上游连接的双向对应关系,因此Response匹配的对上游进行L7层过滤器解码、通过Router关联关系找到下游并编码发送HTTP请求
- 以上所提到的EnvoyL4层网络读取及数据发送为全异步读写模式,采用网络事件触发机制完成响应数据的接收和发送
- 由于Router部分请求处理方向需要进行更多路由选择计算及负载均衡计算工作,因此通常outbound方向处理较复杂,CPU消耗比inbound更高
四、Envoy问题分析方法
查看istio配置
- 查看listener:istioct pc listener backend-welink-649fdfd55d-2xhzw--port 8123 -o json
- 查看endpoint:istioctl pc endpoint backend-welink-649fdfd55d-2xhzw
打开运行期日志
- Accesslog:格式
- https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access log/usage
- 调试日志:pilot-agent request POST /logging?connection=trace
- 抓包
- 进入pod容器网络空间执行tcpdump-ianyport(15001 or 8080)’-w fortio.cap
- 压测工具
- fortio load -qps 3000-c 128-t 60s --keepalive=false http://backend-welink:8123
- perfrecord-F 2000-g-p $pid;perf script -i perf.data > out.perf; stackcollapse-perf.pl out.perf > out.folded; flamegraph.pl out.folded > cpu.svg
镜像修改
- 编译pilot-agentenvoy二进制后替换现有envoy镜像并配置到自定义deployment的image中并添加annotation: sidecar.istioio/inject:“false”跳过自动注入逻辑覆盖 istio.io/proxylmage:"istio/proxyv2new:1.9.0"#修改默认注入镜像 docker save -o proxyv2.tar istio/proxyv2new:1.9.0 docker load -i proxyv2.tar·Dockerfile:
- From istio/proxyv2:1.9.0
- COPYenvoy /usr/local/bin/envoy
- COPY pilot-agent /usr/local/bin/pilot-agent
五、Lstio数据面发展趋势
现状问题:
- 引入Sidecar模式,导致端到端时延增加、并随着集群规模增加导致系统资源消耗上升,对大规模Istio集群的实际使用造成影响
- 运维难度增加,透明代理模式无法针对不同业务本身的特点定制监控能力,同时只能从业务容器外面收集应用的运行状态
演进方式:
- 从Envoy自身1/0及线程模型、容器网络协议栈优化提升端到端性能,降低tp90网络时延
- 通过运行时拉取集群依赖服务及POD实例配置信息,同时考虑配置信息共享的方式,降低每Envoy资源消耗
- 增加更多运维监控维度及探测点,收集更全面的观测信息同时支持对出现问题的Envoy进行旁路处理
六、总结
名称 |
简介 |
Envoy |
基于C++11.14的高性能服务网格数据面代理
|
XDS |
Envoy与上层控制面如istiod使用的基于gRPC的应用层协议,用于传输配置变更
|
自动注入及流量拦截 |
POD创建时,由istiod进行自动修改deplovment并将istio-init,istio-proxy容器注入到新创建POD内:当发生调用时,iptables规则将自动拦截出入流量进入Envov代理 |
线程模型 |
Envov采用每个工作线程独立处理网络及定时器事件,线程间无数据共享,提升性能
|
过滤器架构 |
Envov采用可扩展插件架构实现监听过滤器、L4网络过滤器、L7 HTTP过波器:同时支持基于L4/L7 WASM及L7 Lua过滤器的二次扩展 |
参考链接
相关内容的华为云官网链接:https://support.huaweicloud.com/usermanual-cce/cce 01 0006.html
详细ASM官网资料:https://support.huaweicloud.com/istiol
Istio官方文档:https://istio.io/latest/docs/
envoy官方文档:https://www.envoyproxy.io/docs/envoy/latest/
本文整理自华为云社区【内容共创】活动第14期
https://bbs.huaweicloud.com/blogs/336904
任务23.华为云云原生钻石课程13:Istio数据面架构(Envoy)深度解析
- 点赞
- 收藏
- 关注作者
评论(0)