ServiceMesh 1:大火的云原生微服务网格,究竟好在哪里?
1 关于云原生
云原生计算基金会(Cloud Native Computing Foundation, CNCF)的官方描述是:
云原生是一类技术的统称,通过云原生技术,我们可以构建出更易于弹性扩展、极具分布式优势的应用程序。
这些应用可以被运行在不同的环境当中,比如说 私有云、公有云、混合云、还有多云场景。
云原生包含了 容器、微服务(涵盖服务网格)、Serverless、DevOps,API管理、不可变基础架构等能力。通过云原生技术构建出来的应用程序,对
底层基础架构的耦合很低,易于迁移,可以充分地利用云所提供的能力,因此云原生应用的研发、部署、管理相对于传统的应用程序更加高效和便捷。
1.1 微服务
微服务是一种架构模式,是面向服务的体系结构(SOA)软件架构模式的一种演变,
它提倡将单一应用程序划分成一组松散耦合的细粒度小型服务,辅助轻量级的协议,互相协调、互相配合,为用户提供最终价值。
具有 单一职责、轻量级通信、独立性、进程隔离、混合技术栈和混合部署方式、简化治理 等特点。
1.2 DevOps
DevOps 作为一种工程模式,本质上是通过对开发、运维、测试,配管等角色职责的分工,实现工程效率最大化,进而满足业务的需求。
1.3 持续交付
在不影响用户使用服务的前提下频繁把新功能发布给用户使用,要做到这点比较难。需要强大的流量管理能力,动态的服务扩缩容为平滑发布、ABTesting提供保障。
1.4 容器化
容器化的好处在于运维的时候不需要再关心每个服务所使用的技术栈了,每个服务都被无差别地封装在容器里,可以被无差别地管理和维护,现在比较流行的技术是docker和k8s。
2 关于ServiceMesh
2.1 什么是ServiceMesh
ServiceMesh 是最新一代的微服务架构,作为一个基础设施层,能够与业务解耦,主要解决复杂网络拓扑下微服务与微服务之间的通信,其实现形态一般为轻量级网络代理,并与应用SideCar部署,同时对业务应用透明。
如果从一个单独链路调用可以得到以下的结构图:
如果我们从一个全局视角来看,绿色的为应用服务,蓝色的为SideCar,就会得到如下部署图:
2.2 相较传统微服务的区别
以SpringCloud与Dubbo为代表的微服务开发框架非常受欢迎。但我们发现,他有优秀的服务治理能力,也有明显的痛点:
1. 侵入性强。
想要集成SDK的能力,除了需要添加相关依赖,业务层中入侵的代码、注解、配置,与治理层界限不清晰。可以想想Dubbo、SpringCloud 等的做法
2. 升级成本高。
每次升级都需要业务应用修改SDK版本,重新进行功能回归测试,并对每一台服务进行部署上线,与快速迭代开发相悖。
3. 版本碎片化严重。
由于升级成本高,而中间件版本更新快,导致线上不同服务引用的SDK版本不统一、能力参差不齐,造成很难统一治理。
4. 中间件演变困难。
由于版本碎片化严重,导致中间件向前演进的过程中就需要在代码中兼容各种各样的老版本逻辑,带着"枷锁”前行,无法实现快速迭代。
5. 内容多、门槛高。
依赖组件多,学习成本高。
6. 治理功能不全。
不同于RPC框架,SpringCloud作为治理全家桶的典型,也不是万能的,诸如协议转换支持、多重授权机制、动态请求路由、故障注入、灰度发布等高级功能并没有覆盖到。
2.3 ServiceMesh的价值 — 赋能基础架构
- 统一解决多语言框架问题,降低开发成本
- 降低测试成本,提升质量
- 控制逻辑集中到控制面
- 为新架构演进提供支持,如Serverless
- 网格半覆盖 转 统一覆盖(弥补service-center并逐渐过度)
- 完整的闭环微服务统筹和管理能力
2.4 ServiceMesh的价值 — 赋能业务
- 框架与业务解耦,减少业务限制。
- 简化服务所依赖SDK版本管理。
- 依托热升级能力,版本召回周期短。
- SDK瘦身,减少业务依赖冲突。
- 丰富的流量治理、安全策略、分布式Trace、日志监控,下沉服务治理底座,让业务专注业务。
3 ServiceMesh 核心能力
3.1 流量治理
微服务应用最大的痛点就是处理服务间的通信,而这一问题的核心其实就是流量管理。
3.1.1 请求路由
将请求路由到服务的版本,应用根据 HTTP 请求 header 的值、Uri的值 路由流量到不同的地方。匹配规则可以是流量端口、header字段、URI等内容。
RuleMatch参考
3.1.2 流量转移
当微服务的一个版本逐步迁移到另一个版本时,我们可以将流量从旧版本迁移到新版本。如下图,使用weight参数进行权重分配,
这个很典型的应用场景就是灰度发布或者ABTesting。
3.1.3 负载均衡
同3.1.2的图,Service B 有多个实例,所以可以另外制定负载均衡策略。
负载均衡策略支持简单的负载策略(ROUND_ROBIN、LEAST_CONN、RANDOM、PASSTHROUGH)、一致性 Hash 策略和区域性负载均衡策略。
3.1.4 超时
对上游的请求设置,设置一个一定时长(0.5s)的超时,请求超过这个时间不响应,可以直接fallback。目标还是过载保护。
3.1.5 重试
当请求在固定的时间内没有返回正确值的时候,可以配置重试次数。设置如果服务在 1 秒内没有返回正确的返回值,就进行重试,重试的条件为返回码为5xx,重试 3 次。
分布式环境下,重试是高可用的重要技术,重试方案慎用。
retries:
attempts: 3
perTryTimeout: 1s
retryOn: 5xx
3.1.6 熔断/限流/降级
熔断的策略比较多,可以配置 最大连接数、连接超时时间、最大请求数、请求重试次数、请求超时时间等,我们都可以给他熔断掉,fallback回去。
但是目前看,Istio 对更灵活、更细粒度的限流、降级等能力支持的还不够好,合理应该有漏斗池算法(如
阿里开源限流框架Sentinel
)或者令牌桶算法(如
Google Guava 提供的限流工具类 RateLimiter
)这样的灵活做法。
但是可以采用其他方式处理,比如可以通过流量转发将部分流量流动到默认服务去,该服务启用默认的fallback,但是需要控制好采样时间、熔断半开的策略。
3.1.7 离群检测(Outlier Detection)
当集群中的服务故障的时候,其实我们最优先的做法是先进行离群,然后再检查问题,处理问题并恢复故障。所以,能否快速的离群对系统的可用性很重要。
Outlier Detection 允许你对上游的服务进行扫描,然后根据你设置的参数来判断是否对服务进行离群。
下面的配置表示每秒钟扫描一次上游主机,连续失败 2 次返回 5xx 错误码的所有主机会被移出负载均衡连接池 3 分钟,上游被离群的主机在集群中占比不应该超过10%。
但无论比例多少,只要你集群下的服务实例>=2个,都将弹出至少1个主机。它有很详细的配置,
参考这边
。
注意:3分钟之后回群,如果再被离群,则为上次离群时间+本次离群时间,即 3+3;默认超过50%(可调整比例)被离群,进入恐慌模式。
outlierDetection:
consecutiveErrors: 2
interval: 1s
baseEjectionTime: 3m
maxEjectionPercent: 10
3.1.8 故障注入
就是用来模拟上游服务对请求返回指定异常码时,当前的服务是否具备处理能力。系统上线前,可以配置注入的httpStatus和比例,来验证下游服务对故障的处理能力。
3.1.9 流量镜像(Mirroring)
这个也叫做影子流量。是指通过一定的配置将线上的真实流量复制一份到镜像服务中去,可以设置流量比例,只转发不响应。
个人觉得这个还是比较有用的,好处是 完整的线上正式环境模拟、流量分析、压力测试;全真的线上问题再现,方便问题排查。
3.2 可观察性
3.2.1 监控与可视化
Prometheus(标配,默认抓取指标数据)、kiali监控(服务视图,Istion链路的可观察性) 、Grafana(BI报表)(数据面、控制面、xDS Service 各健康指标)
后续章节会逐一展开...
3.2.2 访问日志
ELK、EFK (Envoy记录AccessLog,包含SideCard的InBound、OutBound记录)
后续章节会详细展开...
3.2.3 分布式追踪
本质上查找多个HTTP请求之间的相关性的一种方法是使用相关性ID。该ID应该传递给所有请求,以便跟踪平台知道哪些请求属于同一请求。如下图:
尽管Istio利用Envoy的分布式跟踪功能提供开箱即用的跟踪集成,但是其实这是一个误解,我们的应用程序需要做一些工作。应用程序需要传播以下header:
- x-request-id
- x-b3-traceid
- x-b3-spanid
- x-b3-parentspanid
- x-b3-sampled
- x-b3-flags
- x-ot-span-context
Istio Sidecar内的Envoy代理接收这些标头,并将它们传递给配置的tracing系统。所以实际上,Istio中服务追踪默认只会追踪到2级,
例如A -> B -> C, 在Istio中会出现2条追踪链路:A -> B 和B -> C,而不会出现我们期望的A -> B -> C的形式,如果想要服务串联起来,需要对服务间调用进行改造,
在Istio中应用程序通过传播http header来将span关联到同一个trace。
3.3 安全机制
- Service Mesh可以在服务间通信中引入双向TLS加密,确保数据在传输过程中不被篡改和窃听。控制平面负责管理和分发证书,Sidecar Proxy在通信过程中进行加密和解密操作。
- 通过引入身份认证和访问控制策略,可以细粒度地控制哪些服务可以访问其他服务。
3.4 策略执行
Service Mesh通过在每个服务实例旁边部署Sidecar Proxy,实现了对服务间通信的透明代理。这些代理负责拦截出入的所有流量,并根据控制平面下发的配置和策略执行相应的操作。具体工作原理如下:
3.4.1 服务发现:
当一个服务实例启动时,它会向服务注册中心注册自己的信息。控制平面负责管理这些服务实例信息,并将更新的服务列表分发给所有Sidecar Proxy。
3.4.2 流量管理:
当一个服务需要与另一个服务通信时,流量首先经过本地的Sidecar Proxy。代理根据配置的路由规则和负载均衡策略,将流量转发到目标服务实例。
控制平面可以动态更新这些路由规则,实现蓝绿部署、金丝雀发布等高级流量管理功能。
3.4.3 安全认证:
Service Mesh可以在服务间通信中引入双向TLS加密,确保数据在传输过程中不被篡改和窃听。控制平面负责管理和分发证书,Sidecar Proxy在通信过程中进行加密和解密操作。
通过引入身份认证和访问控制策略,可以细粒度地控制哪些服务可以访问其他服务。
3.4.4 可观察性:
Service Mesh中的代理会收集每个请求的日志、监控数据和追踪信息,并将这些数据发送到可观察性组件进行处理和存储。
运维人员可以通过控制平面提供的接口和仪表盘,实时监控服务间的流量情况、延迟、错误率等指标,并进行故障排查和性能优化。
4 总结
Service Mesh相比传统微服务框架以下几方面有明显优势:
- 解耦应用程序和通信逻辑
- 提供增强的服务治理能力
- 提高可观察性和可调试性
- 支持多语言和协议以
- 提高系统可靠性和可扩展性