Memcached CAS协议
介绍
CAS(Check And Set)检查后再赋值,是为了解决多线程并发问题而设计的一种解决方案。
Memcached于1.2.4版本新增CAS(Check and Set)协议类似于Java并发的CAS(Compare and Swap)
原子操作,处理同一key被多个线程更改过程的并发问题。
在Memcached中,每个key关联有一个64-bit长度的long型惟一数值,表示该key对应value的版本号。
这个数值由Memcached server产生,从1开始,且同一Memcached server不会重复。
在两种情况下这个版本数值会加:
1、新增一个key-value对
2、对某已有key对应的value值更新成功
备注:删除key版本值不会减小
备注就相当于版本号,但是memcached的版本号管理并不是针对每个key都有一个版本号维护的。
并且每次取版本号是取对应key值的最新版本号(注意不是取整个memcached服务器里的最新版本号)。
CAS协议解决的问题
假如现在有ClientA和ClientB都连接到同一台memcached服务器,此时ClientA对key进行更新操作,
set key="AAA",此时ClientA想读取出key的值,期望值应该是"AAA",但是在取出值之前ClientB
又对key进行了更新操作,set key="BBB",那么ClientA取出的数据就不是自己期望的"AAA"而是"BBB"了,
导致这种问题原因就是ClientA它不知道key已经被ClientB修改了这样就可能导致业务处理出错。
这就是并发场景下会遇到的问题。
CAS协议解决这种并发修改问题。有线程试图修改当前key-value对的value时,先由gets方法得到
key的版本号,操作完成提交数据时,使用cas方法谨慎变更,如果在本地对key操作过程中这个key-value
对在Memcached server端被其它线程更改过,就放弃此次修改(乐观锁概念)。
memcached client 使用CAS
/**
* 基于net.spy.memcached客户端使用CAS操作。
*
* @author xuyi3
* @2016年7月1日 @上午11:23:09
* @VersionTest
* @功能说明:<br>
* @春风十里不如你
* @备注
*/
public class VersionAppMain {
public static void main(String[] args) {
// 获得memcached连接
MemcachedClient connection = MemClient.getConnection();
String key = "key";
// 获得对应key的版本号
CASValue<Object> casValue = connection.gets(key);
long version = casValue.getCas();
Object oldValue = casValue.getValue();
// TODO 假如这个过程有一些列业务操作 ...
Object newValue = "xxx";
// 使用CAS操作
CASResponse casResponse = connection.cas(key, version, newValue);
// 备注CAS操作返回对象是一个枚举对象里面包含各种结果如下:
// (OK,NOT_FOUND,EXISTS,OBSERVE_ERROR_IN_ARGS,OBSERVE_MODIFIED,OBSERVE_TIMEOUT)
}
}
参考
1、http://langyu.iteye.com/blog/680052
2、http://blog.csdn.net/poechant/article/details/7082684
3、https://www.zhihu.com/question/23284469