假设我在redis中有一个列表,上面有一个分布式服务,其想法是让分布式系统将数据写入这个列表,然后可以被其他主机查询。
给出这样的列表:
1,2,3,4,1
我希望能够执行
increment the first element by 5
和 increment the second element by 2
等操作来获取最终结果列表:
6,4,3,4,1
由于服务是分布式的,我不能只抓取列表,然后由服务进行计算,然后设置,因为两台机器可能会尝试将 1 添加到列表中,但由于它们抓取相同的列表,我们将得到一个竞争条件。
我也无法通过上游强制执行一致的散列,因为热键可能具有高负载并导致数据倾斜,因此我需要一个可以通过上游循环或其他一些基于非散列的算法进行负载平衡的解决方案。
如何使用 Redis 完成此任务?
您可以使用以下两个命令来实现您的目标:
LINDEX
:获取给定索引处的值。LSET
:将给定索引处的值设置为增加的值。为了使这两个命令原子化,以便它在分布式环境中工作。你可以将这两个命令包装成一个 Lua 脚本:
local key = KEYS[1]
local index = ARGV[1]
local incr = ARGV[2]
local val = redis.call('lindex', key, index)
if not val then return nil end
val = tostring(tonumber(val) + tonumber(incr))
redis.call('lset', key, index, tonumber(val) + incr)
return val
但是,
LINDEX
和LSET
都是慢命令(尤其是长列表),即O(N)操作。您可能需要使用更高效的数据结构重新设计代码。