【导读】服务网格(Service Mesh)的概念自2017年初提出之后,受到了业界的广泛关注,作为微服务的下一代发展架构在社区迅速发酵,并且孵化出了诸如Istio等广受业界关注的面向于云原生(Cloud Native)的微服务架构。
那么,服务网格在百度的落地情况又如何呢?
近日,在百度技术沙龙上,百度服务网格技术负责人乔元才发表了『服务网格在百度核心业务大规模落地实践』的主题演讲。
1. 从微服务到服务网格
何谓微服务?据维基百科的定义:微服务是一种软件架构风格,它是以专注于单一责任与功能的小型功能区块为基础,利用模块化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关的API集相互通信。
Service Mesh 最早在2016年9月29日由开发 Linkerd 的 Buoyant 公司首次提出,Service Mesh 是用于处理服务间通信的基础设施层,它负责通过构成现代云原生应用程序的复杂拓扑结构来可靠地传递请求。
因此 Service Mesh 也被称为微服务时代的TCP协议。
第一代微服务的常见架构如下图所示:
在黄色的容器内有服务A、服务B。A和B都包含自己的业务逻辑,如果想要A调用B,同时试图对这个服务进行治理,通常会在业务的内部集成一个SDK,来实现服务发现、负载均衡、服务路由、重试、熔断限流等功能。
但是,这个架构存在三个主要问题:
第一,开发成本。因为A和B的服务已经是微服务了,它们可能是由不同语言开发的而且各自的框架可能也不同,如果希望把绿色的部分进行升级或者提供新的功能,就需要重复的迭代和开发。
第二,升级成本。因为SDK的部分跟业务耦合在一起,在新增一些能力时需要重新部署业务的模块。
第三,部署成本。由于相关治理的功能需要耦合在业务的配置里面,所以很难做到实时的下发配置,服务间拓扑关系和治理配置无法统一管理。
Service Mesh 是如何解决这些问题的?
如下图左侧所示,它通过将SDK 、开发框架提供的服务治理能力下沉到一个和业务进程独立的轻量级网络代理中,由这个网络代理作为微服务通信的基础设施层,它可以提供业务无关、语言无关、独立演进,透明升级的特性。这个轻量级的网络进程被称作Sidecar代理,是服务网格的数据面。
同时如右侧所示,通过一个对 Sidecar 进行统一控制和管理的服务控制平面,来提供对微服务治理和运维的统一入口。
这种架构实现了服务治理技术和业务逻辑的解耦,是云原生时代微服务治理技术的发展方向,也得到了越来越多的公司的关注。
2. 百度微服务治理的现状和痛点
百度在服务网格以及微服务相关的探索大概可以追溯到2013年,当时在内部独立部署了流量转发系统,同时在一些业务有所推广实施;2016年 Service Mesh 这个概念被首次提出,因为百度本身有相关需求,便尝试引入Mesh的概念,于是内部自研了一套遵循社区 Mesh 概念的通过 Golang 开发的包含控制面和数据面的 BMesh 系统,在搜索服务前端服务上线,不过没有在特别多业务推广;直到2019年,百度内部做了拥抱开源的决定,希望基于社区方案:Istio + Envoy 进行深度定制开发。
目前,百度核心业务线已全面完成了微服务架构改造,基于微服务构建了包括百度信息流、百度App、百度地图、百度小程序等核心业务的应用架构;微服务模块大量采用C++、Golang、PHP、Java等语言来开发和快速迭代;而且百度长期积淀了许多自研和二次开发的开源微服务框架:bRPC、GDP、ODP、SpringCloud等, 这些微服务间通信除了标准的HTTP、GRPC协议外,广泛地采用了大量的私有协议,比如baidu-std、Nshead等。
所以百度的核心业务线形成了多开发语言、多开发框架和多通信协议构成的复杂的异构系统,传统的基于入侵的微服务框架已经不能满足这种复杂系统的服务治理要求——升级Mesh迫在眉睫!
在升级之前,有一些重点问题需要综合考虑:
- 改造成本
- 各种各样的微服务框架网格化改造和适配
- 各种各样的通信协议支持
- 性能问题和资源问题
- 因为Sidecar的引入,微服务间的通信链路变长,业务延迟增加,甚至某些敏感业务无法接受Sidecar带来的额外损耗。
- Sidecar自身会消耗资源,增加业务的成本。
- 规模问题
随着Sidecar规模的增长,开源的控制平面计算开销变大,导致Mesh配置下发时间变长,甚至无法工作。
3. 百度服务网格整体方案
如何解决这些问题?
在服务网格的技术选型问题上,百度选择了开源的 Istio + Envoy 作为网格控制面和数据面,在其上进行深度的定制和开发。
但是 Istio + Envoy 的社区方案和K8S的技术生态进行了深度绑定。而在百度内部有自研的基础技术平台,包括对标 K8S 的 PaaS部署系统、Trace系统、监控系统和Naming系统等,这些都是业务模块包括 Istio + Envoy 部署运行的依赖系统。所以,将 Istio + Envoy 和内部依赖系统进行了深度的技术融合,打通了公司基础技术平台,降低了业务接入成本。
在数据面和控制面之上,又建设了 Mesh 控制中心,即微服务的配置管理中心,提供服务治理和运维的统一入口;基于底层架构的建设,向上提供了流量复制、负载均衡、过载保护、流量镜像等系统能力。
这些系统能力在核心业务的服务治理、运维止损、容量管理、混沌工程和服务可观测等场景中得到了应用,并且取得了不错的业务收益和使用效果。
那么,实现这样一套系统,我们需要解决哪些问题呢?
3.1 网格接入优化方案
首先是流量劫持方案的问题,在社区方案中,一般是通过Naming Service(如:DNS服务)获取到目标 Server 的真实地址。同时,通过配置 iptables 进行流量劫持,将客户端的请求直接转发给 Sidecar。但是,当 iptables 配置有大量匹配规则时有性能的问题,而且无法动态修改客户端访问服务端的行为,如:重试、超时等,且没有办法平滑的在 Mesh 和非Mesh 模式切换。
在百度内部采用了另外一种劫持的方案,首先 Sidecar 启动的时候会将自己注册给Naming Service(在百度内部叫BNS),在框架经过 Naming Service 查询的时候,框架的内部集成了一个和 Naming Service 对接的小模块,这个小模块从 Naming Service 拿到的就是 Sidecar 的地址,动态的改变了目标服务器的地址,直接将目标的IP变成 Sidecar 的地址(loopbackIp),同时,还会覆盖客户端的重试、超时等参数,这一切对业务来说都是无感的。
这样就可以很便捷的调整客户端服务治理参数、切换Mesh和非Mesh模式。因为如果Sidecar挂掉了,会在Naming系统里把自己解除注册,这样上游的框架会自然而然的访问下游服务的真实地址了。
第二,对自有协议的支持的问题。在社区里面是支持不同的协议,比如HTTP、Thrift、Dubbo,但会涉及重复的开发。如果要支持一个新协议,可能需要重新实现超时控制、重试、请求路由、流量镜像等。百度内部将这通用的部分单独剥离出来:于是支持一个新的协议变得简单起来,我们只需要将下图中绿色的部实现简单的Codec,即:将这个协议进行编解码就可以,大大降低开发支持新协议的成本。
最后是对多框架和协议的支持问题。Mesh 对协议的要求包括具有请求特征信息扩展的能力,可以实现请求特征路由;具有元信息扩展能力:能够在框架和 Sidecar 间传递信息(如:一致性哈希的Code),在上下游服务模块间传递信息(如:TraceID,SpanID)
内部传统的老协议如何接入 Mesh?通过框架实现协议升级,用可扩展的 baidu-std 协议封装老协议进行传输,到达下游服务之后再由框架拆解开报文。
3.2 服务网格性能优化
针对代理架构如下图所示,社区方案是从APP1进入 Sidecar 再到下游服务的 Sidecar再到APP2,这里面经过了两次 Sidecar,会有两倍延迟或者两倍资源开销,在百度内部可能并没有这么复杂,没有对这个很高要求的场景,多数情况下只经过 Sidecar一次。比如,APP1经过Sidecar后直接到达了APP2,并没有再次经过 Sidecar。
另外一种模式,内部很敏感的业务并不希望经过 Sidecar。比如,APP2通过框架直接访问到APP3,并没有经过任何的 Sidecar。下图左是经过一次 Sidecar 的模式(在百度内部称为一跳)这是通过 NamingService 注册再访问本地IP。而下图右 Proxyless 模式 Sidecar 会将自己服务的参数以及目标服务的IP通过 NamingService 下发给框架,框架拥有下游服务的IP以及服务治理的全部参数,可以直接完成访问。
针对数据面性能方面的优化,社区的 Envoy 在性能方面并不是特别优越,所以。百度整合了一个 bRPC 开源框架作为内核去转发流量,在上层 bRPC 框架依然兼容了xDS协议(服务治理参数的协议),便于同步社区的新设计、新变化,做到了鱼和熊掌都可以兼得的效果,经过升级内核的版本以后,在各个延时、长尾以及CPU使用率上都有很好的优化。
最后是控制面性能优化,控制面在没有配置 Sidecar CRD 的情况下,会下发所有的服务列表,我们通过内部的关键路径优化,实际上只会下发 Sidecar 关注的下游,大大减少控制面对配置计算以及下发的性能优化。
经过上述改造后,最后就完成了百度内部对 Mesh 的整体优化和修改。
4. 业务收益及案例启示
经过上图所展示的高级服务治理策略,在 SLA 以及故障恢复时间上都有很高的优化。在此基础上还有全局的智能容灾系统,可以优化高级服务策略参数。
服务可观测性方面,可以通过框架传递 TraceID、SpanID 等,再通过 Sidecar 再采集到内部的 Trace平台和监控平台,可以在内部的监控平台上展示 Trace,方便监控以及进行故障的排查和追踪。
自动止损方面,整个系统结合内部的监控平台,监控平台将这些指标存储在自己的平台上,稳定性预案平台根据监控平台的指标异常进行实时调参,执行流量降级、切机房、切流等。同时这个效果会实时反馈给监控平台,包括稳定性预案平台持续的对系统进行调参,形成闭环。
混沌工程方面,会通过控制平面下发给故障任务,然后控制平面将命令下发给Sidecar,Sidecar 通过这个命令注入一些延迟,这样去影响内部的系统,内部系统同样会产生监控的指标,这些指标再上报给监控平台,然后混沌平台再通过这些指标评估系统的弹性以及容错等。
系统容量评估方面,容量平台可以发起压测任务,这个任务对接到控制平面。如:由控制平面下发切20%的流量到某下游服务,对它进行压测,实时产生的指标上报给监控平台,容量平台对监控平台的指标进行实时评估。
百度内部业务接入情况:
- 百度App、信息流、百度地图、智能小程序、好看视频等产品线
- 接入实例十万级
- 每天处理请求数千亿次
业务接入收益:
- 大幅提升核心链路的可用性和系统整体容灾、防雪崩能力
- 大大降低治理迭代成本、服务治理迭代周期从数月缩短到天级别
- 解锁服务可观测,自动止损,容量探测等高级场景能力
最后,乔元才总结了通过接入Mesh服务网格得到的一些启示:
- 服务网格不是微服务治理的银弹
- 完全无入侵的,支持所有协议,所有框架和所有治理策略的 Mesh 方案是不存在的
- 大规模工业化落地的平滑、稳定可控接入方案,涉及到大量对已有服务治理组件的兼容升级和改造
- 服务网格确实实现了业务逻辑和服务治理架构的解耦,解锁了很多新能力
- 服务网格结合可观测、故障止损、混沌工程,容量管理等场景化,才能发挥出最大价值
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。