from:http://ugc.renren.com/2010/01/28/ugc-nuclear-guide-theory/
原理篇
嗯……其实这张图对各位看官意义不大,只是罗列出了Nuclear中的各个组件及简单的层次关系。下面着重分析分区、节点增减、路由的原理。
分区
前文讲到,我们是一个分布式的Key-Value存储系统,那么key对应的数据分布在什么节点上,需要遵守一定的规则。熟悉Memecached Client的同学一定清楚一致性Hash的应用,没错,Hash Ring就是我们的不二选择。在Nuclear中,数据分布在0~264的Hash Ring上,Nuclear集群初始化的时候,根据节点数均分整个Hash Ring。如下图所示:
在N=3时,A,B,C三个节点的配置就是系统需要的最少节点了。Nuclear中,顺时针的开始值和结束值确定一个分区管理的数据范围,同时规定分区的范围左开右闭。因此,如上图,我们记录A,B,C分别管理的分区范围是:
A {[c,a],[b, c],[a,b]}
B {[a,b],[c,a],[b,c]}
C {[b,c],[a,b],[c,a]}
可以看出,A处理管理自己的分区数据外,还会把自己管理的数据顺时针往前复制到2(N-1)个节点中。
节点变更
Nuclear增加节点时需要制定目标节点的名称,即增加的节点是用来分担目标节点的负载的。这点不同于Dynamo的分区策略,节点增加的时候会均衡的从现有的节点窃取分区,Nuclear中增加的节点只会影响到邻近的三个节点。加入我们在上面的例子中增加一个新节点N后分区图如下所示:
记录N,A,B,C管理的分区如下:
N {[c,n],[b,c],[a,b]}
A {[n,a],[c,n],[b,c]}
B {[a,b],[n,a],[c,n]}
C {[b,c],[a,b],[n,a]}
Nuclear的分区管理模块将自动的计算出需要同步到N上的数据:
A [a,b] => N
B [b,c] => N
C [c,n] => N
各位看官不难明白,其实就是把A,B,C不再需要的数据挪给新的节点了。删、替换节点原理大同小异,不再冗述。
路由
Nuclear提供服务器端路由策略,Client的请求随机落在Node节点上,由接收到请求的节点处理后续的逻辑。相对于Client端路由来说,优点是Client无需知道Nuclear集群元数据,易于维护;缺点是会造成一定程度的延时,不过我们的测试结果显示延时在可接受范围之内。
两个设计上的Tips贡献给大家:
1. 万事皆异步
我们在编码的过程中走了一些弯路,同步的操作在高并发的情况下带来的性能下降是非常恐怖的,于是乎,Nuclear系统中任何的高并发操作都消除了Block。no waiting, no delay。
2. 根据系统负载控制后台线程的资源占用
Nuclear系统中有不少的后台线程默默无闻的做着各种辛苦的工作,但是它们同样会占用系统资源,我们的解决方案是根据系统负载动态调整线程的运行和停止,并达到平衡。
展望篇
Nuclear中计划在不远的将来(不远有多远?)实现如下功能:
- Eventually Consistent 最终的一致性问题,在保重数据完整性上至关重要。
- Async Store 异步数据库存储,各位可以参考:adbcj, async-mysql-connector
- Read Cache
- Balance Monitor 建立集群的负载监控体系,在新节点加入的时候可以自动去平衡负载最高的节点。
全文完^_^,谢谢各位的捧场,同时有任何好的建议欢迎提出!
参考资料:
- Amazon’s Dynamo
http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html - Cassandra
http://incubator.apache.org/cassandra/ - Voldemort
http://project-voldemort.com/