例如,redis上的1,2,3,4,5列表,
server1想要1到8所以它会增加6,7,8,如果成功,列表将是1,2,3,4,5,6,7,8;
server2想要1到7所以它会增加6,7,它就成功了,列表将是e 1,2,3,4,5,6,7;
你看到元素6,7在重复,所以实际上列表可能是1,2,3,4,5,6,7,8,6,7或1,2,3,4,5,6 ,7,6,7,8
我正在制作一个拖尾记录缓存,如何解决这个问题?只排序集?但缓存需要lpush
答案 0 :(得分:1)
如果你真的想使用list,那么你可以添加另一个数据结构来获取一个数字是否快速存在:Set。
使您的设置数据与您的列表保持一致。当你想要一个数字到你的列表时,首先使用SISMEMBER检查该数字是否已经在集合(或列表)中,如果在,则不要LPUSH,如果不在,SADD进入set和LPUSH进入列表。 SISMEMBER是O(1),因此不会增加太多的时间成本。
需要注意的一件事:
存在一个事务问题,因为您有两个或更多服务器保持与redis的连接。所以在上面,一些动作需要是原子的。 例如,如果发生类似此订单的事情:
服务器1检查7使用SISMEMBER =>返回不存在
服务器2检查7使用SISMEMBER =>返回不存在
服务器1 lpush 7进入列表& sadd 7 into set
服务器2 lpush 7进入列表& sadd 7 into set
然后列表将有两个7。那么如何应对呢?
至少和最好,服务器检查一个号码使用SISMEMBER,如果不存在,使用SADD inser进入集合,如果存在,则不做任何设置应该是原子的。如果这是原子的,那么上面的内容将是这样的:
服务器1检查7使用SISMEMBER =>返回不存在&& sadd 7 into set
服务器2检查7使用SISMEMBER =>返回已存在。
server 1 lpush 7 into list
服务器2什么都不做
如何实现这一目标?只需使用MULTI使SISMEMBER和SADD成为原子。
MULTI
SISMEMBER set n
SADD set n
EXEC
然后你可以使用SISMEMBER的回复做出决定:lpush或什么也不做。 而SADD只会忽略一个重复的元素,所以没关系。
<强> EDITED 强>
如果您想一次性推送多个值,您可以使用pipeline来加速SISMEMBER。例如。在一个管道中:
MULTI
SISMEMBER set n1
SISMEMBER set n2
...
SADD set n1,n2,....
EXEC
在一个回复中得到每个n的结果(存在或不存在),然后将需要被推入数组的所有值分组,lpush一起。
答案 1 :(得分:0)
排序集是开始(或甚至设置)的方式。根据其性质,列表允许重复项目。实现你想做的事情的唯一方法是使用MULTI / LREM / LPUSH / EXEC,但这是一个坏主意(LREM是O(N),随着列表的增长,这可能非常昂贵。)