跳到主要内容

Istio 之流量镜像

· 阅读需 5 分钟

在 k8s 集群中部署 Istio 作为 Service Mesh 之后,利用 Envoy 代理转发流量的特性,只需在配置文件里加几行就能开启流量镜像。镜像流量的响应不会返回给客户端,对原有业务代码完全透明,用得当的话可以在生产环境发挥很大价值。

什么是流量镜像

流量镜像也叫影子流量(Shadow Traffic):Envoy 在把客户端请求转发给真实服务的同时,复制一份发送到指定的镜像服务。关键点有两个:

1)镜像请求是"发后即忘"(fire-and-forget)的,Envoy 不会等待镜像服务的响应,更不会把它返回给客户端。镜像服务处理慢、报错甚至挂掉,都不影响主链路。

2)镜像发生在流量进入业务容器之前,由 Sidecar 代理完成,业务代码不需要任何改动,只要另外部署一套接收镜像流量的服务即可。

官方文档见:镜像

典型使用场景

1、测试环境:测试版本的容器服务可以使用生产实例的真实流量,不会影响正常生产的关键路径。例如预发布环境就可以更好的进行实时测试校验,减少发布后出现的各种异常情况,给开发团队更好的上线信心 😂,上线几乎可以做到清晰明了,不用熬夜加班发版。

2、数据采集:同步收集请求信息,则可在其他容器中做风控分析,日志记录以便于得到对应的用户画像信息。

3、性能与兼容性验证:新版本服务、重构后的接口、换了框架或依赖的实现,都可以先用镜像流量"陪跑"一段时间,对比新旧两边的日志和指标,确认行为一致后再正式切流。

4、问题复现:线上偶发的异常请求很难在测试环境构造,把流量镜像到一个开了详细日志或调试开关的实例上,就能拿到第一手现场。

配置方式

Istio 中流量镜像通过 VirtualService 的 mirror 字段声明。假设 httpbin 服务有 v1、v2 两个版本,想把打到 v1 的流量镜像一份给 v2,写法大致如下:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- httpbin
http:
- route:
# 真实流量:全部转发给 v1,响应返回客户端
- destination:
host: httpbin
subset: v1
weight: 100
# 镜像流量:复制一份发给 v2,响应被丢弃
mirror:
host: httpbin
subset: v2
# 镜像的采样比例,不写默认 100%
mirrorPercentage:
value: 100.0

几个字段的含义:

1)route.destination 是主路由,决定真实请求发给谁,客户端拿到的是它的响应。

2)mirror 指定镜像目标,同样是 host + subset 的组合,subset 需要提前在 DestinationRule 里定义好。

3)mirrorPercentage 控制镜像采样比例。镜像目标容量比生产小的时候,按 1%、10% 这样逐步放量比直接 100% 稳妥得多。

配置写好后 kubectl apply -f 即可生效,不需要重启任何业务 Pod,这也是 Sidecar 模式的好处之一。

踩坑与注意

1)镜像流量的 Host 头会被加上 -shadow 后缀,例如 httpbin:8000 会变成 httpbin-shadow:8000。镜像服务如果对 Host 做了校验或路由,要提前处理这个差异;反过来,这个后缀也可以用来在日志里区分真实流量和影子流量。

2)镜像的是请求,不是幂等性。写接口被镜像后会在影子环境再执行一次,如果镜像服务连的是同一个数据库、同一个下游,就可能造成重复写入或重复调用第三方。要么让镜像服务连独立的数据源,要么在镜像侧对写操作做拦截。

3)镜像会放大出口带宽和 Envoy 的开销,请求体大、QPS 高的服务尤其明显,先用 mirrorPercentage 小比例验证再放量。

4)镜像服务的报错不会影响客户端,这既是优点也是盲区——影子环境挂了没有用户感知,需要单独给它配监控告警,否则"陪跑"很可能早就停了都没人发现。

小结

流量镜像把"用生产流量验证"这件高风险的事变成了低成本操作:一段 VirtualService 配置,业务零改动,主链路零影响。预发验证、风控分析、问题复现这些场景都能受益。需要留意的主要是写操作的副作用、Host 头的 -shadow 后缀以及镜像侧自身的监控,把这几点处理好,它就是一个非常值得常备的工具。

评论 / COMMENTS