一致性哈希算法C++模板实现

关于一致性哈希概念上的理解可以参考:http://blog.csdn.net/cywosp/article/details/23397179

       参考代码:http://www.cnblogs.com/coser/archive/2011/11/27/2265134.html

一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简 单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用。 
    一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义:
1、平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。
2、单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。 
3、分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。 
4、负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同 的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。

参考图:

《一致性哈希算法C++模板实现》

下面给出主要代码(底层采用红黑树+MD5算法实现):

consistent_hash.h

#ifndef _CONSISTENT_HASH_H
#define _CONSISTENT_HASH_H

#include "lb_util.h"
#include "md5_hash.h"
#include "rb_tree.h"
#include "entity_node.h"
#include "virtual_node.h"

namespace lb
{

static const int MESSAGE_SIZE = 1000;
static const int MAX_NUM_SIZE = 10;

template <typename T, typename HASH=md5_hash>   //T is the entity_node data, HASH is the method of hash
class consistent_hash {
public:
	consistent_hash(const HASH& hash_obj);
	~consistent_hash();
public:
	void set_hash_class(const HASH& hash_obj);
	entity_node<T>* lookup_node(const char* object);

	void add_node(const entity_node<T>& node);
	void del_node(const entity_node<T>& node);
	long get_vnodes_amount() const;
public:
	int                         vnodes_amount_;      //the number of virtual number
	HASH                        hash_obj_;
	rb_tree<virtual_node<T> >*  vnode_tree_;
};

template <typename T, typename HASH>
consistent_hash<T,HASH>::consistent_hash(const HASH& hash_obj)
	:vnodes_amount_(0), hash_obj_(hash_obj), vnode_tree_(new rb_tree<virtual_node<T> >())
{
}

template <typename T, typename HASH>
consistent_hash<T, HASH>::~consistent_hash()
{
	delete vnode_tree_;	
}

template <typename T, typename HASH>
void consistent_hash<T, HASH>::set_hash_class(const HASH& hash_obj)
{
	hash_obj_ = hash_obj;
}

template <typename T, typename HASH>
entity_node<T>* consistent_hash<T, HASH>::lookup_node(const char* object)
{
	if(object == NULL || vnodes_amount_ <= 0)
		return NULL;
	
	long hash = hash_obj_.calc_md5_hash(object);
	virtual_node<T> virt_node;
	virt_node.set_hash(hash);
#ifdef _DEBUG_
	fprintf(stdout, "client hash:> %ld\n", hash);
#endif

	rb_tree_node<virtual_node<T> >* rb_node_ptr;
	if((rb_node_ptr = vnode_tree_->lookup(virt_node)) == NULL){
		fprintf(stdout, "lookup %s failed.\n", object);
		return NULL;
	}
	else{
#ifdef _DEBUG_
		fprintf(stdout, "machine assign:> %ld\n", (rb_node_ptr->get_data()).get_hash());
#endif
		return (rb_node_ptr->get_data()).get_entity_node();
	}

}


template <typename T, typename HASH>
void consistent_hash<T, HASH>::add_node(const entity_node<T>& node)
{
	int num_vnodes = node.get_num_vnodes();
	char str[MESSAGE_SIZE] = {'\0'};;
	char num[MAX_NUM_SIZE] ={'\0'};
	strcpy(str, node.get_identity());
	
	for(int i=1; i<=num_vnodes; ++i){
		int ret = sprintf(num, "%d", i);
		assert(ret >= 0);
		strcat(str, num);
		std::cout<<str<<std::endl;
		long hash = hash_obj_.calc_md5_hash(str);
	
		virtual_node<T> virt_node(node);    //create n virtual nodes
		virt_node.set_hash(hash);
		virt_node.set_entity_node(node);                
		
		if(!vnode_tree_->insert(virt_node))
			fprintf(stdout, "the num : %d virtual node insert failed\n", i);
		else{
			++vnodes_amount_;
#ifdef _DEBUG_
			fprintf(stdout, "insert virtual node %d success.\n", i);
#endif
		}

	}
}

template <typename T, typename HASH>
void consistent_hash<T, HASH>::del_node(const entity_node<T>& node)
{
	int num_vnodes = node.get_num_vnodes();
	char str[MESSAGE_SIZE] = {'\0'};
	char num[MAX_NUM_SIZE] ={'\0'};
	strcpy(str, node.get_identity());
	
	virtual_node<T>* virt_node = NULL;
	for(int i=1; i<=num_vnodes; ++i){
		int ret = sprintf(num, "%d", i);
		assert(ret >= 0);
		strcat(str, num);
		long hash = hash_obj_.calc_md5_hash(str);
		
		virtual_node<T> virt_node(node);  
		virt_node.set_hash(hash);
		virt_node.set_entity_node(node);
		
		if(!vnode_tree_->remove(virt_node))
			fprintf(stdout, "the virtual node %d did not in the rb_tree.\n", i);
		else{
				--vnodes_amount_;
#ifdef _DEBUG_
			fprintf(stdout, "delete virtual node %d success.\n", i);
#endif
			}
	}
}


template <typename T, typename HASH>
long consistent_hash<T, HASH>::get_vnodes_amount() const
{
	return vnodes_amount_;
}

}
#endif

实体结点entity_node.h

#ifndef _ENTITY_NODE_H
#define _ENTITY_NODE_H

#include <string>
#include <string.h>
#include <iostream>
#include <assert.h>

namespace lb
{

const int IDENTITY_SIZE = 100;

template <typename T>
class entity_node {
public:
	entity_node() {}
	entity_node(const char* identity, int num_vnodes, const T& data);	
	~entity_node() {}
public:
	const char* get_identity() const;
	long get_num_vnodes() const;
	
	void set_data(const T& data);
	const T& get_data() const;

protected:
	void set_entity_node(const char* identity, int num_vnodes, const T& data);
private:   
	char identity_[IDENTITY_SIZE];
	int  num_vnodes_;
	T    data_;
};

template <typename T>
entity_node<T>::entity_node(const char* identity, int num_vnodes, const T& data)
	:num_vnodes_(num_vnodes), data_(data)
{
	assert(identity != NULL);
	assert(num_vnodes >= 0);
	strcpy(identity_, const_cast<char *>(identity));
}

template <typename T>
inline const char* entity_node<T>::get_identity() const
{
	return identity_;
}

template <typename T>
inline long entity_node<T>::get_num_vnodes() const
{
	return num_vnodes_;
}

template <typename T>
inline void entity_node<T>::set_data(const T& data)
{
	data_ = data;
}

template <typename T>
inline const T& entity_node<T>::get_data() const
{
	return data_;
}

template <typename T>
inline void entity_node<T>::set_entity_node(const char* identity, int num_vnodes, const T& data)
{
	strcpy(identity_, const_cast<char *>(identity));;
	num_vnodes_ = num_vnodes;
	data_ = data;
}

}
#endif

虚拟节点virtual_node.h

#ifndef _VIRTUAL_H
#define _VIRTUAL_H

#include "lb_util.h"
#include "entity_node.h"

namespace lb 
{

template <typename T>
class virtual_node {
public:
	virtual_node();
	virtual_node(const entity_node<T>& node);
	~virtual_node() {}
public:
	void set_entity_node(const entity_node<T>& node);
	entity_node<T>* get_entity_node() const;

	void set_hash(long hash);
	long get_hash() const;
public:
	bool operator<(const virtual_node<T> other) const;
	bool operator>(const virtual_node<T> other) const;
	bool operator==(const virtual_node<T> other) const;
	bool operator>=(const virtual_node<T> other) const;
private:
	long                   hash_;
	mutable entity_node<T> node_;
};

template <typename T>
virtual_node<T>::virtual_node()
{
	hash_ = -1;
}

template <typename T>
inline virtual_node<T>::virtual_node(const entity_node<T>& node)
	: node_(node), hash_(-1)
{
}

template <typename T>
inline void virtual_node<T>::set_entity_node(const entity_node<T>& node)
{
	node_ = node;
}

template <typename T>
inline entity_node<T>* virtual_node<T>::get_entity_node() const
{
	return (entity_node<T>*)&node_;
}

template <typename T>
inline void virtual_node<T>::set_hash(long hash)
{
	hash_ = hash;
}

template <typename T>
inline long virtual_node<T>::get_hash() const
{
	return hash_;
}

template <typename T>
inline bool virtual_node<T>::operator<(const virtual_node<T> other) const
{
	return hash_ < other.hash_;
}

template <typename T>
inline bool virtual_node<T>::operator>(const virtual_node<T> other) const
{
	return hash_ > other.hash_;
}

template <typename T>
inline bool virtual_node<T>::operator==(const virtual_node<T> other) const
{
	return hash_ == other.hash_;
}

template <typename T>
inline bool virtual_node<T>::operator>=(const virtual_node<T> other) const
{
	return hash_ >= other.hash_;
}

}
#endif

    
         

    原文作者:哈希算法
    原文地址: https://blog.csdn.net/FreeeLinux/article/details/53043396
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞