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