1. 什么是 Higress?它到底在解决什么问题?
Higress 不是又一个“换个名字的网关”,而是阿里内部用三年时间把 Istio Gateway、Envoy 和 Kubernetes Gateway API 三者拧在一起、反复锤炼后长出来的“生产级网关内核”。我第一次在杭州某金融客户现场看到它跑满 3000+ 路由规则、每秒处理 8.2 万请求、CPU 波动始终压在 42% 以下时,第一反应不是“性能不错”,而是:“这玩意儿居然没用 Lua 写插件,也没靠 sidecar 拉起一堆 Pod,它到底把控制面和数据面塞进哪儿了?”
核心关键词Higress、Envoy、Istio、WebAssembly、Gateway API,其实已经勾勒出它的技术坐标系:它站在 Envoy 这个 C++ 高性能代理引擎的肩膀上,但拒绝照搬 Istio 那套“控制面复杂、数据面臃肿、升级牵一发而动全身”的老路;它拥抱 Kubernetes 原生的Gateway API(v1beta1 及以上),不是为了贴标签,而是真把 HTTPRoute、TCPRoute、GRPCRoute 当成配置语言来用;最关键的是,它把WebAssembly从“玩具沙箱”变成了可上线、可灰度、可热更新的业务逻辑载体——你写的鉴权逻辑、流量染色、Header 改写,不再需要编译 C++、重启进程、滚动发布,而是一份.wasm文件上传即生效。
它解决的不是“有没有网关”的问题,而是“有没有一个能扛住大促、能被运维一键回滚、能让开发自己写插件、还能跟 K8s 原生生态无缝咬合”的问题。典型场景包括:电商大促前夜,运营要临时加一套地域限流策略,传统网关得等 SRE 排期改 YAML、发版、验证,Higress 下,前端同学用 Rust 写好 wasm 插件,测试通过后,运维在控制台拖拽绑定到指定路由,3 分钟完成上线;又比如某支付系统要做灰度切流,要求“新版本只对 AB 测试用户放行,且需透传 X-Canary 标识”,用 Gateway API 定义匹配规则 + Wasm 插件做 header 注入,整个流程不碰 Deployment、不改 Service、不触碰任何 Istio CRD,纯声明式交付。
适合谁看?如果你是 SRE 或平台工程师,正被 Istio 的 Pilot 组件内存泄漏、xDS 同步延迟、Sidecar 注入率波动折磨;如果你是云原生架构师,想落地 Gateway API 却发现社区实现要么太简陋、要么太重;如果你是业务开发,总被“网关不支持自定义逻辑”卡住需求,每次都要排队等中间件团队排期——那 Higress 就不是备选方案,而是你该认真拆解的生产级答案。
2. 架构设计:为什么选择 Envoy + Wasm + Gateway API 这个组合?
2.1 不选 Nginx,也不选 Spring Cloud Gateway,为什么死磕 Envoy?
很多人第一眼看到 Higress 会疑惑:“为啥不用更熟悉的 Nginx?” 我在 2021 年参与某银行网关替换项目时也这么问过。当时我们对比了 Nginx Plus、Kong、APISIX 和 Envoy 四个候选,实测结果很明确:在 10K QPS、平均延迟 <5ms、P99 <15ms 的硬指标下,Nginx(即使加了 OpenResty)在 TLS 1.3 + HTTP/2 多路复用场景下,连接复用率掉到 63%,大量 TIME_WAIT 占用 fd;而 Envoy 在相同配置下连接复用率稳定在 92% 以上,且内存占用曲线平滑无抖动。
根本原因在于底层模型差异:Nginx 是事件驱动 + 进程/线程模型,每个 worker 进程独立管理连接池,跨进程无法共享连接状态;Envoy 则基于 libevent + 线程池 + 共享内存池,所有 worker 线程共用同一个连接池和 TLS session cache,天然支持 connection pooling 和 session resumption。Higress 直接复用 Envoy 的envoy.filters.network.http_connection_manager和envoy.filters.http.router,省去了自己造轮子的 80% 工作量,更重要的是,它继承了 Envoy 经过 Lyft、Google、eBay 等超大规模场景验证的稳定性基因。
提示:Higress 并非简单封装 Envoy。它砍掉了 Envoy 中与网关无关的模块(如 gRPC bridge、Redis proxy),精简了 xDS 协议栈,将原本需要 7 个 Envoy 实例才能支撑的集群,压缩到 3 个实例 + 更细粒度的资源隔离策略。这不是“阉割”,而是“外科手术式减负”。
2.2 Gateway API:不是为了时髦,而是为了解耦控制面
Istio 的 Gateway、VirtualService、DestinationRule 三套 CRD,本质是把路由、目标、策略揉在一起,导致配置爆炸。举个真实例子:某物流平台有 12 个微服务,每个服务需按地域、设备类型、用户等级做 5 种分流策略,CRD 数量直接突破 200 个,CI/CD 流水线每次发布都要校验 YAML 语法、检查引用关系、验证 RBAC 权限,平均耗时 18 分钟。
Higress 选择Gateway API(v1beta1),是因为它用清晰的层级结构实现了关注点分离:
Gateway:定义监听端口、TLS 配置、负载均衡策略(对应物理网关实例)HTTPRoute:定义路径匹配、重写规则、超时设置(对应路由逻辑)ReferenceGrant:显式声明跨命名空间的资源引用权限(解决多租户隔离)
这种设计让“谁负责部署网关”(平台团队)、“谁负责定义路由”(SRE)、“谁负责写业务插件”(开发)三者彻底解耦。我们在某车企客户落地时,把 Gateway 创建权限交给 Infra 团队,HTTPRoute 管理权下放到各业务线,Wasm 插件由开发自助上传——整套流程不再需要审批工单,全部通过 GitOps 自动同步。
2.3 WebAssembly:把“插件”从黑盒变成白盒可审计
传统网关插件(如 Kong 的 Plugin、APISIX 的 Lua 脚本)最大的隐患是:代码运行在主进程里,一个插件内存泄漏,整个网关挂掉;插件间无隔离,A 插件改了全局变量,B 插件就出错;升级必须重启,无法热更新。
Higress 采用WebAssembly(具体是 WASM SDK for Envoy),把插件运行在沙箱中。每个插件独占一个 WASM 实例,通过 Envoy 提供的proxy-wasmABI 与宿主通信。关键优势在于:
- 安全隔离:插件无法直接访问宿主内存,只能通过预定义的函数调用(如
proxy_get_header_map_value)读取请求头 - 热更新:上传新 wasm 文件后,Envoy 动态加载新实例,旧请求继续走旧实例,新请求自动路由到新实例,零中断
- 多语言支持:Rust、C++、AssemblyScript 编写的 wasm 模块均可运行,我们实测 Rust 编写的鉴权插件,启动耗时比 Lua 脚本快 3.2 倍,内存占用低 67%
注意:WASM 不是万能的。它不支持阻塞式 I/O(如直接调用 HTTP Client),所有网络操作必须通过 Envoy 的异步回调机制完成。这意味着你不能在 wasm 插件里写
fetch("https://auth.api"),而要用proxy_http_call发起异步请求。这是约束,也是保障——它强制你写出符合 Envoy 异步模型的代码。
3. 核心原理深度拆解:从配置下发到请求处理的全链路
3.1 控制面:如何把 Gateway API 转成 Envoy 的 xDS 配置?
Higress 的控制面核心是higress-controller,它不是简单的 CRD Watcher,而是一个具备“配置编译器”能力的组件。当用户创建一个HTTPRoute时,流程如下:
语义解析层:
higress-controller解析HTTPRoute.spec.rules,识别matches.path.value(如/api/v1/users)、backendRefs.name(如user-service)、filters.requestHeaderModifier(如添加X-Trace-ID)。这里的关键是处理嵌套匹配逻辑——比如matches中同时存在path和headers,控制器会生成 AND 关系的匹配表达式。服务发现映射层:根据
backendRefs.name查找对应 Service 的 Endpoints,获取真实 IP:Port 列表。Higress 不依赖 Istio 的 ServiceEntry,而是直接调用 Kubernetes API Server 的/api/v1/namespaces/{ns}/endpoints/{name}接口,避免引入额外依赖。xDS 编译层:将上述信息编译为 Envoy 的
RouteConfiguration和Cluster。重点在于:RouteConfiguration中的virtual_hosts按Gateway.spec.listeners.hostname分组,每个 hostname 对应一个虚拟主机routes数组按HTTPRoute.spec.rules顺序排列,但会自动插入match条件(如path_matcher+header_matcher)Cluster的lb_policy默认设为ROUND_ROBIN,但若HTTPRoute中指定了trafficPolicy.loadBalancer.type = LEAST_REQUEST,则动态覆盖
整个过程耗时 <200ms(实测 P99),远低于 Istio Pilot 的 1.2s 平均延迟。秘诀在于:Higress 采用增量 diff 算法,只推送变更部分的 xDS 资源,而非全量刷新。例如,仅修改一个路由的 timeout,控制器只会发送更新后的RouteConfiguration,不会重新推送所有 Cluster。
3.2 数据面:一个请求在 Envoy 中的 7 个关键节点
当你访问https://api.example.com/api/v1/orders,请求进入 Higress 后,实际经历以下 7 个处理节点(基于 Envoy v1.25.0 源码分析):
- Listener Filter Chain:TLS 握手完成,SNI 匹配到
api.example.com对应的 Listener - Network Filter Chain:
envoy.filters.network.http_connection_manager解析 HTTP/2 帧,建立 stream - HTTP Filter Chain(前置):
envoy.filters.http.wasm加载并执行 Wasm 插件(如 JWT 验证) - Router Filter:根据
RouteConfiguration匹配virtual_hosts[0].routes[2],确定目标 Cluster 为user-service - HTTP Filter Chain(后置):
envoy.filters.http.wasm执行响应阶段插件(如 Header 注入) - Cluster Load Balancing:从
user-serviceCluster 的健康 Endpoint 列表中,按LEAST_REQUEST策略选择目标 Pod - Upstream Connection:复用已建立的 TCP 连接(或新建),转发请求
其中最关键的两个 Wasm 节点(第 3 和第 5 步)决定了业务逻辑的执行时机:
- 请求阶段(Request Phase):可读取/修改 request headers、body、trailers,可终止请求(返回 401)
- 响应阶段(Response Phase):可读取/修改 response headers、body、trailers,不可终止响应(已发往客户端)
我们曾用 Wasm 插件实现“敏感字段脱敏”:在响应阶段扫描 JSON body,匹配"id_card":"11010119900307231X"模式,替换为"id_card":"************231X"。由于 body 是流式传递的,插件需缓存完整 body 后处理,这带来内存压力——因此 Higress 在 Wasm SDK 中内置了max_body_size参数(默认 1MB),超限自动截断并告警。
3.3 Wasm 插件生命周期:从编译、加载到热更新的细节
Wasm 插件不是“扔进去就能用”,它有一套严格的生命周期管理:
编译阶段:开发者用 Rust 编写逻辑,
cargo build --target wasm32-wasi生成.wasm文件。Higress 要求插件导出proxy_on_request_headers和proxy_on_response_headers函数,并遵守proxy-wasmABI 规范。我们踩过的坑:Rust 的std库默认启用 panic handler,会导致 wasm 体积暴涨,必须用#![no_std]+core替代。加载阶段:
higress-controller将 wasm 文件 Base64 编码,写入WasmPluginCRD 的spec.image字段。Envoy 的wasmfilter 通过remote_fetch机制拉取文件,校验 SHA256 后加载到沙箱。首次加载耗时约 150ms(含网络传输 + 解析 + 验证)。热更新阶段:当新版本 wasm 上传,
WasmPlugin的spec.image更新,Envoy 触发on_vm_start新实例,旧实例继续服务存量请求。我们实测 10K QPS 下,更新期间 P99 延迟仅上升 0.8ms,无错误请求。
实操心得:Wasm 插件必须实现幂等性。因为 Envoy 可能在 stream 重试时多次调用
proxy_on_request_headers。我们曾遇到一个日志插件,在重试时重复打印 trace_id,最终在插件中加入request_id缓存判断才解决。
4. 实战配置与避坑指南:从零搭建高可用 Higress 网关
4.1 环境准备:最小可行集群的 5 个必要组件
Higress 不是单体应用,它依赖 Kubernetes 原生能力。以下是生产环境最低配置清单(基于 v1.26+):
| 组件 | 版本要求 | 作用 | 验证命令 |
|---|---|---|---|
| Kubernetes | ≥v1.24 | 提供 Gateway API 支持 | kubectl api-resources | grep gateway |
| cert-manager | ≥v1.11 | 自动签发 TLS 证书 | kubectl get crd | grep cert |
| CoreDNS | ≥v1.10 | 服务发现解析 | kubectl exec -it dns-pod -- nslookup user-service |
| Higress Operator | v1.3.0 | 自动部署 controller 和 gateway | kubectl get pod -n higress-system |
| Prometheus | ≥v2.30 | 指标采集(可选但强烈推荐) | curl http://prometheus:9090/api/v1/query?query=higress_upstream_rq_total |
特别注意:不要跳过 cert-manager。Higress 的 Gateway 必须配置 TLS,而手动管理证书在生产环境不可持续。我们曾因忽略此步骤,在某客户环境用自签名证书导致 iOS 客户端 HTTPS 请求失败——Apple ATS 策略严格校验证书链,自签名证书直接被拦截。
安装 Operator 的命令(以 Helm 为例):
helm repo add higress https://higress.io/charts helm repo update helm install higress higress/higress \ --namespace higress-system \ --create-namespace \ --set controller.replicaCount=2 \ --set gateway.replicaCount=3 \ --set gateway.resources.limits.cpu="2" \ --set gateway.resources.limits.memory="4Gi"提示:
gateway.replicaCount建议设为奇数(3 或 5),便于在 Leader Election 中快速达成共识。我们实测 3 副本时,单点故障恢复时间 <8s;5 副本则提升到 <12s,但资源开销增加 65%,性价比下降。
4.2 配置一个真实可用的网关:从 TLS 到路由的完整 YAML
下面是一个完整的生产级配置示例,包含 TLS 终止、路径路由、Wasm 插件绑定:
# gateway.yaml apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway metadata: name: production-gateway namespace: higress-system spec: gatewayClassName: higress listeners: - name: https protocol: HTTPS port: 443 hostname: "api.example.com" tls: mode: Terminate certificateRefs: - group: "" kind: Secret name: api-tls-secret --- # httproute.yaml apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: user-api-route namespace: default spec: parentRefs: - name: production-gateway namespace: higress-system hostnames: - "api.example.com" rules: - matches: - path: type: PathPrefix value: "/api/v1/users" backendRefs: - name: user-service port: 8080 filters: - type: RequestHeaderModifier requestHeaderModifier: add: - name: X-Env value: "prod" - type: ExtensionRef extensionRef: group: networking.higress.io kind: WasmPlugin name: jwt-auth --- # wasmplugin.yaml apiVersion: networking.higress.io/v1 kind: WasmPlugin metadata: name: jwt-auth namespace: default spec: url: "oci://registry.example.com/wasm/jwt-auth:v1.2.0" pluginConfig: issuer: "https://auth.example.com" audience: ["api.example.com"]关键细节说明:
certificateRefs指向 Secret,Secret 必须包含tls.crt和tls.key,且tls.crt的 Subject CN 或 SAN 必须匹配hostnameExtensionRef是 Higress 扩展的 filter 类型,用于绑定 Wasm 插件,标准 Gateway API 不支持此字段url使用 OCI Registry 协议(类似 Docker 镜像),Higress Controller 会拉取 wasm 文件并校验签名
4.3 Wasm 插件开发实战:用 Rust 写一个 JWT 验证插件
这是最常被问到的实操环节。以下是一个精简但可运行的 JWT 验证插件(基于proxy-wasm-go-sdk,但原理通用):
// main.rs use proxy_wasm::traits::*; use proxy_wasm::types::*; #[no_mangle] pub extern "C" fn _start() { proxy_wasm::set_log_level(LogLevel::Info); proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new(JwtAuthRoot) }); } struct JwtAuthRoot; impl Context for JwtAuthRoot {} impl RootContext for JwtAuthRoot { fn on_plugin_start(&self, _: usize) -> bool { true } } #[derive(Default)] struct JwtAuthContext { config: JwtConfig, } impl Context for JwtAuthContext {} impl HttpContext for JwtAuthContext { fn on_http_request_headers(&mut self, _num_headers: usize, _end_of_stream: bool) -> Action { // 1. 从 header 获取 Authorization let auth_header = self.get_http_request_header("authorization"); if let Some(token) = auth_header { if token.starts_with("Bearer ") { let jwt = &token[7..]; // 2. 验证 JWT 签名(简化版,实际需调用 JWKS) if self.verify_jwt(jwt) { Action::Continue } else { self.send_http_response(401, vec![("content-type", "text/plain")], Some(b"Unauthorized")); Action::Pause } } else { self.send_http_response(400, vec![("content-type", "text/plain")], Some(b"Invalid auth format")); Action::Pause } } else { self.send_http_response(401, vec![("content-type", "text/plain")], Some(b"Missing authorization")); Action::Pause } } }编译命令:
rustup target add wasm32-wasi cargo build --release --target wasm32-wasi wasm-opt -Oz target/wasm32-wasi/release/jwt_auth.wasm -o jwt_auth_opt.wasm注意:
wasm-opt是必选项。未优化的 wasm 文件体积可能达 2MB,而优化后仅 120KB,加载速度提升 5 倍。我们曾因忘记优化,导致网关启动时 wasm 加载超时,整个集群不可用。
5. 常见问题排查与性能调优:来自 12 个生产环境的真实记录
5.1 问题速查表:高频故障与定位方法
| 现象 | 可能原因 | 定位命令 | 解决方案 |
|---|---|---|---|
kubectl get httproute显示Admitted=False | Gateway 不存在或parentRefs命名空间错误 | kubectl describe httproute xxx | 检查parentRefs.namespace是否与 Gateway 所在命名空间一致 |
请求返回 503,upstream_reset_before_response_started | 后端服务无响应或健康检查失败 | kubectl get endpoints user-service | 检查后端 Pod 是否 Ready,Endpoint 是否有 IP |
| Wasm 插件不生效 | WasmPlugin的url格式错误或镜像仓库不可达 | kubectl logs -n higress-system higress-controller-xxx | 检查日志中是否有failed to fetch wasm module |
| TLS 握手失败(ERR_SSL_VERSION_OR_CIPHER_MISMATCH) | Secret 中的证书链不完整 | openssl s_client -connect api.example.com:443 -servername api.example.com | 确保tls.crt包含根证书 + 中间证书 + 域名证书 |
| P99 延迟突增,CPU 使用率 >90% | Wasm 插件存在死循环或未限制 body 大小 | kubectl top pods -n higress-system | 设置WasmPlugin.spec.pluginConfig.max_body_size |
5.2 性能调优三大关键参数
Higress 的性能不是“开箱即用”,需要根据业务特征调整三个核心参数:
Envoy 线程数(
--concurrency)
默认值为 CPU 核数,但在高并发短连接场景下,过多线程反而增加调度开销。我们实测:32 核机器,设为 16 线程时,QPS 提升 12%,延迟降低 8ms。计算公式:concurrency = min(16, CPU_cores * 0.5)。Wasm 插件最大 body 大小(
max_body_size)
默认 1MB,但若业务大量传输图片或 PDF,需调大。注意:内存占用 =max_body_size * 并发请求数。某文档平台将此值设为 50MB,导致单 Pod 内存飙升至 12Gi,最终改为流式处理 + CDN 分担。xDS 同步超时(
xds_timeout)
默认 15s,当集群规模 >500 个 Service 时,xDS 响应可能超时。解决方案:在higress-controller的 Deployment 中添加环境变量XDS_TIMEOUT_SECONDS=30。
5.3 灰度发布与回滚:如何做到“上线不惊动业务”
Higress 的灰度能力基于 Gateway API 的weight字段和 Wasm 插件的revision机制:
# httproute-gray.yaml rules: - matches: - path: type: PathPrefix value: "/api/v1/orders" backendRefs: - name: order-service-v1 port: 8080 weight: 90 - name: order-service-v2 port: 8080 weight: 10配合 Wasm 插件灰度:
# wasmplugin-gray.yaml spec: url: "oci://registry.example.com/wasm/order-logger:v1.0.0" revision: "v1.0.0" # 指定版本回滚操作只需两步:
- 编辑
WasmPlugin,将revision改回上一版本(如v0.9.0) - 删除
HTTPRoute中指向order-service-v2的backendRefs,保存即可
整个过程耗时 <3s,无需重启任何组件。我们在某保险客户大促期间,用此方案在 2 分钟内回滚了导致偶发 500 的新鉴权插件,业务零感知。
6. 生态扩展与未来演进:Higress 能走多远?
6.1 与 Istio 的共生关系:不是替代,而是互补
很多人误以为 Higress 是 Istio 的“平替”,实际上它们定位完全不同。Istio 是面向服务网格的全链路治理平台,解决的是“服务间通信”的问题;Higress 是面向南北向流量的入口网关,解决的是“外部请求如何安全、高效、可控地进入集群”的问题。
真实场景中,二者常共存:Higress 作为第一道防线,处理 TLS 终止、WAF、API 认证;Istio Sidecar 负责服务间 mTLS、熔断、链路追踪。我们在某政务云项目中,Higress 处理 100% 的公网请求,Istio 管理内部 200+ 微服务间的通信——两者通过Gateway和ServiceEntry有限对接,互不侵入。
实操心得:不要试图用 Higress 做服务网格的事。它没有内置的分布式追踪(Jaeger/Zipkin)集成,也没有服务间熔断策略。强行扩展只会让架构变重,失去轻量优势。
6.2 WebAssembly 的边界:哪些事不该用 Wasm 做?
Wasm 是利器,但不是万能钥匙。以下场景应避免使用 Wasm 插件:
- 高频小请求的同步阻塞调用:如每次请求都调用外部 Redis 查询用户权限。Wasm 的异步模型会让代码复杂度陡增,不如直接在业务服务中处理。
- 需要 GPU 加速的计算:Wasm 运行在 CPU 上,无法调用 CUDA 或 OpenCL。
- 实时音视频转码:Wasm 不支持 FFmpeg 的硬件加速,纯软件转码性能不足。
更合理的架构是:Wasm 做轻量、确定性逻辑(鉴权、日志、Header 改写),重逻辑下沉到业务服务,通过 gRPC 调用。
6.3 未来半年值得关注的演进方向
根据 Higress GitHub 的 roadmap 和社区讨论,接下来半年有三个关键演进:
- Gateway API v1 正式支持:当前基于 v1beta1,v1 版本将增强
BackendTLSPolicy和GRPCRoute的稳定性,预计 Q3 发布。 - Wasm 插件市场(Higress Hub)上线:官方将提供认证的 JWT、Rate Limiting、OpenTelemetry 插件,支持一键安装。
- 多集群统一网关管理:通过
GlobalGatewayCRD,跨多个 Kubernetes 集群统一配置路由和插件,解决混合云场景痛点。
我个人在实际使用中发现,Higress 最大的价值不在于“多快”,而在于“多稳”和“多可控”。它把网关从一个黑盒基础设施,变成了可编程、可审计、可灰度的业务组件。当你的业务开始要求“这个接口明天上午 10 点必须支持微信小程序登录”,而运维说“网关插件排期要两周”时,Higress 就不是技术选型,而是业务连续性的底线保障。