最近在本地环境上测试memcached集群怎么实现动态扩容。看了一下libmemcached中选择server的代码,做一个简单的总结。
主要涉及的代码:
// 增删服务结点时,重新计算数据分发需要的参考值
memcached_return_t run_distribution(Memcached *ptr);
enum memcached_server_distribution_t;
// 通过key哈希值得到服务结点索引值,操作数据相关的操作都会用到该函数
static uint32_t dispatch_host(const Memcached *ptr, uint32_t hash);
枚举memcached_server_distribution_t
表示多种分发方式
enum memcached_server_distribution_t {
MEMCACHED_DISTRIBUTION_MODULA, // key_hash % server_count
MEMCACHED_DISTRIBUTION_CONSISTENT, // key_hash和server_hash比较
MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA, // key_hash和server_hash比较
MEMCACHED_DISTRIBUTION_RANDOM, // 随机值 % server_count
MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY, // key_hash和server_hash比较
MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED, // key_hash和server_hash比较
MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET, // key_hash & (bucket_size-1)
MEMCACHED_DISTRIBUTION_CONSISTENT_MAX
};
主要分为四大类:
- 基于key_hash取模
MEMCACHED_DISTRIBUTION_MODULA
实现:对key取哈希值,哈希算法支持配置,支持很多种。用key_hash对服务器个数取模就可以得到服务器的索引了。
缺点:当增删服务结点时,所有的key必须进行rehash。 - 基于Ketama一致性哈希算法
MEMCACHED_DISTRIBUTION_CONSISTENT
MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA
MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY
MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED
实现:基于server的某些key取哈希值,并将哈希值和server索引的映射关系保存起来。对key取哈希值,用key_hash和所有server_hash进行比较,如果server1_hash < key_hash < server2_hash,则将数据server1_hash对应的结点上。
这样实现,就可以保证增删服务结点时,只对小部分的key进行rehash。
比如:新插入一个服务结点,得到server3_hash满足server1_hash < server3_hash < server2_hash,此时只需要将server1上key_hash大于server3_hash的key迁移到server3上即可。 - 基于随机数取模
MEMCACHED_DISTRIBUTION_RANDOM
实现:每次需要操作数据时,都获取一个随机数random,通过random % server_count得到服务结点索引。如果有大于1个以上的服务结点,数据被添加到内存后,再找到它就难了。
测试代码:
ret = memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_RANDOM);
测试结果:
添加key1:data1后,紧接着查询,查询失败。 - 基于桶
MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET
这个还没分析代码,后续补上。