存储架构

解析envoy处理http请求(下):事件模型和连接管理

Envoy是istio的核心组件之一,以sidecar的方式与服务运行在一起,对服务的流量进行拦截转发。 具有路由,流量控制等等强大特性。
本文以istio1.1所对应的Envoy版本进行源码流程分析。

Envoy并发架构

摘自 https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310

  • Envoy进程由一个Main Thread和多个Worker Thread 组成

  • 每个Main和Worker包含一个eventloop,所有的处理都是由eventloop触发开始

  • Main负责xDS等功能,Worker负责处理连接和请求

  • 当一个client向Envoy建立连接的时候,因为所有Worker的EventLoop都注册了listening fd,会由内核决定分配给哪个Worker

  • 当一个下游client连接到了Envoy,在保持连接不断的情况下,会和同一个Worker进行通讯

libevent函数

  • evconnlistener_new

    把一个 已经bind port 的listening fd和callback注册到eventloop,当accept到新连接的时候会触发callback。Envoy里面采用这个函数把同一个listening fd注册到所有的Worker的eventloop中,当新连接来的时候,由内核选择应该分发给哪个Worker

  • event_assign

    把一个fd和一个callback注册到eventloop,当read write closed事件触发的时候触发callback

  • event_active

    立即触发一个eventloop中的event,执行callbac

事件触发各阶段

1. client向Envoy建立连接

2. client发送请求到Envoy,Envoy挑选节点向上游Server建立连接(如果连接池有空闲连接直接发送请求)

3. Envoy向上游建连接成功,发送请求

4. 上游server返回响应给Envoy

5. Envoy返回请求给下游的client

Cluster管理 (HTTP1)

层次结构图

  • 上面的实线表示下方的头部是上方的属性之一

  • 虚线表示两者相关

  • ClusterManagerImpl是Envoy内的单例,用于管理多个Worker上ThreadLocalClusterManagerImpl

  • ThreadLocalCusterManagerImpl 每个Worker都拥有一个,用于管理上游的连接和负载均衡上下文

连接结构简介

1. 负载均衡器只挑选host,然后会从conn_pool_map取出对应host的连接池

2.每个worker都都包含自己独立的连接池和负载均衡上下文

(此处有发现设置RoundRobin负载均衡策略的时候,只有client保持长连接(不换worker)的情况下,才是严格的轮询)

3.同一个上游节点的不同协议(http10, http11, http2, tcp)的连接池都是分开的


连接管理

对于同一个Worker,同一个Host,同一个协议,Envoy会维护一个连接池,连接池中http1有关属性如下(一下情况没有对Limit做说明,实际各个阶段会有stats和config limit来进行限制):

  • busy_clients_ 当前发送了请求,还没处理响应的connection

变多:

-有新的请求需要发送的时候,如果ready_clients非空, 就会把ready_clients_.front()移到busy_clients.front(), 并发送请求;

-向上游的连接connected时,如果 (!pending_requests_.empty() && !ready_clients_.empty()) 就会把ready_clients_.front() 移到busy_clients_;

-当有连接close的时候,如果pending_requests_.size() > (ready_clients_.size() + busy_clients_.size()),就会创建新的connection到busy_clients_并发送请求;

变少:

-connpool被删除,busy_clients_会被清空;

-连接关闭时,如果是正在包含stream_wrapper (正在发送请求)的client,就会从busy_clients移除;

  • ready_clients_ 空闲连接

变多:

-((连接connected的时候 || 有响应完成的时候) && pending_requests_ 为空) ,就会加入ready_clients

变少:


-在有新的请求需要发送的时候,如果ready_clients非空, 就会把ready_clients_.front()移到busy_clients.front()

-向上游的连接connected时,如果 (!pending_requests_.empty() && !ready_clients_.empty()) 就会把ready_clients_.front() 移到busy_clients_

-connpool被删除,ready_clients_会被清空

-空闲的连接被关闭的时候,会从ready_clients_ 中移除

  • pending_requests_ 代发送的请求

变多:
-ready_clients 为空的时候,有新的请求,就会加入到pending_requests

变少:

-当上游连接connected时,发送请求到连接,并从pending_requests 中移除

-请求被终止的时候(超时,或者收到上游的响应结束 ),就会从pending_requests 中移除

1.每个Worker的连接池和负载均衡上下文都是独立的。

2.连接池内的连接都是同一worker,同一upstream host,同一协议。

展开阅读全文

微信扫一扫,分享到朋友圈

解析envoy处理http请求(下):事件模型和连接管理
0

从0到Reverseshell:Mikrotik SMB漏洞实战(CVE-2018–7445)

上一篇

用Flutter实现58App的首页

下一篇

你也可能喜欢

评论已经被关闭。

插入图片
解析envoy处理http请求(下):事件模型和连接管理

长按储存图像,分享给朋友