原理
分布式的存储,使用多台主机作为存储机器。存放/读取[key, value]时,由key选择目标机器,即使用key值将存储的对象分散在不同的机器上. 散列最简单的方法是目标主机数取模, 假如有n台机器,依次编号(0, 1, 2, ..., n - 1),给定key值,生成一个int hash value,用hash value%n,根据模值找到对应的机器. 这种取模hash的问题在于,两个节点时%2, 三个节点时%3,大部分key的hash值随着节点的数目变化而变化.
cassandra DHT使用的是consistent hash
目的:在增加节点或者减少节点时,避免因为rehash而引起的server 震荡。
实现:将hash value空间固定并形成环形,0~2^32,每个node(主机)生成一个hash值,将node映射到hash空间。给定的key,计算其hash值,沿着hash顺时针找到第一个(或者N个,如果需要N个备份)node即为目标主机(如下图,借图一幅)
添加节点:很显然,添加一个节点,hash空间的一小部分被node重新分割,其他区间不受影响,如下图(再借图一幅),只有node5和node2之间的区间从node2 rehash到node5
cassandra 实现
节点的hash值生成
如下所示,在server启动时,将node的Token(注,token即为上文所讲的hash值,可以是Integer类型的Token,也可以是String类型,只要可比较大小进行排序即可作为token)放入全局token表中(TokenMetaData,全部token表存储集群中所有节点对应的token值)。node的token首先检查“LocationInfo” table(column family),如果存在则取出,不存在则随机生成一个新的token并存储。这样每个node的token仅仅生成一次.
随机Token的生成取决于Partition的方法,默认的Partition是RandomPartitioner(注,随机生成很难保证节点均匀切分hash空间,如果有四个节点,均匀分割,则每个节点分配的hash值为(0/2^32, 2^30, 2 * 2^30, 3 * 2^30),其使用GUID来生成一个BigInteger的Token
GuidGenerator
"s_id(host):System.currentTimeMillis:Random.nextLong"
->
md5.hash
->
hex string
->
->
md5.hash
->
BigInteger
->
abs
TokenMetadata中维护了全局(所有节点)的token,当节点leave或者add时,更新这个全局表(下一篇中另作分析)
给定key值,寻找目标主机
很显然,读写操作都首先要确定目标Server,这里给出weak读(从一个主机读到即可)的Sequence Diagram(再借图一幅)
不见上图,简化版:
CassandraSrever.get_slice
-> StorageProxy.readProtocol
-> StorageService.getNaturalEndpoints
-> .weakReadLocal
-> .weakReadRemote
-> StorageService.findSuitableEndPoint
getNaturalEndpoints
寻找natural end points(目标主机hosts,N = 数据备份数目)分两步
- 由Partition生成key的token, RandomPartitioner用MD5 hash生成
- 由复制策略来找到目标主机, RackUnawareStrategy使用前文所述的consistent hash方法,将所有node的token排序,然后二分查找给定token在序列中的位置,从该位置起,序列中N个token对应的host即为目标主机。(其他的复制策略主要考虑目标主机的物理位置,try to find the host in different rack or data center)
findSuitableEndPoint
返回目标主机中(naturalEndPoint)最近的活着的节点
Java hit
Google collection (另作介绍)
BiMap<Token, InetAddress> tokenToEndPointMap (Token 和 host 为一对一映射)
AbstractIterator, 从(0, n-1)中的某个位置开始,依次遍历所有的数,n-1的下个数是0(ring),回到位置时(全部遍历一次)结束
判断两台主机的物理位置
寻找接近给定主机的hosts
关于环形(ring)中两个区间相交的判断