最近半年,我们团队在生产环境中试点了Istio服务网格,想用它来解决微服务治理的问题,包括流量管理、安全、可观测性等。

Istio的理念很美好:不用改代码,就能为微服务提供流量管理、安全、可观测性等能力,让开发者专注于业务逻辑,把服务治理的事情交给服务网格。

但是实际用起来,坑真的很多。从安装部署到流量管理,从性能问题到兼容性问题,踩了无数的坑,熬了无数个夜。Istio目前还处于快速发展阶段,版本更新很快,功能还不完善,文档也不够清晰,很多问题需要自己摸索和踩坑。

本文将记录我们在使用Istio过程中遇到的各种坑和问题,以及我们是怎么解决的,希望能给想在生产环境中使用Istio的团队一些参考和提醒。

一、为什么选择Istio

先说说我们为什么选择Istio。

我们团队有大概几十个微服务,用Kubernetes部署。随着微服务数量越来越多,服务治理的问题越来越突出:

  1. 流量管理困难:想做灰度发布、蓝绿部署、A/B测试,需要在代码里写很多逻辑,或者用Nginx配置,很麻烦,也不灵活。
  2. 安全问题:微服务之间的调用没有认证和加密,存在安全隐患。想做mTLS(双向TLS),需要改代码,配置证书,很麻烦。
  3. 可观测性不足:微服务之间的调用链不清晰,出了问题很难排查。想做分布式追踪、指标监控、日志收集,需要在每个服务里集成SDK,改代码,工作量大。

这时候,服务网格(Service Mesh)的概念进入了我们的视野。服务网格通过在每个服务旁边部署一个Sidecar代理,把服务治理的逻辑从业务代码中抽离出来,由Sidecar来处理流量、安全、可观测性等问题。开发者不用改代码,就能获得这些能力。

Istio是目前最流行的服务网格实现之一,由Google、IBM、Lyft联合开发,功能强大,社区活跃。我们对比了Istio、Linkerd、Conduit等服务网格,最终选择了Istio,因为它功能最全面,社区最活跃,而且和Kubernetes集成得最好。

于是,我们开始了Istio的踩坑之旅。

二、安装部署的坑

第一个坑,就是安装部署。

坑一:版本选择困难

Istio目前还处于快速发展阶段,版本更新很快,几乎每个月都有新版本。每个版本都有新功能,也有新bug,而且不同版本之间的API和配置可能不兼容。

我们一开始用的是0.5版本,用了一段时间发现有不少bug,想升级到0.6版本,结果发现配置格式变了,很多配置需要改,而且升级过程中服务中断了一段时间。

建议:在生产环境中使用Istio,不要追新,选择一个相对稳定、经过验证的版本,而且在升级之前,一定要在测试环境充分测试,确认兼容性和稳定性。不要在生产环境中直接升级,否则可能会出问题。

坑二:资源占用大

Istio的控制面(Pilot、Mixer、Citadel、Galley等组件)需要占用不少资源,特别是Pilot和Mixer,内存占用比较大。而且每个服务都要注入一个Envoy Sidecar,每个Sidecar也要占用一定的CPU和内存。

我们一开始没有注意资源规划,把Istio部署在一个资源比较紧张的集群里,结果控制面组件经常OOM(内存溢出),Sidecar也因为资源不足而崩溃,导致服务不可用。

建议:部署Istio之前,要做好资源规划。控制面组件至少要给几个G的内存,每个Sidecar也要预留一定的CPU和内存。如果集群规模大、服务多,资源占用会更多,要提前规划好。

坑三:自动注入不生效

Istio支持自动注入Sidecar,只要给命名空间打上标签,部署在这个命名空间里的Pod就会自动注入Sidecar。但是我们一开始配置了自动注入,部署了服务,发现Sidecar没有被注入。

排查了半天,发现是因为我们的Kubernetes版本比较旧,不支持MutatingAdmissionWebhook,而Istio的自动注入依赖这个特性。升级了Kubernetes版本之后,自动注入才正常工作。

建议:使用Istio之前,要确认Kubernetes的版本满足要求,特别是要支持AdmissionWebhook。如果Kubernetes版本太旧,要么升级,要么用手动注入的方式。

坑四:Sidecar启动顺序问题

Istio的Sidecar注入到Pod里之后,和业务容器共享一个Pod。但是Sidecar和业务容器的启动顺序是不确定的,有时候业务容器先启动,这时候Sidecar还没准备好,业务容器发起的网络请求就会失败。

我们就遇到了这个问题:服务启动的时候,偶尔会报连接错误,过一会儿又好了。排查了很久,才发现是Sidecar还没准备好,业务容器就开始发请求了。

解决方案:在业务容器的启动脚本里加一个等待,等Sidecar准备好之后再启动业务服务。或者用Istio的holdApplicationUntilProxyStarts配置(新版本支持),让业务容器等Sidecar启动之后再启动。

建议:使用Istio的时候,要注意Sidecar的启动顺序问题,在业务容器启动的时候加一个等待,避免因为Sidecar没准备好而导致服务启动失败。

三、流量管理的坑

Istio最强大的功能之一就是流量管理,可以做灰度发布、蓝绿部署、A/B测试、流量镜像、故障注入等。但是流量管理的坑也很多。

坑五:VirtualService配置不生效

Istio用VirtualService来配置流量路由规则。我们配置了一个VirtualService,想把10%的流量路由到新版本,90%的流量路由到旧版本,做灰度发布。但是配置了之后,发现流量没有按照预期分配,还是全部路由到了旧版本。

排查了很久,发现是因为我们没有配置DestinationRule。VirtualService里引用了新版本的subset,但是这个subset没有在DestinationRule里定义,所以路由规则不生效。配置了DestinationRule之后,流量分配才正常。

建议:配置VirtualService的时候,如果引用了subset,一定要在DestinationRule里定义对应的subset,否则路由规则不生效。而且VirtualService和DestinationRule要配合使用,缺一不可。

坑六:灰度发布的流量比例不准确

我们做灰度发布的时候,配置了10%的流量到新版本,90%到旧版本。但是实际观察下来,流量比例不太准确,有时候新版本的流量超过10%,有时候又不到。

后来了解到,Istio的流量分配是基于概率的,不是精确的。在流量比较小的时候,比例可能会有偏差,流量大了之后,比例会越来越准确。而且Envoy的负载均衡算法也会影响流量分配的准确性。

建议:做灰度发布的时候,不要期望流量比例100%准确,特别是在流量比较小的时候。可以通过监控观察实际的流量比例,适当调整配置。如果需要精确的流量控制,可以考虑用其他方案。

坑七:故障注入导致服务雪崩

Istio支持故障注入,可以在路由规则里注入延迟或者错误,用来测试服务的容错能力。我们在测试环境做故障注入,给一个服务注入了5秒的延迟,想测试下游服务的超时和重试。

结果,因为下游服务没有配置合理的超时和重试,故障注入导致请求大量堆积,线程池被占满,服务雪崩了,整个测试环境都不可用了。

建议:做故障注入的时候,一定要确保服务有合理的超时、重试、熔断等容错机制,否则故障注入可能会导致服务雪崩。而且故障注入要在测试环境做,不要在生产环境做,除非你非常确定不会出问题。

坑八:流量镜像的性能问题

Istio支持流量镜像,可以把生产环境的流量镜像一份到测试环境,用来测试新版本的服务。我们试了一下流量镜像,发现开启之后,服务的延迟增加了不少,而且资源占用也增加了。

因为流量镜像需要Sidecar把请求复制一份发送到镜像服务,这会增加Sidecar的处理开销和网络开销。如果流量大的话,性能影响会比较明显。

建议:使用流量镜像的时候,要注意性能影响。如果流量大,可能需要增加资源,或者只镜像一部分流量。而且流量镜像适合在测试环境用,不建议在生产环境长期开启。

四、安全的坑

Istio的安全功能也很强大,支持mTLS(双向TLS)、认证策略、授权策略等。但是安全功能的坑也不少。

坑九:mTLS配置导致服务不通

Istio支持mTLS,可以在服务之间自动加密通信,不需要改代码。我们开启了全局mTLS,想让所有服务之间的通信都加密。结果开启之后,发现很多服务不通了,报连接错误。

排查了很久,发现是因为有些服务没有注入Sidecar,或者Sidecar还没准备好,mTLS握手失败,导致连接被拒绝。还有一些外部服务(比如数据库、缓存)没有Sidecar,不能用mTLS,需要配置例外。

解决方案:关闭全局mTLS,改用命名空间级或者服务级的mTLS,只在已经注入Sidecar的服务之间开启mTLS。对于没有Sidecar的外部服务,配置DestinationRule,禁用mTLS。

建议:开启mTLS的时候,不要一上来就开全局mTLS,要循序渐进,先在小范围测试,确认没问题之后再逐步扩大范围。而且要考虑没有Sidecar的服务,配置好例外规则。

坑十:证书过期导致服务中断

Istio的Citadel组件负责证书的签发和轮换。默认情况下,证书的有效期是90天,Citadel会自动轮换证书。但是我们遇到了一次证书过期的问题,导致服务之间的mTLS握手失败,服务中断了。

排查发现,是因为Citadel组件出了问题,没有自动轮换证书,导致证书过期了。重启Citadel之后,证书重新签发,服务才恢复正常。

建议:使用Istio的mTLS的时候,要监控证书的有效期和Citadel的状态,确保证书能正常轮换。可以配置告警,证书快过期的时候及时通知,避免因为证书过期导致服务中断。

五、可观测性的坑

Istio的可观测性功能也很强大,集成了Prometheus、Grafana、Jaeger、Kiali等工具,可以做指标监控、分布式追踪、服务拓扑可视化等。但是可观测性的坑也不少。

坑十一:Mixer性能瓶颈

Istio的Mixer组件负责收集指标和日志,做策略检查。但是Mixer是一个中心化的组件,所有Sidecar都要把请求的指标和日志发送给Mixer,当流量大的时候,Mixer会成为性能瓶颈,导致延迟增加,甚至Mixer崩溃。

我们就遇到了这个问题:流量大的时候,Mixer的CPU和内存占用飙升,请求延迟增加,甚至有请求超时。后来我们把Mixer的check功能关掉了(因为我们没有用策略检查),只保留了report功能,并且调整了Mixer的资源配置,性能才好了一些。

建议:使用Istio的时候,如果不需要策略检查,可以关掉Mixer的check功能,减少性能开销。而且要给Mixer足够的资源,监控Mixer的状态,避免Mixer成为瓶颈。新版本的Istio在逐步把Mixer的功能下沉到Sidecar,减少中心化组件的性能问题,可以关注一下。

坑十二:分布式追踪的采样率问题

Istio集成了Jaeger,可以做分布式追踪。但是默认情况下,追踪的采样率是1%,也就是100个请求只采样1个。如果流量小的话,可能很久都采不到一个请求,看不到追踪数据。

我们一开始不知道采样率的问题,以为分布式追踪坏了,怎么都看不到追踪数据。后来才知道是采样率太低了,把采样率调高之后,就能看到追踪数据了。

建议:使用Istio的分布式追踪的时候,要注意采样率的配置。在测试环境可以把采样率调高一些,方便排查问题;在生产环境可以根据流量和存储成本,设置合理的采样率。

坑十三:Kiali的性能问题

Kiali是Istio的服务网格可视化工具,可以展示服务拓扑、流量情况、配置状态等,非常好用。但是Kiali在服务多、流量大的时候,性能会比较差,页面加载慢,甚至会卡顿。

我们的集群有几十个服务,Kiali加载服务拓扑图的时候,要等好几秒,而且有时候会卡顿。后来我们调整了Kiali的刷新频率和数据保留时间,性能才好了一些。

建议:使用Kiali的时候,如果服务多,可以调整刷新频率和数据保留时间,减少性能开销。而且Kiali适合用来做可视化和排查问题,不适合做实时监控,实时监控还是用Grafana+Prometheus比较好。

六、性能和兼容性的坑

除了上面这些,Istio还有一些性能和兼容性的坑。

坑十四:Sidecar的性能开销

每个服务都要注入一个Envoy Sidecar,Sidecar会代理所有的入站和出站流量,这会带来一定的性能开销,包括延迟增加、CPU和内存占用增加。

我们测试了一下,注入Sidecar之后,服务的平均延迟增加了几毫秒到十几毫秒,CPU和内存占用也增加了一些。对于延迟敏感的服务,这个开销可能会有影响。

建议:使用Istio之前,要评估Sidecar的性能开销对服务的影响。对于延迟敏感、资源紧张的服务,要谨慎使用Istio,或者做好性能优化。而且要给Sidecar预留足够的资源,避免因为资源不足导致性能下降。

坑十五:和其他工具的兼容性问题

Istio和一些其他的工具可能会有兼容性问题。比如,和某些Ingress Controller、服务发现工具、监控工具等,可能会有冲突或者不兼容的情况。

我们就遇到了Istio和我们原来的Ingress Controller冲突的问题。Istio自己有Ingress Gateway,和我们原来的Ingress Controller功能重叠,而且配置方式不一样,导致了一些混乱。后来我们统一用Istio的Ingress Gateway,才解决了这个问题。

建议:使用Istio之前,要评估和现有工具栈的兼容性,避免功能重叠和冲突。特别是Ingress、服务发现、监控这些领域,Istio都有自己的方案,要考虑是替换还是共存,做好规划。

坑十六:升级困难

Istio版本更新很快,每个版本都有新功能和bug修复,但是升级也很困难。不同版本之间的API和配置可能不兼容,升级的时候需要改配置,而且升级过程中可能会导致服务中断。

我们从0.5升级到0.6的时候,就改了不少配置,而且升级过程中服务中断了一段时间。后来我们就不敢轻易升级了,除非有特别重要的功能或者安全修复。

建议:在生产环境中使用Istio,不要频繁升级。选择一个稳定的版本,用一段时间,等新版本稳定了、经过验证了,再考虑升级。升级之前,一定要在测试环境充分测试,确认兼容性和稳定性,制定好回滚方案。

七、我们的经验和建议

踩了这么多坑,我们也总结了一些经验和建议。

建议一:不要急于在生产环境大规模使用

Istio目前还处于快速发展阶段,功能还不完善,稳定性还有待提高。不要一上来就在生产环境大规模使用,建议先在测试环境或者非核心业务中试点,积累经验,确认稳定性和性能满足要求之后,再逐步推广到核心业务。

建议二:做好资源规划和监控

Istio的控制面和Sidecar都需要占用不少资源,要做好资源规划,给足CPU和内存。而且要做好监控,监控控制面组件的状态、Sidecar的状态、服务的延迟和错误率等,及时发现问题,及时处理。

建议三:从简单的功能开始用起

Istio的功能很强大,但是不要一开始就把所有功能都用上。建议从简单的功能开始用起,比如先做流量管理(灰度发布、蓝绿部署),再做可观测性(指标、追踪),最后再做安全(mTLS、认证授权)。一步一步来,踩一个坑解决一个坑,不要一下子把所有坑都踩了。

建议四:关注社区和文档

Istio的社区很活跃,文档也在不断完善。遇到问题的时候,可以先查文档、查GitHub issue、查社区讨论,很多问题都能找到解决方案。而且要关注版本更新,了解新功能和bug修复,及时升级(但不要盲目升级)。

建议五:做好回滚方案

Istio的配置比较复杂,而且版本更新快,可能会出现配置错误或者版本不兼容的问题,导致服务不可用。所以一定要做好回滚方案,出了问题能快速回滚,减少服务中断的时间。

八、总结

Istio是一个非常有前景的服务网格项目,它的理念很美好,功能也很强大,能解决微服务治理的很多痛点。但是目前它还处于快速发展阶段,还不够成熟,坑比较多,在生产环境中使用需要谨慎。

我们团队用了半年Istio,踩了很多坑,熬了很多夜,但是也收获了很多。通过Istio,我们实现了灰度发布、蓝绿部署、分布式追踪、指标监控等功能,服务治理能力提升了不少,虽然过程很痛苦,但是结果还是值得的。

如果你也在考虑在生产环境中使用Istio,我的建议是:谨慎评估,小步试点,做好规划,踩坑总结。不要被它的美好理念冲昏头脑,也不要因为坑多就望而却步。服务网格是未来的趋势,Istio是目前最有前景的实现之一,值得关注和尝试。

最后,希望Istio能越来越成熟,坑越来越少,功能越来越强大,让微服务治理变得越来越简单。

也希望这篇踩坑记能给正在使用或者想要使用Istio的你,带来一些帮助和参考。少踩一些坑,少熬一些夜。