我们现实场景中经常会遇到多个redis服务节点的情况, jedis提供实现分片存储的实现,jedis通过ShardedJedis支持多个节点地址,简单的shardedJedis代码示例:
3,多实例模式:
import java.util.ArrayList;
import java.util.List;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.exceptions.JedisConnectionException;
public class ShardedJedisUtil {
private ShardedJedis shardedJedis;
private String addresss;
public ShardedJedisUtil(String addresss) {
this.addresss = addresss;
initShardedJedis();
}
public void initShardedJedis() {
List<JedisShardInfo> shards = new ArrayList<>();
JedisShardInfo info = null;
for (String address : addresss.split(",")) {
String[] hostAndPort = address.split(":");
info = new JedisShardInfo(hostAndPort[0], Integer.valueOf(hostAndPort[1]));
shards.add(info);
}
shardedJedis = new ShardedJedis(shards);
}
public void set(String key, String value) {
try {
shardedJedis.set(key, value);
} catch (JedisConnectionException e) {
System.out.println(e.getMessage());
} finally {
shardedJedis.close();
}
}
public String get(String key) {
String result = null;
try {
result = shardedJedis.get(key);
} catch (JedisConnectionException e) {
System.out.println(e.getMessage());
} finally {
shardedJedis.close();
}
return result;
}
public static void main(String args[]) {
for (int i = 0; i < 100; i++) {
ShardedJedisUtil ShardedJedisUtil = new ShardedJedisUtil("127.0.0.1:4100,127.0.0.1:4101");
ShardedJedisUtil.set("key" + i, "value" + i);
System.out.println(ShardedJedisUtil.get("key" + i));
}
}
}
在示例构造方法中调用initShardedJedis()方法,首先创建一个JedisShardInfo对象的List集合shards,将传入的地址解析之后创建两个JedisShardInfo对象放入shards中,JedisShardInfo是继承了ShardInfo<Jedis>类的一个包含redis节点信息的包装类对象
public class JedisShardInfo extends ShardInfo<Jedis> {
private int connectionTimeout;
private int soTimeout;
private String host;
private int port;
private String password = null;
private String name = null;
private int db = 0;
private boolean ssl;
private SSLSocketFactory sslSocketFactory;
private SSLParameters sslParameters;
private HostnameVerifier hostnameVerifier;
public JedisShardInfo(String host) {
super(Sharded.DEFAULT_WEIGHT);
URI uri = URI.create(host);
if (JedisURIHelper.isValid(uri)) {
this.host = uri.getHost();
this.port = uri.getPort();
this.password = JedisURIHelper.getPassword(uri);
this.db = JedisURIHelper.getDBIndex(uri);
this.ssl = uri.getScheme().equals("rediss");
} else {
this.host = host;
this.port = Protocol.DEFAULT_PORT;
}
}
public JedisShardInfo(String host, SSLSocketFactory sslSocketFactory,
SSLParameters sslParameters, HostnameVerifier hostnameVerifier) {
super(Sharded.DEFAULT_WEIGHT);
URI uri = URI.create(host);
if (JedisURIHelper.isValid(uri)) {
this.host = uri.getHost();
this.port = uri.getPort();
this.password = JedisURIHelper.getPassword(uri);
this.db = JedisURIHelper.getDBIndex(uri);
this.ssl = uri.getScheme().equals("rediss");
this.sslSocketFactory = sslSocketFactory;
this.sslParameters = sslParameters;
this.hostnameVerifier = hostnameVerifier;
} else {
this.host = host;
this.port = Protocol.DEFAULT_PORT;
}
}
public JedisShardInfo(String host, String name) {
this(host, Protocol.DEFAULT_PORT, name);
}
public JedisShardInfo(String host, int port) {
this(host, port, 2000);
}
.....
}
之后创建了ShardedJedis对象 ,在ShardedJedis构造方法中
public ShardedJedis(List<JedisShardInfo> shards) {
super(shards);
}
public ShardedJedis(List<JedisShardInfo> shards, Hashing algo) {
super(shards, algo);
}
public ShardedJedis(List<JedisShardInfo> shards, Pattern keyTagPattern) {
super(shards, keyTagPattern);
}
public ShardedJedis(List<JedisShardInfo> shards, Hashing algo, Pattern keyTagPattern) {
super(shards, algo, keyTagPattern);
}
构造参数有一个JedisShardInfo对象的集合,JedisShardInfo对象中包含host,port,password等属性信息,
ShardedJedis继承了BinaryShardedJedis类,BinaryShardedJedis继承了Sharded<Jedis, JedisShardInfo>,并实现了BinaryJedisCommands接口,Sharded的构造方法
public Sharded(List<S> shards) {
this(shards, Hashing.MURMUR_HASH); // MD5 is really not good as we works
// with 64-bits not 128
}
public Sharded(List<S> shards, Hashing algo) {
this.algo = algo;
initialize(shards);
}
public Sharded(List<S> shards, Pattern tagPattern) {
this(shards, Hashing.MURMUR_HASH, tagPattern); // MD5 is really not good
// as we works with
// 64-bits not 128
}
public Sharded(List<S> shards, Hashing algo, Pattern tagPattern) {
this.algo = algo;
this.tagPattern = tagPattern;
initialize(shards);
}
Sharded构造方法中有一个参数Hashing.MURMUR_HASH,由Austin Appleby在2008年发明,之后衍生出MURMUR2,MURMUR3等版本,Hashing.MURMUR_HASH是一个高运算低碰撞的哈希算法,
Sharded构造方法中还调用了initialize(shards)方法:
private void initialize(List<S> shards) {
nodes = new TreeMap<Long, S>();
for (int i = 0; i != shards.size(); ++i) {
final S shardInfo = shards.get(i);
if (shardInfo.getName() == null)
for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
nodes.put(this.algo.hash("SHARD-" + i + "-NODE-" + n), shardInfo);
}
else
for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
nodes.put(this.algo.hash(shardInfo.getName() + "*" + shardInfo.getWeight() + n), shardInfo);
}
resources.put(shardInfo, shardInfo.createResource());
}
}
initialize方法实现了对redis节点的分片处理,存放在定义TreeMap类型的nodes中,nodes的key通过murmur_hash哈希算法计算的哈希值,value值是之前传入的JedisShardInfo对象,默认分片大小是160*weight,weight是权重大小,默认为1。最后将JedisShardInfo创建的资源放入resuources的LinkedHashMap中。
初始化shardedJedis对象完成之后,调用set方法,
public String set(String key, String value) {
Jedis j = getShard(key);
System.out.println("master:"+j.getClient().getHost()+":"+j.getClient().getPort());
return j.set(key, value);
}
在set方法中首先调用了一个getShard(key)方法,该方法获取分片后的具体某一个分片信息,也就是分片中放入的jedis对象,
public R getShard(String key) {
return resources.get(getShardInfo(key));
}
public S getShardInfo(String key) {
return getShardInfo(SafeEncoder.encode(getKeyTag(key)));
}
public S getShardInfo(byte[] key) {
SortedMap<Long, S> tail = nodes.tailMap(algo.hash(key));
S s = null;
Long num = null;
if (tail.isEmpty()) {
num = nodes.firstKey();
s = nodes.get(num);
return s;
}
num = tail.firstKey();
s = tail.get(num);
return s;
}
最终调用到getShardInfo(byte[] key)方法,该方法中nodes调用tailMap方法,查询文档可知tailMap方法用于返回此映射,其键大于或等于fromKey的部分视图。nodes.tailMap(algo.hash(key))将nodes集合中将key键的值大于等于algo.hash(key)哈希值的所有键值对都返回。这里采用的哈希算法与初始化shardedJedis的分片算法一致都采用Murmur_hash算法。
然后通过tail的firstKey方法获取到第一个键值对的键值,也就是一个第一个键值对的key,在通过tail.get(key)获取到初始化时放入的Jedis对象。最后调用jedis的set方法将key,value放入其中。
3463

被折叠的 条评论
为什么被折叠?



