浅谈一致性hash
相信做过互联网应用的都知道,如何很好的做到横向扩展,其实是个蛮难的话题,缓存可横向扩展,如果采用简单的取模,余数方式的部署,基本是无法做到后期的扩展的,数据迁移及分布都是问题,举个例子:
假设采用取模的方式来实现的分布式缓存,缓存节点为10个,这时候所有的缓存分布在10个节点上,任意一个节点down掉都会导致其他的缓存需要重新分布,从而会让所有缓存失效,这种在互联网应用上基本上是绝不允许出现的,那么如何来解决这个问题呢?!
一般目前互联网上的很多开源应用都是在客户端采用一致性hash来实现分布的,一致性hash又称环状hash,任意一节点出现问题不会影响全局数据有效性,具体的原理可以参考这里:一致哈希
下面简单贴出一致性hash的java实现参考:
import java.nio.ByteBuffer;
import java.nio.ByteOrder; /**
* This is a very fast, non-cryptographic hash suitable for general hash-based
* lookup. See http://murmurhash.googlepages.com/ for more details.
* <p/>
* <p>
* The C version of MurmurHash 2.0 found at that site was ported to Java by
* Andrzej Bialecki (ab at getopt org).
* </p>
*/
public class MurmurHash implements Hashing {
/**
* Hashes bytes in an array.
*
* @param data
* The bytes to hash.
* @param seed
* The seed for the hash.
* @return The 32 bit hash of the bytes in question.
*/
public static int hash(byte[] data, int seed) {
return hash(ByteBuffer.wrap(data), seed);
} /**
* Hashes bytes in part of an array.
*
* @param data
* The data to hash.
* @param offset
* Where to start munging.
* @param length
* How many bytes to process.
* @param seed
* The seed to start with.
* @return The 32-bit hash of the data in question.
*/
public static int hash(byte[] data, int offset, int length, int seed) {
return hash(ByteBuffer.wrap(data, offset, length), seed);
} /**
* Hashes the bytes in a buffer from the current position to the limit.
*
* @param buf
* The bytes to hash.
* @param seed
* The seed for the hash.
* @return The 32 bit murmur hash of the bytes in the buffer.
*/
public static int hash(ByteBuffer buf, int seed) {
// save byte order for later restoration
ByteOrder byteOrder = buf.order();
buf.order(ByteOrder.LITTLE_ENDIAN); int m = 0x5bd1e995;
int r = 24; int h = seed ^ buf.remaining(); int k;
while (buf.remaining() >= 4) {
k = buf.getInt(); k *= m;
k ^= k >>> r;
k *= m; h *= m;
h ^= k;
} if (buf.remaining() > 0) {
ByteBuffer finish = ByteBuffer.allocate(4).order(
ByteOrder.LITTLE_ENDIAN);
// for big-endian version, use this first:
// finish.position(4-buf.remaining());
finish.put(buf).rewind();
h ^= finish.getInt();
h *= m;
} h ^= h >>> 13;
h *= m;
h ^= h >>> 15; buf.order(byteOrder);
return h;
} public static long hash64A(byte[] data, int seed) {
return hash64A(ByteBuffer.wrap(data), seed);
} public static long hash64A(byte[] data, int offset, int length, int seed) {
return hash64A(ByteBuffer.wrap(data, offset, length), seed);
} public static long hash64A(ByteBuffer buf, int seed) {
ByteOrder byteOrder = buf.order();
buf.order(ByteOrder.LITTLE_ENDIAN); long m = 0xc6a4a7935bd1e995L;
int r = 47; long h = seed ^ (buf.remaining() * m); long k;
while (buf.remaining() >= 8) {
k = buf.getLong(); k *= m;
k ^= k >>> r;
k *= m; h ^= k;
h *= m;
} if (buf.remaining() > 0) {
ByteBuffer finish = ByteBuffer.allocate(8).order(
ByteOrder.LITTLE_ENDIAN);
// for big-endian version, do this first:
// finish.position(8-buf.remaining());
finish.put(buf).rewind();
h ^= finish.getLong();
h *= m;
} h ^= h >>> r;
h *= m;
h ^= h >>> r; buf.order(byteOrder);
return h;
} public long hash(byte[] key) {
return hash64A(key, 0x1234ABCD);
} public long hash(String key) {
return hash(SafeEncoder.encode(key));
}
}
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; public interface Hashing {
public static final Hashing MURMUR_HASH = new MurmurHash();
public ThreadLocal<MessageDigest> md5Holder = new ThreadLocal<MessageDigest>(); public static final Hashing MD5 = new Hashing() {
public long hash(String key) {
return hash(SafeEncoder.encode(key));
} public long hash(byte[] key) {
try {
if (md5Holder.get() == null) {
md5Holder.set(MessageDigest.getInstance("MD5"));
}
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("++++ no md5 algorythm found");
}
MessageDigest md5 = md5Holder.get(); md5.reset();
md5.update(key);
byte[] bKey = md5.digest();
long res = ((long) (bKey[3] & 0xFF) << 24)
| ((long) (bKey[2] & 0xFF) << 16)
| ((long) (bKey[1] & 0xFF) << 8) | (long) (bKey[0] & 0xFF);
return res;
}
}; public long hash(String key); public long hash(byte[] key);
}
一致性Hash在分布式应用中使用的很多,memcached,redis等等。
浅谈一致性hash的更多相关文章
- 浅谈一致性Hash原理及应用
在讲一致性Hash之前我们先来讨论一个问题. 问题:现在有亿级用户,每日产生千万级订单,如何将订单进行分片分表? 小A:我们可以按照手机号的尾数进行分片,同一个尾数的手机号写入同一片/同一表中. 大佬 ...
- 浅谈字符串Hash
浅谈字符串Hash 本篇随笔讲解Hash(散列表)的一个重要应用:字符串Hash. 关于Hash Hash是一种数据结构,叫做Hash表(哈希表),也叫散列表.关于Hash的实现,其实与离散化颇为类似 ...
- 浅尝一致性Hash原理
写在前面 在解决分布式系统中负载均衡的问题时候可以使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡的作用.但是普通的余数ha ...
- 浅谈一致性哈希(My转)
一致性哈希(Consistent hashing)算法是由 MIT 的Karger 等人与1997年在一篇学术论文(<Consistent hashing and random trees: d ...
- 浅谈NTLM Hash
认识Windows Hash 早期SMB协议在网络上传输明文口令.后来出现LAN Manager 挑战/响应验证机制(LM),其很容易破解,因此微软提出了WindowsNT挑战/响应验证机制(NTLM ...
- $.ajax()方法详解 ajax之async属性 【原创】详细案例解剖——浅谈Redis缓存的常用5种方式(String,Hash,List,set,SetSorted )
$.ajax()方法详解 jquery中的ajax方法参数总是记不住,这里记录一下. 1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为Str ...
- [转帖]浅谈分布式一致性与CAP/BASE/ACID理论
浅谈分布式一致性与CAP/BASE/ACID理论 https://www.cnblogs.com/zhang-qc/p/6783657.html ##转载请注明 CAP理论(98年秋提出,99年正式发 ...
- Hash表从了解到深入(浅谈)
· Hasn表,将一个数据进行Value化,再进行一个映射关系到Key直接进行访问的一个数据结构,这样可以通过直接的计算进行数据的访问和插入.关于Hash表的基本概念这里就不一一叙述,可以通过百度了解 ...
- 【转】浅谈Java中的hashcode方法(这个demo可以多看看)
浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...
随机推荐
- golang的reflect
引用自 http://www.jb51.net/article/115002.htm 和 C 数据结构一样,Go 对象头部并没有类型指针,通过其自身是无法在运行期获知任何类型相关信息的.反射操作所需要 ...
- React Native 让组件做到局部刷新
利用RN的状态机机制,我们可以通过this.setState({optional:...})来控制界面的刷新,但是一定会触发render方法,那如何保证不调用render方法从而做到界面的局部刷新呢? ...
- 在iPhone上取消APP订阅
1.在iPhone上打开APP Store,在精品推荐那个界面滚动到底部. 2.点击Apple ID那一栏,如图: 3.点击查看Apple ID,如图: 4.点击管理,如图: 5.关掉此选项,如图: ...
- Java杂谈6——Java安全模型
Java语言安全模型是其有别于传统的编程语言的一个很重要的特点,采用一种沙箱模型隔离了Java的运行环境与具体的操作系统,使得Java在网络环境下能够更为安全的运行.理解Java的安全模型,能够帮助我 ...
- ZooKeeper服务器是用Java创建的,它在JVM上运行。
ZooKeeper服务器是用Java创建的,它在JVM上运行. 创建配置文件 使用命令 vi conf/zoo.cfg 和所有以下参数设置为起点,打开名为 conf/zoo.cfg 的配置文件. $ ...
- 如何使用FlashgameMaster修改游戏
1 打开任意一款游戏,注意最好是AS2.0版的,我们以黄金矿工为例. 2 使用方法: 点击编辑按钮的打开编辑面板出现编辑面板后在对话框中输入要查找的数值,点击查找按钮,会列表出所以等于该值的变量. 如 ...
- Unity 编辑器扩展 场景视图内控制对象
http://blog.csdn.net/akof1314/article/details/38129031 假设有一个敌人生成器类,其中有个属性range用来表示敌人生成的范围区域大小,那么可以用O ...
- 【翻译自mos文章】在Oracle单机数据库中定义database service
来源于: Defining a Database Service with a Stand Alone Database (文档 ID 1260134.1) APPLIES TO: Oracle Da ...
- select * from (select user())a 为什么是查询user()的意思?
步骤:1.先查询 select user() 这里面的语句,将这里面查询出来的数据作为一个结果集 取名为 a2.然后 再 select * from a 查询a ,将 结果集a 全部查询出来
- Oracle 存储过程调用返回游标的另一个存储过程。
一个扩展存储过程调用另一个存储过程,示例: 被调用存储过程:最后会返回一个游标,游标返回一个值.调用这个存储过程的存储过程同样需要获取它. procedure SearchBill --根据到货单号查 ...