欢迎访问Spring Cloud中国社区

我们致力于成为中国最专业的Spring Boot和Spring Cloud交流社区。推荐使用Github直接登录,欢迎加微信号Software_King进入社区微信交流群。若发现网站bug欢迎反馈!

腾讯云TSF微服务平台以及ServiceMesh技术实践经验

程序媛 · 27天前 · 396 ·

在当今信息爆炸的时代,各行业的业务量都在爆发性增长,对于传统企业来说,增长的业务量往往对IT系统带来不少挑战,出现了如应用模块耦合、业务代码滚雪球式增长、项目迭代时间长、单模块故障影响全局等问题。因此,很多传统企业希望转型微服务架构来解决上面的问题。而微服务框架自身的复杂性及架构多样性,则为该架构的选型及构建增加了入门门槛。因此,希望TSF对微服务的摸索经验和技术实践能为众多企业构建微服务框架发挥一定的借鉴作用。

首先我们来聊聊微服务框架的技术演进
微服务架构来源于分布式架构,是分布式系统在云计算时代产物,一个或多个微服务可以组成一个大型复杂软件应用,微服务之间是松耦合的架构、可以独立部署、升级。基于微服务的系统可提供高级别的系统水平扩展能力。
在微服务架构的实现中,为提升效率和降低门槛,应用开发者会基于微服务框架来实现微服务。微服务框架一定程度上为使用者屏蔽了底层网络的复杂性及分布式场景下的不确定性。通过API/SDK的方式提供服务注册发现、服务RPC通信、服务配置管理、服务负载均衡、路由限流、容错、服务监控及治理、服务发布及升级等通用能力。

第一代微服务框架(准确来说应该属于分布式RPC通信框架),分层架构如下:

代表是COBRA及WebServices,通过协议描述文件(IDL/WSDL)约定双方的通信接口,应用通过SDK来进行服务通信。但是,应用开发者需要写大量复杂及重复的代码来解决分布式场景下的服务发现、失败重试、过载熔断等问题。

为了解决第一代框架中遇到的问题,出现了第二代微服务框架,分层架构如下:

典型的产品是SpringCloud, Finagle, dubbox等。开发人员通过集成相应的类库SDK,通过配置以及调用SDK接口的方式来进行微服务的开发。由于Java语言的便捷以及Spring框架的普及,当前这种模式的微服务框架是业界使用最广泛的微服务框架。传统行业中,对于那种本身是基于Java&Spring开发的应用、或者新开发的应用,基本上都首选采用该微服务框架来进行改造。

但是第二代框架也不能解决所有问题,对于一些类似传统银行、敏感机关、或者小型企业的行业客户,其应用的特点具备跨语言、应用改造流程复杂、线上节点替换升级风险大、ISV技术积累较浅的特质。在这种情况下,往往难以说服他们使用框架SDK进行改造。
在这种背景下,催生了下一代微服务架构SeviceMesh,一种基于外置sidecar模式的微服务框架。其架构特点是把微服务框架的能力移到了微服务外部,作为独立的sidecar进程来提供。微服务之间通过sidecar透明代理的方式来进行通信。使得服务开发者只需要聚焦业务本身,服务可随意跨语言实现。而在升级过程中,sidecar可以独立升级,无需与微服务进行联动替换。从而解决了第二代框架所遗留的问题。
典型的开源产品有spring cloud sidecar(无独立控制面)以及istio/envoy(带独立控制面),分层架构如下:

接下来我们针对TSF中使用的Spring Cloud及ServiceMesh的能力做一个展开的分享。
当前腾讯云的TSF的微服务能力主要包括2部分:
1.服务框架层包括嵌入式SDK以及ServiceMesh。
2.服务生命周期管理层包括自研的PaaS以及治理运维平台(不在本次分享范围之内)

嵌入式SDK主要是基于Spring Cloud来实现。Spring Cloud是业界覆盖量比较高的一个优秀的开源微服务框架,其特点是基于springboot微容器能力的基础上,融合了netflix, hashicorp等组织所开源的组件,形成的一个配置驱动,能力相对完备,高度可扩展的服务框架。如下为其组件与微服务框架能力的对应表:

由表格可以看出,spring cloud的核心能力在于微服务交互本身,但是其存在以下的问题:
1.缺乏复杂的服务治理能力(服务降级、服务监控、动态扩缩容、灰度发布),在一些可靠性、性能要求较高的场景下,也缺少相应的原生能力支撑(如异地多活,服务本地缓存,四层协议通信)
2.在一些生产态的问题定位定界上,由于spring cloud自身打印的日志以debug为主,但是为了性能考虑,现网往往不会开启debug日志。因此当出现服务丢失等问题时,最常见的做法是依赖服务治理平台集成外部的APM框架来进行应用内部监控。
因此,大家在基于spring cloud作为服务框架的实践过程中,要注意规避或解决上面所提及的问题。而TSF对spring cloud通过自研及集成开源的方式,补齐了spring cloud的所缺失的短板,提供了完善的含paas及运维治理能力的服务框架,但由于篇幅关系今天不展开讨论。

接下来我们重点讲讲ServiceMesh的实现。
TSF服务框架的ServiceMesh主要是有2类实现。
第一类ServiceMesh实现是无独立控制面的全功能sidecar,主要适用于有一定的研发能力,且对定制化要求较高的企业客户。TSF主要是基于Spring Cloud Sidecar能力来实现全功能sidecar。Spring Cloud Sidecar的灵感来源于Netfix的Prana (https://github.com/Netflix/Prana),这个也是Spring Cloud与ServiceMesh融合的重要手段。其主要工作流程如下图所示:

每个服务节点上会部署一个sidecar进程,sidecar根据配置将自身监听地址以及服务名注册到Consul Server。当收到外部请求时,会直接到达Zuul Servlet,此时首先判断请求是否来源于自身节点服务,假如来源于自身节点服务,则直接走本地路由。否则,就走ribbon流程进行服务路由及转发。Sidecar在运行过程中,会定期调用所代理的服务的健康检查接口,获取服务健康状态并上报Consul Server。这种Sidecar代理+服务的方式,所表现出来的行为,与直接嵌入Spring Cloud SDK模式所表现的行为是一致的。Spring Cloud Sidecar模式的缺点在于对服务的URL有要求(来源于zuul的约束,必须带有服务名),同时原生的zuul+ribbon转发模式的性能较差,缺少独立控制面使得运维成本较高。

第二类实现是带独立控制面的sidecar,主要适用于对定制化要求不高,但是对性能比较敏感,业务代码改造工作量大,希望低成本运维的企业客户。带独立控制面的sidecar也是ServiceMesh的业界通用实现。但是开发团队应该如何去实现这种ServiceMesh呢?
实现微服务框架的关键在于开源选型。TSF在Mesh构建初期,业界已经有不少优秀的开源数据面sidecar产品,如envoy, linkrd, nginmesh, conduit等,而且各有各的亮点和最佳适用场景。但最终数据面选定envoy的原因在于:
1.envoy社区成熟度较高,商用稳定版本面世时间较长。如nginMesh以及conduit至今仍未有商用版本
2.envoy底层基于C++,性能上优于使用scala的linkrd,同时C++与腾讯系的语言体系较吻合
3.envoy在腾讯内部使用相对广泛,稳定性相当高,对于运行态代理,稳定性直接影响交付质量。

而对于数据面的开源选型,则可选范围相对较少,当前控制面集大成者是istio,业界几乎所有的开源数据平面产品(conduit除外),都支持对接istio,但是istio存在2个问题使得当时在选型上挣扎了一下:

1.原生的istio大部分能力与kubernetes是强关联的。而TSF则是与P层平台解耦的,框架在设计上需要能够对接多P层平台。
2.istio至今未有商用稳定版本,当前最新版本是0.7.1

最终控制平台仍然选型istio,原因如下:
1.istio拥有极高的社区影响力,开发团队来源于google和ibm。所基于的xDS(LDS, RDS, CDS, EDS)控制接口规范几乎成为控制面的实际规范。
istio版本速度较快,今年内极有可能会推出1.0版本。

3.通过调研istio代码,发现通过一定程度的定制及扩展,可以使得istio与kubernetes成功解耦。
经过选型后,我们mesh产品架构如下:

Mesh涉及的部件所提供的功能如下:
istio-Pilot:ServiceMesh的大脑,对接注册中心与配置中心,通过不同的接口给数据面节点提供服务调用所需要的全部规则及信息(包括envoy的内部监听及转发规则、集群服务信息、服务路由规则、负载均衡规则、服务实例信息等),所依赖的控制接口描述可参考:https://github.com/envoyproxy/data-plane-api/tree/master/envoy/api/v2
Istio-Mixer:提供了一套attribute处理框架,可供用户去定制服务权限控制、服务quota限流、调用统计信息上报及采集分析的能力。
Istio-CA:主要是安全相关的。提供证书的更新、密钥集中管理下发、RBAC权限模型的更新及维护等能力。
Pilot-agent: 提供环境初始化、服务注册、envoy进程监控的能力。
Envoy:提供服务的透明代理能力,可以根据控制面下发的控制信息进行消息的投递。当前支持的协议包括HTTP, HTTP2, GRPC。Envoy本身提供listener接口供自定义私有协议。

下面通过一个例子讲解一下ServiceMesh内部如何进行消息路由:

1.服务A通过http://<targetServiceName>:<port>/url的方式对服务B发起REST服务调用
2.A节点的流量接管能力将该报文接管到本节点的envoy进程。
3.envoy进程通过Pilot下发的控制信息(该控制信息的分类及运算比较复杂,鉴于篇幅关系不详细展开,后续有机会再单独开篇介绍),经过一系列的负载均衡计算及权限检查,确定了B服务的目标实例节点,将信息投递给该节点。
4.B节点收到消息后,流量接管能力将消息接管进envoy。envoy通过quota限流策略检查是否已经达到上限,检查通过后,则根据Pilot下发的内部路由规则,路由给节点内的服务实例。
5.服务实例收到请求后,进行业务逻辑的处理。

最后,分享下ServiceMesh在使用过程中所遇到的待改进点以及思路。
当前ServiceMesh在推广过程中,遇到的最大的障碍实际上还是istio未有商用版本的问题。不过其实从isito官网可以了解到,当前istio大部分核心能力已经是beta或者stable状态
(https://istio.io/about/feature-stages.html)
因此在商用前只要能够仔细评估涉及的能力范围,原则上不会出现较大的问题。其他潜在问题的待改进思路如下:
1.平台耦合问题:开源istio对kubernetes是有依赖的,其服务发现、安装部署、配置获取等核心能力都依赖于kubernetes容器环境,在虚拟机场景下支持不友好。需要对istio做了少量增强,使其与kubernetes解耦,一套代码可以同时支持虚拟机及容器环境。
2.暴力流量接管:这个也是网上诟病比较多的问题。由于istio的数据面依赖于针对容器内流量进行全接管,但是对于虚拟机场景下可能不适用,毕竟虚拟机上可能不仅仅只有mesh的服务。因此,需要考虑细粒度的接管方案,使得mesh与非mesh应用在同一个虚拟机/容器中可以共存。
3.全量服务发现问题:istio是一个集中的控制面,在构建路由数据时,会默认从注册中心获取全量的服务实例数据,一旦服务节点量级上升后,会导致较严重的性能及资源占用问题。因此,定制过程中可以考虑采用服务元数据的方式来业务运行过程中所服务发现涉及的传输数据量。
4.Mixer缓存穿透的问题。由于envoy在每个请求的发送前以及接受到请求后,都需要往mixer去查询权限及quota信息,为提升性能,envoy会对这些查询结果进行缓存。而由于这些信息是per request的,而且envoy无法知道会有哪些attributes(key)需要去缓存,从而缓存的总量有可能根据调用时长而呈现不断增长的趋势,引发资源占用问题。因此,在这方面可以适当引入LRU算法来解决。
5.多租户隔离的支持。在公有云场景下,用户对隐私和隔离看得非常重要。往往不同用户/租户之间,服务配置、节点信息、控制信息等资源数据是隔离的,互相不可见。但是istio本身并不支持这种级别的隔离。需要框架集成者去进行扩展。
6.自动服务注册能力的支持。istio并不提供自动服务注册能力(其服务模型依赖kubernetes的service),因此,假如需要将istio脱离kubernetes运行,首要解决的是自动服务注册的问题。思路是pilot提供接口获取应用节点服务信息,然后通过通过每个节点部署的pilot-agent拉取并注册节点服务实例。

由于ServiceMesh是一个技术栈相当深的系统,在不同业务场景下,所面对的挑战以及所需要的底层技术并非今天的分享就能够介绍全面的。也欢迎对这个方向感兴趣的朋友多和我们交流。
同时也欢迎大家到腾讯云官网https://cloud.tencent.com/product/tsf去了解并体验更多TSF的能力。

【分享人】单家骏,腾讯中间件研发高级工程师,负责腾讯云中间件PaaS以及ServiceMesh的研发与架构。曾在华为公司任职,从事云计算及中间件7年有余。热爱开源、崇尚技术,希望能够使用技术使软件的应用变得简单、高效和美好。