最近有個分佈式限速的需求。支付寶的接口雙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