如圖1所示,當往Memcached寫入500萬的160 Bytes的數據項,內存利用率計算:59485199(bytes)/67108864(limit_maxbytes)=89%。內存利用率達到89%時,從evictions看到MC主動踢出很多緩存數據,為什么MC達到90%的內存利用率時開始踢出緩存數據?
要分析原因,我們首先要了解下Slab Allocation機制,可參考理解memcached的內存存儲。
從圖2 growth factor=1.25的Slab Allocation看到,160 Bytes的數據項選擇192 Bytes的chunk,浪費32 Bytes內存。雖然Slab Allocation解決了malloc/free固有的內存碎片問題,卻不能有效利用分配到的內存。
我們計算每個chunk的期望內存利用率:
120B的chunk放置的數據項期望長度是(96+120)/2=108,期望的內存利用率為108/120=90%;
152B的chunk放置的數據項期望長度是(120+152)/2=136,期望的內存利用率為136/152=89%;
......
n B的chunk放置的數據項期望長度是(n/1.25+n)/2=9n/10,期望的內存利用率為9n/10/n=90%;
所以,內存利用率到90%就意味growth factor=1.25的MC內存已經放滿數據,在沒有過期數據的情況下,保存新數據只能淘汰LRU(Least Recent Used)的數據。
推廣到任意growth factor(gf),n Bytes的chunk放置的數據項期望長度是(n/gf+n)/2=(1+gf)n/(2*gf),期望的內存利用率為(1+gf)/(2*gf),比如:
gf=1.25,期望的內存利用率為90%;
gf=2,期望的內存利用率為75%;
.......
極端情況,gf=1,期望的內存利用率為100%,但是growth factor必須大于1,否則會如圖3的報錯。
那是不是說growth factor接近1,期望的內存利用率就能接近100%?結果出人意料。
在分配64M內存的MC中,growth factor=1.000001,如圖4、圖5所示,1~199個Slab class的chunk size為96 Bytes,第200個Slab class的chunk size為1MB。
當growth factor=1.000001,往64M內存MC插入163 Bytes的數據項,如圖6和圖7所示,內存利用率:bytes(10432)/limit_maxbytes(67108864)=0.01%,趨近于0。163 Bytes的數據項不能放入到96 Bytes的chunk,只能放到slab class 200的64MB的chunk,幾乎浪費64M所有的空間,總共寫入163 Bytes * 64=10432 Bytes的數據。從這個例子看出,growth factor不能趨近與1,否則內存利用率趨近于0。但是growth factor也不能太大,否則內存利用率也會很低。
實踐經驗表明,growth factor最好介于1.05~2之間,并且根據業務緩存數據塊大小而定。