java中hashcode
有时候我们新写个类的话,我们要重写类的hashcode,equals方法
- 因为对象比较会先比较hashcode是否相等,再去比较equals方法
- 在HashMap中的数组+链表的结构是通过key的hash存放的
public class HashTest {
private String key;
private String value;
@Override
public int hashCode() {
return Objects.hash(key, value);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
HashTest other = (HashTest) obj;
return Objects.equals(key, other.key) && Objects.equals(value, other.value);
}
}
哈希
- 做负载的时候,我们想让某个ip的访问一直请求在某一个台服务器中
- 做分库分表的时候我们想把数据分布在不同的DB上
- 还有个就是做缓存大key的时候,拆分数据
问题
- 扩容的问题需要重新计算hash
- 最常见的做法 hash(key)%n 但这有个问题就是key的分布不均
一致性哈希(geektutu.com/post/geecac…)
结构流程
- 一致性哈希算法将 key 映射到 2^32 的空间中,将这个数字首尾相连,形成一个环。
- 图1中有peer2,4,6三个节点,节点查找是算出来的hash最近一个>=它的值
- key11,key2属于peer2节点,key23属于peer4节点,key27属于peer2节点
- 图2扩容添加了peer8节点那么需要修改的只有key27节点,就是>=上一个节点和<=当前节点的数据
分布不均的问题
- 这里引入了虚拟节点,也就是一个机器对应多个节点
- 当查找key对应的节点的时候,先求出hash找到最近一个>=的值,然后再找节点
java的demo
public class Consistenthash {
private int keys[];//槽位
private int replace;//虚拟个数
private Map<Integer, String> mappingHash;
public Consistenthash() {
keys=new int[10000];//槽位限制住了,实际是2^32 可以用其他集合代替
replace=5;
mappingHash=new HashMap<>();
}
//添加节点
public void addMachine(String des) {
for(int i=0;i<replace;i++) {
int hash=oneByOneHash(des+i)%keys.length;
keys[hash]=1;
mappingHash.put(hash, des);
System.out.println("[机器]:"+des+"[槽位]:"+hash);
}
}
//通过key获取节点
public String getDescBykey(String key) {
String descString="";
int hash=oneByOneHash(key)%keys.length;
int index=-1;
for(int i=hash;i<keys.length;i++) {
if(keys[i]>0) {
index=i;
break;
}
}
if(index>-1) {
descString=mappingHash.get(Integer.valueOf(index));
}
System.out.println("[key]:"+key+"[hash]:"+hash+"[在节点]:"+descString);
return descString;
}
/**
* 一次一个hash
* @param key
* @return 输出hash值
*/
public int oneByOneHash(String key) {
int hash, i;
for (hash = 0, i = 0; i < key.length(); ++i) {
hash += key.charAt(i);
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
// return (hash & M_MASK);
if(hash<0) {
return Math.abs(hash);
}
return hash;
}
public static void main(String[] args) {
Consistenthash consistenthash=new Consistenthash();
consistenthash.addMachine("机器1");
consistenthash.addMachine("机器2");
consistenthash.addMachine("机器3");
consistenthash.getDescBykey("student");
consistenthash.getDescBykey("sql");
}
}
效果