ITPub博客

首页 > 应用开发 > IT综合 > Envoy代理深度解析:基于xDS与WASM的微服务治理实践

Envoy代理深度解析:基于xDS与WASM的微服务治理实践

IT综合 作者:bhluo 时间:2026-02-11 14:23:19 0 删除 编辑

# Envoy代理深度解析:基于xDS与WASM的微服务治理实践


在云原生微服务架构中,数据平面作为服务通信的关键组件,其性能与灵活性直接影响整个系统的稳定性。Envoy作为云原生服务网格的事实标准数据平面,通过xDS协议和WebAssembly扩展机制,为微服务提供了强大的流量管理、可观测性和安全能力。


## Envoy核心架构设计


Envoy采用多线程事件驱动架构,每个工作线程独立处理连接,共享配置和连接池,实现高性能的流量转发。


```yaml

# envoy-bootstrap.yaml - 初始配置

admin:

  access_log_path: /tmp/admin_access.log

  address:

    socket_address: { address: 0.0.0.0, port_value: 9901 }


dynamic_resources:

  lds_config:

    resource_api_version: V3

    api_config_source:

      api_type: GRPC

      transport_api_version: V3

      grpc_services:

        - envoy_grpc:

            cluster_name: xds_cluster

      set_node_on_first_message_only: true


static_resources:

  clusters:

  - name: xds_cluster

    type: STATIC

    typed_extension_protocol_options:

      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:

        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions

        explicit_http_config:

          http2_protocol_options: {}

    load_assignment:

      cluster_name: xds_cluster

      endpoints:

      - lb_endpoints:

        - endpoint:

            address:

              socket_address:

                address: control-plane.envoy.svc.cluster.local

                port_value: 5678

```


## xDS协议动态配置机制


xDS(发现服务)协议族允许Envoy从控制平面动态获取配置,实现零停机配置更新。


```protobuf

// resources.proto - xDS资源定义示例

syntax = "proto3";


package envoy.config.route.v3;


message RouteConfiguration {

  string name = 1;

  repeated VirtualHost virtual_hosts = 2;

  

  message VirtualHost {

    string name = 1;

    repeated string domains = 2;

    repeated Route routes = 3;

    

    message Route {

      RouteMatch match = 1;

      RouteAction route = 2;

      

      message RouteMatch {

        oneof path_specifier {

          string prefix = 1;

          string path = 2;

          string safe_regex = 3;

        }

      }

      

      message RouteAction {

        oneof cluster_specifier {

          string cluster = 1;

          WeightedCluster weighted_clusters = 2;

        }

        

        message WeightedCluster {

          repeated ClusterWeight clusters = 1;

          

          message ClusterWeight {

            string name = 1;

            uint32 weight = 2;

          }

        }

      }

    }

  }

}

```


```cpp

// xds-client.cpp - xDS客户端实现示例

#include <iostream>

#include <memory>

#include <string>


#include "envoy/config/core/v3/config_source.pb.h"

#include "envoy/service/discovery/v3/discovery.pb.h"

#include "envoy/config/route/v3/route.pb.h"


class XdsClient {

public:

    XdsClient(const std::string& control_plane_address) 

        : control_plane_addr_(control_plane_address) {}

    

    void subscribeToRoutes() {

        envoy::service::discovery::v3::DiscoveryRequest request;

        

        // 设置订阅信息

        request.set_type_url("type.googleapis.com/envoy.config.route.v3.RouteConfiguration");

        request.mutable_node()->set_id("envoy-proxy-1");

        request.mutable_node()->set_cluster("service-cluster");

        

        // 发送订阅请求

        sendDiscoveryRequest(request);

    }

    

    void handleRouteUpdate(const envoy::config::route::v3::RouteConfiguration& route_config) {

        std::cout << "接收到路由配置更新: " << route_config.name() << std::endl;

        

        // 应用新路由配置

        applyRouteConfiguration(route_config);

        

        // 发送ACK确认

        sendDiscoveryResponseACK(route_config.version_info());

    }

    

private:

    std::string control_plane_addr_;

    

    void sendDiscoveryRequest(const envoy::service::discovery::v3::DiscoveryRequest& request) {

        // 实现gRPC客户端发送逻辑

        std::cout << "发送xDS订阅请求到: " << control_plane_addr_ << std::endl;

    }

    

    void applyRouteConfiguration(const envoy::config::route::v3::RouteConfiguration& config) {

        // 实现配置应用逻辑

        std::cout << "应用路由配置,虚拟主机数量: " << config.virtual_hosts_size() << std::endl;

    }

    

    void sendDiscoveryResponseACK(const std::string& version_info) {

        envoy::service::discovery::v3::DiscoveryRequest ack_request;

        ack_request.set_version_info(version_info);

        ack_request.set_response_nonce("");

        ack_request.set_type_url("type.googleapis.com/envoy.config.route.v3.RouteConfiguration");

        

        sendDiscoveryRequest(ack_request);

    }

};

```


## WebAssembly过滤器扩展


Envoy通过WebAssembly支持自定义过滤器开发,实现业务特定的流量处理逻辑。


```rust

// wasm-filter.rs - WASM过滤器示例

use proxy_wasm::traits::*;

use proxy_wasm::types::*;

use serde::{Deserialize, Serialize};


#[derive(Serialize, Deserialize)]

struct FilterConfig {

    header_name: String,

    header_value: String,

}


proxy_wasm::main! {{

    proxy_wasm::set_log_level(LogLevel::Info);

    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {

        Box::new(HttpHeadersRoot {})

    });

}}


struct HttpHeadersRoot;


impl Context for HttpHeadersRoot {}


impl RootContext for HttpHeadersRoot {

    fn on_configure(&mut self, _: usize) -> bool {

        if let Some(config_bytes) = self.get_configuration() {

            let config: FilterConfig = serde_json::from_slice(&config_bytes).unwrap();

            self.set_property(vec!["config"], Some(config.header_name.as_bytes()));

            true

        } else {

            false

        }

    }

    

    fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {

        Some(Box::new(HttpHeadersFilter {}))

    }

}


struct HttpHeadersFilter;


impl Context for HttpHeadersFilter {}


impl HttpContext for HttpHeadersFilter {

    fn on_http_request_headers(&mut self, _num_headers: usize) -> Action {

        // 读取配置

        let header_name = self.get_property(vec!["config"])

            .unwrap()

            .unwrap();

        

        let header_name_str = String::from_utf8(header_name).unwrap();

        

        // 添加自定义请求头

        self.add_http_request_header(

            &header_name_str,

            "custom-value-from-wasm"

        );

        

        // 记录日志

        self.log(LogLevel::Info, "自定义请求头已添加");

        

        Action::Continue

    }

    

    fn on_http_response_headers(&mut self, _num_headers: usize) -> Action {

        // 添加响应头

        self.add_http_response_header(

            "x-wasm-processed",

            "true"

        );

        

        // 记录处理时间

        self.set_http_response_header(

            "x-processing-time",

            &format!("{}ms", self.get_current_time_nanos() / 1_000_000)

        );

        

        Action::Continue

    }

}

```


## 动态流量管理配置


```yaml

# envoy-route-config.yaml - 路由配置

static_resources:

  listeners:

  - name: http_listener

    address:

      socket_address:

        address: 0.0.0.0

        port_value: 8080

    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: backend_service

              domains: ["*"]

              routes:

              - match:

                  prefix: "/api/v1/"

                route:

                  cluster: backend_cluster

                  retry_policy:

                    retry_on: "5xx,connect-failure"

                    num_retries: 3

                    per_try_timeout: 2s

                  timeout: 5s

                typed_per_filter_config:

                  envoy.filters.http.circuit_breaker:

                    "@type": type.googleapis.com/envoy.extensions.filters.http.circuit_breaker.v3.CircuitBreaker

                    max_connections: 100

                    max_pending_requests: 50

                    max_requests: 200

          <"bfd.j9k5.org.cn"><"iky.j9k5.org.cn"><"ynh.j9k5.org.cn">

          http_filters:

          - name: envoy.filters.http.router

            typed_config:

              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

          

  clusters:

  - name: backend_cluster

    type: STRICT_DNS

    lb_policy: ROUND_ROBIN

    load_assignment:

      cluster_name: backend_cluster

      endpoints:

      - lb_endpoints:

        - endpoint:

            address:

              socket_address:

                address: backend-service.default.svc.cluster.local

                port_value: 80

    circuit_breakers:

      thresholds:

      - priority: DEFAULT

        max_connections: 1000

        max_pending_requests: 1000

        max_requests: 2000

    outlier_detection:

      consecutive_5xx: 5

      interval: 10s

      base_ejection_time: 30s

      max_ejection_percent: 50

```


## 高级流量治理特性


```cpp

// custom-loadbalancer.cpp - 自定义负载均衡器

#include "envoy/upstream/load_balancer.h"

#include "envoy/upstream/upstream.h"


#include <algorithm>

#include <random>


namespace Envoy {

namespace Upstream {


class CustomLoadBalancer : public LoadBalancer {

public:

    CustomLoadBalancer(const PrioritySet& priority_set, 

                      ClusterStats& stats, 

                      Runtime::Loader& runtime,

                      Random::RandomGenerator& random,

                      const envoy::config::cluster::v3::Cluster::CustomLoadBalancerConfig& config)

        : priority_set_(priority_set), 

          stats_(stats), 

          runtime_(runtime),

          random_(random) {

        

        // 解析自定义配置

        parseCustomConfig(config);

    }

    

    HostConstSharedPtr chooseHost(LoadBalancerContext* context) override {

        // 获取可用主机列表

        const auto& hosts = priority_set_.hostSetsPerPriority()[0]->hosts();

        

        if (hosts.empty()) {

            stats_.lb_healthy_panic_.inc();

            return nullptr;

        }

        

        // 基于业务逻辑的选择算法

        HostConstSharedPtr selected_host = nullptr;

        

        // 考虑权重

        if (use_weighted_selection_) {

            selected_host = selectByWeight(hosts, context);

        } 

        // 考虑地域亲和性

        else if (context && !context->downstreamConnection()->remoteAddress()->ip()->addressAsString().empty()) {

            selected_host = selectByLocality(hosts, context);

        }

        // 默认随机选择

        else {

            selected_host = hosts[random_.random() % hosts.size()];

        }

        

        // 记录选择指标

        if (selected_host) {

            stats_.lb_selected_.inc();

        }

        

        return selected_host;

    }

    

private:

    const PrioritySet& priority_set_;

    ClusterStats& stats_;

    Runtime::Loader& runtime_;

    Random::RandomGenerator& random_;

    bool use_weighted_selection_ = true;

    

    HostConstSharedPtr selectByWeight(const HostVector& hosts, LoadBalancerContext* context) {

        uint32_t total_weight = 0;

        

        // 计算总权重

        for (const auto& host : hosts) {

            total_weight += host->weight();

        }

        

        if (total_weight == 0) {

            return hosts[random_.random() % hosts.size()];

        }

        

        // 基于权重随机选择

        uint32_t selected = random_.random() % total_weight;

        uint32_t cumulative = 0;

        

        for (const auto& host : hosts) {

            cumulative += host->weight();

            if (selected < cumulative) {

                return host;

            }

        }

        

        return hosts.back();

    }

    

    HostConstSharedPtr selectByLocality(const HostVector& hosts, LoadBalancerContext* context) {

        // 实现地域亲和性选择逻辑

        const std::string client_region = extractClientRegion(context);

        

        // 优先选择同地域主机

        for (const auto& host : hosts) {

            if (host->locality().region() == client_region) {

                return host;

            }

        }

        

        // 回退到随机选择

        return hosts[random_.random() % hosts.size()];

    }

    

    std::string extractClientRegion(LoadBalancerContext* context) {

        // 从上下文提取客户端地域信息

        return "default";

    }

    

    void parseCustomConfig(const envoy::config::cluster::v3::Cluster::CustomLoadBalancerConfig& config) {

        // 解析自定义负载均衡配置

        const auto& typed_config = config.typed_config();

        // 解析配置逻辑...

    }

};


} // namespace Upstream

} // namespace Envoy

```


## 安全策略实施


```yaml

# envoy-security-config.yaml - 安全配置

static_resources:

  listeners:

  - name: https_listener

    address:

      socket_address:

        address: 0.0.0.0

        port_value: 8443

    filter_chains:

    - filter_chain_match:

        server_names: ["api.example.com"]

      transport_socket:

        name: envoy.transport_sockets.tls

        typed_config:

          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext

          common_tls_context:

            tls_certificates:

            - certificate_chain: { filename: "/etc/ssl/certs/server.crt" }

              private_key: { filename: "/etc/ssl/private/server.key" }

            validation_context:

              trusted_ca: { filename: "/etc/ssl/certs/ca.crt" }

              verify_subject_alt_name: ["api.example.com"]

          

          require_client_certificate: true

          

      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: https_ingress

          

          http_filters:

          - name: envoy.filters.http.rbac

            typed_config:

              "@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC

              rules:

                action: ALLOW

                policies:

                  "service-access":

                    permissions:

                    - any: true

                    principals:

                    - authenticated:

                        principal_name:

                          exact: "spiffe://cluster.local/ns/default/sa/frontend"

          <"nyr.j9k5.org.cn"><"ytn.j9k5.org.cn"><"rtg.j9k5.org.cn">

          - name: envoy.filters.http.jwt_authn

            typed_config:

              "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication

              providers:

                my_provider:

                  issuer: "https://auth.example.com"

                  audiences:

                  - "api.example.com"

                  remote_jwks:

                    http_uri:

                      uri: "https://auth.example.com/.well-known/jwks.json"

                      cluster: auth_service

                    cache_duration: { seconds: 300 }

          

          - name: envoy.filters.http.rate_limit

            typed_config:

              "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit

              domain: api_gateway

              failure_mode_deny: false

              rate_limit_service:

                grpc_service:

                  envoy_grpc:

                    cluster_name: rate_limit_service

                  timeout: 0.25s

          

          - name: envoy.filters.http.router

```


## 可观测性配置


```yaml

# envoy-telemetry.yaml - 遥测配置

static_resources:

  listeners:

  - name: metrics_listener

    address:

      socket_address:

        address: 0.0.0.0

        port_value: 9102

    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: stats

          route_config:

            name: local_stats_route

            virtual_hosts:

            - name: stats

              domains: ["*"]

              routes:

              - match: { prefix: "/stats" }

                route: { cluster: admin_interface }

          http_filters:

          - name: envoy.filters.http.router


stats_sinks:

- name: envoy.stat_sinks.prometheus

  typed_config:

    "@type": type.googleapis.com/envoy.extensions.stat_sinks.prometheus.v3.PrometheusSinkConfig

    emit_tags_as_labels: true

    use_text_based_protocol: true


- name: envoy.stat_sinks.open_telemetry

  typed_config:

    "@type": type.googleapis.com/envoy.extensions.stat_sinks.open_telemetry.v3.OpenTelemetrySinkConfig

    grpc_service:

      envoy_grpc:

        cluster_name: otel-collector


stats_config:

  stats_tags:

  - tag_name: service_name

    fixed_value: "backend-service"

  - tag_name: pod_name

    regex: "^pod_name=(.+)$"

  

  use_all_default_tags: true


tracing:

  http:

    name: envoy.tracers.opentelemetry

    typed_config:

      "@type": type.googleapis.com/envoy.extensions.tracers.opentelemetry.v3.OpenTelemetryConfig

      grpc_service:

        envoy_grpc:

          cluster_name: otel-collector

        timeout: 0.250s

      service_name: "envoy-proxy"

```


基于xDS协议与WebAssembly的Envoy数据平面,为云原生微服务架构提供了高度灵活和动态的流量治理能力。通过声明式配置和运行时扩展,企业可以构建适应复杂业务需求的微服务通信基础设施。在实际部署中,建议结合具体业务场景设计流量策略,并建立完善的监控告警体系,确保服务网格的稳定运行和持续优化。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3110456/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    933672