最近有个分布式限速的需求。支付宝的接口双11只容许每秒调用10次。html
单机的限速,天然是用google guava的RateLimiter。java
http://docs.guava-libraries.googlecode.com/git-history/master/javadoc/com/google/common/util/concurrent/RateLimiter.htmlgit
分布式的ReteLimiter,貌似没有如今的实现方案。不过用memcached或者Redis来实现一个简单的也很快。github
好比上面的要求,每秒钟只容许调用10次,则按下面的流程来执行,以memcached为例:shell
上面是Memcached 文本协议的作法。由于文本协议不容许incr 设置不存在的key。ubuntu
若是是二进制协议,则能够直接用incr命令设置初始值,过时时间。服务器
上面扯远了,下面来讲下memcached incr指令的bug。tcp
在测试的时间,用XMemcached作客户端,来测试,发现有的时候,incr函数返回两个1。分布式
因而,在命令行,用telnet来测试,结果发现有时候返回很奇怪的数据:ide
明显END后面跟了一些很奇怪的数据。并且返回数据的长度是22,而正确的长度应该是1。
正常的返回应该是这样的:
开始觉得是XMemcached客户端的bug,也有多是序列化方式有问题。因而调试了下代码,没发现什么可疑的地方。
因而祭出wireshakr来抓包。发现XMemcached发出来的数据包是正常的。并且服务器的确返回了22字节的数据。
那么这个多是Memcached自己的bug了。这个使人比较惊奇,由于Memcached自己已经开发多年,很稳定了,怎么会有这么明显的bug?
检查下当前的Memcahcd版本,是memcached 1.4.14。
因而去下载了最新的1.4.21版,编绎安装以后,再次测试。发现正常了。
因而到release log里查看是哪一个版本修复了:
https://code.google.com/p/memcached/wiki/ReleaseNotes
发现1417版的release note里有incr相关的信息:
https://code.google.com/p/memcached/wiki/ReleaseNotes1417
Fix for incorrect length of initial value set via binary increment protocol.
因而再到github上查看修改了哪些内容:
https://github.com/memcached/memcached/commit/8818bb698ea0abd5199b2792964bbc7fbe4cd845?diff=split
对比下修改内容,和查看下源代码,能够发现,实际上是开发人员在为incr指令存储的数据分配内存时,没有注意边界,一会儿分配了INCR_MAX_STORAGE_LEN,即24字节的内存,却没有正常地设置'\r\n'到真实数据的最后。因此当Get请求拿到数据是,会把22字节 + "\r\n"的数据返回给用户,形成了内存数据泄露。
修复前的代码:
修复后的代码:
从测试的版本能够看到,至少从12年这个bug就存在了,从github上的代码来看,09年以前就存在了。直到13年12月才被修复。
为何这个bug隐藏了这个久?多是由于返回的22字节数据里中间有正确的加了\r\n,后面的才是多余的泄露数据,可能大部分解析库都以"\r\n"为分隔,从而跳过了解析到的多余的数据。好比XMemcached就能解析到。
另外,只有混用二进制协议和文本协议才可能会发现。
估计有很多服务器上运行的memcached版本都是比1.4.17要老的,好比ubuntu14默认的就是1.4.14。
不过这个bug的危害比较小,由于泄露的只有20个字节的数据。对于一些云服务指供的cache服务,即便后面是memcached作支持,也会有一个中转的路由。
窃取到有效信息的可能性很小。
wireshark默认是支持解析memcached文本和二进制协议的,不过默认解析端口是11211,因此若是想要解析其它端口的包,要设置下。
在"Edit", ”Preferences“ 里,找到Memcached协议,就能够看到端口的配置了。
参考:https://ask.wireshark.org/questions/24495/memcache-and-tcp
上面说到Memcached的文本协议是不支持incr设置不存在的key的,可是XMemcached却提供了相关的函数,并且能正常运行,是为何呢?
实际上,XMemcached内部包装了incr和add指令,代表上是调用了incr但其实是两条指令:
另外,要注意XMemcached默认是文本协议的,只有手动配置,才会使用二进制协议。
据这个演示的结果,二进制协议比文本协议要略快,第14页:
http://www.slideshare.net/tmaesaka/memcached-binary-protocol-in-a-nutshell-presentation/
https://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol
二进制协议介绍的ppt:
http://www.slideshare.net/tmaesaka/memcached-binary-protocol-in-a-nutshell-presentation/
转载:http://blog.csdn.net/hengyunabc/article/details/40897421