1. 从 Istio 到 Higress:云原生网关的演进逻辑
1.1 为什么 Envoy 是云原生网关的基石
聊 Higress 之前,得先把 Envoy 这个地基说清楚。Envoy 是 Lyft 开源的高性能 L4/L7 代理,用 C++ 编写,核心设计理念是基于事件驱动的多线程架构加可插拔的过滤器链。它的线程模型很讲究:主线程负责配置更新和 xDS 协议交互,Worker 线程各自独立处理连接,每个 Worker 跑一个事件循环,连接不跨线程,避免了锁竞争。实测下来,单核 QPS 能跑到几万级别,这个性能底子在网关场景里非常关键。
Envoy 的过滤器链分四层:Listener Filter、Network Filter、HTTP Filter、Upstream Filter。HTTP 层的扩展点最丰富,Wasm 插件就是挂在这一层。理解这个分层对后面分析 Higress 的 Wasm 扩展机制至关重要,因为 Higress 的插件能力本质上是在 Envoy 的 HTTP Filter Chain 里做文章。
另一个关键点是xDS 协议。Envoy 本身不存储配置,所有路由、集群、监听器信息都通过 xDS(Discovery Service)从控制面动态下发。这套机制让 Envoy 天然适合做数据面,控制面可以独立演进。Higress 的架构选择,很大程度上就是围绕"如何做一个更轻、更快的控制面"展开的。
1.2 Istio 的架构优势与落地痛点
Istio 是 Service Mesh 领域的标杆,控制面用 Go 写的 Pilot 组件统一管理流量规则,数据面默认用 Envoy。它的核心价值在于把服务治理能力从业务代码里剥离出来,通过 Sidecar 模式实现流量管理、安全、可观测性。这套思路在微服务场景下非常优雅。
但 Istio 在实际落地时,有几个绕不开的痛点。第一是资源开销,每个 Pod 注入一个 Sidecar,内存占用动辄 50-100MB,几千个 Pod 的集群光 Sidecar 就要吃掉大量资源。第二是运维复杂度,Istio 的 CRD 一大堆,VirtualService、DestinationRule、Gateway、ServiceEntry 之间的关系错综复杂,排查问题经常要在多个 CRD 之间来回跳。第三是配置生效延迟,Pilot 推送配置到 Envoy 需要时间,大规模集群下这个延迟可能到秒级甚至更长。
更关键的是,很多团队其实并不需要完整的 Service Mesh,他们只是想要一个好用的南北向入口网关。Istio 的 Gateway 虽然能干活,但配置繁琐,扩展能力也受限于 Envoy 原生 Filter。这就给 Higress 留出了空间。
1.3 Higress 的定位:站在 Istio 肩膀上的轻量网关
Higress 是阿里开源的云原生网关,它的定位很明确:兼容 Istio 生态,但专注于网关场景,做得更轻、更快、扩展性更强。它复用了 Istio 的控制面能力(准确说是兼容 Istio API),数据面依然是 Envoy,但在控制面做了大量精简和优化。
Higress 的核心卖点有三个:一是Wasm 插件扩展,用 Wasm 替代传统的 Lua 脚本,性能和安全性都更好;二是配置秒级生效,通过优化 xDS 推送机制,配置变更几乎实时生效;三是多协议支持,HTTP、gRPC、Dubbo、MQTT 都能接,这对国内很多用 Dubbo 的团队很友好。
从架构上看,Higress 的控制面叫Higress Controller,它监听 K8s 的 Ingress、Gateway API、以及自定义的 WasmPlugin 等 CRD,转换成 Envoy 能理解的 xDS 配置下发。数据面就是标准的 Envoy,但 Higress 对 Envoy 做了一些定制,比如内置了一些常用插件、优化了配置加载逻辑。
2. Higress 核心架构拆解
2.1 控制面与数据面的职责划分
Higress 的架构可以简单理解成"一个 Controller + N 个 Envoy 实例"。Controller 负责配置管理,Envoy 负责流量转发。这个划分和 Istio 类似,但 Higress 的 Controller 更轻量,它不依赖 Istiod,而是自己实现了一套配置转换逻辑。
控制面的核心工作流是这样的:用户创建 Ingress 或 Gateway API 资源,Higress Controller 监听到变更,把 K8s 资源转换成 Envoy 的 xDS 配置(主要是 Listener、Route、Cluster、Endpoint 四类),然后通过 gRPC 推送给 Envoy。Envoy 收到配置后热更新,整个过程不需要重启。
这里有个设计细节值得说:Higress 的 Controller 用了增量推送机制。传统的 xDS 推送是全量下发,配置大了之后推送慢、内存占用高。Higress 通过对比配置差异,只推送变化的部分,实测在几千条路由的场景下,配置生效时间能控制在毫秒级。这个优化对大规模集群很关键。
数据面这边,Higress 对 Envoy 的定制主要在两方面:一是内置插件,把常用的鉴权、限流、跨域等能力做成 Wasm 插件预置进去;二是配置优化,比如调整了 Envoy 的线程数、连接池参数,让它在网关场景下表现更好。
2.2 Wasm 插件机制:Higress 的扩展利器
Wasm(WebAssembly)是 Higress 最核心的扩展机制。传统的 Envoy 扩展要么改 C++ 代码重新编译,要么用 Lua 脚本(性能差)。Wasm 的好处是沙箱隔离、多语言支持、热加载。你可以用 Go、Rust、C++ 写插件,编译成 Wasm 字节码,运行时动态加载,不用重启 Envoy。
Higress 的 Wasm 插件运行在 Envoy 的Wasm Runtime里,底层用的是 V8 引擎(没错,就是 Chrome 那个 V8)。每个插件跑在独立的沙箱里,插件崩溃不会影响 Envoy 主进程。插件通过ABI(Application Binary Interface)和 Envoy 交互,可以访问请求头、请求体、响应头等数据,也能调用外部服务。
写一个 Higress Wasm 插件的基本流程是这样的:用 Go 的proxy-wasm-go-sdk定义插件逻辑,实现OnHttpRequestHeaders、OnHttpRequestBody等回调函数,编译成.wasm文件,然后通过 WasmPlugin CRD 挂载到指定路由上。整个过程不需要改 Envoy 代码,也不需要重启网关。
这里有个实操心得:Wasm 插件虽然方便,但性能不是免费的。每次请求进出插件都有序列化/反序列化开销,复杂插件可能增加几毫秒延迟。我的经验是,鉴权、限流这类轻量逻辑用 Wasm 没问题,但如果要做复杂的请求体转换,最好评估一下性能影响。
2.3 多协议支持的技术实现
Higress 支持 HTTP、gRPC、Dubbo、MQTT 等多种协议,这在网关产品里不多见。实现方式上,HTTP 和 gRPC 是 Envoy 原生支持的,Dubbo 和 MQTT 则是通过协议转换插件实现的。
以 Dubbo 为例,Higress 的做法是在 Envoy 里挂一个 Dubbo 协议解析插件,把 HTTP 请求转换成 Dubbo 协议调用后端服务。这个插件是用 Wasm 写的,核心逻辑是解析 HTTP 请求的路径和参数,映射成 Dubbo 的服务名和方法名,然后走 Dubbo 的序列化协议发给后端。对前端来说,它就是一个普通的 HTTP 接口,感知不到后面是 Dubbo。
MQTT 的支持类似,Higress 内置了 MQTT 协议的解析能力,可以把 MQTT 消息转成 HTTP 或者直接转发到 MQTT Broker。这对 IoT 场景很有用,设备用 MQTT 上报数据,网关统一做鉴权和限流。
多协议支持的技术难点在于协议识别和转换的性能。Higress 的做法是在 Listener 层做协议嗅探,根据端口或者首包特征判断协议类型,然后走对应的 Filter Chain。这个设计比较巧妙,避免了为每种协议单独开端口。
3. 核心功能模块深度解析
3.1 路由匹配:从 Ingress 到 Envoy Route 的转换
路由是网关最基础也最核心的功能。Higress 的路由配置来源有三种:K8s Ingress、Gateway API、以及 Higress 自定义的 McpBridge(多集群桥接)。不管哪种来源,最终都要转换成 Envoy 的 Route 配置。
Envoy 的路由匹配规则很灵活,支持精确匹配、前缀匹配、正则匹配,还能根据 Header、Query 参数、HTTP 方法做条件路由。Higress 在转换时,会把 Ingress 的path和pathType映射成 Envoy 的prefix或path匹配。比如 Ingress 里写path: /api、pathType: Prefix,转换后就是 Envoy 的prefix: /api。
这里有个容易踩的坑:路由优先级。Envoy 的路由匹配是按顺序来的,先匹配到的生效。Higress 在转换时会根据路径长度、匹配类型自动排序,确保精确匹配优先于前缀匹配。但如果你手动写了多条路由,最好自己确认一下顺序,避免出现预期外的匹配结果。
另一个细节是路由的元数据传递。Higress 支持在路由上挂 Wasm 插件,这个挂载关系是通过 Route 的typed_per_filter_config字段实现的。理解这个机制,对排查插件不生效的问题很有帮助。
3.2 负载均衡与健康检查
Higress 的负载均衡复用了 Envoy 的能力,支持轮询、随机、最少连接、一致性哈希等策略。默认是轮询,但实际生产环境里,一致性哈希用得比较多,因为它能保证同一用户的请求落到同一后端,对缓存友好。
健康检查分主动检查和被动检查。主动检查是 Envoy 定期发探测请求,比如每 5 秒发一个 HTTP 请求到/health,连续失败几次就把实例摘掉。被动检查是根据实际请求的失败率来判断,比如连续 5 个请求返回 5xx,就临时摘除实例。Higress 默认开启被动检查,主动检查需要手动配置。
配置健康检查时,有几个参数需要仔细调:interval(检查间隔)、timeout(超时时间)、unhealthy_threshold(连续失败几次标记不健康)、healthy_threshold(连续成功几次标记健康)。我的经验是,interval不要设太短,否则探测请求本身会成为负担;unhealthy_threshold也不要太小,避免网络抖动导致误摘。
3.3 限流与熔断:保护后端的最后一道防线
限流和熔断是网关的保命功能。Higress 的限流支持本地限流和全局限流两种模式。本地限流是在每个 Envoy 实例上独立计数,实现简单但不够精确;全局限流需要一个 Redis 做集中计数,精度高但有网络开销。
Higress 的全局限流是基于Envoy 的 Rate Limit Service实现的,底层用 Redis 做计数器。配置时需要在 WasmPlugin 里指定 Redis 地址和限流规则,比如"每个 IP 每分钟最多 100 次请求"。实测下来,Redis 限流的延迟在 1-2 毫秒左右,对大部分场景可以接受。
熔断这块,Higress 用的是 Envoy 的Circuit Breaker机制。可以配置最大连接数、最大并发请求数、最大重试次数等阈值,超过阈值就直接拒绝请求,避免后端被压垮。熔断的触发和恢复是自动的,Envoy 会根据后端实例的健康状态动态调整。
这里分享一个实操经验:限流和熔断的阈值不要拍脑袋定。最好先压测一下后端的承载能力,然后按 80% 的量设置阈值。另外,限流规则要留出应急通道,比如给内部调用或者特定用户开白名单,避免误伤。
4. 实操部署与配置指南
4.1 快速搭建 Higress 环境
部署 Higress 最简单的方式是用 Helm。前提是你有一个 K8s 集群(1.20+ 版本),并且装了 Helm 3。下面是完整的部署步骤:
# 添加 Higress Helm 仓库 helm repo add higress.io https://higress.io/helm-charts helm repo update # 创建命名空间 kubectl create namespace higress-system # 安装 Higress helm install higress higress.io/higress \ --namespace higress-system \ --set global.hub=higress-registry.cn-hangzhou.cr.aliyuncs.com/higress \ --set global.tag=latest安装完成后,用kubectl get pods -n higress-system检查 Pod 状态。正常情况下会看到higress-controller、higress-gateway等 Pod 处于 Running 状态。
接下来部署一个测试服务,验证网关是否工作:
# 部署一个简单的 echo 服务 kubectl create deployment echo --image=higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/echo-server:latest kubectl expose deployment echo --port=80 # 创建 Ingress 规则 cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: echo-ingress spec: ingressClassName: higress rules: - host: echo.example.com http: paths: - path: / pathType: Prefix backend: service: name: echo port: number: 80 EOF配置完成后,通过网关的 LoadBalancer IP 或者 NodePort 访问echo.example.com,应该能看到 echo 服务的响应。这一步验证了从 Ingress 到 Envoy 的完整链路。
4.2 Wasm 插件开发实战
写一个 Higress Wasm 插件,需要 Go 1.18+ 和 TinyGo(用于编译 Wasm)。下面是一个简单的鉴权插件示例,功能是检查请求头里有没有Authorization,没有就返回 401。
package main import ( "github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm" "github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types" ) func main() { proxywasm.SetVMContext(&vmContext{}) } type vmContext struct { types.DefaultVMContext } func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext { return &pluginContext{} } type pluginContext struct { types.DefaultPluginContext } func (*pluginContext) NewHttpContext(contextID uint32) types.HttpContext { return &httpContext{} } type httpContext struct { types.DefaultHttpContext } func (*httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action { auth, err := proxywasm.GetHttpRequestHeader("Authorization") if err != nil || auth == "" { proxywasm.SendHttpResponse(401, nil, []byte("Unauthorized"), -1) return types.ActionPause } return types.ActionContinue }编译成 Wasm:
tinygo build -o auth-plugin.wasm -target=wasi main.go然后通过 WasmPlugin CRD 挂载:
apiVersion: extensions.higress.io/v1alpha1 kind: WasmPlugin metadata: name: auth-plugin namespace: higress-system spec: url: file:///opt/plugins/auth-plugin.wasm phase: AUTHN priority: 100 matchRules: - ingress: - echo-ingress这个插件会在请求进入时检查Authorization头,没有就返回 401。phase: AUTHN表示在鉴权阶段执行,priority控制多个插件的执行顺序。
4.3 全局限流配置详解
全局限流需要先部署 Redis,然后配置 Rate Limit Service。Higress 内置了限流插件,配置方式如下:
apiVersion: extensions.higress.io/v1alpha1 kind: WasmPlugin metadata: name: rate-limit namespace: higress-system spec: url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/rate-limit:latest phase: AUTHZ priority: 200 config: redis: serviceName: redis-service servicePort: 6379 timeout: 1000 rules: - match: prefix: /api limit: requestsPerUnit: 100 unit: minute key: remote_address这个配置表示:对/api前缀的请求,按客户端 IP 限流,每分钟最多 100 次。key字段支持remote_address、header、query等多种取值方式。
配置生效后,可以用ab或wrk压测验证:
wrk -t4 -c100 -d30s http://echo.example.com/api/test如果限流生效,超过阈值的请求会返回 429 状态码。
5. 性能调优与问题排查
5.1 性能调优的关键参数
Higress 的性能调优主要围绕 Envoy 的线程模型和连接池展开。下面几个参数是重点:
| 参数 | 默认值 | 调优建议 | 说明 |
|---|---|---|---|
concurrency | CPU 核数 | 保持默认 | Envoy Worker 线程数,一般等于 CPU 核数 |
max_connections | 1024 | 按需调大 | 每个 Listener 的最大连接数 |
max_pending_requests | 1024 | 按需调大 | 等待上游响应的最大请求数 |
max_requests | 1024 | 按需调大 | 每个连接的最大并发请求数 |
connect_timeout | 5s | 按后端调整 | 连接后端服务的超时时间 |
调优的核心思路是匹配后端能力。如果后端服务能扛 1000 并发,网关的连接池就要能撑住这个量。但也不能无限调大,否则网关本身会成为瓶颈。
另一个优化点是Wasm 插件的执行顺序。插件是按priority顺序执行的,把轻量插件(如日志)放前面,重量插件(如鉴权)放后面,能减少不必要的开销。实测下来,合理排序能降低 10%-20% 的延迟。
5.2 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 502 Bad Gateway | 后端服务不可达 | 检查 Service 和 Endpoint | 确认后端 Pod 状态和端口 |
| 404 Not Found | 路由未匹配 | 检查 Ingress 规则和 Host | 确认 path 和 host 配置正确 |
| 插件不生效 | WasmPlugin 未挂载 | 检查 matchRules 和 phase | 确认插件 URL 和优先级 |
| 配置不生效 | Controller 未推送 | 查看 Controller 日志 | 检查 xDS 连接状态 |
| 限流不准确 | Redis 连接异常 | 检查 Redis 连通性 | 确认 Redis 地址和密码 |
| 延迟高 | 插件过多或过重 | 用 Envoy 的 stats 分析 | 精简插件或优化逻辑 |
排查问题的第一步永远是看日志。Higress Controller 的日志在higress-system命名空间下,Envoy 的日志可以通过kubectl logs查看。Envoy 还提供了/stats接口,能看到详细的请求指标,对定位性能问题很有帮助。
5.3 踩坑记录与经验总结
说几个我实际踩过的坑。第一个是Wasm 插件的内存限制。Envoy 默认给每个 Wasm 插件分配的内存有限,如果插件里做了大量数据缓存,可能会触发 OOM。解决办法是在 WasmPlugin 配置里调大vmConfig的内存限制,或者优化插件逻辑,减少内存占用。
第二个是路由匹配的顺序问题。有一次配了两条路由,一条是/api/v1,一条是/api,结果/api/v1的请求被/api匹配走了。原因是/api的路由优先级更高。后来在 Higress 的配置里显式指定了优先级,问题才解决。这个坑提醒我,路由配置一定要仔细检查顺序。
第三个是限流规则的粒度。一开始按 IP 限流,结果发现同一个 NAT 后面的用户共享 IP,容易被误伤。后来改成按用户 ID 限流,从请求头里取X-User-ID,精度高了很多。这个经验说明,限流的 key 选择要根据实际业务场景来定。
Higress 这个项目,从架构设计到功能实现,都体现了"轻量、高效、易扩展"的思路。它没有重复造轮子,而是站在 Envoy 和 Istio 的肩膀上,把网关场景做深做透。Wasm 插件机制是它最大的亮点,让扩展变得简单又安全。如果你正在选型 API 网关,或者想深入了解云原生网关的实现原理,Higress 值得花时间研究。