如何为分布式系统优雅的更换rpc

author author     2022-11-05     455

关键词:

为啥需要更换RPC?

很多小伙伴都遇到过需要为分布式系统调用更换RPC的问题,为什么会遇到这种事呢?其实,在系统搭建初期,需求简单,架构简单,最重要的是请求量也少,所以很多系统都采用快速原型开发模式,对rpc的要求不高,随便找一个顺手的或者熟悉的rpc框架套进系统中即可。但是随着业务复杂度增高,系统承载的请求量增高,可能一开始所采用的RPC框架显现出一些致命的问题,比如大扇出问题。我们以Thrift为例。例如随着业务复杂度的增长,我们面临着如下的需求。
技术分享图片
如图所示,每一次请求,上游服务都要获取下游A~Z一共26个服务的结果,然后把这26个服务的结果拼装返回给前端服务。有人说,26个服务是不是有些夸张了,我的系统中根本没有遇到过这个情况。这实际一点不夸张,一个业务复杂的系统经过服务拆分,最后拆成一些高内聚低耦合的独立服务,非常容易达到这样一个服务种类数,而且26还远远不是很多。那么遇到这种问题,传统的同步的RPC怎么解决这个问题呢?

以Thrift为例,如果需要访问26个服务,为了保证请求处理速度,必须要并行访问各个下游服务(不能串行请求,因为这将导致 一次请求的响应时间至少为timeA + timeB + ...... + timeZ),那么我们只能通过多线程进行并发。

技术分享图片

通过多线程并发请求,我们基本能够达到处理一次请求至多需要 max(timeA, timeB, ......, timeZ),但是实际上要比这个稍多。看样子我们必须弄一个请求线程池,可是这个池子要多大呢?假如现在前端请求速率为 P,那么为了保证每个请求处理时间都尽可能快,我们需要一个大小为 26 * P的线程池。虽然,初看起来可能还可以应付,毕竟请求线程在发送网络请求后,会阻塞在IO,它会放弃CPU,从而使得计算线程获得CPU,不会浪费多少CPU的资源,但是当P太大就不好了。比如P为100或者1000,这个时候线程数过多可能就会造成CPU调度开销增大,因为它会增加CPU的线程切换负担。

所以,我们更换RPC,当且仅当,当前的RPC已经造成了系统负担,对于业务量不大的系统,RPC的更换并没有必要,但是为了技术提升你也可以更换RPC,只不过收益可能不大。

需要什么样的RPC?

考虑到Thrift对于大扇出并不合适,我们可能需要下面这样工作模式的RPC。
技术分享图片
这种反应器模型(只是简单举例子)可以减少请求线程数。这种RPC使用系统的Epoll进行后端服务的请求以及数据的接收,这样无论多少请求,只使用一个线程完成,通过Epoll的机制在数据到来或者可发送的情况下通知用户进程,只不过最后需要把接收到的数据返回给计算线程使用。这种模型其实要比Thrift那种那好一些。我自己也在业余时间实现了一个简单的RPC框架:http://www.cnblogs.com/haolujun/p/7527313.html ,比较粗糙但是足够小。
还有有很多开源的RPC框架,fbthrift,GRPC都可以应对大扇出,找到适合你的系统,并且改动量和后期维护成本最低的那个。

如何迁移到新的RPC?

把系统迁移到新的RPC上,除了改动代码外,就是要做到兼容,系统在迁移过程中可能需要在两套RPC框架上运行,并且必须做到平滑迁移。例如,一般的分布式系统可能会长成如下的样子。
技术分享图片
服务B1~B4把自己的地址写入到ETCD中,但是由于我们一开始并未考虑到RPC的迁移,所以value对应的是服务的地址,没有服务使用的rpc类型等等。

方案1 添加新key

对于A1~A2,B1~B4,可以先选择一部分进行平滑过渡,例如我们选择A1,B1~B2进行迁移。
技术分享图片
上线步骤如下:

  • 下线A1,B1,B2。

  • 更新A1配置,使其从新的key:service_new_rpc中读取后端服务列表。

  • 更新B1,B2配置,使其在新的key:service_new_rpc中注册自己。

  • 启动B1,B2。

  • 启动A1。

  • 对于A2,B3,B4重复如上步骤。

通过这种方式,我们可以平滑的进行服务迁移。但是它的缺点很明显,需要一个新的key,而且后期还需要一点点把服务挪回到旧的key上。

方案2 代码兼容

这个方案必须更改一些解析代码,使其能够兼容新的ETCD中value的格式,如下图。
技术分享图片

  • 首先改造A代码,使其能够兼容新地址解析格式。新地址格式在每个地址后加上RPC类型标识:T(Thrift),G(GRPC),新格式和旧格式的兼容很容易,只需在解析的时候找一下分割符,并判断分隔符最后一部分是T是G还是什么都没有,没有就默认为T。

  • 改造A代码,使其能够根据后端服务在ETCD中的RPC类型使用不同的RPC框架调用后端。

  • 改造B1~B4的配置,在ETCD中注册自己的时候把RPC类型顺便加上。

  • 改造B1~B2,使用新RPC作为服务端,并且在注册的时候把RPC类型设置为G。

  • 改造B3~B4,使用新RPC作为服务端,并且在注册的时候把RPC类型设置为G。

通过这个步骤,我们就能做到RPC的平滑迁移。这个方式的缺点也有:需要同时维护两套RPC框架,直到其中一种RPC彻底下线。但是优点也有,没有增加新key。

总结

更换RPC并不像想象中的那样困难,只要理清前后逻辑,一点点的迁移,最终你的服务会全部搞定。最重要的问题是你的系统真的达到了非得换RPC的地步了么?


如何为一元 rpc 定义响应标头

】如何为一元rpc定义响应标头【英文标题】:Howtodefineresponseheadersforunaryrpc【发布时间】:2018-02-0521:06:44【问题描述】:在Go中,我想从我的rpc处理程序实现中设置一些响应标头。具体来说,我想设置一些与缓存控制相关的标头。... 查看详情

如何为 RabbitMQ RPC 请求设置超时?

】如何为RabbitMQRPC请求设置超时?【英文标题】:HowtosetatimeouttoaRabbitMQRPCrequest?【发布时间】:2020-04-1321:45:25【问题描述】:在AMQP(RabbitMQ)RPC模型中向主题发布消息是否存在超时?我不想等待很长时间(超时后)消费者对生产者消... 查看详情

如何为笔记本电脑安装上指纹识别系统?

1、首先你的机器内置指纹认证装置,如没有可以买USB外接的2、装好驱动和指纹软件,并保证该软件开机启动3、第一次使用时,打开软件,根据提示,放好手指,录入你的指纹。以后开机用指纹登陆就可以了。参考技术A我是做DE... 查看详情

spring优雅整合redis缓存

...单的消息队列?”“Redis缓存啊!”“小明,分布式锁这玩意有什么方案?”“Redis缓存啊!”“小明,公司系统响应如蜗牛,咋整?&rdqu 查看详情

分布式系统中的必备良药——rpc

...的解决方案剖析性能测试结语 一、前言  在上一篇分布式系统系列中《分布式系统中的必备良药——服务治理》中阐述了服务治理的一些概念,那么与服务治理配套的必然会涉及到RPC框架。在当前互联网的大背景下... 查看详情

如何为蜂巢中的点后的位数建立分布表?

】如何为蜂巢中的点后的位数建立分布表?【英文标题】:Howtobuilddistributiontablefornumberofdigitsafterthedotinhive?【发布时间】:2018-08-1517:39:53【问题描述】:hive表中有一个从float(double)转换而来的字符串列。我需要一个表格,表示点... 查看详情

TypeScript:如何为函数中的任何键键入对象剩余分布

】TypeScript:如何为函数中的任何键键入对象剩余分布【英文标题】:TypeScript:Howtotypeobjectrestspreadforanykeysinfunction【发布时间】:2021-05-1705:16:03【问题描述】:我有一个函数,它接受一个对象并返回一个对象。它返回整个传入对象... 查看详情

如何为文件的每一行运行命令?

】如何为文件的每一行运行命令?【英文标题】:Howdoyourunacommandforeachlineofafile?【发布时间】:2012-12-0600:25:02【问题描述】:例如,现在我正在使用以下内容来更改我将其Unix路径写入文件的几个文件:catfile.txt|whilereadin;dochmod755"$... 查看详情

如何为具有多个模式分布的controller编写单元测试(代码片段)

我正在尝试为我的控制器编写一个单元测试,但我需要帮助,我的控制器外面有两个modelAttribute作为枚举,用于我的所有控制器,所以这是我的代码。请帮助我,我是测试单元的新手。@AutowiredprivateMaintenanceServicemaintenanceService;@Mod... 查看详情

如何为 django 管理员创建选项卡?

】如何为django管理员创建选项卡?【英文标题】:Howtocreatetabsfordjangoadmin?【发布时间】:2020-03-1601:32:42【问题描述】:如何为管理语言创建选项卡。例如:ChangebookEnglishJapanese部分型号【问题讨论】:你的问题不清楚。您能否提... 查看详情

如何为 python unittest 指定测试超时?

】如何为pythonunittest指定测试超时?【英文标题】:Howtospecifytesttimeoutforpythonunittest?【发布时间】:2016-04-1701:19:53【问题描述】:我正在使用python框架unittest。是否可以通过框架的能力指定测试超时?如果不是,是否可以为所有测... 查看详情

什么是rpc?

...程调用的复杂性。回到顶部为什么需要RPC?微服务、分布式应用的开发越来越常见,RPC可以解决各个节点之间的服务调用以及通信问题。治理功能,比如连接管理、健康检测、负载均衡、优雅 查看详情

如何为我们的系统提供 API [关闭]

】如何为我们的系统提供API[关闭]【英文标题】:howtoprovideAPIforoursystem[closed]【发布时间】:2009-05-1418:59:38【问题描述】:我在Web服务或API方面没有太多经验。我们有一个基于Oracle->SunAppServer->Java->Struts2框架的网站。我们需... 查看详情

何为http?何为rpc?

RPC(即RemoteProcedureCall,远程过程调用)和HTTP(HyperTextTransferProtocol,超文本传输协议)他们最本质的区别,就是RPC主要工作在TCP协议之上,而HTTP服务主要是工作在HTTP协议之上,我们都知道HTTP协议是在传输层协议TCP之上的,所以... 查看详情

rpc

...的解决方案剖析性能测试结语 一、前言  在上一篇分布式系统系列中《分布式系统中的必备良药——服务治理》中阐述了服务治理的一些概念,那么与服务治理配套的必然会涉及到RPC框架。在当前互联网的大背景下,RPC的... 查看详情

时钟轮在rpc中的应用

分布式环境下,RPC框架自身以及服务提供方的业务逻辑实现,都应该对异常进行合理地封装,让使用方可以根据异常快速地定位问题;而在依赖关系复杂且涉及多个部门合作的分布式系统中,我们也可以借助分布式链路跟踪系统... 查看详情

如何为两个不同实体之间的复杂消息系统设计表?

】如何为两个不同实体之间的复杂消息系统设计表?【英文标题】:Howtodesigntablesforacomplicatedmessagingsystembetweentwodifferententities?【发布时间】:2019-08-2623:27:50【问题描述】:我正在开发一个包含消息传递系统的Web应用程序。Web应用... 查看详情

分布式远程服务调用(rpc)框架

分布式远程服务调用(RPC)框架finagle:一个支持容错,协议无关的RPC系统热门度(没变化) 10.0活跃度(没变化) 10.0 Watchers:581Star:6174Fork:1138创建时间: 2010-10-2006:10:09最后Commits: 昨天finagle:一个支持容错,协议... 查看详情