首页 > 工作 > RedisCluster数据覆盖问题

RedisCluster数据覆盖问题

碰到一个典型的问题:
redis的set数据,有大量的读redis和少量的写源(同时删除redis中对应的key),在读的时候做miss回源。

碰到的问题:
少量写后删除key,会同时有大量的读去回源,源压力暴涨,且导致了多次写。回源越慢,源的压力就越大。

计划由读miss回源改为写时覆盖,问题是:set好像没办法覆盖,只能先删除key后再加,删除key时,还是会引发读回源。

看到redis支持rename,就想到一个办法:
少量写的时候,先把数据写到一个新key里,然后rename成老key,从命令上看是支持覆盖的:https://redis.io/commands/rename

RENAME key newkey

Available since 1.0.0.
Time complexity: O(1)
Renames key to newkey. It returns an error when key does not exist. If newkey already exists it is overwritten, when this happens RENAME executes an implicit DEL operation, so if the deleted key contains a very big value it may cause high latency even if RENAME itself is usually a constant-time operation.
Note: Before Redis 3.2.0, an error is returned if source and destination names are the same.
Return value
Simple string reply

Examples
redis> SET mykey "Hello"
"OK"
redis> RENAME mykey myotherkey
"OK"
redis> GET myotherkey
"Hello"
redis> 

结果是出错:

>rename newkey oldkey
(error) CROSSSLOT Keys in request don't hash to the same slot

从错误上看,应该是两个key在不同的slot上,如果想办法把新key和老key放到一个slot里就可以了。
搞了搞redis的hash算法,甚至想到随机生成一批key,去查哪一个跟老key在同一个slot上,然后去用它。这种方式需要用到CLUSTER KEYSLOT命令:

CLUSTER KEYSLOT key

Available since 3.0.0.
Time complexity: O(N) where N is the number of bytes in the key
Returns an integer identifying the hash slot the specified key hashes to. This command is mainly useful for debugging and testing, since it exposes via an API the underlying Redis implementation of the hashing algorithm. Example use cases for this command:
Client libraries may use Redis in order to test their own hashing algorithm, generating random keys and hashing them with both their local implementation and using Redis CLUSTER KEYSLOT command, then checking if the result is the same.
Humans may use this command in order to check what is the hash slot, and then the associated Redis Cluster node, responsible for a given key.
Example
> CLUSTER KEYSLOT somekey
11058
> CLUSTER KEYSLOT foo{hash_tag}
(integer) 2515
> CLUSTER KEYSLOT bar{hash_tag}
(integer) 2515
Note that the command implements the full hashing algorithm, including support for hash tags, that is the special property of Redis Cluster key hashing algorithm, of hashing just what is between { and } if such a pattern is found inside the key name, in order to force multiple keys to be handled by the same node.
Return value
Integer reply: The hash slot number.

感觉这个路子太野,应该不对。

留意到它有个{hash_tag},研究了一下,发现一条新路,可以简单搞定。参考:https://redis.io/topics/cluster-spec#keys-hash-tags
原文就不转述了,简单来说,就是当key中出现{}时,redis会只用{}中的字符串做hash运算。然后事情就好办了:新key命名为xx{oldkey}即可。
rename xx{oldkey} oldkey
就可以正常执行了。

延伸一下:可以把某个用户所有的相关缓存都放到同一个splot下,只需要命名规范统一为xxx{userId}即可。比如:当需要muti get某个用户的多个key值的时候,这个用户的数据会在同一个slot上,效率应该会更高一些。

分类: 工作 标签: , , , ,
  1. 本文目前尚无任何评论.