前言
(本文适合对Dst项目有一定认识的人阅读)项目地址
最近,我一直有一个问题,我始终没有思考明白,Dst中,Dst-Server 要采用WorkerPool的模型去进行数据操作的必要性有多大,因为从实现角度而言,Dst所采用的DRPC是基于Netty的。对于Netty来说,他的Worker线程池完全可以复用。比如加一个ThreadLocal的变量,也就是Shard。按照架构设计的话也是没有问题的,而且Netty的Worker线程中也有BlockingQueue,这样对一个Shard的操作也是不会出现冲突的情况,会按照入队的顺序去执行相应的操作。所以从实现角度来说说不定这种方法的实现成本也较低。下面就是我对这个问题的一些思考。
正文
其实从我个人思考角度,设计这种结构的最重要的原因是 解耦。为什么这样说呢?首先,我觉得虽然前言提到的复用的方法是一种看似可行的策略,但是这会使得整个DRPC和Dst会有很大的耦合,不利于DRPC项目的发展。当然这个理由其实不太成立,因为如果对于Dst来说,RPC只是其中一部分,没有必要为了RPC放弃全部。但是除了RPC部分,我们的分布式架构还包括主从同步,数据迁移,容灾恢复,等部分,这些部分每一个都和shard的结构有着千丝万缕的关系,如果考虑了这一点,就不能更好的考虑另一点,而且每做一步都得考虑这对于远程传输性能的影响,从某种程度上增加了思考的负担。和代码编写的难度。
除此之外, 解耦的另一大好处就是软件升级的成本小,比如我们RPC要做保序的话,完全就可以不考虑其他的限制,只在RPC层面进行考虑。比如如果出现了比Netty性能好的RPC,而线程模型又和Netty不一样,我们就可以无缝切换。但耦合就不行。
当然除了这些问题,耦合的话好处确实很多,比如,性能,因为没有因为没有Dst-WorkerPool,线程只是在Netty内部管控,这样管理效率更高,因为只有一个线程池可以对他做各种优化。而且线程数量也少于非耦合。可能在linux的上线程是在用户态进行管理,但windows,就得在内核态。等。
通过此次的思考,我觉得分布式系统的设计是一门很复杂的学问,虽然本此只引出一个耦合的点,但实际的东西需要更多。
最终方案
前面我们讲到,目前这种双线程池的结构,是为了解耦。不过在我们内部讨论的时候,王清提出了更好的意见:为什么我们不让RPC支持关掉自己的WorkerPool呢?我们都知道,Netty的WorkerPool是Worker线程的“栖息地”,如果没有了RPC-WorkerPool,那么RPC就只留下传输的功能,而在RPC的API层面,我们将其作为可选项。我觉得这个想法非常好,首先RPC有这样的功能选项,意味着我们无需改造RPC。也就没有了耦合,就没有耦合导致的一些坏处。其次像单线程池的一些优势,比如性能好,代码简洁等等也都能兼顾。
目前我们通过了几次讨论,确定了这个想法的正确性,于是我们就决定这么去做,在不久即将发布的Dst2.0上,我们相信,对极致性能的追求所做的努力,是不会白费的!