twemproxy上做交并集合操作
业务线上出错,返回给用户的结果不正确。
使用了ZINTERSTORE这个接口对多个集合做交并集返回预期外的空集。如下图:
这是因为twemproxy只是把指令转发给redis而已,而多个集合被哈希算法分片在不同的redis节点上,所以转发这个redis并没有这几个集合,会直接返回空集。
这并不是BUG,redis3.0也存在这个特性,当多个集合做交并集操作时,需要使用hash_tag特性。
首先DBA需要修改配置文件
然后业务逻辑的KEY这样操作
此时twemproxy只会对括号内的test关键字进行哈希,能够强制性保证这三个集合在同一个redis上。
hash_tag的说明
twemproxy使用一致性哈希来对key进行分片到不同的redis后端上。
由于一些特殊的需求使得两个key必须分布在同一个redis后端上(例如交并集合等等),那么此时不能对整个key进行分片。
使用hash_tag对key做截断,截取其中相同的部分进行哈希,就能使得分片在同一个后端redis上。
在代码中的逻辑很简单:
(struct context *ctx, struct conn *c_conn, struct msg *msg)
req_forward{
...
/*
* If hash_tag: is configured for this server pool, we use the part of
* the key within the hash tag as an input to the distributor. Otherwise
* we use the full key
*/
if (!string_empty(&pool->hash_tag)) {
struct string *tag = &pool->hash_tag;
uint8_t *tag_start, *tag_end;
= nc_strchr(msg->key_start, msg->key_end, tag->data[0]);
tag_start if (tag_start != NULL) {
= nc_strchr(tag_start + 1, msg->key_end, tag->data[1]);
tag_end if (tag_end != NULL) {
= tag_start + 1;
key = (uint32_t)(tag_end - key);
keylen }
}
}
if (keylen == 0) {
= msg->key_start;
key = (uint32_t)(msg->key_end - msg->key_start);
keylen }
...
}
hash_tag由两个符号组成,分别是tag->data[0]和tag->data[1]
逻辑上对每个key做字符寻找操作,找到key中第一个出现的tag->data[0]以及紧跟着出现的tag->data[1]
把这中间的部分作为新的key来hash
也就说如果hash_tag设置为{}后
对于值为"a{b}c{d}e"这样的key来说,只会对b进行hash。
-
2014-11-21
twemproxy的性能应该很好,毕竟是twitter在使用的,稳定性应该很高。
然而测试组的同学对其二倍扩容以后,基本没提升QPS,甚至QPS还降低了
我和我的小伙伴们一直以为是客户端或者服务端代码的问题,各种抓包,LOG分析,查不出原因。写了C,JAVA等多个客户端版本。
后面发现原来是测试组的布线坑爹了。
关于之前测试环境redis集群极限qps提升不上去的问题,认定是由于之前4台测试环境部署的宿主机,走的交换机,交换机网络达到瓶颈导致的。