晁岳攀:软件开发的老兵,Scala集合技术手册(简/繁版)的作者, 高性能的服务治理rpcx (Go)框架的开发者,先前在同方、Motorola、comcast从事软件开发工作,现在在微博平台研发部做基础平台的研发工作。经常在网上和个人网站(http://colobu.com)发表一些技术文章。

前言

大家好,我是来自微博研发中心的平台架构组的晁岳攀,我这次给大家分享的是grpc框架的开发。我所在的组比较倾向于后台平台软件开发。大家知道微博前端基本都是用 php 做开发,它属于另外一个部门负责,我们这边平台研发部门全部是做后台开发的,主要使用的语言是Java,最近这几年,像我们平台架构组开始的新项目都开始用 go 开发,我们去年做的是原来微博的配置中心平台Vintage。微博的Motan是Java的RPC服务治理框架,它的服务发现中心是我们组负责的配置中心软件Vintage,我们不用做EPCD,是因为我们主要面对的服务高可用性的产品,而不是数据一致性优先的服务,所以我们自己开发微博的配置中心软件。最开始Java+Redis的实现,经常会有一些问题,去年用go开发的新的版本,已经将原来的产品替换了,经过了明星出轨还有春节等等一些热点事件,用我们那边的网红说的,能支持8个明星出轨的场景是没有问题的,是很稳定的平台。后来用go还做了消息云平台。

我从事软件开发也有18年了,从2000年毕业就一直在做这方面的相关工作,做了十几年的 Java,用 Scala 去做的大数据,又做 go,总的来说我觉得语言不是给大家打的一个标签,而是一个称手的工具。大家需要做一个项目的时候,会选择一个正确的语言。来到这的各位,肯定是对go是特别感兴趣,或者工作语言主要是go的,大家是最聪明的一群人,会选择正确的语言,同时大家也是最勤奋的人,在星期六的时候,还来参加这次技术分享,我衷心的感谢你们。

我们先回顾一下 rpc 的历史,再介绍我们常用的两个Go RPC框架。一个是 rpc 本身的官方库,还有就是大家常用的 Grpc 框架,我并不想在这个分享会推广我的框架,而是想跟大家分享一下我在做这个框架的过程中考虑的一些问题。大家如果没有用过 rpc 的框架的话可以了解一下这方面的知识,正在用的同学也可以熟悉一下使用rpc框架的时候需要考虑的方面, 如果碰巧你正在做rpc框架,可以互相交流一下,看看其他人是怎么做rpc框架的,了解一下别人做的工作。

在介绍之前,可以分享一个 rpc 的改造故事。

一个RPC改造的故事

这是今年年初春节的时候,一个网友的故事,在QQ群里面分享的一个真实的励志故事。这是一位游戏开发界知名的网友,现在在一家香港公司主要做海外游戏的项目,他们面临一个问题:他们部署了很多游戏服务器,但是当大家登录的时候会有一些恶意的攻击,他要拦截相关所有的操作把日志发到一个集群里面,存到数据库做分析。一开始用 Java 去做,然后出现诸多的问题,性能也非常低下,在去年的时候,他们用了 rpcx2.0 框架去做了改造,这是改造完运行半年的数据一张数据截图,应该是不到一天的统计量,有32亿的请求量。年终的时候他们老板算了一下,通过这次改造减少了一半的服务器的数量,费用从一个月100万港元减少到50万港元租赁服务器带宽等等费用,这给公司的运行成本带来不少好处,也给开发和运维人员带来了非常大的便利。我觉得它是非常好、典型的例子,它在半年的运营过程中,没有发现一个问题,非常稳定。只有一个问题是其中一个路由器坏了闪断了一下,但是和我们的软件没有任何关系。

RPC的历史

我们看看rpc的历史演变过程,最开始起源应该从互联网创建的时候就有这种萌芽,那时候不叫 rpc ,发一个request消息到另外一台机器上,返回相应的结果response。

1970年-1995年

1980年的时候SUN提出一个 onerpc 的概念,他在做NFS的时候用到了rpc的概念,接下来的几年,相继提出了好几个RFC规范,但是rpc的概念真正提出的是是1981年施乐公司的Bruce Jay Nelson,也可以称之为rpc之父,施乐公司大家都清楚那是一家传奇性的公司,这个人提出RPC概念以后,在九几年获得ACM的大奖,但是他不到50岁的时候因为一场病去世了,后来1991年的时候, 比较老一点的程序员都了解CORBA的服务调用,但是非常的复杂,以前我们给美国做视频项目的时候,就使用CORBA,使用起来特别的难,我觉得基本上就算被历史淘汰了。

1997年-2010年

1997年各家公司都在炒分布式服务调用的概念,windows 的DCOM+等等,Java提供了 RMI 远程调用的概念,1998年IBM、微软、谷歌等公司提出了webservice的概念。多年前的SOA,各家公司都拼命的推自己的标准,这里面形成了一批以 WS 开头的标准,虽然号称当时还是比较成功的,但是从现在看起来,过于复杂,而且各个公司之间互相的利益的关系, 给SOA的应用带来了制约。同时也有一些开发者提供了一些简化性的 XMRPC 的开发,但是我觉得大家记得比较清楚的是2000年 RESTFUL 这个概念,对资源来说,我们常做CRUD 的开发,创建、查询、修改、删除等操作,然后映射到 Post、Get、Put、Delete、Patch 等HTTP方法上,它把操作对象看成一种资源,这种风格一直影响到现在,现在有很多rpc的框架都是以这种方式提供的。Facebook 提出一个 rpc 的框架 THRIFT。 json -rpc 推出2.0。Go 标准库里面有json-rpc 1.0的支持,json-rpc 2.0有一些第三方库。

2011年-2018年

DUBBO在2011年开源,当时淘宝内部不使用了,但是墙内开花墙外香,外面很多公司,尤其是电商方面的公司,反而相应fork 进行维护,印象中当当网和京东最初都使用了 dubbo rpc 的框架,dubbo 在去年的时候,这个项目重新做维护,也专门有了相应的维护开发人员,一些依赖包的版本也做了升级,现在又活跃起来了。当时的时候,基本上处于一种不再维护的状态。Spring cloud这种框架很多在使用。2015年Grpc出现,2017年腾讯和百度也推出了自己的 Grpc 的框架,但是属于C++的框架,流行度还不广,基本上都在自家使用,现在像淘宝的蚂蚁金服和淘宝本身相当于两个公司,蚂蚁金服也在推自己的rpc的框架。rpc 的框架太多了,这里也就不一一列举了。

Client&Server

rpc本身调用流程是非常简单的,在 Client端利用stub,相当于把方法的调用传递给服务器,再返回到Client。

内部的处理流程,一般会使用Stub,将调用过程封装起来,接口调用会通过一个框架去实现。

官方RPC库

首先来介绍 golang 标准库的rpc,  也是由当初的大牛开发的,功能强大,但是代码非常的简便非常的好。利用标准库开发rpc非常简单,我们首先定义传入参数和传出参数,再定义一个对象,实现它的服务方法就可以了。

client首先连接你的服务器,直接把你的服务方法的名字和参数传进来,传出的内容作为最后一个参数,官方的库是非常好的,但是没有人维护,所有的功能都已经冻结了,除非有特殊的 BUG。如果我们自己要写简单rpc程序 建议你用官方的 rpc 库去开发。

如果要自己定义库或者是方法,可以实现这两个接口,但是要想做进一步的扩展比较困难,所以后来我自己写内核传输的协议,不再包装它,之前我看到有人想这个包装一下实现rpc框架,我建议你不要去做,因为被限制住了,可以参考它的之后写自己的rpc框架。

GRPC-Go

GRPC-GO

Grpc 是跨语言rpc框架,提供很多流行编程语言的支持,dubbo和Motan则是偏重服务治理的框架。Grpc是通过IDL文件,定义我们的服务,内部的通讯是通过HTTP/2进行通讯的,效率是非常高的,去年的时候又专门针对性能做了进一步的优化,花了很长时间提升了性能,我测试了一下,大约有50%的性能的提升,所以说性能提升非常的高。本身的数据编码方式通过ProTobuf 编码协议实现的,我们一般使用 gogo-protobuf 第三方库做开发。它的性能比官方的性能更好。这是Grpc库的服务端的代码,几行就可以实现服务。

GRPC-GO streaming

CLIENT 服务调用也非常简单,提供了流的控制,可以是单向的也可以是双向的,grpc是支持双向的。

HTTP

HTTP 本身有性能的瓶颈, 即使设置长连接, 客户端也需要等待前一个消息返回才能处理下一个(可能有些框架,比如fasthttp支持pipelining)。而GRPC, 是通过HTTP/2的传输方式,可以并行的发送请求,极大的提高了服务的并行调用。 它将一些元数据放在head frame中,payload放在data frame中。用 wireshark 抓包分析,可以看到grpc的具体的协议的实现。

GRPC-GO protocol

wireshark已经支持了GRPC协议,你可以方便的看它的协议以及protobuf的数据。

服务治理的RPC框架的实现

下面我讲一下开发rpcx这个框架过程中一些考量和技巧,希望对大家做rpc的框架开发有帮助。

RPC框架

当我们谈论RPC的时候,比如官方的rpc或者GRPC, 一般谈论的是rpc的一个范围很小的概念。但是当我们从大的方面去考虑的时候,比如说微服务, 我们需要考虑很多方面。在这一点上,rpc和grpc很欠缺,虽然grpc开始增加一些load balancer的实验性的功能,但是从服务治理的方面来讲,还是很欠缺的,我觉得这一欠缺导致了grpc不会大规模的在企业中应用,除非再做进一步的开发。

Protocol

协议可以采用http restful api的方式,或者HTTP/2,但是从性能上考虑,最好采用TCP。当然从便利性上考虑,http restful api还是很不错的。通过Magic number可以对每一帧进行校验,貌似dubbo的magic number是DUBB。MagicNumber的多少是Tradeoff的决策。rpcx只是用它来辅助校验,所以只使用了一个字节。

最好接着就是version字段,这样不同的版本后面可能是不同的数据格式, 如果放在最后就限制死了。

一些参数尽量压缩以节省空间。

Transport

我们看传输方式,一个是TCP方式传输,另外是 UDP 协议,UDP 是不可靠的传输方式,中间有丢包的概念,有很多库试下了可信赖的UDP,相当于它做了很多的检查,常用的有谷歌的 quic,腾讯有的部门也在使用,还有KCP,rudp等。

codec

可用的编码方式有很多,但是首先要支持跨语言的处理,msgpack 是常用的编码方式,protobuf也是常用的编码方式,json是通用的实现方式,thrift也是跨语言的,但是追求极致性能的话可以用go特有的编码库,有些比protobuf性能高出一倍,右侧列了很多项目,大家可以关注一下,这里面有很多性能优异的编码库,但不是跨语言的,只能在go里面使用。

注册中心

另一个非常重要的是注册中心,做服务治理,注册中心是非常重要的一个组件,我们需要把服务登记到注册中心里面,之后客户端才能感知到相应的服务节点,比较常用的是 etcd 、consul、zookeeper,有人问是ETCD 好还是 consul 好,这个很难说,本身都是很优秀的框架,但是微博里面都没有使用,因为这些框架追求的是要数据一致性,而我们追求的是高可用性,我们自己做配置开发平台,跨数据中心的。

路由/负载均衡

随机

当有多个服务器时,甚至分布在多个数据中心,我们需要一定的算法从中挑选出来给客户端调用,在这列举几个常用的算法,最简单的是随机算法,随机选择一个,分配到谁就到谁。

轮询

还有一个是轮询,保证每个服务器平均得到访问调用的机会。

一致性哈希

一致性哈希,可以根据用户的请求,计算哈希值,可以映射到对应的服务器上面,可以保证相同的请求能路由到相同的节点,根据哈希选择的不同,可以有不同的算法;或者根据clientIP地址计算相同的IP就路由到同一台机器上。

基于权重的轮询

基于权重的轮询,这个比较好的算法是nginx的平滑的基于权重的轮训算法,即使在很短的时间内,也不会出现强求都落在一台机器上,避免雪崩现象。

基于地理位置

基于地理位置选择,就是北京的机器client尽量访问北京的机房,如果北京和广州之间要访问有几十毫秒的延迟,美国东海岸和西海岸的机房,有上百的数据延迟。所以要尽量选择同一地区的机房的数据。

基于网络质量

但是有时基于地理位置,同一个机房,同是在北京,分布在不同的地方,不同的网络服务商,可能访问也是不太一样的,所以有时候可能会基于网络质量去访问,可以调用服务,看看反馈花费时间是多少,进行相应权重的分配,这也是一种常见的算法。

定制路由算法

定制路由算法:有些用户提出来某一个服务,要分配到其中一个机房的其中一台测试机器上,可以提供一个接口让用户定制他的算法,要把相应的参数要传递过来,基于这些参数做一个选择。


失败处理

失败的处理完全是参考 dubbo 的实现,但是额外加了一些功能。比如说 failbackup。如果服务节点意外挂了或者服务失败了,设置failfast的话就会马上反馈给 client ;如果是failtry在网络闪断情况下有重试的功能;failover,访问第一个节点失败可以继续访问第二个节点;还有failbackup,就是利用这种资源换延迟,来一个请求之后,如果等十毫秒还没有结果的话,立马把这个请求发送给第二个节点,这两个节点谁先返回过来,我就把结果返回回去,提高延迟,但是有时候会占用双倍资源。


超时、容错

微服务调用有连接超时的时候,网络的原因还有恶意攻击问题,比如很多客户端连接你的服务器,也不断掉,会占用很多资源,处理这些请求,相当于占用你大量的服务器的资源,如果设置超时,可以在一定的时间内把一些关闭。还有 Context 超时是常用的方式。断路器的模式,如果一个服务器暂时不可用的话,最好把它标记为在一定时间内不可用,这样我以后的服务不会再选择它做路由,这样可以避免大量的请求发送到无用或者暂时不可用的服务器上,这个熔断器可能在一定的时间内要进行重试,在可用的时候要恢复过来。熔断器也有好几个框架实现。


跨语言

跨语言,是一个很严重的问题,在初创公司里面,没有太大的问题,都用go开发,没有语言的问题,但是在大的公司里面有很多不同语言,这种情况下要考虑跨语言的问题。现在小米的张志勇负责做rpcx-java的开发,支持纯java方式实现rpcx,做的很不错,还有gateway,http 接口等方式提供http接口,以便支持跨语言调用。


双向调用

本身rpc不设置双向调用,但是有一些需求,要求服务器发一些通知给客户端,所以需要双向的通讯,这一功能grpc也支持。


管理界面

提供UI管理服务,禁用一些服务,进行一些管理的东西,都是通过注册中心拉取过来数据。

另外微服务很重要的一点,是要对服务有trace的概念,我们一般记录节点的一些信息,trace会中间请求一些信息发送过去。Java可以往很多服务器发送数据,我们也可以加相应的数据展示出来进行监控。


安全

其他还有一些安全的东西,比如 Auth,需要权限验证;另外还有限流。还有消息大小的限制,假设提供一个服务里面有一个字段,本来是希望用255个字节数据,假设有个人传个2G的葫芦娃的数据,会对你本身的服务器的资源极大的占用,要对服务器接收的数据大小进行控制,另外提供白名单和黑名单进行控制。


压缩

zip 是普遍的压缩方式,snappy 追求流的压缩方式。


benchmark

去年做过一些对于rpc框架 benchmark 的测试。因为我们不可能做一个覆盖各种各样的测试场景,这里只是提供一个特定的场景。假设服务是有一个10毫秒的消耗的话或者30毫秒的消耗(sleep),标准库性能最好,其次是rpcx, grpc和thrift稍差一些,但也比http restful api高很多。

我分享的原因就是大家以后在使用rpc框架开发的时候,或者是自己做rpc框架的时候,可以从这几个角度进行考虑。

Q&A

提问:之前我们也做过 go rpc,用的是你刚才提的 gateway 的方式,对client提供http接口,使用http和grpc两种方式跟后面的微服务通讯。我们刚开始在一个服务上用了HTTP跟gsrpc这两种方式,但是测试结果显示,用grpc跟http相比,性能提升不是很大。还有 Gateway 链接服务的时候是一条链接还是多条链接?自己去做一个链接还是一个链接池?

晁岳攀:首先回答你第二个问题:一个链接就足够了。很多同学说,为什么用一个链接?从数据传输来说,一个链接是足够的,因为是异步地,性能不会阻塞在网络数据的传输上。现在回答第一个问题:可能你有两个原因,一是你的服务占用时间较长,第二个原因可能你的client通讯方式是瓶颈, 你gateway提供给client是http方式。

提问:rpcx 和 grpc 出来的定位是什么? rpcx支持protobuf3吗?

晁岳攀:grpc 不会在企业大规模使用,或者说不会直接在企业中规模很大的服务中的推广。因为本身它的服务治理很弱。rpcx支持protobuf3, 而且默认提供了protobuf3的编码器实现。

提问:比如说春节的时候做降级的时候,具体动作是什么,我们这边没有降级,我刚才想了一下,去年天猫双十一的时候,看过阿里那边的双十一数据,前半小时,比如说你打开界面,是不会给你展示有几个红包给你发送,客户端做了处理,比如流量比较大的时候,有一些不是特别重要的服务直接关掉,客户端做一些处理,会把模块隐藏掉,做限流,几个容器在做处理,其他的容器在客户端,容器数量比较少的,是小范围提供,大范围的用户在用服务的时候怎么用,客户端要做怎样的处理?

晁岳攀:每个公司处理方式不一样,拿微博举例子,春节的时候,会把不太重要的功能暂时关掉,我们把业务分成核心和非核心的,有选择的去降级,在后台就标记这个服务是不可用的状态。

晁岳攀---基于go的 rpc框架实践相关推荐

  1. Gopher China 2019 讲师专访 -晁岳攀

    第五届 Gopher China 大会将于2019年4月26日-4月28日在北京市海淀区朗丽兹西山花园酒店举办,Gopher China 大会目前是国内最大规模,最专业的 Go 语言线下技术交流大会. ...

  2. Courier:Dropbox 基于gRPC 的 RPC 框架开发过程

    Dropbox运行着数百个用不同语言编写的服务,每秒交换数百万次请求.Courier是我们面向服务的架构的核心,这是一个基于gRPC的远程过程调用(RPC)框架.在开发Courier时,我们学习了很多 ...

  3. 手动实现一个基于netty的RPC框架(模拟dubble)

    轻量级RPC框架开发 内容安排: 1.掌握RPC原理 2.掌握nio操作 3.掌握netty简单的api 4.掌握自定义RPC框架 RPC原理学习 什么是RPC RPC(Remote Procedur ...

  4. 基于Netty的RPC框架

    概述 RPC(Remote Procedure Call),远程过程调用,是一个计算机通信协议,该协议允许运行一个进程调用另一个进程,而程序员无需额外为这个交互作用编程. 两个或者多个应用程序分布在不 ...

  5. RPC框架实践之:Apache Thrift

    一.概述 RPC(Remote Procedure Call)即 远程过程调用,说的这么抽象,其实简化理解就是一个节点如何请求另一节点所提供的服务.在文章 微服务调用链追踪中心搭建 一文中模拟出来的调 ...

  6. dubbo协议_Dubbo协议解析与OPPO自研ESA RPC框架实践

    本文来自OPPO互联网基础技术团队,转载请注名作者.同时欢迎关注我们的公众号:OPPO_tech,与你分享OPPO前沿互联网技术及活动. 1. 背景 Dubbo是一款高性能.轻量级的开源Java RP ...

  7. Java编写基于netty的RPC框架

    一 简单概念RPC: ( Remote Procedure Call),远程调用过程,是通过网络调用远程计算机的进程中某个方法,从而获取到想要的数据,过程如同调用本地的方法一样.阻塞IO :当阻塞I/ ...

  8. 基于RDMA的RPC框架(一) 环境搭建

    文章目录 一.简介 二.Ubuntu 14安装SoftRoce 2.1.编译内核 2.2.安装用户库 三.Ubuntu 18安装Soft Roce 引用 一.简介 二.Ubuntu 14安装SoftR ...

  9. Java 中几种常用的 RPC 框架介绍

    RPC是远程过程调用的简称,广泛应用在大规模分布式应用中,作用是有助于系统的垂直拆分,使系统更易拓展.Java中的RPC框架比较多,各有特色,广泛使用的有RMI.Hessian.Dubbo等.RPC还 ...

最新文章

  1. Docker的基本使用-Ubuntu18.04
  2. 关于numpy中eye和identity的区别详解
  3. 敏捷开发思想及Scrum实践
  4. 一个不错的权限管理模块设计案例
  5. POJ3272 Cow Traffic
  6. MongoDB 主从复制集搭建
  7. SqlServer用户数据库的系统视图sysobjects、syscolumns、systypes
  8. 309. Best Time to Buy and Sell Stock with Cooldown 最佳买卖股票时机含冷冻期
  9. python继承多重继承
  10. position:sticky布局
  11. Android-- Dialog对话框的使用方法
  12. Vue-cli proxyTable 解决开发环境的跨域问题(转)
  13. Extjs学习(3):事件和动作
  14. 【SQL】实验十 数据库完整性实验
  15. java源程序的运行命令_Java源程序名为Test.java,运行它的Java程序的命令是( )。 (10.0分)_学小易找答案...
  16. mysql strtolower_自己写的mysql类_PHP教程 - strtolower
  17. OpenCvSharp N幅图片叠加成一张图片
  18. Tensorflow2.6.0-MKL for C++
  19. TSP问题(贪心法)最近邻点和最短连接
  20. React H5 使用div自定义简单富文本编辑器

热门文章

  1. 计算机二级笔试题vf,有关计算机二级vF笔试的真题
  2. 计算机二级vf上机试题,全国计算机二级VF上机试题 20
  3. 光驱驱动问题,出现黄色感叹号,找不到盘符的解决办法
  4. JDBC中的ResultSetMetaData获取列名字
  5. 女生最容易就业的5个专业,你知道几个?
  6. go 操作 Excel
  7. Qt for Android 定时器
  8. 粤嵌实习51小车day 1-基于51单片机
  9. 德玛西亚之WorkFlow(三)流程引擎配置与服务组件
  10. 解决魔兽世界wow中鼠标莫名其妙消失或自动跳回屏幕中间等类似问题整理