2019独角兽企业重金招聘Python工程师标准>>>

最近的项目要依赖于一个分布式计数器的实现,因为公司使用memcached历史已久,所以就想到了使用memcached来作为计数器。之前也用过memcached的incr操作,但是有人封装好了,也没有深究,自己测试起来,越到了问题。经过大半天的调试、查阅文档、查看源码,解决了问题,现在将收集到的信息整理一下。

incr/decr是memcached 1.2.4加入的原子性整数操作(changelog:2006-10-03)。这个功能常用于分布式项目中的计数。

1.incr/decr在memcached中的保存方式是:字符串(十进制)表示的无符号64bit整数。    

memcached的wiki中这样描述:

Increment and Decrement. If an item stored is the string representation of a 64bit integer, you may run incr or decr commands to modify that number. You may only incr by positive values, or decr by positive values. They does not accept negative values.

为了验证,在memcached telnet终端中如下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
seta 0 0 2
12
STORED
#设置key=a的项为"12"
incr a 1    
13
#incr 1 返回13
append a 0 0 1
3
STORED
#在a项后面增加一个字符'3'
get a
VALUE a 0 3
133
END
#a变为133
incr a 1
134
#a incr 1后变为134

可以看到,在把a当做字符串进行append操作后,得到字符串133,此时incr 1,变为134,证明memcached内部确实incr项将保存为字符串。

那么,如果我们使用二进制协议,将a写入数字后,再使用incr会产生什么结果呢?(使用Java语言,memcached客户端为:spymemcached-2.5)。

1
2
3
4
5
6
memcachedClient.set(key, exp,51);
Object object = memcachedClient.get(key);
System.out.println("init "+ object);
longincr = memcachedClient.incr(key,1);
object = memcachedClient.get(key);
System.out.println("after incr "+ incr +" "+ (object));

输出为:

1
2
init 51
after incr 4 52

是不是无法理解?按道理,incr的返回值就是memcached中的最终结果,与get结果相同。结果一个返回4,一个返回52?

等等,4和52,为什么看起来那么眼熟?

查阅ascii表得知,4的ascii值刚好是52,难道真这么巧,第二次get的时候,spymemcached客户端将4的字符值当做整型展开,得到了52?

不急,先使用telnet终端连接memcached,得到:

1
2
3
get a
VALUE a 512 1
4

其中512是flag属性。

这里简单提到一下memcached协议中的flag机制。flag是memcached除了key、value、expireTime之外额外保存的一个16bit(1.2.4之后为32bit)值,它标志着这个值的”类型“。这个值对于memcached-server是无意义的,它提供给client,来定义对value的处理方式(主要是编码,也有些客户端用flag作为是否压缩的依据)。

在spymemcached-client中,0为字符串,512为整数。所以这里虽然值保存为字符串4,但是spymemcached仍然将其当做整数解析,那么就得到了52!

于是我们得到一个教训:初始化计数器的时候,请使用字符串memcachedClient.set(key, exp, "0"),或者自行封装方法。否则可能得到不可预知的结果!

2. incr/decr操作无法刷新过期时间。

memcached的协议可以看这里。incr/decr操作无法刷新过期时间,所以过期时间以初始化的时间为准。

最开始以为spy的memcacheClient的incr(String key, int by, long def, int exp)可以刷新过期时间,后来才发现,此方法是封装了incr/decr和add的组合操作。这个exp指的是,若incr失败,则将def值add到此key,并使用这个过期时间exp,如果成功,过期时间不变!

因此,如果使用memcached作为长期的计数器,必须用额外的机制定时刷新item。memcached协议提供了touch方法,只刷新时间,不对值作修改,最新的spymemcached 客户端中提供了这个功能。

3. 如果对应值不存在,incr/decr会失败,而不会从0开始计数。

telnet下输入:

1
2
incr b 1
NOT_FOUND

返回NOT_FOUND,没有incr成功。memcachedClient.incr(key,delta)调用之后,若key不存在,则返回-1。

转载于:https://my.oschina.net/flashsword/blog/93109

构建一个可靠的分布式计数器--memcached之incr/decr操作实战分析相关推荐

  1. java memcached incr_Redis与Memcached的incr/decr差异对比

    目前广泛使用的分布式缓存Redis和Memcached均支持对整数型Value值的增减,对应到具体命令中就是incr和decr命令. incr/decr是原子性操作(memcached 1.2.4及以 ...

  2. 利用angular4和nodejs-express构建一个简单的网站(六)—用户模块和路由分析

    上一节解决了用户注册和登录数据部分的内容.这一节开始分析用户模块.用户路由.## 用户管理模块UserModule分析 ## UserModule主要代码如下: import { NgModule } ...

  3. java memcached incr_Memcached incr/decr 命令

    Memcached incr 与 decr 命令用于对已存在的 key(键) 的数字值进行自增或自减操作. incr 与 decr 命令操作的数据必须是十进制的32位无符号整数. 如果 key 不存在 ...

  4. 如何构建一个分布式爬虫:实战篇

    本篇文章将是『如何构建一个分布式爬虫』系列文章的最后一篇,拟**从实战角度**来介绍如何构建一个*稳健的分布式微博爬虫*.这里我*没敢谈高效*,抓过微博数据的同学应该都知道微博的反爬虫能力,也知道微博 ...

  5. python爬虫分布式怎么构造_如何构建一个分布式爬虫:实战篇

    本篇文章将是『如何构建一个分布式爬虫』系列文章的最后一篇,拟**从实战角度**来介绍如何构建一个*稳健的分布式微博爬虫*.这里我*没敢谈高效*,抓过微博数据的同学应该都知道微博的反爬虫能力,也知道微博 ...

  6. 还不会分布式事务,seata xa模式入门实战送上

    文章目录 前言 一.什么是seata? 二.seata原理说明 1.角色说明 2.什么是 Seata 的事务模式? 三.SEATA 的分布式案例 1.业务逻辑说明 2.架构图 3.SEATA 的分布式 ...

  7. 构建一个分布式操作系统的简单方案—答陈硕的“分布式系统中的进程标识”一文...

    对分布式系统中的进程标识"一文的疑问 刚才看到陈硕先生的一篇blog:"分布式系统中的进程标识",地址:http://www.cnblogs.com/Solstice/a ...

  8. 如何构建一个分布式爬虫:理论篇

    ## 前言 本系列文章计划分三个章节进行讲述,分别是理论篇.基础篇和实战篇.理论篇主要为构建分布式爬虫而储备的理论知识,基础篇会基于理论篇的知识写一个简易的分布式爬虫,实战篇则会以微博为例,教大家做一 ...

  9. python分布式爬虫系统_如何构建一个分布式爬虫:理论篇

    前言 本系列文章计划分三个章节进行讲述,分别是理论篇.基础篇和实战篇.理论篇主要为构建分布式爬虫而储备的理论知识,基础篇会基于理论篇的知识写一个简易的分布式爬虫,实战篇则会以微博为例,教大家做一个比较 ...

最新文章

  1. 30. 多线程编程之threading模块
  2. 什么是WebService??
  3. 本页由试用版打印控件lodop6.2.6输出_Visual Basic 6.0 Sirk 迷你版
  4. [leetcode sort]56. Merge Intervals
  5. php opcache 安装,php opcache安装和配置
  6. Makefile的基本规则实例说明
  7. websocket替代方案_码农手记 | 前后端实时交互方案概述
  8. 选择Eclipse 的列编辑模式
  9. mybatis_07动态SQL_foreach循环
  10. 当不知轴承型号时如何寻找轴承故障频率_知课堂 | 快速计算轴承特征频率
  11. oracle执行计划中cost cpu
  12. 中国医药中间体行业盈利状况与竞争趋势预测报告(新版)2022-2027年
  13. 报警器——基于arduino
  14. 计算机视觉实战的深度学习实战二:图像预处理
  15. 编码器基础知识大扫盲
  16. 深入浅出C++ ——初识C++
  17. linux网卡链路聚合
  18. 艾赛克科技《RFID智能仓库管理系统》
  19. elementplus中表格组件使用固定列时出现滚动条粘性布局固定表头
  20. Facebook广告营销指南!Facebook广告投放技巧与策略!新手教程

热门文章

  1. liunx 环境下docker安装mysql
  2. 算数计算机在线应用,数学计算器
  3. linux修改mdc时钟,Linux下用xsupplicant或mdc拨号上网
  4. php中的echo单引号_PHP 邮件漏洞小结
  5. c#语言经典程序100例,C#入门必看的实例程序100个 - 源码下载|Windows编程|其他小程序|源代码 - 源码中国...
  6. vue 给取data值_一些Vue相关的面试题,帮助求职者提升竞争力
  7. 移动端html右滑空白,BootStrap.css 在手机端滑动时右侧出现空白的原因及解决办法...
  8. indexed true mysql_一行代码,搞定浏览器数据库 IndexedDB
  9. before start of result set_Mac也能有庞大的游戏库,体验腾讯start云游戏,真的流畅...
  10. 数据分析基本思路及手法