架构师训练营第 1 期第 5 周作业
发布于: 2020 年 10 月 25 日
作业题目:自己实现一个 consistent hash。10 个节点,100 万个虚拟节点。
以下是 github 上的一致性 hash 的 cpp 代码。学习了代码实现,部分做了修改,因为虚拟节点多,所以注释掉了大部分打印,防止打印比较久。
一致性 hash 封装在模板类 consistent_hash_map 中,放在头文件,cpp 直接包含即可。使用了 stl map 风格的接口,内部用 map 来维护和管理所有节点。本身并不支持虚拟节点,而是实际的节点,但可以通过定制 T 和 hash 类型实现。
模板参数是:
T 是 consistent hash 的节点类型。
Hash 是一元函数对象。接收 T 类型对象作为参数,返回整型作为 hash 值,用于内部排序。
Alloc 是内存分配器,默认是 std::allocator。
#include <algorithm>
#include <functional>
#include <list>
#include <map>
#include <string>
#ifndef __CONSISTENT_HASH_H__
#define __CONSISTENT_HASH_H__
template <typename T, typename Hash,
typename Alloc = std::allocator<std::pair<const typename Hash::result_type, T>>>
class consistent_hash_map {
public:
typedef typename Hash::result_type size_type;
typedef std::map<size_type, T, std::less<size_type>, Alloc> map_type;
typedef typename map_type::value_type value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef typename map_type::iterator iterator;
typedef typename map_type::reverse_iterator reverse_iterator;
typedef Alloc allocator_type;
consistent_hash_map() {}
~consistent_hash_map() {}
std::size_t size() const { return nodes_.size(); }
bool empty() const { return nodes_.empty(); }
std::pair<iterator, bool> insert(const T& node) {
size_type hash = hasher_(node);
return nodes_.insert(value_type(hash, node));
}
void erase(iterator it) { nodes_.erase(it); }
std::size_t erase(const T& node) {
size_type hash = hasher_(node);
return nodes_.erase(hash);
}
iterator find(size_type hash) {
if (nodes_.empty()) {
return nodes_.end();
}
iterator it = nodes_.lower_bound(hash);
if (it == nodes_.end()) {
it = nodes_.begin();
}
return it;
}
iterator begin() { return nodes_.begin(); }
iterator end() { return nodes_.end(); }
reverse_iterator rbegin() { return nodes_.rbegin(); }
reverse_iterator rend() { return nodes_.rend(); }
private:
Hash hasher_;
map_type nodes_;
};
#endif
复制代码
实现虚拟节点的例子代码如下。例子用了 10 个节点,每个主机生成 1000000 个虚拟节点,然后加入 consistent_hash_map 中:
#include <stdint.h>
#include <boost/crc.hpp>
#include <boost/format.hpp>
#include <boost/functional/hash.hpp>
#include <iostream>
#include <string>
#include "consistent_hash_map.hpp"
constexpr int NODE_COUNT = 100;
constexpr int VIRTUAL_NODE_COUNT = 1000000;
const char* nodes[] = {"192.168.1.100", "192.168.1.101", "192.168.1.102", "192.168.1.103",
"192.168.1.104", "192.168.1.105", "192.168.1.106", "192.168.1.107",
"192.168.1.108", "192.168.1.109"};
struct vnode_t {
vnode_t() {}
vnode_t(std::size_t n, std::size_t v) : node_id(n), vnode_id(v) {}
std::string to_str() const {
// return boost::str(boost::format("%1%-%2%") % nodes[node_id] % vnode_id);
return "test";
}
std::size_t node_id;
std::size_t vnode_id;
};
struct crc32_hasher {
uint32_t operator()(const vnode_t& node) {
boost::crc_32_type ret;
std::string vnode = node.to_str();
// std::cout << "vnode:" << vnode << std::endl;
ret.process_bytes(vnode.c_str(), vnode.size());
return ret.checksum();
}
typedef uint32_t result_type;
};
int main(int argc, char const* argv[]) {
typedef consistent_hash_map<vnode_t, crc32_hasher> consistent_hash_t;
consistent_hash_t consistent_hash_;
for (std::size_t i = 0; i < NODE_COUNT; ++i) {
for (std::size_t j = 0; j < VIRTUAL_NODE_COUNT; j++) {
consistent_hash_.insert(vnode_t(i, j));
}
}
{
// std::cout << "=========================================================" << std::endl;
std::size_t sums[] = {0, 0, 0, 0, 0};
consistent_hash_t::iterator i = consistent_hash_.begin();
consistent_hash_t::reverse_iterator j = consistent_hash_.rbegin();
std::size_t n = i->first + UINT32_MAX - j->first;
// std::cout << boost::format("vnode:%1%,hash:%2%,contains:%3%") % i->second.to_str() % i->first %
// n
// << std::endl;
sums[i->second.node_id] += n;
uint32_t priv = i->first;
uint32_t cur;
consistent_hash_t::iterator end = consistent_hash_.end();
while (++i != end) {
cur = i->first;
n = cur - priv;
// std::cout << boost::format("vnode:%1%,hash:%2%,contains:%3%") % i->second.to_str() % cur % n
// << std::endl;
sums[i->second.node_id] += n;
priv = cur;
}
// for (std::size_t i = 0; i < NODE_COUNT; ++i) {
// std::cout << boost::format("node:%1% contains:%2%") % nodes[i] % sums[i] << std::endl;
// }
}
{
consistent_hash_t::iterator it;
it = consistent_hash_.find(290235110);
// std::cout << boost::format("node:%1%,vnode:%2%,hash:%3%") % nodes[it->second.node_id] %
// it->second.vnode_id % it->first
// << std::endl;
}
return 0;
}
复制代码
参考链接:https://github.com/ioriiod0/consistent_hash
注:如有侵权,请联系作者删除。
划线
评论
复制
发布于: 2020 年 10 月 25 日阅读数: 38
好吃不贵
关注
还未添加个人签名 2018.11.20 加入
还未添加个人简介
评论