处理Memcached竞争条件

时间:2016-07-01 13:11:34

标签: ruby key memcached race-condition

我有两种不同的数据来源,我需要结合在一起。数据集A将具有foo_key属性,该属性可以映射到具有一对多关系的数据集B的bar_key属性。

数据集A:

[{ foo_key: 12345, other: 'blahblah' }, ...]

数据集B:

[{ bar_key: 12345, other: '' }, { bar_key: 12345, other: '' }, { bar_key: 12345, other: '' }, ...]

数据集A来自SQS队列,当我轮询A时,与数据集B的任何关系都可用。

数据集B来自一个单独的SQS队列,我试图将其转储到memcached缓存中,以便在对象进入数据集A时快速查看。

最初我打算从数据集B中的对象设置memcached键为bar_key,但后来意识到如果我这样做,就有可能覆盖该值,因为可能存在许多相同的bar_key值。然后我想我可以创建一个键bar_key,值只是一个SQS消息的数组。但是由于我有多个主机轮询SQS队列,我认为当我检查密钥是否在memcached中时,检查它,将新消息附加到它,然后设置它,另一个主机可能是尝试执行相同的操作,因此第一个主机尝试附加该值只会被覆盖。

我查看了memcached键锁定,但我不确定我完全理解它。解决方案是,当我从memcached获取键/值对时,我在一个名为bar_key_dummy的新键上创建一个临时虚拟锁,该键在x秒后到期,如果我尝试获取一个bar_key_dummy锁激活的键,我只需发送SQS消息返回队列而不删除,在x秒内再试一次?

这是我头脑中的一些伪代码。这有什么意义吗?

store = MemCache.new(host)

sqs_messages.poll do |message|
  dummy_key = "#{message.bar_key}_dummy"
  sqs.dont_delete_message && next unless store.get(dummy_key).nil?
  # set dummy_key in memcache with a value of 1 for 3 seconds
  store.set(dummy_key, 1, 3)
  temp_data = store.get(message.bar_key) || []
  temp_data << message
  store.set(message.bar_key, temp_data, 300)
  # delete dummy key when done in case shorter than x seconds
  store.delete(dummy_key)
end

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

Memcached有一项特殊操作 - cas比较和交换。

命令gets返回Item及其唯一的CAS值。 然后可以搜索数据集,并且必须使用cas命令发布更新,该命令采用原始的唯一CAS值。

如果在两个命令之间更改了CAS,则更新操作将失败并显示EXISTS错误