云原生小课堂 | Envoy请求流程源码解析(二):请求解析
2022-03-10

云原生小课堂 envoy2 (1).png

前言

Envoy 是一款面向 Service Mesh 的高性能网络代理服务。它与应用程序并行运行,通过以平台无关的方式提供通用功能来抽象网络。当基础架构中的所有服务流量都通过 Envoy 网格时,通过一致的可观测性,很容易地查看问题区域,调整整体性能。

Envoy也是istio的核心组件之一,以 sidecar 的方式与服务运行在一起,对服务的流量进行拦截转发,具有路由,流量控制等等强大特性。本系列文章,我们将不局限于istio,envoy的官方文档,从源码级别切入,分享Envoy启动、流量劫持、http 请求处理流程的进阶应用实例,深度分析Envoy架构。

本篇是Envoy请求流程源码解析的第二篇,主要分享Envoy的outbound方向上篇,包含启动监听和建立连接。注:本文中所讨论的issue和pr基于21年12月。

envoy当中基于libevent进行封装了各种文件,定时器事件等操作,以及dispatch对象的分发,和延迟析构,worker启动,worker listener绑定等部分不在这里作解读,后续有空可以单独再进行分析。跳过envoy当中的事件循环模型,这里以请求触发开始。


outbound方向

filter解析

1 (3).png


启动监听

1. 通过xDS或者静态配置,获得Envoy代理的监听器信息

2. 如果监听器bind_to_port,则直接调用libevent的接口,绑定监听,回调函数设置为ListenerImpl::listenCallback 

2-合.png    


关于reuseport

1. https://github.com/envoyproxy/envoy/issues/4602#issuecomment-544704931

2. https://github.com/envoyproxy/envoy/issues/8794

3. https://lwn.net/Articles/542629/

4. https://tech.flipkart.com/linux-tcp-so-reuseport-usage-and-implementation-6bfbf642885a

3-reuseprt链接后.jpg

多个 server socket 监听相同的端口。每个 server socket 对应一个监听线程。内核 TCP 栈接收到客户端建立连接请求(SYN)时,按 TCP 4 元组(srcIP,srcPort,destIP,destPort) hash 算法,选择一个监听线程,唤醒之。新连接绑定到被唤醒的线程。所以相对于非SO_REUSEPORT, 连接更为平均地分布到线程中(hash 算法不是绝对平均)

envoy当中是支持在listener去设置开启这个特性,但是热重启场景时,对内核版本有一定要求(4.19-rc1)

https://www.envoyproxy.io/docs/envoy/v1.18.3/api-v3/config/listener/v3/listener.proto

4-内核版本要求链接后.png


验证观察

默认未开启,通过envoyfilter进行开启后,可见15001的端口被开启

5-验证观察.png

6-接上.png

需要重启 POD

7-重启POD.png

而对于没有应用reuseport

8-没有应用reu.png

大致的平均

9-平均.png

关于绝对的链接平衡, 可以试试 Listener 的配置connection_balance_config:exact_balance,不过由于有锁,对高频新连接应该有一定的性能损耗。目前只适用于 TCP 监听器

10.png

11-合.png


建立连接

1. DispatcherImpl通过libevent,接收到请求,调用ListenerImpl::listenCallback

2. client向envoy发起连接,envoy的worker接收eventloop的callback, 触发 Envoy::Network::ListenerImpl::listenCallback(port: 15001)

3. 15001的useOriginalDst": true,accept_filters_中会带有OriginalDstFilter

4. 在OriginalDstFilter.OnAccept中用os_syscalls.getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, &orig_addr, &addr_len)获取在iptables修改之前dst ip  iptables与getsockopt  

12-序号4之后.png

5. 在newconnection当中,还会通过 getBalancedHandlerByAddress寻找到实际的虚拟listener

6. 

13-6后.png 

7. 通过ConnectionHandlerImpl::findActiveListenerByTag 

14-7后.png

查到addr对应的Listener

● 先查找Listener.IP==addr.ip && Listener.Port==addr.port的Listener

● 再查找Listener.IP==0.0.0.0 && Listener.Port==addr.port的Listener (对于tcp服务,ip会有值,对于http服务,ip为4个0)

8. dispatcher.createServerConnection传入accept到的fd 创建Server连接对象ConnectionImpl, 并把onFileEvent注册到eventloop,等待读写事件的到来,因为socket是由一个non-blocking listening socket创建而来,所以也是non-blocking

9. 且注册的触发方式为epoll的边缘触发

15-合.png

10. http的listener里filters为envoy.http_connection_manager,buildFilterChain里会把HTTP::ConnectionManagerImpl加入到upstream_filters_(list)中,这样在请求数据到达的时候,就可以使用http_connection_manager的on_read方法

11. 

16-11后.png     

12. 当连接刚刚加入eventloop的时候, Write Event会被立即触发,但因为write_buffer_没有数据,所以不会写入任何数据

13. 

17-合.png


ASM试用申请

Envoy是Istio中的Sidecar官方标配,是一个面向Service Mesh的高性能网络代理服务。

当前Service Mesh是Kubernetes上微服务治理的最佳实践,灵雀云微服务治理平台Alauda Service Mesh(简称:ASM)可完整覆盖微服务落地所需要的基础设施,让开发者真正聚焦业务。

如果您想深入体验ASM,扫描下方二维码即可报名!

18-二维码.png


关于【云原生小课堂】

15-小课堂.png

【云原生小课堂】是由灵雀云、Kube-OVN社区、云原生技术社区联合开设的公益性技术分享类专题,将以丰富详实的精品内容和灵活多样的呈现形式,持续为您分享云原生前沿技术,带您了解更多云原生实践干货。
在数字化转型的背景下,云原生已经成为企业创新发展的核心驱动力。作为国内最早将 Kubernetes 产品化的厂商之一,灵雀云从出生便携带“云原生基因”,致力于通过革命性的技术帮助企业完成数字化转型,我们期待着云原生给这个世界带来更多改变。关注灵雀云,学习更多云原生知识,一起让改变发生。


上一篇:云原生小课堂 | Envoy请求流程源码解析(一):流量劫持

下一篇:超硬核攻略!《2022金融云原生落地实用指南》重磅发布(附下载链接)

为您数字化转型提供更为完善的解决方案和更加优质的全栈服务。

申请试用
© 2024 All Rights Reserved. 灵雀云 版权所有 备 案号:京ICP备15011102号-2      隐私条款
电话咨询 在线客服 微信咨询 公众号