Service Mesh 是近两年比较火的微服务化新方式,也产生了一大批以 Istio 为代表的 Service Mesh 实现。
微博基于实际业务需求,打造并开源了自己的 Weibo Mesh,并且内部已经在重点业务上进行大规模落地。
本文将从如下几个部分为大家详细解读 Weibo Mesh,希望可以为大家带来服务化方向上的一些灵感,更好的服务于自己的业务:
-
微博服务化挑战
-
服务化新思路
-
Weibo Mesh 方案介绍
-
生产实践
-
总结
微博服务化挑战
首先,为大家介绍下微博服务化面临的挑战。微博的形态比较特殊,除去常态午/晚高峰流量较高外,突发热点事件的杀伤力更大。
热点事件来袭时,流量极短时间内呈现爆炸式增长,并且往往事件爆发没有任何征兆。这对于微博服务化及稳定性均带来了极大挑战。
如果其中某一个环节掉链子,不能及时感知并作出应对,极有可能会导致雪崩式宕机,导致全站挂掉。
那么怎么解决这种问题呢?首先会想到自动扩缩容/降级建设,但是我们决策依赖是什么呢?又如何满足系统可观测性要求,以及如何评价系统可用性及冗余度呢?
究其本质,系统的服务治理建设非常重要,它会直接影响到服务可用性。但是微博技术栈的多样性又导致了在微服务化和服务治理方面困难重重。
从技术层面看,微博的典型服务调用大致如上图,业务体系会调用平台体系的多个接口,例如通过平台接口获取微博内容。
平台体系主要是 Java 技术栈,本来微服务相关解决方案也多,再加上服务化时间较早,平台微服务体系建设相对比较完善,同时也产出了一些优秀开源框架,比如 Motan 微服务框架。
业务方的语言栈:多样化,基本涵盖了所有主流语言,其中 PHP 相关系统流量占比较大。
调用链路:通常情况下业务方和平台使用 RestFul API 进行交互。一次请求调用要经过 4,7 层的层层调度,服务稳定性还时常遭受网络抖动及 DNS 不稳定的困扰,在中间层的消耗是不容忽视的。
另外,业务部门的语言种类繁多,间接导致了各部门微服务体系建设参差不齐。
峰值流量应对需要所有部门所有业务模块的通力协助和联动,考验的是整站实力,我们需要所有模块都能具备高水平的服务治理能力。因此我们迫切需要解决跨语言微服务化问题。
上图是微博平台内部的微服务体系支撑图,平台实现以 Motan 框架为核心的微服务治理体系 。
此外,还有自研的 Vintage 注册中心及 Open DCP 智能弹性调度平台以及 Graphite 实时监控平台,可以看出平台微服务架构有完善的 DevOps 支撑。
业界的大趋势是云原生,微服务作为云原生重要的一环,是我们必须要突破的。
微博服务化新思路
跨语言服务治理尝试
为了解决跨语言服务治理的问题,我简单介绍一下我们尝试过哪些解决方案。
这里有个大背景,Motan 由于是微博内部使用已久,经历过重大考验并且开源的优秀框架,它积累了很多优秀的服务治理经验,所以我们服务化改造要充分考虑 Motan 的存在。
我们尝试将 Motan 适配 Yar 这种 PHP 的 RPC 协议,PHP 可以与 Server 端的 Java 进行通讯,但 PHP 并不能进行服务发现。
于是我们在 PHP 旁边加一个 Daemon 程序,也考虑过使用 Nginx,来做服务发现。
当然问题也是显而易见的,这样改造会导致业务侵入变高,成本变大,扩展性也较差,何况并没有解决 PHP 做 Server 端的服务治理问题。
我们也尝试过 GRPC,当然跨语言调用能解决,但是这里遇到几个问题,一个是如何进行服务治理,另外一个是 PB 序列化问题。
由于微博场景的内容结构体非常大,效率并不比 Json 高,业务变更导致 PB 文件的变更让升级维护成本变得难以接受,另外序列化数据遇到问题调试也变的困难。
此外 ,技术栈的多样性也会引发一系列的问题。即使我们解决了 PHP 到 Java 的调用问题。但是相同的治理功能,不同的语言不可能再实现一遍。
Motan 框架积累下来的服务治理经验是我们需要传承和发扬的,那如何均衡这些问题及解决方案呢?
跨语言服务化本质
我认为跨语言服务化的本质,总结下来有两点:
-
数据交互
-
服务治理
数据交互设计要考虑跨语言及协议中立,服务治理设计要灵活全面且可扩展。
上图我列举了跨语言服务化方式的优缺点:
传统的 HTTP 代理,可以解决不同服务之间的调用。HTTP 就是传统的走网关,较容易实现,但因为内部的调用每个人都要加网关,这就增加了链路,导致扩展能力低。
RPC 模块或者 Agent 代理。RPC 框架业界有很多,大多 Java 栈的,功能也齐全,但跨语言维护成本非常之高。
Agent 代理是一个新的思路,Agent 代理的研发成本、维护成本、使用成本对比起来均比较折中,即我们独立一个 Agent 来专门解决我们遇到的跨语言服务化困扰。
那样既能释放传统的业务端的服务治理压力,又能传承 Motan 框架的精髓,也不需要实现多语言服务治理逻辑,更可以让业务和 Agent 互相独立发展,可谓一举多得。
这个思路最终也演化成了今天的 Weibo Mesh:
由此微博走向了 Service Mesh。微博走向 Service Mesh,并不是盲目追赶最新的技术潮流。
我们立足于现状,立足于解决实际业务问题,并一步步探索过后,发现最终的解决方案与 Service Mesh 思路不谋而合。从侧面也验证了 Service Mesh 思路解决服务化问题的合理性和前瞻性。
上图,我们可以用正交分解法来理解 Service Mesh,可以看到,原有的微服务被拆分成业务逻辑层和服务交互治理层,其中服务交互治理层抽象为 Service Mesh。
Service Mesh 把服务间的交互与治理逻辑从业务中进行解耦,抽象独立成一个专门的处理模块。
通常 Mesh Agent 以 Sidecar 的形式和业务进行本机部署,Agent(以下 Mesh Agent 简称 Mesh 或 Agent)可以理解为服务的基础设施层,业务无需关心服务间交互/治理细节,全部交由 Agent 统一处理。
Service Mesh 带来的是微服务架构思路的转变,为业务开发带来了诸多架构上的优势,Agent 及业务均可独立发展,通常 Agent 交由运维管理,业务开发交由业务线,故整体可以做到持续开发、持续集成。
Mesh 思路不光可以解决跨语言服务化的问题,也可以解决资源服务化问题,而这些改造基本都对业务方透明。
Weibo Mesh 方案介绍
下面具体介绍下 Weibo Mesh 的实现方案。上图是 Weibo Mesh 架构图,除了必须的 Mesh Agent 外,考虑到业务迁移及实际落地需要,这里在业务代码和 Mesh 之间增加了 Client。
这个 Client 非常轻,其核心功能是封装 Mesh 请求,方便业务进行 Mesh 调用,最大限度降低业务迁移成本。
实际上在 Client 中我们也实现了其他一些对业务友好的功能,同时对 Mesh 调用进行了功能增强。
比如可以在 Client 中进行跨语言的序列化,Mesh 故障转移,请求多发,超时控制等。
当然不同业务方可以进行功能定制。Client 和业务相同的语言编写,其核心目的是帮助业务进行平滑迁移。
Mesh 层实现了 Service Mesh 的核心功能,包括发现、交互、路由、治理。
Weibo Mesh 是由 Go 实现的,国内各大厂商的 Mesh 数据平面也大多使用 Go 来实现。
Go 具有优秀的性能及易用性,又是云时代比较推崇的语言,未来 Mesh 层极有可能结合容器,沉淀成为容器的一个基础设施层。
Weibo Mesh 数据面
剖析一个 Service Mesh 服务,一般通过数据面和控制面。首先来看一下 Weibo Mesh 在数据平面的表现,包含五个核心模块:
-
Cluster(集群管理),对分组下通过服务发现回来的的节点列表的抽象管理。
-
HA(高可用策略)、LB(负载均衡)。
-
Endpoint(服务节点的抽象),本质上是 IP 和端口,但从代码层面看,它是服务节点的抽象,通过 Endpoint 可以进行直接的调用,可以理解为它是调用的一个单元。
-
Protocol(Motan2/传输协议+Simple/序列化协议)。
下面一一介绍这些模块。
①Cluster 模块
调用方请求通过本机的 Mesh,在 Cluster 模块处理中,首先经过一系列集群粒度的 Filter Chain(过滤链,包含集群 Metric,熔断,拦截,鉴权,分组切换等功能,它们以链式结构进行组织调用,支持任意过滤功能扩展)。
然后再经过高可用策略跟负载均衡策略筛选出一个可用的 Endpoint,在 Endpoint 中又会进行请求粒度的 Filter Chain(单机的日志记录,Metric 等),通过进行请求序列化,根据传输协议进行组装,最终通过 Endpoint 把请求发到对端的 Mesh 上。
②高可用策略
Weibo Mesh 中的高可用策略,支持一般的常用策略,比如 Failfast,Failover 等,负载均衡支持权重轮巡,根据权重轮巡、随机等常用策略。当然也可以定制自己的 HA/LB 策略。
Weibo Mesh 中推荐采用的高可用策略是 Backup Request,又叫双发。双发继承自 Motan 框架,是我们探索出来的比较高效可靠的机制。它可以有效解决长尾问题,同时能提升系统吞吐量。
传统解决接口超时问题可能通过重试,在一次请求发送之后等待指定的超时时间,如果没有返回则再请求一次,最差情况下要消耗 2 倍的超时时间。
而双发机制则不然,在发送一次请求后等待 P90(在 T1 时间内有 90% 的请求都能返回则称 P90=T1,通常系统的 P90 和程序设置的超时时间相比小很多)时间。
如果请求没有返回则在此刻再次发送一次请求,在超时时间内,这两个请求中取最快返回的那个。
当然,这里有个防雪崩机制,假如,超过一定数量的请求(比如 15%)都在进行双发,则认为服务整体有问题,会自动停止双发。实践证明,双发机制的去长尾效果非常明显。
③节点抽象
Endpoint 是调用方 Mesh 到对端 Mesh 的调用单元。当我们启动 Weibo Mesh,在初始化 Cluster 的同时,也会对 Endpoint 进行初始化,绑定 Filter Chain,并为每个 Endpoint 保持一定数量的长链接供选择调用。
当然这里还会有一些细节,如果某个节点的调用失败,计数超过一定阈值则自动摘除节点,并进行定期探测等待可用,再重新加入可用节点列表。
④Motan2 传输协议
Weibo Mesh 整体沿用了 Motan 的协议设计,并进行了升级。
Motan 支持 Java 的序列化,当时考虑的是 Java 间相互通信,但是考虑到跨语言通信及未来扩展需要,我们把协议设计分成序列化协议与传输协议。传输协议负责把序列化后的数据进行传输,序列化协议是跨语言的关键。
Motan 传输协议是典型的三段式:
-
Header
-
Metadata
-
Body
Header 中会标记序列化类型,消息类型(心跳还是正常请求),可以定义自己的 PB 序列化或是自研的 Simple 序列化。
在 Metadata 中会有一些方法名、属性名、用户参数;在 Body 中存放的是经过序列化后的请求/响应体。
Simple 序列化:Simple 设计比较简单实用。目前 Simple 序列化支持了基础类型,包括 Bool、String、Int、Float,当然它还会支持一些组合类型,例如 String、Bool 组合成的 Map,Array 等。
上图示例,type 是一个字节的数据类型,比如 Bool、String,接下来是字节长度,接下来是 UTF-8 字节流。Content 中可以进行嵌套,下方就是进行嵌套的例子。
协议转换过程:从协议层面看 Weibo Mesh 请求流转是调用方通过函数调用 Client,然后经过 Motan2 传输协议以及 Simple 序列化后,经过本机 Mesh,Mesh 层再转发给对端的 Mesh。
对端 Mesh 上层可能是任意一种形式的服务,比如非 RPC 服务,所以这里我们有个 Provider 模块,可以代理 HTTP/CGI 等非标准 Service Mesh 服务,它能把这些服务导出成一个具有 Motan 协议的 RPC 服务。
通过 Provider 屏蔽了 Server 端服务的真实协议。Provider 外面是标准的 Motan 协议服务,内部是原有协议的服务,这样对 Server 端来说,迁移到 Weibo Mesh 成本极低。
Weibo Mesh 控制面
控制面主要分两方面:
①策略扩展
Cluster 和 Endpoint 都有相应的 Filter Chain,他们实现了不同纬度或者粒度的调用控制策略。
Filter Chain 包括访问日志记录、Metric、熔断、限流、降级等。折中调用效率和耦合程度,它们都是以插件形式存在于 Weibo Mesh 中,也可以自由定制 Filter 策略及调用顺序。
②流量调度
Weibo Mesh 的流量调度基于注册中心。注册中心不仅为 Mesh 提供了服务的注册和发现,也提供了服务的配置下发,Mesh 在订阅注册中心的同时,也需要订阅相关的配置项。
比如我们把 A 机房的流量都路由到 B 机房去,我们在 Mesh 只要支持这条指令就可以。
生产实践
典型场景
上图是网关,Mesh 在微服务架构中的整体分布图。一般情况下网关架设在服务边缘,边缘节点主要把控宏观的流量调度控制问题。
在内部,各微服务之间构建 Weibo Mesh,来有效提高服务间通信质量、可观测性等要求。
迁移成本的考量:
-
真正将 Service Mesh 引入到业务场景中时,需要考虑一些问题点,比如业务部署模式是非云,混合云还是云原生?像微博是混合云,场景不同,因此架构也不尽相同。
-
Weibo Mesh 要适配注册中心。
-
各语言要适配 Client,目前已经支持 PHP/C++/C/Python/Lua 等主流语言,Java/Go 原生支持。
-
要适配相应的 DevOps 建设。需要相应的监控/统计等平台支撑,任何架构改造都要有足够的 DevOps 支撑。
接下来为大家介绍 Weibo Mesh 正反向代理实践。
正向 Mesh
上图是 Weibo Mesh 场景下的正向代理流程。Server 端服务进行注册,被调用方订阅到,调用方请求经过 Client,再经过本机 Mesh,最终到对端的 Mesh。需要注意的是虚线部分是故障转移的流程。
假如本机 Mesh Agent 挂掉,Client 会通过服务发现回来的节点快照选择可用节点进行调用,达到故障转移的目的。
反向 Mesh
上图是 Weibo Mesh 场景下的反向代理流程。一般我们的服务类型是 HTTP/CGI,或者其他私有协议。
反向 Mesh 的亮点在于,不需要 Server 端做任何架构的改造,直接架 Weibo Mesh 就可以了。
Mesh Agent 通过 Provider,将原有协议导出成 Motan2 协议的服务对外进行暴露,只需要把导出的服务注册到注册中心即可提供服务。
同时也不会影响原有服务的提供。这里如果你需要把私有协议导出成 Motan2 协议服务,可以自行扩展开发。默认支持 http/php-cgi 服务的导出。
反向 Mesh 特色:
-
提供 HTTP/cgi provider,可定制扩展。
-
HTTP 框架自动转 RPC,业务无需开发新 RPC 框架。
-
Mesh 对 Server 改造无侵入。
总结
治理模式的差异
传统服务调用,中间可能经过网关或者 RPC。服务治理只能存在于一端,一般在 Server 端进行服务治理。
但是 Mesh 服务,由于 Agent 本机部署,封装了服务治理,可以实现 Client 端或 Server 端的双向治理,这是 Mesh 服务的一大特色。
Weibo Mesh 优势
实战效果如下图:
上图可以看到,Mesh 服务的 Client 端 RT 曲线逼近 Server 端的 RT,这说明点对点的 Mesh 调用,由于没有中间层的损耗,再加上合适服务治理手段,两端性能也比较接近。而 HTTP 服务则有较多的中间层损耗。
右图可以看到双发的 p999 曲线相对比较直,这说明双发起到有效削长尾功能,间接也对系统性能有提升。
Weibo Mesh 集群
目前,微博内几个核心业务之间调用已经 Mesh 化,并经历过重大事件以及春晚的考验,支撑流量还是相当大的。
和 Istio 的区别
从控制层面看,Weibo Mesh 把类似 Istio 中的 Mixer 和 CA 的功能以插件化的形式放到 Filters 里面。
Istio 服务需要通过 Pilot 来做服务发现,而 Weibo Mesh 是直接通过注册中心,Istio 用 Envoy 做 Sidecar,而我们基于 Motan 打造了全新的 Agent。
Istio 有一个特色,上面每个模块都可以理解为一个微服务,都可独立拆分部署。
但是 Weibo Mesh 为了效率和内部落地的方便,更多的进行了插件式耦合,整体性能相比 Istio 也会更好。
上图可以看到 Istio 通过云平台适配各种 API,来进行服务发现,Weibo Mesh 则是适配注册中心。
Istio 更强调依据容器层面的发现(直奔云原生),Weibo Mesh 则可支持通用注册中心比如 Consul、ZK 等。
Weibo Mesh 通过 Client 拦截 Mesh 请求,模块化耦合部分功能。高定制化时,并不能对服务做到完全透明。而 Istio 通过 IPtables 流量拦截实现了业务完全无感知。
WM 进行中
我们知道 Mesh Agent 并不关心代理转发的是什么服务,所以就有一个新方向,即资源服务化,让资源存储层也能进行服务化。
Weibo Mesh 解决跨语言服务化的思路也同样适用于服务与资源之间的调用问题。微博服务有很多资源依赖,MC、Redis、MySQL、MCQ 等。
我们可以在资源层架设 Agent,同样可以达到资源即服务,也就是泛服务化。目前我们内部也已经有基于 Weibo Mesh 的资源服务化使用场景。
WM 未来发展方向
未来 Weibo Mesh 主要有两个方向,一个是继续推进云原生,一个是在易用性方面继续打磨。
Weibo Mesh 打通云平台和注册中心推进云原生,结合容器编排在服务治理上进行优势互补。
此外,我们也会积极努力推进,让 Mesh 整合进 L5 这一层。我们还会继续进行探索解决业务方接入不方便的地方,比如说更加方便的流量拦截方式;更广泛的语言支持…
Weibo Mesh 始终推崇落地简单、功能高效可靠,随着 Mesh 更大规模的推广,场景越来越极端,性能要求越来越高,我们在这方面也会持续打磨。欢迎大家一起加入 Weibo Mesh!