浅谈memcached的CAS机制

2022-04-13 00:00:00 操作 更新 缓存 出了 版本号

CAS,check and set。看到这个解释就很清楚它是用来每次set 之前进行check 一次。而这次我要讲的是关于memcached,因为都知道memcached在大并发面前内部是多线程去处理的。多线程的话,客户端过来的命令的执行顺序就不是串行化,就容易出现一个item被多个线程更改的问题。不过涉及到这种案例的时候,我建议还是使用redis。在我看来memcached只是一个简单便捷的缓存中间件,一些重要的操作还是慎用。

现在我就讲讲CAS的原理,在同一个memcache服务中,针对每一对key/value都维护了一个号码,可以称为版本号,这个值是一直递增的,不会重复,当增加或者更新的时候就会自增+1,删除的时候不会改变。一般的操作是先获取到这个key的值,然后再update新的值进去。自然这个会先gets命令出value 和版本号,然后再使用cas 命令去update 的时候,就会带上刚才的版本号,此时这个带过来的版本号就会和缓存本身的版本号进行对比,看下是否一致,如果不一致,那么就认为这个数据被其他线程更新过,本次更新失败,如果一致,那么更新成功。机制就差不多是这样。下面说一个例子,这样会比较清晰。

现在 key 为’hot_topic_list‘,value,[x1,x2,x3]是近热门的话题id。现在有a,b两个去操作它,未使用cas机制的情况:

a 取出了 hot_topic_list,[x1,x2,x3]

b 取出了 hot_topic_list,[x1,x2,x3]

a发现了一个新的topic_id为x4,准备要添加进去,[x1,x2,x3,x4]

同时b也发现了一个新的topic_id为x5,准备要添加进去,[x1,x2,x3,x5]

所以我们发现不管是a和b谁先执行更新操作,都将丢失一个数据。

现在使用了cas机制的情况:

        a 用gets取出了 hot_topic_list,[x1,x2,x3],同时还有版本号 100

        b 用gets取出了 hot_topic_list,[x1,x2,x3],同时也获取了版本号 100

        然后 a 发现了一个新的topic_id为x4,准备cas进去,此时发现带进去的版本号100和缓存里面自身的版本号100是相同的,更新成功,缓存自身的版本号+1,成为了101。

        然后 b发现了一个新的topic_id为x4,准备cas进去,此时发现带过去的版本号100和缓存内部的版本号101不相同,更新失败,重新执行失败之后的操作。

    上面简单的唠唠了cas,其实我也没有用到cas命令,都是用set覆盖写,所以我觉得它只是作为一个数据可丢失的缓存,一些其他的操作还是建议使用redis。毕竟redis支持的数据结构特别多,而且也不用担心并发问题。下次想说说redis 大key的清理方案。

来源 https://www.modb.pro/db/191199

相关文章