最近在使用redis的集合命令做对账比较时,上线前一切正常,上线后差异对比失效,两个完全相同的集合,在做diffAndStore后,差异的结果不为空。
本地进行了测试,本地redis使用了集群方式,结果本地复现,复现代码如下
// redis的key的定义
String localBillKey = "pay:reconciliation:local";
String remoteBillKey = "pay:reconciliation:remote";
String unionBillKey = "pay:reconciliation:union";
String localMoreBillKey = "pay:reconciliation:localMore";
String remoteMoreBillKey = "pay:reconciliation:remoteMore";
List<String> keys = new ArrayList<>();
keys.add(localBillKey);
keys.add(remoteBillKey);
keys.add(unionBillKey);
keys.add(localMoreBillKey);
keys.add(remoteMoreBillKey);
// 对账前清理旧数据
redis.delete(keys);
BoundSetOperations<String, String> localBillKeyBoundSetOps = redis.boundSetOps(localBillKey);
localBillKeyBoundSetOps.add("31812281457172855520647ffdEjiCtC,4200000214201812288098277144,0.01,2018-12-28 14:57:22",
"31812281902498165520647526wg2aL1,4200000230201812285953513148,0.02,2018-12-28 19:02:58",
"3181228095336491552064927e7V8AXl,4200000213201812285727593109,0.02,2018-12-28 09:53:41",
"3181228094542800552064927eL6sNF5,4200000212201812282025391199,0.02,2018-12-28 09:45:48",
"3181228094117343552064e2e3yfko10,4200000237201812286581975010,0.01,2018-12-28 09:41:23",
"318122814105006455206475267JKCTr,4200000218201812283499936418,0.02,2018-12-28 14:10:57",
"31812281736495635520647526utHwU5,4200000209201812283114535740,0.02,2018-12-28 17:36:55",
"31812281443495415520647526BSD8dJ,4200000223201812280997256864,0.02,2018-12-28 14:43:55",
"3181228095450983552064927egO84KB,4200000238201812285307041090,0.02,2018-12-28 09:54:56",
"31812281531203625520648bdeOQLgBN,4200000231201812283770763156,0.02,2018-12-28 15:31:26",
"31812281752496305520647526RVHKFG,4200000216201812289494841996,0.02,2018-12-28 17:52:55");
BoundSetOperations<String, String> remoteBillKeyBoundSetOps = redis.boundSetOps(remoteBillKey);
remoteBillKeyBoundSetOps.add("31812281902498165520647526wg2aL1,4200000230201812285953513148,0.02,2018-12-28 19:02:58",
"3181228095450983552064927egO84KB,4200000238201812285307041090,0.02,2018-12-28 09:54:56",
"3181228095336491552064927e7V8AXl,4200000213201812285727593109,0.02,2018-12-28 09:53:41",
"31812281531203625520648bdeOQLgBN,4200000231201812283770763156,0.02,2018-12-28 15:31:26",
"3181228094542800552064927eL6sNF5,4200000212201812282025391199,0.02,2018-12-28 09:45:48",
"31812281752496305520647526RVHKFG,4200000216201812289494841996,0.02,2018-12-28 17:52:55",
"31812281736495635520647526utHwU5,4200000209201812283114535740,0.02,2018-12-28 17:36:55",
"31812281443495415520647526BSD8dJ,4200000223201812280997256864,0.02,2018-12-28 14:43:55",
"3181228094117343552064e2e3yfko10,4200000237201812286581975010,0.01,2018-12-28 09:41:23",
"31812281457172855520647ffdEjiCtC,4200000214201812288098277144,0.01,2018-12-28 14:57:22",
"318122814105006455206475267JKCTr,4200000218201812283499936418,0.02,2018-12-28 14:10:57");
// 4, 进行对比,获取共同的结果
localBillKeyBoundSetOps.intersectAndStore(remoteBillKey, unionBillKey);
Set<String> membersxx = redis.boundSetOps(unionBillKey).members();
LOGGER.info("union {}", membersxx);
// 5,获取本地多的情况,需要结合对账详情表
localBillKeyBoundSetOps.diffAndStore(unionBillKey, localMoreBillKey);
Set<String> members = redis.boundSetOps(localMoreBillKey).members();
if (CollectionUtils.isNotEmpty(members)) {
LOGGER.error("doReconciliation summary,localMore {}", members);
}
// 6,获取支付宝/微信多的情况,需要结合对账详情表
redis.boundSetOps(remoteBillKey).diffAndStore(unionBillKey, remoteMoreBillKey);
Set<String> members2 = redis.boundSetOps(remoteMoreBillKey).members();
if (CollectionUtils.isNotEmpty(members2)) {
LOGGER.error("doReconciliation summary,remoteMore {}", members2);
}
// 7,对账后,清理中间数据
redis.delete(keys);
return "success";
}
各种纠结后,猛然想起之前测试时时redis单点测试的,想到redis集群模式下是根据key的hash映射来分布数据的,两个集合的key不一样,可能会分布到不同的节点上,这样diffAndStore时就出现问题。
想到这里,使用redis提供的tag方式,重新修改了测试代码
// redis的key的定义
String localBillKey = "{pay:reconciliation}:local";
String remoteBillKey = "{pay:reconciliation}:remote";
String unionBillKey = "{pay:reconciliation}:union";
String localMoreBillKey = "{pay:reconciliation}:localMore";
String remoteMoreBillKey = "{pay:reconciliation}:remoteMore";
List<String> keys = new ArrayList<>();
keys.add(localBillKey);
keys.add(remoteBillKey);
keys.add(unionBillKey);
keys.add(localMoreBillKey);
keys.add(remoteMoreBillKey);
// 对账前清理旧数据
redis.delete(keys);
BoundSetOperations<String, String> localBillKeyBoundSetOps = redis.boundSetOps(localBillKey);
localBillKeyBoundSetOps.add("31812281457172855520647ffdEjiCtC,4200000214201812288098277144,0.01,2018-12-28 14:57:22",
"31812281902498165520647526wg2aL1,4200000230201812285953513148,0.02,2018-12-28 19:02:58",
"3181228095336491552064927e7V8AXl,4200000213201812285727593109,0.02,2018-12-28 09:53:41",
"3181228094542800552064927eL6sNF5,4200000212201812282025391199,0.02,2018-12-28 09:45:48",
"3181228094117343552064e2e3yfko10,4200000237201812286581975010,0.01,2018-12-28 09:41:23",
"318122814105006455206475267JKCTr,4200000218201812283499936418,0.02,2018-12-28 14:10:57",
"31812281736495635520647526utHwU5,4200000209201812283114535740,0.02,2018-12-28 17:36:55",
"31812281443495415520647526BSD8dJ,4200000223201812280997256864,0.02,2018-12-28 14:43:55",
"3181228095450983552064927egO84KB,4200000238201812285307041090,0.02,2018-12-28 09:54:56",
"31812281531203625520648bdeOQLgBN,4200000231201812283770763156,0.02,2018-12-28 15:31:26",
"31812281752496305520647526RVHKFG,4200000216201812289494841996,0.02,2018-12-28 17:52:55");
BoundSetOperations<String, String> remoteBillKeyBoundSetOps = redis.boundSetOps(remoteBillKey);
remoteBillKeyBoundSetOps.add("31812281902498165520647526wg2aL1,4200000230201812285953513148,0.02,2018-12-28 19:02:58",
"3181228095450983552064927egO84KB,4200000238201812285307041090,0.02,2018-12-28 09:54:56",
"3181228095336491552064927e7V8AXl,4200000213201812285727593109,0.02,2018-12-28 09:53:41",
"31812281531203625520648bdeOQLgBN,4200000231201812283770763156,0.02,2018-12-28 15:31:26",
"3181228094542800552064927eL6sNF5,4200000212201812282025391199,0.02,2018-12-28 09:45:48",
"31812281752496305520647526RVHKFG,4200000216201812289494841996,0.02,2018-12-28 17:52:55",
"31812281736495635520647526utHwU5,4200000209201812283114535740,0.02,2018-12-28 17:36:55",
"31812281443495415520647526BSD8dJ,4200000223201812280997256864,0.02,2018-12-28 14:43:55",
"3181228094117343552064e2e3yfko10,4200000237201812286581975010,0.01,2018-12-28 09:41:23",
"31812281457172855520647ffdEjiCtC,4200000214201812288098277144,0.01,2018-12-28 14:57:22",
"318122814105006455206475267JKCTr,4200000218201812283499936418,0.02,2018-12-28 14:10:57");
// 4, 进行对比,获取共同的结果
localBillKeyBoundSetOps.intersectAndStore(remoteBillKey, unionBillKey);
Set<String> membersxx = redis.boundSetOps(unionBillKey).members();
LOGGER.info("union {}", membersxx);
// 5,获取本地多的情况,需要结合对账详情表
localBillKeyBoundSetOps.diffAndStore(unionBillKey, localMoreBillKey);
Set<String> members = redis.boundSetOps(localMoreBillKey).members();
if (CollectionUtils.isNotEmpty(members)) {
LOGGER.error("doReconciliation summary,localMore {}", members);
}
// 6,获取支付宝/微信多的情况,需要结合对账详情表
redis.boundSetOps(remoteBillKey).diffAndStore(unionBillKey, remoteMoreBillKey);
Set<String> members2 = redis.boundSetOps(remoteMoreBillKey).members();
if (CollectionUtils.isNotEmpty(members2)) {
LOGGER.error("doReconciliation summary,remoteMore {}", members2);
}
// 7,对账后,清理中间数据
redis.delete(keys);
return "success";
结果通过预期行为。测试环境redis和当初开发时redis均使用了单点,从而没有出现该问题。