XMemcachedClient 操作 Memcached

Posted 笑虾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XMemcachedClient 操作 Memcached相关的知识,希望对你有一定的参考价值。

XMemcachedClient 操作 Memcached

安装

CentOS

docker 安装/运行 memcached

# 查看镜像是否存在
docker search memcached
# 拉取镜像
docker pull memcached
# 运行
docker run -dp 11211:11211 --name memcache memcached

--name:给容器指定名称 memcache 。如果不加 docker 会自己取。
-p:本服务器端口11211–> 容器端口11211
-d:后台运行。
memcached:这个就是要启动的镜像名
docker ps -a:查看容器是运行
netstat -anlp | grep 11211:查看服务端口 11211 是否在监听中。

Windows

菜鸟教程 Windows 下安装 Memcached 下载 直接运行即可。

配个 启动-memcached.bat

memcached.exe -p 9527 -l 127.0.0.1 localhost -m 50 -vv

启动参数

-d: 选项是启动一个守护进程,
-m: 是分配给Memcache使用的内存数量,单位是MB,默认64MB
-M: 内存耗尽时返回错误(而不是删除项)
-u: 是运行Memcache的用户,如果当前为root 的话,需要使用此参数指定用户。
-l: 是监听的服务器IP地址,默认为所有网卡。支持多个地址空格分隔,默认 0.0.0.0 允许任何人连接。
-p: 是设置Memcache的TCP监听的端口,最好是1024以上的端口
-c: 选项是最大运行的并发连接数,默认是1024
-P: 是设置保存Memcache的pid文件
-f: chunk 大小的扩容因子 (默认: 1.25)
-vv: 打印客户端的请求和返回信息

操作命令

命令说明
stats itemsslab 细分返回:所储存元素的一些信息。如:个数
stats slabs获取所有slab的信息,如 page, chunk 的数量、大小、各操作的命中情况等

set 添加数据,如果存在就修改

set key flags exptime bytes [noreply]
value
STORED

key:键。存取都靠它。
flags:一个标识符,存什么返什么。但是客户端可能对其做封装。
exptime:在缓存中保存键值对的时间长度(单位秒,0 永不过期)
bytes:在缓存中存储的字节数 (和 value 大小要一至,否则报错)
noreply(可选): 该参数告知服务器不需要返回数据
value:值。在第二行输入。

set jerry 0 666 3 sssssssssssssssss
abc
STORED # 成功返回提示
get jerry
VALUE jerry 0 3
abc
END
  1. 多余的 sssssssssssssssss 被忽略,值在第二行输入 。
  2. 成功显示 STORED

add 新增键值

参数一样,与 set 的区别在于,已经有了就保持不变。

add jerry 0 300 3 
123
STORED
add jerry 0 300 3
asd
NOT_STORED
get jerry
VALUE jerry 0 3
123
END

replace

参数一样,替换值,如果不存在则失败。

append 在 value 后追加数据

append jerry 0 300 3
789
STORED
get jerry
VALUE jerry 0 6
efg789
END

prepend 在 value 前插入数据

prepend jerry 0 300 3
fff
STORED
get jerry
VALUE jerry 0 9
fffefg789
END

CAS 比较和交换

再比较再更新,提交时需要带上 gets 返回的 unique_cas_token

gets jerry
VALUE jerry 0 5 13587
abcde
END
# 拿到 unique_cas_token = 13587
cas jerry 0 8000 3 13587
123
STORED # 保存成功后输出
# 取值查看
get jerry
VALUE jerry 0 3
123
END
# 再用原来的令牌提交一次
cas jerry 0 8000 3 13587
abe
EXISTS # 在最后一次取值后另外一个用户也在更新该数据。

delete 删除

delete jerry
DELETED
get jerry
END

incr 与 decr 自增自减命令

必须是十进制的32位无符号整数
如果 key 不存在返回 NOT_FOUND,如果键的值不为数字,则返回 CLIENT_ERROR,其他错误返回 ERROR

add jerry 0 8000 1
0
STORED
incr jerry 1
1
incr jerry 1
2
incr jerry 1
3
incr jerry 1
4
incr jerry 1
5
get jerry
VALUE jerry 0 1
5
END
decr jerry 3
2
get jerry
VALUE jerry 0 1
2
END

stats

属性说明
pidmemcache服务器进程ID
uptime服务器已运行秒数
time服务器当前Unix时间戳
versionmemcache版本
pointer_size操作系统指针大小
rusage_user进程累计用户时间
rusage_system进程累计系统时间
curr_connections当前连接数量
total_connectionsMemcached运行以来连接总数
connection_structuresMemcached分配的连接结构数量
cmd_getget命令请求次数
cmd_setset命令请求次数
cmd_flushflush命令请求次数
get_hitsget命令命中次数
get_missesget命令未命中次数
delete_missesdelete命令未命中次数
delete_hitsdelete命令命中次数
incr_missesincr命令未命中次数
incr_hitsincr命令命中次数
decr_missesdecr命令未命中次数
decr_hitsdecr命令命中次数
cas_missescas命令未命中次数
cas_hitscas命令命中次数
cas_badval使用擦拭次数
auth_cmds认证命令处理的次数
auth_errors认证失败数目
bytes_read读取总字节数
bytes_written发送总字节数
limit_maxbytes分配的内存总大小(字节)
accepting_conns服务器是否达到过最大连接(0/1)
listen_disabled_num失效的监听数
threads当前线程数
conn_yields连接操作主动放弃数目
bytes当前存储占用的字节数
curr_items当前存储的数据总数
total_items启动以来存储的数据总数
evictionsLRU释放的对象数目
reclaimed已过期的数据条目来存储新数据的数目

客户端 XMemcachedClient 演示

客户端封装后,最简单的版本 set 只需要输入 keyvalue过期时间
顺便提一句,有 SpringBoot 版的。

  • pom.xml
    <dependency>
      <groupId>com.googlecode.xmemcached</groupId>
      <artifactId>xmemcached</artifactId>
      <version>2.4.7</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.36</version>
    </dependency>
  • 简单测几个效果
private static String url = "192.168.0.258:11211";
private static MemcachedClient memcachedClient;
public static final InetSocketAddress address = AddrUtil.getOneAddress(url);

static 
    try 
    	// 当很多额外参数支持自定义配置时使用:建造者模式
        memcachedClient = new XMemcachedClientBuilder(AddrUtil.getAddresses(url)).build();
     catch (IOException e) 
        e.printStackTrace();
    


@Test
public void setTest() throws InterruptedException, MemcachedException, TimeoutException 
    String key = "jerry";  // 键
    int exptime = 300 ;    // 过期时间,单位为秒。最长可达30天。在30天之后,被视为一个精确日期的unix时间戳
    String value = "耀眼的笨笨"; // 值 
    long timeout = 60000;  // 操作超时,单位毫秒
    memcachedClient.set(key, exptime, value, timeout);


@Test
public void getTest() throws InterruptedException, MemcachedException, TimeoutException 
    String value = memcachedClient.get("jerry");
    System.out.println(value); // 耀眼的笨笨
    
// CAS 
@Test
public void casTest() throws InterruptedException, MemcachedException, TimeoutException 
    GetsResponse<Object> getsResponse = memcachedClient.gets("jerry");
    memcachedClient.cas("jerry", 30, "xyz", getsResponse.getCas());

// CAS 自动提交。不必每次手动获取。
@Test
public void CASOperationTest() throws InterruptedException, MemcachedException, TimeoutException 
    CASOperation<String> casOperation = new CASOperation<String>() 
        public int getMaxTries()  return 3;  // 最多尝试 3 次
        public String getNewValue(long currentCAS, String currentValue)  return "耀眼的笨笨"; 
    ;
    memcachedClient.add("jerry", 3, "笑虾");
    memcachedClient.cas("jerry", 1, casOperation);
    System.out.println(""+memcachedClient.get("jerry"));

// CAS 自动提交。不必每次手动获取。10个线程争抢,反而更慢了。
@Test
public void CASOperationTest() throws InterruptedException, MemcachedException, TimeoutException 
    AtomicInteger l = new AtomicInteger();
    CASOperation casOperation = new CASOperation<String>() 
        public int getMaxTries() 
            System.out.println(Thread.currentThread().getName() + " 尝试 " + l.incrementAndGet() + " 次");
            return 10; // 最多尝试 10 次。因为有10个线程争抢,重试要浪费好多时间。
        
        public String getNewValue(long currCAS, String currV) 
            String newValue = "耀眼的笨笨" + l.get();
            System.out.println("当前CAS=" + currCAS + "; 当前Value=" + currV +"; 目标Value=" + newValue);
            return newValue;
        
    ;
    memcachedClient.add("jerry", 3, "耀眼的笨笨");
    IntStream.rangeClosed(1,10).parallel().forEach(i -> 
        try 
            memcachedClient.cas("jerry", 0, casOperation);
            System.out.println(l.get());
         catch (Exception e)  e.printStackTrace(); 
    );
    System.out.println("最终结果: "+ memcachedClient.get("jerry"));

// 遍历所有键值对
@Test
@SuppressWarnings("deprecation")
public void getAllTest() throws InterruptedException, MemcachedException, TimeoutException 
    HashMap<String, Object> map = new HashMap<>();
    KeyIterator keyIterator = memcachedClient.getKeyIterator(address);
    while (keyIterator.hasNext()) 
        String key = keyIterator.next();
        map.put(key, memcachedClient.get(key));
    
    System.out.println(map);

// 获取信息
@Test
public void statsTest() throws InterruptedException, MemcachedException, TimeoutException 
    String statsJson = memcachedClient.stats(address).entrySet().stream()
            .map(entry -> String.format("\\"%s\\":\\"%s\\"", entry.getKey(), entry.getValue()))
            .collect(Collectors.joining(", ", "", ""));
    System.out.println(statsJson);

// 更新有效时间
@Test
public void touchTest() throws InterruptedException, MemcachedException, TimeoutException 
    memcachedClient.add("jerry", 3, "耀眼的笨笨");
    TimeUnit.SECONDS.sleep(2);
    memcachedClient.touch ("jerry", 3); // 更新过期时间,否则再取就是 null 了
    TimeUnit.SECONDS.sleep(1);
    String value = memcachedClient.get("jerry");
    System.out.println("获得:" + value);

// 清空所有数据
@Test
public void clear() throws InterruptedException, MemcachedException, TimeoutException 
    memcachedClient.flushAll();

// 命名空间内的值,可以统一失效。
@Test
public void withNamespaceTest() throws InterruptedException, MemcachedException, TimeoutException 
    // 向命名空间 jerry 内批量插入数据。
    Boolean bool = memcachedClient.withNamespace("jerry", client -> 
         IntStream.rangeClosed(1, 10).mapToObj(i -> 
            try 
                return client.add("key" + i, 30, "value="+i);
             catch (Exception e)  e.printStackTrace(); 
            return false;
        ).allMatch(b -> b)
    );
    System.out.println("向命名空间 jerry 内批量插入数据成功:" + bool);
    
    // 获取命名空间内的值
    String s = memcachedClient.withNamespace("jerry", client -> client.get("key5"));
    System.out.println("从命名空间 jerry 获取 key5 的值:"+ s);
    // 批量取一波
    IntStream.rangeClosed(1, 10).forEach(i->try 
        String str = memcachedClient.withNamespace("jerry", client -> client.get("key"+i));
        System.out.println("获取第 "+i+" 个值:" + str);
     catch (Exception e)  e.printStackTrace(); );

    // 让整个命名空间内容失效
    this.memcachedClient.invalidateNamespace("jerry");
    System.out.println("让整个命名空间内容失效");

    // 再获取命名空间内的值,已经为 null
    String ss = memcachedClient.withNamespace("jerry", client -> client.get("key5"));
    System.out.println("再获取命名空间内的值,已经为:"+ ss);

参考资料

Memcached 官网
官方手册 Commands
memcached 命令行参数
XMemcachedClient JavaDoc

killme2008 / Xmemcached 中文用户指南
菜鸟教程 Windows 下安装 Memcached
菜鸟教程 Docker 命令大全
阿里云培训中心 Memcache完全自学手册
知乎dubx:memcached

以上是关于XMemcachedClient 操作 Memcached的主要内容,如果未能解决你的问题,请参考以下文章

Xmemcached学习笔记二(简单使用)

redis 连接池

php操作memcache缓存

Python中操作Redis

缓存序列化信号

Django缓存机制