不少小伙伴都遇到过须要为分布式系统调用更换RPC的问题,为何会遇到这种事呢?其实,在系统搭建初期,需求简单,架构简单,最重要的是请求量也少,因此不少系统都采用快速原型开发模式,对rpc的要求不高,随便找一个顺手的或者熟悉的rpc框架套进系统中便可。可是随着业务复杂度增高,系统承载的请求量增高,可能一开始所采用的RPC框架显现出一些致命的问题,好比大扇出问题。咱们以Thrift为例。例如随着业务复杂度的增加,咱们面临着以下的需求。
如图所示,每一次请求,上游服务都要获取下游A~Z一共26个服务的结果,而后把这26个服务的结果拼装返回给前端服务。有人说,26个服务是否是有些夸张了,个人系统中根本没有遇到过这个状况。这实际一点不夸张,一个业务复杂的系统通过服务拆分,最后拆成一些高内聚低耦合的独立服务,很是容易达到这样一个服务种类数,并且26还远远不是不少。那么遇到这种问题,传统的同步的RPC怎么解决这个问题呢?html
以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,只不过收益可能不大。网络
考虑到Thrift对于大扇出并不合适,咱们可能须要下面这样工做模式的RPC。
这种反应器模型(只是简单举例子)能够减小请求线程数。这种RPC使用系统的Epoll进行后端服务的请求以及数据的接收,这样不管多少请求,只使用一个线程完成,经过Epoll的机制在数据到来或者可发送的状况下通知用户进程,只不过最后须要把接收到的数据返回给计算线程使用。这种模型其实要比Thrift那种那好一些。我本身也在业余时间实现了一个简单的RPC框架:http://www.cnblogs.com/haolujun/p/7527313.html ,比较粗糙可是足够小。
还有有不少开源的RPC框架,fbthrift,GRPC均可以应对大扇出,找到适合你的系统,而且改动量和后期维护成本最低的那个。多线程
把系统迁移到新的RPC上,除了改动代码外,就是要作到兼容,系统在迁移过程当中可能须要在两套RPC框架上运行,而且必须作到平滑迁移。例如,通常的分布式系统可能会长成以下的样子。
服务B1~B4把本身的地址写入到ETCD中,可是因为咱们一开始并未考虑到RPC的迁移,因此value对应的是服务的地址,没有服务使用的rpc类型等等。架构
对于A1~A2,B1~B4,能够先选择一部分进行平滑过渡,例如咱们选择A1,B1~B2进行迁移。
上线步骤以下:并发
下线A1,B1,B2。框架
更新A1配置,使其重新的key:service_new_rpc中读取后端服务列表。分布式
更新B1,B2配置,使其在新的key:service_new_rpc中注册本身。ide
启动B1,B2。
启动A1。
对于A2,B3,B4重复如上步骤。
经过这种方式,咱们能够平滑的进行服务迁移。可是它的缺点很明显,须要一个新的key,并且后期还须要一点点把服务挪回到旧的key上。
这个方案必须更改一些解析代码,使其可以兼容新的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的地步了么?