经过这段时间对淘宝开源K/V缓存系统tair基础接口put/get/get_range等源码的详细剖析后,按自己的理解简单总结下tair中我较关心的get和get_range这两个接口的基本实现流程。由于get_range接口是最新几个版本才加入的功能,因此以前的tair Java客户端及最新版本安装后的命令行测试中都没有加入get_range测试接口,这无疑给需要专门优化get_range接口的我带来了不便,因此本文最后给出了在tair中实现get_range命令行测试的方法和示例。
1 tair基础接口Get
Get基础接口的实现主要分为两个部分:tair client端和tair server端,这里的server端指的是存储引擎之一leveldb。
1.1 client端的实现(tair_client_api_impl.cpp::get)
在分布式通信中,client端是封装给用户使用的接口,本质上并不实现真正的存储功能,而是将请求打包发送给server端,让server端实现具体的功能,然后将返回结果也打包发送给client端解析处理完成用户所要求的功能。
client端get接口的大致实现流程如下:
int get(int area, const data_entry &key, data_entry* &data);
(1)首先检查key和area参数的有效性;
if(!key_entry_check(key)){
return TAIR_RETURN_ITEMSIZE_ERROR;
}
if(area < 0 || area >= TAIR_MAX_AREA_COUNT){
return TAIR_RETURN_INVALID_ARGUMENT;
}
(2)利用MurmurHash2哈希算法取得key所在的server list;
vector<uint64_t> server_list;
if (!get_server_id(key, server_list)) {
TBSYS_LOG(DEBUG, "can not find serverId, return false");
return -1;
}
TBSYS_LOG(DEBUG,"get from server:%s",tbsys::CNetUtil::addrToString(server_list[0]).c_str());
在分布式存储系统中,数据都是存储在多台服务器上,如何将数据均匀的分布在各个服务器上即如何实现负载均衡也是分布式存储的一大难题,最多采用的一般是hash做法,比如有10台服务器,那么存储key所用的server id可以取hash(key) % 10。当然这是最粗糙的做法,有很多缺点,比如key1和key2就很有可能不在同一台服务器上,这样当我们get_range key为前缀的数据时就需要到所有服务器上找一遍,十分低效。为此,tair采取了一种更好的hash做法,使用prefix key而非整个key作为hash的参数,并采用著名的MurmurHash2哈希算法,一方面使得相同前缀的key都能存储在同一台或同几台服务器上方便查找,另一方面与其它流行的哈希函数相比,MurmurHash对于规律性较强的key的随机分布特征表现更良好,使得负载相对更均衡。
(3)将所有参数封装成一个packet,然后调用tbnet库函数向服务器端发送get请求,底层通过socket通信和RPC远程过程调用机制。注意,在send_request之前创建wait_object用于异步通信。
while (loop_count < s_size) {