JedisCluster模式尝试进行批量操作
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="5" />
<property name="maxTotal" value="1024" />
<property name="maxWaitMillis" value="5000" />
<property name="testOnBorrow" value="true" />
</bean>
<bean id="redisCluster" class="redis.clients.jedis.JedisCluster"
<constructor-arg name=“nodes">
<set>
<ref bean="hostport1" />
<ref bean="hostport2" />
<ref bean="hostport3" />
<ref bean="hostport4" />
<ref bean="hostport5" />
<ref bean="hostport6" />
</set>
</constructor-arg>
<constructor-arg name="timeout" value="6000" />
<constructor-arg name="poolConfig"
<ref bean="jedisPoolConfig" />
</constructor-arg>
</bean>

public JedisClusterConnectionHandler(Set<HostAndPort> nodes,
final GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout) {
this.cache = new JedisClusterInfoCache(poolConfig, connectionTimeout, soTimeout);
initializeSlotsCache(nodes, poolConfig);
} private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig) {
for (HostAndPort hostAndPort : startNodes) {
Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort());
try {
cache.discoverClusterNodesAndSlots(jedis);
break;
} catch (JedisConnectionException e) {
// try next nodes
} finally {
if (jedis != null) {
jedis.close();
}
}
} for (HostAndPort node : startNodes) {
cache.setNodeIfNotExist(node);
}
}
./redis-cli -c -h xxx -p 63xx cluster nodes
e54b82fd2b5ab238906cff7fc6250a7bc66c6fec 192.168.1.1xx:6389 master - 0 1469151811362 31 connected 0-5460
166baa38c8ab56339c11f0446257c7a6059a219b 192.168.1.1xx:6389 slave 1609b090dfaaac702449b72d30b2330521ce2506 0 1469151812364 29 connected
1609b090dfaaac702449b72d30b2330521ce2506 192.168.1.1xx:6390 master - 0 1469151811362 29 connected 10923-16383
539627a393aa43e82ca8c16d1e935611fec4e709 192.168.1.1xx:6388 myself,master - 0 0 28 connected 5461-10922
d9b3738ff16e99075242b865a0b6cc137c20d502 192.168.1.1xx:6390 slave 539627a393aa43e82ca8c16d1e935611fec4e709 0 1469151810859 28 connected
101227d3cb13f08a47ad2afe1b348d0efc3cb3b0 192.168.1.1xx:6388 slave e54b82fd2b5ab238906cff7fc6250a7bc66c6fec 0 1469151810357 31 connected
public void discoverClusterSlots(Jedis jedis) {
w.lock(); try {
this.slots.clear(); List<Object> slots = jedis.clusterSlots(); for (Object slotInfoObj : slots) {
List<Object> slotInfo = (List<Object>) slotInfoObj; if (slotInfo.size() <= 2) {
continue;
} List<Integer> slotNums = getAssignedSlotArray(slotInfo); // hostInfos
List<Object> hostInfos = (List<Object>) slotInfo.get(2);
if (hostInfos.size() <= 0) {
continue;
} // at this time, we just use master, discard slave information
HostAndPort targetNode = generateHostAndPort(hostInfos); setNodeIfNotExist(targetNode);
assignSlotsToNode(slotNums, targetNode);
}
} finally {
w.unlock();
}
}
@Override
public Jedis getConnection() {
// In antirez's redis-rb-cluster implementation,
// getRandomConnection always return valid connection (able to
// ping-pong)
// or exception if all connections are invalid List<JedisPool> pools = getShuffledNodesPool(); for (JedisPool pool : pools) {
Jedis jedis = null;
try {
jedis = pool.getResource(); if (jedis == null) {
continue;
} String result = jedis.ping(); if (result.equalsIgnoreCase("pong")) return jedis; pool.returnBrokenResource(jedis);
} catch (JedisConnectionException ex) {
if (jedis != null) {
pool.returnBrokenResource(jedis);
}
}
} throw new JedisConnectionException("no reachable node in cluster");
}
cluster nodes
e54b82fd2b5ab238906cff7fc6250a7bc66c6fec 192.168.1.163:6389 master - 0 1469600305090 31 connected 0-5460
166baa38c8ab56339c11f0446257c7a6059a219b 192.168.1.165:6389 slave 1609b090dfaaac702449b72d30b2330521ce2506 0 1469600304588 29 connected
1609b090dfaaac702449b72d30b2330521ce2506 192.168.1.163:6390 master - 0 1469600305592 29 connected 10923-16383
539627a393aa43e82ca8c16d1e935611fec4e709 192.168.1.163:6388 myself,master - 0 0 28 connected 5461-10922
d9b3738ff16e99075242b865a0b6cc137c20d502 192.168.1.165:6390 slave 539627a393aa43e82ca8c16d1e935611fec4e709 0 1469600305090 28 connected
101227d3cb13f08a47ad2afe1b348d0efc3cb3b0 192.168.1.165:6388 slave e54b82fd2b5ab238906cff7fc6250a7bc66c6fec 0 1469600304088 31 connected
- 节点 ID :例如 3fc783611028b1707fd65345e763befb36454d73 。
- ip:port :节点的 IP 地址和端口号, 例如 127.0.0.1:7000 , 其中 :0 表示的是客户端当前连接的 IP 地址和端口号。
- flags :节点的角色(例如 master 、 slave 、 myself )以及状态(例如 fail ,等等)。
- 如果节点是一个从节点的话, 那么跟在 flags 之后的将是主节点的节点 ID : 例如 127.0.0.1:7002 的主节点的节点 ID 就是 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 。
- 集群最近一次向节点发送 PING 命令之后, 过去了多长时间还没接到回复。
- 节点最近一次返回 PONG 回复的时间。
- 节点的配置纪元(configuration epoch):详细信息请参考 Redis 集群规范 。
- 本节点的网络连接情况:例如 connected 。
- 节点目前包含的槽:例如 127.0.0.1:7001 目前包含号码为 5960 至 10921 的哈希槽。
0——5460,5461——10922,10923——16383;
public void initCluster() {
if (jedis instanceof BinaryJedisCluster) {
BinaryJedisCluster jedisCluster = (BinaryJedisCluster) jedis; Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes(); Map<String, ClusterNodeObject> hpToNodeObjectMap = new HashMap<>(clusterNodes.size());
for (Map.Entry<String, JedisPool> entry : clusterNodes.entrySet()) {
JedisPool jedisPool = entry.getValue();
Jedis jedis = jedisPool.getResource(); String clusterNodesCommand = jedis.clusterNodes(); String[] allNodes = clusterNodesCommand.split("\n");
for (String allNode : allNodes) {
String[] splits = allNode.split(" "); String hostAndPort = splits[1];
ClusterNodeObject clusterNodeObject =
new ClusterNodeObject(splits[0], splits[1], splits[2].contains("master"), splits[3],
Long.parseLong(splits[4]), Long.parseLong(splits[5]), splits[6],
splits[7].equalsIgnoreCase("connected"), splits.length == 9 ? splits[8] : null); hpToNodeObjectMap.put(hostAndPort, clusterNodeObject);
}
}
List<Integer> slotStarts = new ArrayList<>();
for (ClusterNodeObject clusterNodeObject : hpToNodeObjectMap.values()) {
if (clusterNodeObject.isConnected() && clusterNodeObject.isMaster()) {
String slot = clusterNodeObject.getSlot();
String[] slotSplits = slot.split("-");
int slotStart = Integer.parseInt(slotSplits[0]);
// int slotEnd = Integer.parseInt(slotSplits[1]);
slotStarts.add(slotStart);
}
}
Collections.sort(slotStarts);
this.slotStarts = slotStarts;
} }
private int getSlotByKey(String key) {
int slot = JedisClusterCRC16.getSlot(key);
int slotInsertion = Collections.binarySearch(slotStarts, slot);
if (slotInsertion < 0) {
slotInsertion = Math.abs(slotInsertion + 2);
}
return slotInsertion;
}
if (keys.length > 2 && jedis instanceof JedisCluster) {
//如果批量请求key长度大于2,启动批量查询方式
Map<Integer, List<String>> keySlotsMapList = new HashMap<>(); for (String key : keys) {
int slotByKey = getSlotByKey(key); if (!keySlotsMapList.containsKey(slotByKey)) {
keySlotsMapList.put(slotByKey, new ArrayList<String>());
}
keySlotsMapList.get(slotByKey).add(key);
} for (Map.Entry<Integer, List<String>> entry : keySlotsMapList.entrySet()) {
List<String> slotSameKeys = entry.getValue();
List<String> mgetValues = ((ZhenJedisCluster) jedis)
.mget(slotSameKeys.toArray(new String[slotSameKeys.size()])); for (int i = 0; i < slotSameKeys.size(); i++) {
result.set(keyList.indexOf(slotSameKeys.get(i)), mgetValues.get(i));
}
} } else {
for (String key : keys) {
result.add(jedis.get(key));
}
}
public T run(int keyCount, String... keys) {
if (keys == null || keys.length == 0) {
throw new JedisClusterException("No way to dispatch this command to Redis Cluster.");
} // For multiple keys, only execute if they all share the
// same connection slot.
if (keys.length > 1) {
int slot = JedisClusterCRC16.getSlot(keys[0]);
for (int i = 1; i < keyCount; i++) {
int nextSlot = JedisClusterCRC16.getSlot(keys[i]);
if (slot != nextSlot) {
throw new JedisClusterException("No way to dispatch this command to Redis Cluster "
+ "because keys have different slots.");
}
}
} return runWithRetries(SafeEncoder.encode(keys[0]), this.redirections, false, false);
}
Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: CROSSSLOT Keys in request don't hash to the same slot
at redis.clients.jedis.Protocol.processError(Protocol.java:117)
at redis.clients.jedis.Protocol.process(Protocol.java:151)
at redis.clients.jedis.Protocol.read(Protocol.java:205)
at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:297)
at redis.clients.jedis.Connection.getBinaryMultiBulkReply(Connection.java:233)
at redis.clients.jedis.Connection.getMultiBulkReply(Connection.java:226)
at redis.clients.jedis.Jedis.mget(Jedis.java:355)
at redis.clients.jedis.ZhenJedisCluster$129.execute(ZhenJedisCluster.java:1382)
at redis.clients.jedis.ZhenJedisCluster$129.execute(ZhenJedisCluster.java:1)
at redis.clients.jedis.ZhenJedisClusterCommand.runWithRetries(ZhenJedisClusterCommand.java:119)
at redis.clients.jedis.ZhenJedisClusterCommand.run(ZhenJedisClusterCommand.java:51)
at redis.clients.jedis.ZhenJedisCluster.mget(ZhenJedisCluster.java:1384)
at com.api.pub.cache.JedisClient.batchGet(JedisClient.java:525)
at com.zhen.commons.redis.test.RedisTest.main(RedisTest.java:46)
redis-cli -c -h 192.168.1.138 -p 6388
192.168.1.138:6388> set key1 "key1"
-> Redirected to slot [9189] located at 192.168.1.137:6390
OK
192.168.1.137:6390> set key2 "key2"
-> Redirected to slot [4998] located at 192.168.1.137:6389
OK
192.168.1.137:6389> set key3 "key3"
OK
192.168.1.137:6389> mget key2 key3
(error) CROSSSLOT Keys in request don't hash to the same slot
192.168.1.137:6389> get key2
"key2"
192.168.1.137:6389> get key3
"key3"
192.168.1.137:6389> get key1
-> Redirected to slot [9189] located at 192.168.1.137:6390
"key1"
192.168.1.137:6390> set {aaa}1 "1"
OK
192.168.1.137:6390> set {aaa}2 "2"
OK
192.168.1.137:6390> mget {aaa}1 {aaa}2
1) "1"
2) "2"
public static int getSlot(String key) {
int s = key.indexOf("{");
if (s > -1) {
int e = key.indexOf("}", s + 1);
if (e > -1 && e != s + 1) {
key = key.substring(s + 1, e);
}
}
// optimization with modulo operator with power of 2
// equivalent to getCRC16(key) % 16384
return getCRC16(key) & (16384 - 1);
}
JedisCluster模式尝试进行批量操作的更多相关文章
- UWP学习记录8-设计和UI之控件和模式5
UWP学习记录8-设计和UI之控件和模式5 1.日历.日期和时间控件 日期和时间控件提供了标准的本地化方法,可供用户在应用中查看并设置日期和时间值. 有四个日期和时间控件可供选择,选择的依据如下: 日 ...
- Java--设计模式心得体会
1.策略模式: 策略模式就是将能够通用的算法,封装成不同的组件,实现同一个接口,使之可以互换. 例子:SpringMVC的9大组件,都采用策略模式.比如HandlerMethodArgumentRes ...
- 【设计模式 - 11】之享元模式(FlyWeight)
1 模式简介 当系统中存在大量对象时,非常容易造成内存溢出.为了解决这个问题,我们把这些对象中共有的部分抽象出来,如果有相同的业务请求,则直接返回在内存中已有的对象,避免重新创建,这就是享元 ...
- Head First设计模式之享元模式(蝇量模式)
一.定义 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式. ...
- 设计模式学习心得<享元模式 Flyweight>
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式. 享元模式尝 ...
- 设置GRUB密码以防止单用户模式下root密码被恶意更改
在使用LInux系统的时候可能会发生忘记root密码的情况,通常管理员会进入单用户模式下进行重置root密码.那么问题来了,既然管理员可以进入单用户模式,如果恶意用户可以接触的到计算机的话毫无疑问也是 ...
- 二十、Flyweight 享元模式
原理: 代码清单: BigChar public class BigChar { //字符名称 private char charname; //大型字符 # . \n 组成 private Stri ...
- 设计模式-创建型模式,python享元模式 、python单例模式(7)
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式. 享元模式尝 ...
- 享元(FlyWeight)模式
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式.享元模式尝试 ...
随机推荐
- Python学习(007)-函数的特性
一..函数是什么 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 1.代码重用 2.保持一致性 3.可扩展性 二.创建 2.1格式 de ...
- prop和state的区别
1.prop用于定义外部接口,state用于记录内部状态: 2.prop的赋值在外部世界使用组件时,state的赋值在组件内部: 3.组件不应该改变prop的值,但是state的存在目的就是让组件来改 ...
- [leetcode] 94. Binary Tree Inorder Traversal 二叉树的中序遍历
题目大意 https://leetcode.com/problems/binary-tree-inorder-traversal/description/ 94. Binary Tree Inorde ...
- PHP CURL HTTPS内存泄露问题
还原场景:通过一直运行脚本,向微信用户发送模板消息,发现运行了一段时间,内存就爆了,然后立马看了一下代码,发现跟其他的消息逻辑一模一样,唯一不一样的就是请求了微信的接口:然后继续开始找问题,发现当时使 ...
- 《DSP using MATLAB》Problem 4.14
代码: %% ---------------------------------------------------------------------------- %% Output Info a ...
- DZY Loves Math系列
link 好久没写数学题了,再这样下去吃枣药丸啊. 找一套应该还比较有意思的数学题来做. [bzoj3309]DZY Loves Math 简单推一下. \[\sum_{i=1}^n\sum_{j=1 ...
- ZH奶酪:Python使用ElementTree解析XML【译】
19.7. xml.etree.ElementTree — The ElementTree XML API 源代码: Lib/xml/etree/ElementTree.py Element类型是一种 ...
- centos下yum安装pip失败
[root@wfm ~]# yum -y install pip Loaded plugins: fastestmirror, refresh-packagekit, securityLoading ...
- Linux 性能工具安装部署
docker 一.运行docker Linux内核版本需要在3.8以上,针对centos6.5 内核为2.6的系统需要先升级内核.不然会特别卡 在yum的ELRepo源中,有mainline(4.5) ...
- 使用 Python 连接到 PADS Layout
使用 Python 连接到 PADS Layout PADS Layout 使用的是 VBA 编程,很多人说 VBA 很简单,但是实在学不会,可能是太笨了. 后来发现 PADS Layout 有 CO ...