胡忠想|微博微服务架构的Service Mesh实践之路

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:

前言

说到Service Mesh,在如今的微服务领域可谓是无人不知、无人不晓,被很多人定义为下一代的微服务架构

Service Mesh在诞生不到两年的时间里取得令人瞩目的发展,在国内外都涌现出一批具有代表性的新产品,最著名的莫过于GoogleIBM领导的Istio,也是Service Mesh技术的代表之作。

而国内在这一方面也不遑多让,秉承了Service Mesh的思想也走出了各自的实践之路,并且已经开始在线上的核心业务中大规模使用,比如微博的Weibo Mesh华为公有云Service Mesh以及蚂蚁金服的SOFA Mesh等。

今天我就来带给大家详细介绍下微博的微服务架构是如何一步步走向Service Mesh之路的

跨语言服务调用的需求

微博最早服务化框架采用的是自研的Motan,Motan诞生于2013年,出于微博平台业务单体化架构拆分为微服务改造的需求,在结合当时的开源服务化框架和自身实际的需求,选择了采用自研的方式。

而且由于微博平台的业务采用的是Java语言开发,所以Motan早期只支持Java语言。后期随着微博业务的高速发展,越来越多的PHP业务开始登上舞台,于是在微博的流量体系中。

主要是三股服务之间的相互调用:

一个是Java与Java语言,一个是PHP和Java语言,一个是PHP和PHP语言

Java应用之间的调用采用的是Motan协议,而Java应用与PHP、PHP与PHP应用之间采用的都是HTTP协议

我回忆了一下当时一次PHP与Java之间的HTTP调用过程,大致需要经过DNS解析、四层LVS负载均衡、七层Nginx负载均衡,最后才能调用Java应用本身。

bc5712b39d1d999453dc3ea67ee1a5356114cb22

从上面这张图可以看出,一次HTTP调用的链路相当长,从我的实践来看,经常会遇到好几个问题。

第一个问题:中间链路损耗大

由于一次HTTP调用要经过DNS、LVS、Nginx这三个基础设施,每一层都会带来相应的损耗。

我曾经在线上就碰到过因为DNS解析延迟、LVS带宽打满引起的网络延迟,以及Nginx本地磁盘写满引起的转发延迟等各种情况,造成接口响应在中间链路的损耗甚至超过了接口本身业务逻辑执行的时间。

第二个问题:全链路扩容难

由于微博业务经常要面临突发热点事件带来的流量冲击,所以需要能够随时随地动态扩缩容。

其实在应用本身这一层扩容并不是难点,比较麻烦的是四七层负载均衡设备的动态扩缩容,它涉及如何评估容量、如何动态申请节点并及时修改生效等,要完成一次全链路扩容的话,复杂度非常高。

所以最后往往采取的办法是给四七层负载均衡设备预备足够的冗余度,在峰值流量到来时,只扩容应用本身。

第三个问题:混合云部署难

微博的业务目前采用的是混合云部署,也就是在内网私有云和公有云上都有业务部署,同样也需要部署四七层负载均衡设备。

并且要支持公有云上的请求经过DNS解析后要能够转发到公有云上的负载均衡设备上去,避免跨专线访问带来不必要的网络延迟和专线带宽占用。

因此,迫切需要一种支持跨语言调用的服务化框架,使得跨语言应用之间的调用能够像Java应用之间的调用一样,不需要经过其他中间链路转发,做到直接交互,就像下图描述的那样。

60f4b37180eb72c8d8d3aecfb0e9dd08769d2115

Yar协议的初步尝试

为此,微博最开始考虑基于Motan框架进行扩展,使其支持PHP语言的Yar协议,下面是扩展后的架构图。

5566b29e52f18dfc1168e90b81e703d80f866946

这个架构的思路是PHP客户端的服务发现通过Nginx来支持经过Nginx把PHP的Yar协议请求转发给服务端

由于Motan框架中了适配Yar协议,服务端会把PHP的Yar协议请求转换成Motan请求来处理,处理完后再转成Yar协议的返回值经过Nginx返回给客户端。

但这种架构主要存在两个问题

第一个问题:Motan协议与Yar协议在基本数据结构和序列化方式的支持有所不同,需要经过复杂的协议转换。

第二个问题:服务调用还必须依赖Nginx,所以调用链路多了一层,在应用部署和扩容时都要考虑Nginx。

gRPC会是救命稻草吗

时间往后推演,gRPC横空出世,它良好的跨语言特性,以及高效的序列化格式的特性吸引了我们,于是便开始考虑在Motan中集成gRPC,来作为跨语言通信的协议。

当时设计了下图的架构,这个架构的思路是利用gRPC来生成PHP语言的Client然后在Motan框架中加入对gRPC协议的支持,这样的话PHP语言的Client就可以通过gRPC请求来调用Java服务。

8343303fde6850427f5cbf14f9f7e5f11aaa2963

但在我们的实际测试中,发现微博的业务场景并不适合gRPC协议,因为gRPC协议高度依赖PB序列化,而PHP对PB的兼容性不是很好,在微博的业务场景下一个接口返回值有可能超过几十KB。

此时在PHP Client端PB数据结构解析成JSON对象的耗时甚至达到几十毫秒,这对业务来说是不可接受的。

而且gRPC当时还不支持PHP作为Server对外提供服务,也不满足微博这部分业务场景的需要。

代理才是出路

考虑到PHP语言本身没有常驻内存控制的能力,在实现服务注册和发现以及其他各种服务框架功能时,仅靠PHP-FPM进程本身难以实现,因此需要一个统一常驻内存的进程来帮助完成服务框架的各种功能

一开始我们考虑过使用本地守护进程OpenResty的Timer来实现服务发现,但其他服务框架的功能不太好实现,比如专栏前面提到的各种复杂的负载均衡策略、双发、熔断等。

为此,我们希望通过一个Agent也就是代理,来帮助PHP进程来完成服务框架的各种功能,PHP进程本身只需要负责运行业务逻辑的代码,以及最简单的Motan协议解析。

基于这个思路,当时我们设计了下面这个架构,它的思路就是在PHP进程的本地也部署一个Agent,PHP进程发出去的请求都经过Agent进行处理后,再发给对应的Java应用。

765411764f9dd21fe28bd108846087970ca07899

向Service Mesh迈进

2017年,就在我们开始采用Agent方案对业务进行改造,以支持PHP应用调用Java应用服务化的时候,Service Mesh的概念突然火热起来,并随着Istio的发布风靡业界。

相信经过我前面对Service Mesh的讲解,你一定会发现这里的Agent不恰恰就是Service Mesh中的SideCar吗?

没错,我们跨语言调用的解决方案竟然与Service Mesh的理念不谋而合

借鉴Service Mesh的思想,我们也对Agent方案进一步演化,不仅客户端的调用需要经过本地的Agent处理后再转发给服务端,服务端在处理前也需要经过本地的Agent,最后再由服务端业务逻辑处理,下面是它的架构图。

bf7c5ec280a0aa70cef06678754223c1fee6510c

如此一来,业务只需要进行集成最简单的Motan协议解析,而不需要关心其他服务框架功能,可以理解为业务只需要集成一个轻量级的Client用于Motan协议解析,而繁杂的服务框架功能全都由Agent来实现,从而实现业务与框架功能的解耦。

Motan-go Agent

考虑到Motan-go Agent要与PHP进程部署在一起,为了减少对本机资源的占用,这里Motan-go Agent采用了Go语言来实现,它包含的功能模块请看下图。

6739bf79d16512688839733164fe8ca9527848c0

我们拆解一下图中Motan-go Agent主要的模块,看看它们的作用是什么。

Filter Chain模块是以请求处理链的组合方式,来实现AccessLog(请求日志记录)、Metric(监控统计)、CircuitBreaker(熔断)、Switcher(降级)、Tracing(服务追踪)、Mock(单元测试)、ActiveLimit(限流)等功能。

0f865e3dbf122fd9e7d6f1cb2929aca5bcb7ef7e

High Available模块是用来保证高可用性,默认集成了Failover、Backup Request等故障处理手段。

Load Balance模块负载均衡,默认集成了Random、Roundrobin等负载均衡算法。

EndPoint模块的作用是封装请求来调用远程的Server端,默认可以封装Motan请求和gRPC请求。

Serialize模块负责实现不同类型的序列化方式,默认支持Simple序列化。

Server模块实现不同类型的Server,要么是采用Motan协议实现,要么是采用gRPC协议。

Motan-go Agent每个模块都是功能可扩展的,你可以在Filter Chain模块加上自己实现的Trace功能,这样请求在经过Filter Chain处理时,就会自动加载你加上的Trace功能。

当然,你也可以在High Available模块添加自己实现的故障处理手段,在Load Balance模块里实现自己的负载均衡算法,在EndPoint模块封装HTTP协议的请求,在Serialize模块添加PB序列化,在Server模块实现HTTP协议等。

另外Motan-go Agent之间的通信采用的是自定义的Motan2协议,它把请求中的Meta信息与请求参数信息进行了分离,更适合对请求进行代理转发,并且默认使用了Simple序列化来对不同语言的数据进行编码,以实现跨语言服务通信。

更多关于Motan2协议和Simple序列化的介绍,你可以点击这里查看。

统一服务治理中心

在Weibo Mesh中是通过统一服务治理平台与Motan-go Agent交互来实现服务治理功能的。

对着下面这张Weibo Mesh的架构图,我们一起看一下统一服务治理平台SGCenter具体是如何与Motan-go Agent交互,来实现服务治理的各项功能的。

8446a4ed3531cc55497f9dffbf119e74a1230753

1.动态服务注册与发现

首先来看下统一服务治理平台是如何实现服务注册与发现的。

如下图所示,在Motan-go Agent中实现了具体的服务注册与发现的逻辑,Server端进程启动时,会通过Motan-go Agent向Vintage注册中心发起注册请求,把服务注册到Vintage中。

Client端发起服务调用时,会经过Motan-go Agent转发,Motan-go Agent会调用Vintage查询该服务在Vintage中的注册信息,获取到服务节点列表后,按照某一种负载均衡算法选择一个服务节点,向这个服务节点发起调用。

可以通过统一服务治理平台SGCenter,调用Vintage的管理接口,执行添加或者删除服务节点等操作,Motan-go Agent会感知到服务节点的变化,获取最新的服务节点。

一般在业务开发或者运维人员需要手工扩容或者缩容一批服务节点时,才会执行这个操作。

87bfbf31a090748575f84411bd73cd50ca5aa2a1

2.监控上报

再看下面这张图,Client端发起的请求经过Motan-go Agent转发时,Motan-go Agent就会在内存中统计每一次调用的耗时、成功率等信息。

并且每隔固定的时间间隔将这段时间内各个服务调用的QPS、平均耗时、成功率以及P999等metric信息发送给Graphite监控系统。

这样的话,通过SGCenter调用Graphite的Web API就可以获取到服务调用的信息了。

68a3cef66709c2df639bb97cff4e50d64966a9a9

3.动态流量切换与降级

动态流量切换与降级的过程请看下面这张图。

Motan-go Agent在查询Vintage中某个服务节点信息的同时也会订阅该服务的变更,这样的话就可以通过SGCenter向Vintage下发服务的切流量或者降级指令。

订阅了这个服务的Motan-go Agent就会收到变更通知,如果是切流量指令,比如把调用永丰机房服务的流量都切换到土城机房,那么Motan-go Agent就会把原本发给永丰机房的请求都发给土城机房。

如果是降级指令,Motan-go Agent就会停止调用这个服务。

711924022079efbcb65e7e7a70a66c71bc019920

4.自动扩缩容

服务调用时Motan-go Agent会把Server端服务调用的监控信息上报给Graphite监控系统,同时Diviner容量评估系统会实时调用Graphite以获取服务在不同区间的QPS信息以计算服务池的水位线。

然后SGCenter会每隔一段时间调用Diviner来获取各个服务池的冗余度以决定是否需要扩容。

假如此时服务池的冗余度不足的话,SGCenter就会调用DCP容器运维平台给服务池进行扩容,DCP完成扩容后新的服务节点就会注册到Vintage当中,这样的话订阅了该服务的Motan-go Agent就会感知到服务节点的变化。

从Vintage中获取最新的服务节点信息,这就是一个服务自动扩缩容的整个流程,你可以参考下面这张图。

2db21ba0c9d83270613e97042173428bbb5bd843

Weibo Mesh的收益

经过前面的讲解,相信你已经对Weibo Mesh的实现方案有了一定的了解。Weibo Mesh是在微博的业务场景下,一步步进化到今天这个架构的,它给微博的业务带来的巨大的收益,总结起来主要有以下几点:

 ●  跨语言服务化调用的能力

Weibo Mesh发展之初最首要的目的,就是想让微博内部的Motan服务化框架能够支持PHP应用与Java应用之间调用,因而开发了Motan-go Agent,并在此基础上演变成今天的Weibo Mesh。

支持多种语言之间的服务化调用,有助于统一公司内部业务不同语言所采用的服务化框架,达到统一技术体系的目的。

 ●  统一服务治理能力

以微博应对突发热点事件带来的峰值流量冲击为例,为了确保首页信息流业务的稳定性,我们有针对性的研发了自动扩缩容系统。

而随着微博的不断发展,不断涌现出新的业务线,比如热门微博和热搜,也同样面临着突发热点事件带来的流量冲击压力。

而开发一套稳定可用的自动扩缩容系统并非一朝一夕之事,如何能够把信息流业务研发的自动扩缩容系统推广到各个业务线,是个比较棘手的问题。

因为信息流业务的后端主要采用了Java语言实现,而热门微博和热搜主要采用的是PHP语言,无法直接接入自动扩缩容系统。

而Weibo Mesh可以支持多种语言,将热门微博和热搜业务进行服务化改造,就可以统一接入到自动扩缩容系统,实现了公司级的统一服务治理能力。

 ●  业务无感知的持续功能更新能力

采用Motan或者Dubbo类似的传统服务化框架,一旦服务框架功能有升级就需要业务同步进行代码升级,这对大部分业务来说都是一种不愿承受的负担。

而采用Weibo Mesh,添加新功能只需要升级Motan-go Agent即可,业务代码不需要做任何变更,对于业务开发人员更友好。

尤其是作为公司级的服务化框架时,服务框架的升级如果跟业务系统升级绑定在一起,从我的实践经验来看,将是一件耗时费力的工作,需要协调各个业务方配合才能完成。

而Weibo Mesh可以看作是服务器上部署的基础组件,它的升级与维护不需要各个业务方的参与,这样才能具备作为公司级的服务化框架推广到各个业务线的前提。

Weibo Mesh的发展规划

在微博的业务场景下,存在大量服务对缓存、数据库以及消息队列等资源的调用,如果把资源也看作是一种服务

那么Weibo Mesh不仅可以管理服务与服务之间的调用,还可以管理服务与资源之间的调用,这样的话Weibo Mesh强大的服务治理能力也能延伸到对资源的治理上,对业务来说又将解决资源治理这一大难题。

另一方面,随着Weibo Mesh治理的服务越来越多,收集的数据也越来越多,利用这些数据可以挖掘一些更深层次的东西,也是Weibo Mesh未来的发展方向之一。

比如,引入机器学习算法,对采集的数据进行分析,进行监控报警的优化等。

2058414eb6f204e40d4b4f8b81002241806c64be

总结

从微博一步步走向Service Mesh之路的过程,你可以看出微博的Weibo Mesh并不是一开始就是设计成这样的,它是随着业务的发展,对跨语言服务调用的需求日趋强烈,才开始探索如何使得原有仅支持Java语言的服务化框架Motan支持多语言。

在这个过程中又不断尝试了各种解决方案之后,才笃定了走Agent代理这条路,并实际应用到线上。

而随着Service Mesh概念的兴起,微博所采用的Agent代理的解决方案与Service Mesh理念不谋而合,于是在Agent代理的方案中吸纳Service Mesh的思想,进一步演变成如今的Weibo Mesh。所以说一个可靠的架构从来都不是设计出来的,是逐步演进而来的。


原文发布时间为:2018-11-16

本文作者:胡忠想

本文来自云栖社区合作伙伴“中生代技术”,了解相关信息可以关注“中生代技术”。

相关文章
|
2天前
|
消息中间件 运维 监控
现代化软件开发中的微服务架构设计与实践
本文将深入探讨现代化软件开发中微服务架构的设计原则和实践经验。通过分析微服务架构的优势、挑战以及常见的设计模式,结合实际案例,帮助开发者更好地理解如何构建可靠、可扩展、高效的微服务系统。
|
2天前
|
负载均衡 Java 开发者
细解微服务架构实践:如何使用Spring Cloud进行Java微服务治理
【4月更文挑战第17天】Spring Cloud是Java微服务治理的首选框架,整合了Eureka(服务发现)、Ribbon(客户端负载均衡)、Hystrix(熔断器)、Zuul(API网关)和Config Server(配置中心)。通过Eureka实现服务注册与发现,Ribbon提供负载均衡,Hystrix实现熔断保护,Zuul作为API网关,Config Server集中管理配置。理解并运用Spring Cloud进行微服务治理是现代Java开发者的关键技能。
|
3天前
|
监控 JavaScript 安全
构建微服务架构下的API网关
【4月更文挑战第15天】在微服务架构中,API网关扮演着至关重要的角色。它作为系统的唯一入口,不仅负责请求的路由、负载均衡和认证授权,还涉及到监控、日志记录和服务熔断等关键功能。本文将探讨如何构建一个高效且可靠的API网关,涵盖其设计原则、核心组件以及实现策略,旨在为后端开发人员提供一套实用的指导方案。
16 4
|
4天前
|
监控 负载均衡 API
构建高性能微服务架构:后端开发的最佳实践
【4月更文挑战第14天】 在当今快速发展的软件开发领域,微服务架构已成为构建可扩展、灵活且容错的系统的首选方法。本文深入探讨了后端开发人员在设计和维护高性能微服务时需要遵循的一系列最佳实践。我们将从服务划分原则、容器化部署、API网关使用、负载均衡、服务监控与故障恢复等方面展开讨论,并结合实际案例分析如何优化微服务性能及可靠性。通过本文的阅读,读者将获得实施高效微服务架构的实用知识与策略。
|
5天前
|
Kubernetes 监控 Cloud Native
构建高效云原生应用:基于Kubernetes的微服务治理实践
【4月更文挑战第13天】 在当今数字化转型的浪潮中,企业纷纷将目光投向了云原生技术以支持其业务敏捷性和可扩展性。本文深入探讨了利用Kubernetes作为容器编排平台,实现微服务架构的有效治理,旨在为开发者和运维团队提供一套优化策略,以确保云原生应用的高性能和稳定性。通过分析微服务设计原则、Kubernetes的核心组件以及实际案例,本文揭示了在多变的业务需求下,如何确保系统的高可用性、弹性和安全性。
11 4
|
5天前
|
Linux 数据安全/隐私保护
Linux基础与服务器架构综合小实践
【4月更文挑战第9天】Linux基础与服务器架构综合小实践
1110 6
|
6天前
|
运维 监控 自动驾驶
构建可扩展的应用程序:Apollo与微服务架构的完美结合
构建可扩展的应用程序:Apollo与微服务架构的完美结合
27 10
|
11天前
|
API 数据库 开发者
构建高效可靠的微服务架构:后端开发的新范式
【4月更文挑战第8天】 随着现代软件开发的复杂性日益增加,传统的单体应用架构面临着可扩展性、维护性和敏捷性的挑战。为了解决这些问题,微服务架构应运而生,并迅速成为后端开发领域的一股清流。本文将深入探讨微服务架构的设计原则、实施策略及其带来的优势与挑战,为后端开发者提供一种全新视角,以实现更加灵活、高效和稳定的系统构建。
18 0
|
25天前
|
负载均衡 测试技术 持续交付
高效后端开发实践:构建可扩展的微服务架构
在当今快速发展的互联网时代,后端开发扮演着至关重要的角色。本文将重点探讨如何构建可扩展的微服务架构,以及在后端开发中提高效率的一些实践方法。通过合理的架构设计和技术选型,我们可以更好地应对日益复杂的业务需求,实现高效可靠的后端系统。
|
25天前
|
监控 持续交付 API
构建高效可扩展的微服务架构
在当今快速迭代和竞争激烈的软件市场中,构建一个高效、可扩展且易于维护的后端系统变得尤为重要。微服务架构作为一种流行的分布式系统设计方式,允许开发者将应用程序划分为一系列小型、自治的服务,每个服务负责执行特定的业务功能。本文将探讨如何利用现代技术栈搭建一个符合这些要求的微服务架构,并讨论其潜在的挑战与解决方案。我们将涵盖服务划分策略、容器化、服务发现、API网关、持续集成/持续部署(CI/CD)以及监控和日志管理等关键主题,以帮助读者构建出既可靠又灵活的后端系统。