你们好,我今天的分享主要围绕如下几点,首先跟你们简要介绍一下微博服务化的演进过程,其次是微博自研跨语言RPC 框架 Motan 实现的一些关键技术要点,主要是跨语言方面,再次,结合目前市面上的一些Service Mesh 实现对比,给出基于 Motan-Go 的更符合微博场景的Weibo Mesh 实现。编程
最后,是我我的对于面向将来泛服务化架构的一些思考。一些同窗对Service Mesh比较感兴趣,也想在生产上作一些实践,若是没有历史包袱,新开发一个项目用什么架构,怎么实现都是能够的。由架构去取舍,看咱们更迫切须要的是什么,所追求的是性能仍是其它高扩展性等等,目前也有一些现成的解决方案。可是若是没有作任何服务化,或者服务化过程当中历史包袱比较重,可能很难找到一种能够直接实施的现成方案,由于须要考虑的每每会更多。本次分享更可能是关于操做性内容,但愿对你们有必定的借鉴意义。后端
微博平台服务化演进安全
咱们先看微博平台服务化的演进过程。服务器
微博2009年上线,在业务高速发展的初期是传统的模块化单体服务,每一个小的业务都有可能随时爆发成长为一个核心业务。咱们的目标很简单,就是知足业务快速发展的需求,而且在突发流量增加时保证服务的高可用。随着业务的扩张,单体架构各个模块严重耦合,导致相互的影响愈来愈大,请求成功率得不到保障,长尾问题严重。为了解决这一系列问题,微博从 2013 年开发了Java 语言的 Motan RPC 框架,并基于此完成了服务化改造。Motan 从2013年上线至今经历过每次热点事件、三节高峰的严峻考验,稳定性和可靠性都获得了实际场景的验证。这些经历之下微博 Motan 也积累了一套服务治理型 RPC 的服务化体系。网络
除了Motan,2015年开始,为了应对愈来愈猛的流量洪峰,更合理的对资源进行整合利用,开发了Open DCP 弹性云计算平台。实现了动态的弹性扩缩容,告别了以往花费动辄几千万的资源成本,以及节前几个月就要开始的劳民伤财为三节作准备的日子,也不须要在为了一个个的热点事件提心吊胆。架构
上图是当时微博平台技术体系的概貌,是一个基于 Open DCP 弹性云计算平台和 Motan RPC 的服务化架构,通过几年的运营和考验,咱们已经在混合云的服务化方向有了丰富的经验和积累。但在解决了微博平台内部服务高可用、高性能的问题后,业务方平台服务调用的问题开始显现出来。好比调用链路过长,致使坑多性能差,又好比,每一个业务方都须要作高可用和服务治理,而这些事情平台已经有丰富的积累,你们都再作一遍特别重复且浪费。当想把在平台上的技术积累服务到微博更多的业务方时,平台内部基于 Java 的服务化体系已经不能完成任务,因此咱们须要一个跨语言的解决方案。从2016年起,咱们开始了跨语言服务化改造之路。并发
跨语言RPC要点负载均衡
异构系统如何作总体服务化的解决方案,也是今天探讨的一个主题。框架
服务化经历了前面几个阶段后,须要构建一个跨语言的服务化体系,将原来在 Java 体系积累的经验加以总结,给其它的技术栈业务赋能,更好的维护微博总体的稳定和高可用。ide
上图我简单列举跨语言 RPC 的几个技术要点,最下面是可靠性和易用性,好比咱们的 Motan 有 Cluster 的概念,每次调用都是从这个 Cluster 里面经过负载均衡(LB)策略来找出可用的节点(Endpoint),再经过一种高可用的策略(HA)完成调用。整个过程的各类理念可复用,各类语言照章实现就好。各类策略也是能够按需根据实际状况进行扩展的。而传输、I/O、进程线程模型等各个语言都不同,须要根据语言自身的特性来选择。
协议和序列化,这是解决跨语言比较重要的一点,由于要让各类语言互相理解对方,互相沟通。
上图的故事你们可能都有所耳闻,人类很狂妄地说,我要建一个塔直通到天堂。可是上帝听到之后以为很不爽,因此让人类说不一样的语言。由于语言不通,致使塔建歪了,整个工程就失败了,这是说交流的重要性。要作跨语言服务化,负责数据通讯的RPC 框架跨语言是重中之重的基础设施。而协议和序列化如何取舍,很关键。
Motan的Java版,所要解决的是微博平台内部 Java 服务之间的调用,所以 Motan1 协议时,其实并无考虑到跨语言的问题,用的是对Java比较友好的 Hessian。后期在跨语言方面,motan1的协议显得对跨语言不是很友好,motan2 的协议就给了一个足够容易理解的协议,是一个简单的TCP描述。好比,要请求一些方法、服务的分组,或Body,请求发过去,对方语言收到后,怎么样让这个语言理解呢?关键一点就在于序列化。
如今 Motan 使用简单序列化的方式(Simple),只支持几种简单的类型。不过咱们一直都在迭代中,也正在之前支持更复杂的类型上作扩充。但本质上,它还是简单的协议,咱们会尽可能保证它的简单。只有足够的简单,才能在跨语言上下降成本,开发成本还好,主要是语言沟通起来解析的成本,好比,编译型语言每每有各类明确的强类型,而解释性语言每每并不须要强制类型约束,如何让他们很好的沟通,这就须要作取舍。
这里给出一个 MotanRPC 框架简图,微博有一个自研的注册中心叫 Vintage,也支持其它像ZK等一些注册中心。图中给出了 Motan RPC 关键的一些组件和他们之间的调用关系。若是对Motan 感兴趣的,欢迎你们到GitHub 搜索关注,咱们有更详细的文档,你们也能够网上搜索。为何要说这些?由于Weibo Mesh 是基于Motan来作的。但愿你们对Motan有个总体的认识。
现有实现跨语言,支持不一样语言的Motan,最下面是Java版,就是最开始的一版,如今支持Golang(Motan-go)、Openresty-Lua(Motan-OpenResty)、PHP(Motan-PHP)。
基于 Motan-Go的 Weibo-Mesh
下一个话题:基于motango的Weibo-Mesh。数人云敖小剑老师扛着ServiceMesh大旗已经冲了一段时间了。刚开始咱们也看到这一点,其实你们的想法都同样,由于需求和痛点基本是同样的。因此咱们严重认同ServiceMesh是下一代微服务,固然不一样人都有本身的理解,经过初步的实践,若是一个很复杂的架构,你们在作服务化,服务化到必定程度,会因为微服务的力度和规模慢慢增大,出现依赖复杂度的增长带来流量交错,难以管控以及服务治理更加困难等一序列的问题。为了解决这些就须要一个东西很好的管控这些服务和流量,这就是为何会有Mesh。
看一下如今业界公认最牛的 Mesh Istio是怎么玩的。这里我但愿你们关注两点,一个是 Istio 有一个基于Envoy 的数据传输层,另外是控制面板,Istio 经过这个控制面板来完成流量调度,鉴权,服务治理等工做。这是 Istio 如今的作法,那微博怎么作的呢?
首先,咱们从2016年开始作跨语言的服务化改造,那时尚未 Service Mesh ,刚开始很简单,只想作跨语言,想解决跨语言调用链路过长的问题。好比,原来全部的跨语言服务都是经过 Restful 接口提供的,每一个请求都须要层层转发,尤为如今是混合云的架构。举个极端又及其常见的例子 , A 机房的服务依赖一个Restful 接口,请求发出后,内部 DNS 解析说这个域名在 B 机房提供服务,你到B 机房后,HA 告诉你,这个请求应该去C 机房的一个Member 上去完成,绕了一大圈,颇有可能发现那个 C 机房在公有云上,链路特别长。因此,但愿经过实现跨语言的 Motan RPC,Client 对Server 发起直连,经过点对点的通讯来解决链路过长的问题。然后来的演进,后面再细说。
今天讲的这个可能比较简单,目的是但愿你们能更好的入戏,更好的理解。能够用直连的方式,或用任何其它方式,像咱们用了 Motan。
微博从2016年开始作这个事情踩了不少坑 。微博作跨语言,刚才在后面跟老师们交流你们还说 GRPC 把跨语言带跑偏了,当时作跨语言的时候就是想GRPC已经作的很好,就想经过Motan支持GRPC 协议的方式来实现Motan的跨语言调用。你们能够去翻 Motan 的开源,里面是有GRPC支持的,如今也还有(不过最先支持的是PHP,对接的是鸟哥写的那个Yar的RPC框架, 最先 Motan还支持Yar协议。)。
因此当时想法很简单,想依托GRPC来解决跨语言的问题,因此是上面这样的一个结构,用GRPC来搞。
这个结构出来之后,咱们开始拿线上的业务来摸索改造。发觉须要把原来的Restful 接口彻底重写成GRPC的服务,这样的改造避免不了大范围的代码重写。硬着头皮改了一些后,发觉性能也没有像宣称的那么好。
你们平时可能都会上微博,咱们一条微博数据里面可能有百十个字段,因此基于GRPC 改造就须要把这些字段和服务都用PB 进行定义,完了之后发现最终的Proto文件写下来一大坨。虽说请求过程并不须要传递这些proto 数据,可是请求数据回来之后须要解析组装。跨语言的时候,好比说PHP来解析那个对象,性能就比较差了,因此这种方案应对微博这种场景最终被淘汰了,并且就算勉强接受性能的损失,这里也只是基于GRPC 解决了跨语言的部分。那另一个很重要的部分 --- 服务治理呢?
由于咱们多年服务化演进,Motan整个体系在服务治理方面作了不少工做,有不少积累。可是基于 Motan 支持GRPC 协议来完成跨语言的服务化的服务治理怎么作呢?好比说这个时候PHP 怎么去作服务发现?PHP 每个过来,都是一次处理整个过程就结束了,没有一个常驻的可用存储每次请求状态的地方来实现服务发现、服务治理这相似的事情。
可是咱们也作了不少尝试,好比经过一个本机的后台进程来作服务发现,或者在Nginx 上基于OpenResty 的timer 来实现服务发现,并发结果写到PHP 的$_SERVER 变量中,让PHP 能直接使用(上面右图那样)等,可是实践的效果并不理想。
因此总体经过 GRPC 来作跨语言这个方案作下来,效果不是很理想,这并不适合咱们的场景。因此咱们就走到WeiboMesh的原形(以下图),咱们想既然解释性语言的跨语言服务化因为语言自己的特性和咱们的特殊场景(主要是改形成本、性能等方面的考量)下,并不适合直接经过语言自己来实现,那这样的话,还不如去作一个代理。这个代理可能就是WeiboMesh的一个雏形,相似如今ServiceMesh 中的SideCar。
好比说Java启动一个服务,一般状况下,好比 Java Client 访问这个服务是这样的一个流程:Java Client 启动的时候会根据配置去注册中心订阅本身须要访问的服务,请求过程当中会有一个线程不断的从注册中心去发现当前可用的节点列表回来,组成Client 端的一个Cluster而完成的调用(如前面Motan 请求处理简图所示的那样),而若是是PHP 须要经过Motan RPC 访问这个服务呢?PHP无法作服务发现,它就把它的请求扔给Go Agent,服务订阅、发现、治理这些事情让Motan Go Agent 来作,其余的都同样。咱们作这个的时候,尚未ServiceMesh这个东西呢,因此一路踩了不少坑。
继续往下想,若是反过来 PHP要作server的时候呢?以前说 RPC 跨语言所要解决的一堆技术问题,比较重要的是传输模型,怎么选一个比较靠谱的模型来做为Server 处理请求呢?如今也有不少很好的现成的解决方案,可是咱们没有从中选哪一套来作。主要由于微博业务实在是很庞杂,里面有不少 PHP 的业务,若是把原来基于 LNMP 的服务架构改为 PHP 直接作Server的话,涉及到排山倒海的业务重写,PHP 同窗可能会要了咱们的命,他们是不会接受的(我要是他们,我也不会干)。因此咱们就想,怎么能更简单的把这个事情作了,由于已经有了前面 PHP 经过 Motan Go Agent 去请求RPC 服务,咱们就继续在上面扩展了一下。
PHP 要作SERVER,咱们使用Motan-Go-Agent来帮助PHP作服务的导出,这个就不是简单的请求调通了,由于 Motan-Go-Agent 除了负责请求的连通,还负责Server 端 PHP 服务的注册。Motan-Go-Agent的角色更像是是一个Motan Server。启动的时候他会把须要导出的PHP的服务,好比注册中心完整导出,并保持像注册中心服务状态的上报更新。导出后,假如说一个Java的Client 须要调动这个服务,Java-Client 会订阅这些服务,请求过程当中会经过服务发现回来的节点对它发起调用。Motan-Go-Agent 接到请求后,它把这个请求转给后端的PHP 处理,它之间多是基于CGI或者是HTTP协议完成的,回来这个请求就完成了。
服务化之后,最直接的感觉,原来服务调用时依赖一些 lib 库、Jar 包,或者Restful接口,如今变成依赖一些服务。在服务调用时,再也不是倒入某个包或者Curl 某个接口,而是直接去注册中心订阅和发现某个服务,这是一个本质的改变。
这个本质的改变提升了服务依赖和复用的效率,可是原来的不少服务都经过这种方式暴露了,也直接提高了服务治理的复杂度,服务治理成本变得相对较高。
可是这一切都是值得的,由于这一来咱们统一了服务治理的方式,高可用等各类保障,通用逻辑的封装等实现起来都更轻松天然。
咱们基于 Motan-Go-Agent提出对像 PHP 这样不方便实现服务化的语言,经过正向、反向代理的方式来实现跨语言服务化,Java、Golang这样很方便实现服务化的语言,有简单的Motan实现,或者也能够直接经过Motan-Go 导出服务,这样就只须要实现一个简单的Motan-Client 来完成服务调用便可。
咱们服务化作到这个阶段,发现性能已经符合预期,可是当想扩大规模的时候,发现节点和服务数量少。服务化规模很小的时候,好比平台提供几个服务,供几个业务方来调用,可能人工确认,事先配好就没问题。但服务化规模大了以后,就无法人工确认来解决,咱们的作法是经过扩展注册中心的功能来解决。
在咱们束手无策的时候,发现Service Mesh这个概念出现了,并且解决的问题和面临的挑战都同样,都是解决跨语言服务化的问题,也都面临流量、服务管控和治理复杂化的挑战。并且,那么多大牛公司在后面作背书,因此咱们就立刻转到这个方向上来,但愿实现一套更符合微博现状的Weibo Mesh。
要更符合微博现状,首先咱们在 Motan RPC、服务治理上有不少积累,这是已有的,不想抛弃的,这是宝贵的技术资源。另外一个目标,要作跨语言。因此,一体化的解决方案更符合微博的结构。
另外,微博是混合云架构,弹性云计算平台已经有了。若是新起一个项目,没有任何历史包袱,任何方案均可以。但假若有历史包袱,就不同了。
这就是基于微博现状作的 Weibomesh。这里给你们详细的说一下,一个是Mesh,跟Istio就很像。可是不同的地方是说,微博体系里除了一些编译型语言,还有一些解释型语言。只有解释型语言须要走用Mesh来导出服务的方式。好比Java 就不须要,由于有比较好的原生积累。Istio宣称不须要业务方改任何一行代码。可是咱们这里须要一个简单的薄薄的client层,算是咱们对本身业务的一点牺牲,对后面的收益极大。
其它都同样,包括服务注册、发现、调用。另外,决策系统比如 Istio 里的控制面板同样,负责发指令。跟Istio不同的地方是,Istio 中是经过一些请求的 Header 的数据,经过一些规则来作基于 iptables 的流量转发,而Weibo Mesh不须要转发,由于服务都是经过发现回来的,要调什么服务,就发现什么服务。调用是明确的,出门以前就知道本身要去哪儿,不须要转发。只是有一点,可能发现回来是一堆节点,须要把控的是怎么让流量更均匀,更好的控制流量,因此有一个自动流量调度和弹性扩容。
弹性扩容自己就有,为了应对峰值流量,应对节日。好比原来为了过年,要提早三个月准备好几千万的服务器。
服务治理是Motan体系的积累,服务传输就是经过它来收发请求,流量过来,由于请求都通过Mesh层,因此经过时时调用的信息,来时时调配流量,对总体系统进行保障。
这就解决了刚才说的,若是微服务力度大,服务划分很细,Services 规模大到必定程度,多个服务之间,怎么互联互通。
这是微博自动台调动体系,分为几个关键点。容量评估模型、是自动化压测容量评估系统。弹性调动要解决的问题,一个是调配集群的流量,一个是控制集群的规模。怎么调配?首先要度量,度量系统包括:它何时是正常的,健康的,何时是冗余的。一个系统的冗余度是怎么度量出来的。
经过上面这个公式来度量集群的冗余度,还评估了集群是否须要扩容,流量是否须要调动。
下面这里有几条水位线的概念,一个是安全线,一个是警惕线,一个是危险线,红色的就是危险线,这个时候就须要扩容了。你们能够理解为水库,一个水库能蓄多少水,何时水位上来,扛不住了就会发生洪灾。
经过对整个集群的流量评估,能够知道这个集群是否空闲,是否安全。当集群流量扛不住,是否把这些流量切到其它集群,支撑整个弹性调动和动态容量调动。
Weibo Mesh改造收益
WeiboMesh改造,通用于任何异构系统。有些操做好比解释型语言,由于某些语言特性,不能实现那个功能,可是用Mesh的方式,能够在 Mesh 层实现。好比, PHP 请求一个接口,若是接口响应慢,一般的作法是重试,这样会带来危险,由于原来走的都是集群的转发。可是若是直连,若是一个节点慢了,一直重试可能就试挂了。若是重试三次不能够,就再也不往这里调了,把它从可用节点里摘掉,解决宕机的问题。
监控里会常常看到一些长尾的调动,发现系统性很好。可是真正跑起来,由于网络或者机器的因素,可能会致使后面的长尾特别长,特别占资源。若是在 Mesh上,时间长于某一个阈值的时候,就再给发一个,若是后发的请求响应先回来的话,能够把前面的请求抛掉。
体系化是说,不须要在每一套语言里都实现一套。这跟通用的ServiceMesh方案同样,你们都是为了通用和统一。
这是微博搜索,接入这个系统以后生产当中的一些数据,也通过了一些实验的验证。好比,这是薛之谦和前妻复合事件,这个图同事在不少场合都讲过,原来运营发一个 PUSH ,你们都提心吊胆。在新浪若是遇到爆炸性的新闻,运营在发 PUSH 以前,都要通知到全部技术。可是如今不须要这样,好比说那次运营发了一个PUSH,你们能够想象一下山洪爆发,调动系统发现已通过了黄色警惕线了,已经须要扩容了,它就自动扩了,冗余就上来了,这是动态扩容。弹性调动也是如此,用的同一个技术体系。
面向将来架构,从新定义服务化
在开发过程当中会遇到不少问题,原来作服务化,所提供的是一些Lib、Jar包或是像接口之类的,可是如今已经再也不依赖那些,如今依赖的是服务,Service Mesh 里甚至都没有Client和Server的概念了,都是Service。可是在Motan里面,是有Client和Server的。它有两端,由于要去发调动,两端的处理不同。调动不是通盘都按Service来说的,是经过服务发现,而后对Server 发起直连。这个过程致使须要每个实现跨语言的地方,都须要一些特殊的处理。
首先通用性方面,使用Motan来刻画一个服务,如今再也不依赖包,而依赖于服务。提供的时候,告诉这个服务,注册到那个分组下,调动那个分组下面的服务就能够了,一个很简单的RPC服务调用的方式,上面会有协议,节点和版本号相似的数据,用URL来惟一刻画一个服务。
微博有历史包袱,但愿已有的系统不要改动太多,以最小的成本获得最大的收益。因此,咱们对原来基于 Jersey 开发的 Cedrus Restful 框架进行了适配,在Motan框架层面把原来全部的Restful 接口自动导出为Motan RPC 服务,经过这种方式减小改造的成本。原来改造的时候,须要把全部 Restful 服务都重写成RPC服务,成本特别高。
支持协议,好比支持GRPC,前面有GPRC能够去调,如今支持HTTP,HTTP对等的是Cedrus(其实就是Servlet)。它其实中间传输的是Motan协议,可是能够按照HTTP的方式调动一个Motan服务,这样的话,Client也不须要改任何一行代码。
咱们对WeiboMesh 的一些思考,Weibo Mesh 跟一般的Service Mesh 有本质的不一样,咱们对服务的调用是经过服务发现后直连的,不是经过拦截和转发。一般Service Mesh 不能直接知足咱们的需求,可能你们也有不少相似的场景。因此这些思考但愿能给你们一些借鉴的意义。
Weibo Mesh的服务调用须要更轻薄的Motan Client,一个缘由是下降已有架构的改形成本,一个是泛服务化的概念。好比访问微博,须要调动用户的服务、微博的服务,评论的服务,可是后端的底层资源,好比说MC,Kafka等的资源都是服务,若是把这些资源用 Motan 协议来实现资源服务化,只须要一个Client就能完成全部的服务调用。并且服务治理体系,流量管控体系均可以复用,解决了你们在开发的时候面对各类资源的不一样Client实现而各类调研,选型。微博基于OpenResty 实现了 Motan-OpenResty 版本,就是想以此来对OpenResty 社区在资源服务化方面实现复用,提供更多更方便的服务。
基于泛服务化理念,经过轻薄的Client,就能够调全部服务。虽然改造的时候须要改一点代码。泛服务化跟 Istio的思路不同之处还在于,泛服务化不止针对本身开发的应用级服务,还有一些底层服务,资源的服务。他们均可以经过封装为简单的 Motan2 协议来进行简单的访问,全部功能都是可编程可扩展的。用过Motan的人都知道,Motan在作扩展的时候特别简单,好比说要加一个通用的逻辑,不管是扩展一个Filter 仍是新增一种HA策略,这个架构是一个可编程,泛服务化的架构。
Weibo Mesh后期规划
微博是混合云架构,若是是新的公司可能就直接上云了,因此咱们后期也考虑在云原生计算方面作一些支持。出于微博自己的技术须要,咱们还会在服务治理的总体方案方面作更多的尝试。咱们也但愿Weibo Mesh 能作成更通用化的服务方案,让更多团队受益。
另外,Motan还有Motan—Openresty 版本。出于我我的对OpenResty的理解,我认为OpenResty 多是目前惟一称得上服务器应用开发平台,把Nginx 做为一个开发平台,在上面开发各类服务,并且是基于极其简单、表现力极强的Lua开发。最使人欣喜若狂的是,重启维护的Stream-lua 模块让OpenResty不止能开发 HTTP 服务,一样能开发 TCP、UDP 服务。基于此的 Motan-OpenResty 能够复用 OpenResty 积累的一切,我但愿能在Openresty方面作一些事情。
由于就Mesh体系来说,你们可能都是有包袱的。当有既有技术体系的时候,Java应用或者其余应用,前面都挂着Nginx,从Nginx 到OpenResty 的迁移成本几乎为零。在整个流量分发当中,它起到比较关键的做用,若是能在这一层上作一些事情,那是否是把不少改造的工做又减轻掉了,平台本身来解决不少问题,应用级别就不须要搞,由于如今比Istio,感受须要强化一点在于说,有一个Client,须要你们改一点代码,可是又但愿能不能更少的成本,因此我须要作这样的一些事情,这是我本身后期的一个摸索的方向。但愿一样对这种思路感兴趣的同窗能一块儿参与,自己整个体系都是开源的,欢迎你们有什么想法或者是有什么问题提出来,一块儿来作。
由于以为在这个方面走的也不算特别早,也不晚,如今在业务场景上真正落地的Mesh的,微博应该是比较早的,而那个Motan-Openresty版本多是基于最新的Openresty Stream模块开发的。那个如今也做为Openresty社区比较标准版的Stream模块开发样板项目,也但愿你们多多的关注,我今天的分享就到这,谢谢你们。
关注Service Mesh中文网公众号(帐号ID:servicemesh),回复1216,便可下载本次演讲实录PPT.