目录

  1. CAS 命令简介
  2. CAS 命令的语法
  3. CAS 命令的参数说明
  4. 使用 Telnet 进行 CAS 操作
  5. 不同编程语言的 CAS 示例
  6. 参考资料

1. CAS 命令简介

CAS(Check And Set)是 Memcached 提供的一种原子性操作,它允许客户端基于现有的值进行条件性更新。在使用 CAS 时,操作会首先验证当前值是否与给定的版本号(CAS 版本号)匹配,若匹配则更新,否则操作失败。这是确保在并发环境下数据一致性的一种方式。

CAS 常用于避免“丢失更新”(lost updates)的情况,在多线程环境下非常有效。


2. CAS 命令的语法

cas <key> <flags> <exptime> <bytes> <cas_unique> [noreply]
<data>

  • <key>:要更新的键(必须已存在)。
  • <flags>:用户自定义标志(通常设为 0)。
  • <exptime>:过期时间(秒),0 代表永不过期。
  • <bytes>:数据大小(字节数)。
  • <cas_unique>:CAS 唯一版本号(由 Memcached 自动生成并返回)。
  • [noreply](可选):如果指定,则服务器不会返回响应。
  • <data>:实际更新的数据(必须与 <bytes> 指定的大小匹配)。

3. CAS 命令的参数说明

参数说明示例
<key>需要更新的键counter
<flags>自定义标志(通常为 0)0
<exptime>过期时间(无效,在 cas 中忽略)0
<bytes>数据大小(字节数)2
<cas_unique>CAS 唯一版本号1234567890
[noreply]可选,不返回响应noreply
<data>更新的数据10

4. 使用 Telnet 进行 CAS 操作

4.1 连接 Memcached

telnet 127.0.0.1 11211

4.2 先存储一个初始值(使用 set

set counter 0 0 1
5

4.3 获取当前的 CAS 唯一版本号

get counter

返回结果:

VALUE counter 0 1 1234567890
5
END

1234567890 是 CAS 唯一版本号。

4.4 使用 cas 更新数据

cas counter 0 0 1 1234567890
10

返回结果:

STORED

4.5 如果 CAS 唯一版本号不匹配(操作失败)

cas counter 0 0 1 9876543210
20

返回结果:

EXISTS

表示 CAS 唯一版本号不匹配,更新失败。


5. 不同编程语言的 CAS 示例

5.1 PHP cas 示例

<?php
$memcached = new Memcached();
$memcached->addServer("127.0.0.1", 11211);

// 先存储一个值
$memcached->set("counter", 5);

// 获取 CAS 唯一版本号
$cas_token = null;
$memcached->get("counter", null, $cas_token);

// 使用 CAS 更新数据
if ($memcached->cas($cas_token, "counter", 10)) {
    echo "Value updated successfully";
} else {
    echo "CAS failed";
}

// 获取数据
echo $memcached->get("counter");
?>


5.2 Python cas 示例

from pymemcache.client import base

client = base.Client(('127.0.0.1', 11211))

# 先存储一个值
client.set('counter', 5)

# 获取 CAS 唯一版本号
current_value, cas_token = client.gets('counter')

# 使用 CAS 更新数据
if client.cas('counter', 10, cas_token=cas_token):
    print("Value updated successfully")
else:
    print("CAS failed")

# 获取数据
print(client.get('counter').decode('utf-8'))


5.3 Java cas 示例

import net.spy.memcached.MemcachedClient;
import net.spy.memcached.CASResponse;
import java.io.IOException;
import java.net.InetSocketAddress;

public class MemcachedTest {
    public static void main(String[] args) throws IOException {
        MemcachedClient client = new MemcachedClient(new InetSocketAddress("127.0.0.1", 11211));

        // 先存储一个值
        client.set("counter", 0, 5);

        // 获取 CAS 唯一版本号
        CASResponse response = client.gets("counter");
        Object casToken = response.getCAS();

        // 使用 CAS 更新数据
        boolean success = client.cas("counter", 0, 10, casToken);
        
        if (success) {
            System.out.println("Value updated successfully");
        } else {
            System.out.println("CAS failed");
        }

        // 获取数据
        System.out.println(client.get("counter"));

        client.shutdown();
    }
}


5.4 Node.js cas 示例

const Memcached = require('memcached');
const memcached = new Memcached("127.0.0.1:11211");

// 先存储一个值
memcached.set("counter", 5, 0, function(err) {
    if (err) console.error(err);

    // 获取 CAS 唯一版本号
    memcached.get("counter", function(err, data) {
        const casToken = data.cas;

        // 使用 CAS 更新数据
        memcached.cas("counter", 10, casToken, function(err, result) {
            if (err) {
                console.error(err);
            } else {
                console.log(result ? "Value updated successfully" : "CAS failed");
            }
        });

        // 获取数据
        memcached.get("counter", function(err, data) {
            if (err) console.error(err);
            console.log(data);
        });
    });
});


6. 参考资料