Envoy 多线程架构处理逻辑分析

1. 概述

Envoy 使用单进程多线程架构。一个单独的主线程(primary thread)控制各种零星的协调任务,而多个工作线程(worker threads)负责执行监听、过滤和转发操作。一旦连接被监听器接受,该连接的整个生命周期将绑定到单个工作线程,这使得 Envoy 的大部分代码是单线程的(令人尴尬的并行),只有少量复杂代码负责处理工作线程之间的协调。

Envoy 被设计为 100% 无阻塞的,对于大多数工作负载,建议将工作线程数量配置为等于机器上的硬件线程数。

2. 多线程架构核心组件

2.1 架构概述

┌─────────────────────────────────────────────────────────────────┐│                   Envoy 多线程架构                             │└─────────────────────────────────────────────────────────────────┘
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐│   主线程         │     │  工作线程        │    │  任务调度        │└──────────┬───────┘     └──────────┬───────┘     └──────────┬───────┘           │                        │                        │           │ 1. 初始化和启动        │                        │           │───────────────────────▶│                        │           │                        │                        │           │                        │ 2. 工作线程初始化      │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 3. 监听器管理          │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 4. 连接接受和处理      │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 5. 任务调度和通信      │           │                        │───────────────────────▶│           │                        │                        │           │ 6. 统计信息收集和更新   │                        │           │◀──────────────────────┴──────────────────────┘

2.2 核心组件 ER 图

┌───────────────────────────────────────────────────────────────────────────────────────────┐│                                       多线程核心组件 ER 图                              │└───────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐│  MainThreadImpl  │     │  WorkerImpl      │     │  ConnectionHandlerImpl  │└──────────┬───────┘     └──────────┬───────┘     └──────────┬───────┘           │                        │                        │           │ 1                   * │                        │ *           │                        │                        │┌──────────▼──────────┐     ┌────▼──────────┐         ┌────▼──────────┐│  ServerImpl       │  │  Dispatcher       │      │  ActiveTcpListener  │└──────────┬──────────┘     └───────────────┘         └───────────────┘           │                        │                        │           │ 1                   1 │                        │ 1           │                        │                        │┌──────────▼──────────┐     ┌────▼──────────┐         ┌────▼──────────┐│  ThreadLocalStorage  │  │  ConnectionImpl  │      │  Network::ServerConnection  │└──────────┬──────────┘     └───────────────┘         └───────────────┘           │                        │                        │           │ 1                   * │                        │ *           │                        │                        │┌──────────▼──────────┐     ┌────▼──────────┐         ┌────▼──────────┐│  ScopeManager      │  │  HttpConnectionManagerImpl  │  │  FilterChain  │└──────────┬──────────┘     └───────────────┘         └───────────────┘           │                        │                        │           │ 1                   1 │                        │ 1           │                        │                        │┌──────────▼──────────┐     ┌────▼──────────┐         ┌────▼──────────┐│  ClusterManagerImpl  │  │  RouterImpl     │      │  FilterManager  │└──────────────────────┘     └───────────────┘         └───────────────┘

3. 主线程和工作线程关系

3.1 线程启动和初始化

// 服务器初始化过程void ServerImpl::initialize() {  // 主线程初始化  main_thread_ = std::make_unique<MainThreadImpl>(*this);
  // 创建工作线程  workers_.reserve(worker_count_);  for (uint32_t i = 0; i < worker_count_; ++i) {    workers_.emplace_back(std::make_unique<WorkerImpl>(*this, i));  }
  // 初始化监听器  listener_manager_->initialize();
  // 启动主事件循环  run();}
// 工作线程启动过程WorkerImpl::WorkerImpl(ServerImpl& server, uint32_t index)    : server_(server),      dispatcher_(server_.api().allocateDispatcher(          absl::StrCat("worker_", index))),      connection_handler_(std::make_unique<ConnectionHandlerImpl>(*dispatcher_,          server_.config().runtime(), server_.api())),      scope_manager_(std::make_unique<ScopeManager>(server.stats())),      thread_factory_(server.api().threadFactory()) {
  // 工作线程初始化任务  dispatcher_->post([this]() {    initializeThreadLocalData();    initializeListeners();  });
  // 启动工作线程  thread_ = thread_factory_.createThread([this]() {    run();  });}

3.2 监听器管理

// 监听器分配到工作线程void ListenerImpl::addOrUpdate(Server::Instance& server) {  // 为每个工作线程创建监听器实例  for (uint32_t i = 0; i < server.workerCount(); ++i) {    auto& worker = server.worker(i);    worker.dispatcher().post([this, &worker]() {      // 在工作线程上创建监听器      worker.connectionHandler().addListener(*this);    });  }}
// 工作线程上的监听器初始化void ConnectionHandlerImpl::addListener(Network::ListenerConfig& config) {  // 创建主动 TCP 监听器  auto active_listener = std::make_unique<ActiveTcpListener>(      *this, config, server_.runtime(), server_.stats());
  // 开始监听  active_listener->listen();
  // 存储监听器  active_tcp_listeners_.push_back(std::move(active_listener));}

4. 任务调度和通信

4.1 任务调度架构

┌─────────────────────────────────────────────────────────────────┐│                     任务调度和通信架构                        │└─────────────────────────────────────────────────────────────────┘
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐│   主线程任务队列  │     │  工作线程任务队列  │    │  任务调度器      │└──────────┬───────┘     └──────────┬───────┘     └──────────┬───────┘           │                        │                        │           │ 1. 主线程提交任务      │                        │           │───────────────────────▶│                        │           │                        │                        │           │                        │ 2. 任务调度器分配任务  │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 3. 工作线程处理任务    │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 4. 任务结果返回        │           │                        │───────────────────────▶│           │                        │                        │           │ 5. 主线程处理结果      │                        │           │◀──────────────────────┴──────────────────────┘

4.2 线程通信实现

// 任务调度实现class TaskDispatcherImpl : public TaskDispatcher {public:  // 将任务调度到特定工作线程  void postToWorker(uint32_t worker_index, TaskCb task) override {    if (worker_index < workers_.size()) {      workers_[worker_index].dispatcher().post(std::move(task));    }  }
  // 将任务调度到任意工作线程(负载均衡)  void postToWorker(TaskCb task, bool force_event) override {    if (workers_.size() == 1) {      workers_[0].dispatcher().post(std::move(task));      return;    }
    // 轮询选择工作线程    uint32_t selected_index = next_worker_.fetch_add(1) % workers_.size();    workers_[selected_index].dispatcher().post(std::move(task));  }
  // 将任务调度到主线程  void postToMain(TaskCb task) override {    main_dispatcher_.post(std::move(task));  }
private:  std::vector<WorkerImpl>& workers_;  Event::Dispatcher& main_dispatcher_;  std::atomic<uint32_t> next_worker_{0};};
// 任务处理过程void WorkerImpl::run() {  // 事件循环  while (true) {    // 处理事件和任务    dispatcher_->run(Event::Dispatcher::RunType::Block);
    // 检查是否需要停止    if (should_stop_) {      break;    }  }}

5. 连接接受和处理

5.1 连接平衡和调度

┌─────────────────────────────────────────────────────────────────┐│                     连接平衡和调度                              │└─────────────────────────────────────────────────────────────────┘
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐│   监听器         │     │  工作线程        │    │  连接调度        │└──────────┬───────┘     └──────────┬───────┘     └──────────┬───────┘           │                        │                        │           │ 1. 监听网络地址        │                        │           │───────────────────────▶│                        │           │                        │                        │           │                        │ 2. 接受新连接         │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 3. 连接调度和平衡      │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 4. 连接处理          │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 5. 连接关闭和清理      │           │                        │───────────────────────▶│           │                        │                        │           │ 6. 统计信息更新        │                        │           │◀──────────────────────┴──────────────────────┘

5.2 连接调度实现

// 连接调度到工作线程void ActiveTcpListener::onAcceptWorker(Network::ConnectionSocketPtr&& socket,                                       bool hand_off_restored_destination_connections,                                       bool rebalanced) {  // 检查是否需要重新平衡连接  if (!rebalanced) {    Network::BalancedConnectionHandler& target_handler =        connection_balancer_.pickTargetHandler(*this);    if (&target_handler != this) {      target_handler.post(std::move(socket));      return;    }  }
  // 创建 ActiveTcpSocket 实例并开始处理  auto active_socket = std::make_unique<ActiveTcpSocket>(*this, std::move(socket),                                                         hand_off_restored_destination_connections);  onSocketAccepted(std::move(active_socket));}
// 连接平衡策略实现class ConnectionBalancerImpl : public Network::BalancedConnectionHandler {public:  ConnectionBalancerImpl(std::vector<Network::BalancedConnectionHandler*>& handlers)      : handlers_(handlers) {}
  Network::BalancedConnectionHandler& pickTargetHandler(      Network::BalancedConnectionHandler& current) override {    // 轮询策略    static thread_local uint32_t index = 0;    index = (index + 1) % handlers_.size();    return *handlers_[index];  }
private:  std::vector<Network::BalancedConnectionHandler*>& handlers_;};

6. 线程本地存储和资源管理

6.1 线程本地存储架构

┌─────────────────────────────────────────────────────────────────┐│                     线程本地存储架构                            │└─────────────────────────────────────────────────────────────────┘
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐│   全局资源       │     │  线程本地存储     │    │  资源访问        │└──────────┬───────┘     └──────────┬───────┘     └──────────┬───────┘           │                        │                        │           │ 1. 资源初始化          │                        │           │───────────────────────▶│                        │           │                        │                        │           │                        │ 2. 线程本地副本创建    │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 3. 资源访问和更新      │           │                        │───────────────────────▶│           │                        │                        │           │                        │ 4. 资源一致性维护      │           │                        │───────────────────────▶│           │                        │                        │           │ 5. 资源销毁和清理      │                        │           │◀──────────────────────┴──────────────────────┘
6.2 线程本地存储实现
// 线程本地存储实现template <typename T>class ThreadLocalImpl : public ThreadLocal<T> {public:  // 获取当前线程的本地值  const T& get() override {    const auto& current_thread_id = Thread::currentThreadId();    return getOrCreateLocalValue(current_thread_id);  }
  // 设置所有线程的本地值(主线程操作)  void set(const T& value) override {    // 首先更新主线程的本地值    getOrCreateLocalValue(Thread::mainThreadId()) = value;
    // 发送更新到所有工作线程    for (auto& worker : workers_) {      worker.dispatcher().post([this, value]() {        const auto& thread_id = Thread::currentThreadId();        getOrCreateLocalValue(thread_id) = value;      });    }  }
private:  // 获取或创建线程本地值  T& getOrCreateLocalValue(const Thread::Id& thread_id) {    auto it = local_values_.find(thread_id);    if (it == local_values_.end()) {      auto emplace_result = local_values_.emplace(thread_id, value_factory_());      it = emplace_result.first;    }    return it->second;  }
  std::unordered_map<Thread::Id, T> local_values_;  std::function<T()> value_factory_;  std::vector<WorkerImpl>& workers_;};
// 线程本地资源访问void ClusterManagerImpl::initializeThreadLocalData() {  // 为每个线程创建线程本地集群数据  thread_local_clusters_ = std::make_unique<ThreadLocalImpl<ThreadLocalCluster>>(      [this]() { return std::make_unique<ThreadLocalCluster>(*this); });}

7. 性能优化和最佳实践

7.1 工作线程配置

# Envoy 工作线程配置admin:  address:    socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:  listeners:  - name: listener_0    address:      socket_address: { address: 0.0.0.0, port_value: 80 }    filter_chains:    - filters:      - name: envoy.filters.network.http_connection_manager        typed_config:          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager          stat_prefix: ingress_http          route_config:            name: local_route            virtual_hosts:            - name: local_service              domains: ["*"]              routes:              - match: { prefix: "/" }                route: { cluster: "local_cluster" }          http_filters:          - name: envoy.filters.http.router
  clusters:  - name: local_cluster    connect_timeout: 0.25s    type: STATIC    lb_policy: ROUND_ROBIN    load_assignment:      cluster_name: local_cluster      endpoints:      - lb_endpoints:        - endpoint:            address:              socket_address: { address: 127.0.0.1, port_value: 8080 }
# 线程配置(通过命令行或配置文件)# 命令行:--concurrency 4# 或配置文件中的配置:# concurrency: 4

7.2 监听器连接平衡

# 监听器连接平衡配置static_resources:  listeners:  - name: listener_0    address:      socket_address: { address: 0.0.0.0, port_value: 80 }    connection_balance_config:      consistent_hash_lb_config:        use_source_ip: true    filter_chains:    - filters:      - name: envoy.filters.network.http_connection_manager        typed_config:          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager          stat_prefix: ingress_http          route_config:            name: local_route            virtual_hosts:            - name: local_service              domains: ["*"]              routes:              - match: { prefix: "/" }                route: { cluster: "local_cluster" }          http_filters:          - name: envoy.filters.http.router

8. 故障排查和监控

8.1 线程相关指标

# 主线程指标envoy.server.version_info - Envoy 版本信息envoy.server.uptime - 服务器启动时间envoy.server.total_connections - 服务器接受的总连接数
# 工作线程指标envoy.server.worker_0.concurrency - 工作线程 0 处理的连接数envoy.server.worker_1.concurrency - 工作线程 1 处理的连接数...envoy.server.total_worker_concurrency - 所有工作线程处理的总连接数envoy.server.dispatcher.0.dispatcher.dispatch_time_ms - 调度器 0 的调度时间envoy.server.dispatcher.1.dispatcher.dispatch_time_ms - 调度器 1 的调度时间...

8.2 调试技巧

# 启用详细的线程日志envoy --config-path envoy.yaml --log-level debug --component-log-level connection:debug,server:debug
# 检查线程配置curl -v http://localhost:9901/stats | grep envoy.server
# 检查工作线程调度curl -v http://localhost:9901/server_info
# 使用 pprof 分析线程性能curl -v http://localhost:9901/pprof/heap > heap.profcurl -v http://localhost:9901/pprof/profile?seconds=30 > profile.profgo tool pprof -http=:8080 profile.prof

9. 总结

Envoy 的多线程架构设计使得它能够高效地处理大量并发连接。通过将连接生命周期绑定到单个工作线程,Envoy 避免了复杂的线程同步问题,并实现了令人尴尬的并行。

核心优势

  1. 高性能:无阻塞设计和线程绑定的连接处理

  2. 可扩展性:通过增加工作线程数量轻松扩展

  3. 简单性:大部分代码是单线程的,简化了开发和维护

  4. 可靠性:线程本地存储和任务调度机制确保资源一致性

未来改进方向

  1. 更智能的任务调度:根据工作负载动态调整线程分配

  2. 更细粒度的资源控制:支持基于连接类型的线程调度

  3. 性能优化:进一步减少线程通信开销

通过深入理解 Envoy 的多线程架构,我们可以更好地配置和优化 Envoy,以满足不同工作负载的性能需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值