Memcached安装使用和源码调试
memcached官網(wǎng):http://memcached.org/
一.安裝
下載
# wget?http://www.memcached.org/files/memcached-1.4.25.tar.gz
解壓
# tar xzvf memcached-1.4.25.tar.gz
#cd memcached-1.4.25
配置
#./configure --prefix=/usr/local/memcached --with-libevent=/usr
注意這里選擇libevent的位置即可? 例如你的是在–with-libevent=/usr/local/libevent/
# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent
編譯安裝
# make &&?make install
---------------需要依賴安裝libevent-------------------
libevent官網(wǎng)?http://libevent.org/
# wget https://github.com/libevent/libevent/releases/download/release-2.0.22-stable/libevent-2.0.22-stable.tar.gz
# tar xzvf libevent-2.0.22-stable.tar.gz
# cd libevent-2.0.22-stable
# ./configure --prefix=/usr/local/libevent
# make &&?make install
----------------------------------
二.使用
啟動
# /usr/local/memcached/bin/memcached -d -m 100 -uroot -l 0.0.0.0 -p 11211 -c 512 -P /usr/local/memcached/memcached.pid
啟動參數(shù):
memcached 1.4.2
-p <num> 監(jiān)聽的TCP端口(默認: 11211)
-U <num> 監(jiān)聽的UDP端口(默認: 11211, 0表示不監(jiān)聽)
-s <file> 用于監(jiān)聽的UNIX套接字路徑(禁用網(wǎng)絡支持)
-a <mask> UNIX套接字訪問掩碼,八進制數(shù)字(默認:0700)
-l <ip_addr> 監(jiān)聽的IP地址。(默認:INADDR_ANY,所有地址)
-d 作為守護進程來運行。
-r 最大核心文件限制。
-u <username> 設(shè)定進程所屬用戶。(只有root用戶可以使用這個參數(shù))
-m <num> 單個數(shù)據(jù)項的最大可用內(nèi)存,以MB為單位。(默認:64MB)
-M 內(nèi)存用光時報錯。(不會刪除數(shù)據(jù))
-c <num> 最大并發(fā)連接數(shù)。(默認:1024)
-k 鎖定所有內(nèi)存頁。注意你可以鎖定的內(nèi)存上限。試圖分配更多內(nèi)存會失敗的,所以留意啟動守護進程時所用的用戶可分配的內(nèi)存上限。(不是前面的 -u <username> 參數(shù);在sh下,使用命令"ulimit -S -l NUM_KB"來設(shè)置。)
-v 提示信息(在事件循環(huán)中打印錯誤/警告信息。)
-vv 詳細信息(還打印客戶端命令/響應)
-vvv 超詳細信息(還打印內(nèi)部狀態(tài)的變化)
-h 打印這個幫助信息并退出。
-i 打印memcached和libevent的許可。
-P <file> 保存進程ID到指定文件,只有在使用 -d 選項的時候才有意義。
-f <factor> 塊大小增長因子。(默認:1.25)
-n <bytes> 分配給key+value+flags的最小空間(默認:48)
-L 嘗試使用大內(nèi)存頁(如果可用的話)。提高內(nèi)存頁尺寸可以減少"頁表緩沖(TLB)"丟失次數(shù),提高運行效率。為了從操作系統(tǒng)獲得大內(nèi)存頁,memcached會把全部數(shù)據(jù)項分配到一個大區(qū)塊。
-D <char> 使用 <char> 作為前綴和ID的分隔符。這個用于按前綴獲得狀態(tài)報告。默認是":"(冒號)。如果指定了這個參數(shù),則狀態(tài)收集會自動開啟;如果沒指定,則需要用命令"stats detail on"來開啟。
-t <num> 使用的線程數(shù)(默認:4)
-R 每個連接可處理的最大請求數(shù)。
-C 禁用CAS。
-b 設(shè)置后臺日志隊列的長度(默認:1024)
-B 綁定協(xié)議 - 可能值:ascii,binary,auto(默認)
-I 重寫每個數(shù)據(jù)頁尺寸。調(diào)整數(shù)據(jù)項最大尺寸。
查看詳情
#ps aux|grep mem???
輸出pid
#cat /usr/local/memcached/memcached.pid
?
狀態(tài)
#?telnet 127.0.0.1 11211
STAT limit_maxbytes就是最大內(nèi)存是100M。
增加內(nèi)存到200M
#?/usr/local/memcached/bin/memcached -d -m 200 -uroot -l 0.0.0.0 -p 11211 -c 512 -P /usr/local/memcached/memcached.pid
先后2次查看內(nèi)存使用
# top -n 1 |grep Mem
在啟動memcached的時候可以通過-vv來查看slab的種類:
# /usr/local/memcached/bin/memcached -d -m 100 -uroot -l 0.0.0.0 -p 11211 -c 512 -P /usr/local/memcached/memcached.pid -vv
# /usr/local/memcached/bin/memcached -d -m 512 -l 0.0.0.0 -p 11211 -u root -vv
默認一個slab=1048576字節(jié)=1024K=1M
默認的truck是48
改為240
# /usr/local/memcached/bin/memcached -d -m 100? -n 240 -uroot -l 0.0.0.0 -p 11211 -c 512 -P /usr/local/memcached/memcached.pid? -vv
# /usr/local/memcached/bin/memcached -d -m 512 -n 240 -l 0.0.0.0 -p 11211 -u root -vv
增長因子f默認是1.25,該值越小所能提供的chunk間隔越小,可以減少內(nèi)存的浪費
# /usr/local/memcached/bin/memcached -d -m 512? -f 2 -l 0.0.0.0 -p 11211 -u root -vv
修改-I改變每個slab的大小:
第一次最大-I只有2048,然后改為4056
查看slabs狀態(tài)
# stats slabs?? 顯示各個slab的信息,包括chunk的大小、數(shù)目、使用情況等
# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
# set key1 0 0 3
www
STORED
# get key1
需要注意的是set 最后一個參數(shù)就是value字符的長度!
下面是故意構(gòu)造多個不同chunk的字符存儲效果
# stats
# stats items
調(diào)整slab參數(shù)
slab對于memcached的空間利用率占有決定因素.
1:比較重要的幾個啟動參數(shù):-f:增長因子,chunk的值會按照增長因子的比例增長(chunk size growth factor).-n:每個chunk的初始大小(minimum space allocated for key+value+flags),chunk大小還包括本身結(jié)構(gòu)體大小.-I:每個slab page大小(Override the size of each slab page. Adjusts max item size)-m:需要分配的大小(max memory to use for items in megabytes)
2:stats slabschunk_size:chunk大小chunk_per_page:每個page的chunk數(shù)量total_pages:page數(shù)量total_chunks:chunk數(shù)量*page數(shù)量used_chunks:已被分配的chunk數(shù)量free_chunks:曾經(jīng)被使用,但是目前被回收的chunk數(shù).free_chunks_end:從來沒被使用的chunk數(shù)mem_requested:請求存儲的字節(jié)數(shù)active_slabs:活動的slabs.total_malloced:實際已分配的內(nèi)存數(shù).
3:重要的結(jié)構(gòu)體和常量typedef struct {
static slabclass_t slabclass[MAX_NUMBER_OF_SLAB_CLASSES];
4:slabs_init函數(shù)slabs_init(const size_t limit, const double factor, const bool prealloc)?
unsigned int size = sizeof(item) + settings.chunk_size; ?
#ifndef DONT_PREALLOC_SLABS
5:do_slabs_newslab 初始化slabsdo_slabs_newslab(const unsigned int id) {
//重新分配slabs個數(shù),默認是分配16個頁,后續(xù)按照2倍增加static int grow_slab_list (const unsigned int id) {
6:slabs_clsid根據(jù)指定大小的數(shù)據(jù),確定應該放入到那個桶unsigned int slabs_clsid(const size_t size) {
7:do_slabs_alloc//從class中分配chunk.static void *do_slabs_alloc(const size_t size, unsigned int id) {
#ifdef USE_SYSTEM_MALLOC
工作流程:memcahed實例啟動,根據(jù) -f 和 -n 進行預分配slab。以 -n 為最小值開始,以 -f 為比值生成等比數(shù)列,直到1m為止(每個slab的chunk size都要按8的倍數(shù)進行補全,比如:如果按比值算是556的話,會再加4到560成為8的整倍數(shù))。然后每個slab分配一個page。當用戶發(fā)來存儲請求時(key,value),memcached會計算key+value的大小,看看屬于哪個slab。確定slab后看里面的是否有空閑 chunk放key+value,如果不夠就再向系統(tǒng)申請一個page(如果此時已經(jīng)達到 -m 參數(shù)設(shè)置的內(nèi)存使用上限,則看是否設(shè)置了 -M 。如果設(shè)置了 -M 則返回錯誤提示,否則按LRU算法刪除數(shù)據(jù))。申請后將該page按本slab的chunk size 進行切割,然后分配一個來存放用戶數(shù)據(jù)。
注意: 1,chunk是在page里面劃分的,而page固定為1m,所以chunk最大不能超過1m。 2,chunk實際占用內(nèi)存要加48B,因為chunk數(shù)據(jù)結(jié)構(gòu)本身需要占用48B。 3,如果用戶數(shù)據(jù)大于1m,則memcached會將其切割,放到多個chunk內(nèi)。 4,已分配出去的page不能回收。
優(yōu)化建議 1,-n 參數(shù)的設(shè)置,注意將此參數(shù)設(shè)置為1024可以整除的數(shù)(還要考慮48B的差值),否則余下來的部分就浪費了。 2,不要存儲超過1m的數(shù)據(jù)。因為要拆成多個chunk,計算和時間成本都成倍增加。 3,善用stats命令查看memcached狀態(tài)。 4,消滅eviction(被刪除的數(shù)據(jù))。造成eviction是因為內(nèi)存不夠,有三個思路:一是在CPU有余力的情況下開啟壓縮(PHP擴展);二是增加內(nèi)存;三是調(diào)整 -f 參數(shù),減少內(nèi)存浪費。5,調(diào)整業(yè)務代碼,提高命中率。 6,緩存小數(shù)據(jù)。省帶寬,省網(wǎng)絡I/O時間,省內(nèi)存。 7,根據(jù)業(yè)務特點,為數(shù)據(jù)尺寸區(qū)間小的業(yè)務分配專用的memcached實例。這樣可以調(diào)小 -f 參數(shù),使數(shù)據(jù)集中存在少數(shù)幾個slab上,內(nèi)存浪費較少。
Memcached的內(nèi)存分配以page為單位,默認情況下一個page是1M?,可以通過-I參數(shù)在啟動時指定。如果需要申請內(nèi)存 時,memcached會劃分出一個新的page并分配給需要的slab區(qū)域。Memcached并不是將所有大小的數(shù)據(jù)都放在一起的,而是預先將數(shù)據(jù)空間劃分為一系列slabs,每個slab只負責一定范圍內(nèi)的數(shù)據(jù)存儲,其大小可以通過啟動參數(shù)設(shè)置增長因子,默認為1.25,即下一個slab的大小是上一個的1.25倍。
Memcached在啟動時通過-m指定最大使用內(nèi)存,但是這個不會一啟動就占用,是隨著需要逐步分配給各slab的。
?? ? ? ? 如果一個新的緩存數(shù)據(jù)要被存放,memcached首先選擇一個合適的slab,然后查看該slab是否還有空閑的chunk,如果有則直接存放進去;如 果沒有則要進行申請。slab申請內(nèi)存時以page為單位,所以在放入第一個數(shù)據(jù),無論大小為多少,都會有1M大小的page被分配給該slab。申請到 page后,slab會將這個page的內(nèi)存按chunk的大小進行切分,這樣就變成了一個chunk的數(shù)組,在從這個chunk數(shù)組中選擇一個用于存儲 數(shù)據(jù)。如下圖,slab 1和slab 2都分配了一個page,并按各自的大小切分成chunk數(shù)組。
默認情況下memcached把slab分為42類(class1~class42),在class 1中,chunk的大小為96字節(jié),由于一個slab的大小是固定的1048576字節(jié)(1M),因此在class1中最多可以有10922個chunk:13107×80 + 16 = 1048576在class1中,剩余的16字節(jié)因為不夠一個chunk的大小(80byte),因此會被浪費掉。每類chunk的大小有一定的計算公式的,假定i代表分類,class i的計算公式如下:chunk size(class i) : ?(default_size+item_size)*f^(i-1)+?CHUNK_ALIGN_BYTES
- default_size: 默認大小為48字節(jié),也就是memcached默認的key+value的大小為48字節(jié),可以通過-n參數(shù)來調(diào)節(jié)其大小;
- item_size: item結(jié)構(gòu)體的長度,固定為32字節(jié)。default_size大小為48字節(jié),item_size為32,因此class1的chunk大小為48+32=80字節(jié);
- f為factor,是chunk變化大小的因素,默認值為1.25,調(diào)節(jié)f可以影響chunk的步進大小,在啟動時可以使用-f來指定;
- CHUNK_ALIGN_BYTES是一個修正值,用來保證chunk的大小是某個值的整數(shù)倍(在32位機器上要求chunk的大小是4的整數(shù)倍)。
?Memcached 采用slab+page+chunk 方式管理內(nèi)存
–Slab,特定大小的一組chunk
–Page,每次分配給slab的內(nèi)存空間,會按照slab大小切分為chunk(默認1MB)–Chunk,存儲記錄的內(nèi)存空間
下面是我畫的memcached的slab結(jié)構(gòu)圖
下面是:http://wenku.baidu.com/view/3e858ff09e314332396893fe.html存儲一個value的大體過程存儲一個value的大體過程
1.先根據(jù)要存儲的key、value和flags計算item的大小
item長度=item結(jié)構(gòu)大小 + 鍵長 + 后綴長 + 存儲值長度
2.如果這個item對應的slab還沒有創(chuàng)建,則申請1個page(默認1MB),將這個page按照這個slab類chunk的大寫進行分割,然后將這個 item 存入
3.如果存在,且對應的slab沒用完,存儲
4.如果存在,且對應的slab用完了,則看內(nèi)存是否用完,用完則啟用LRU,否則申請新的page,存儲
三.調(diào)試(帶參數(shù)+線程)
在make的時候增加參數(shù):
如果之前已經(jīng)安裝需要清理,
必須加上編譯選項-O0,不然在gdb內(nèi)打印變量時提示"<value optimized out>"
# make uninstall
# make CFLAGS="-g -O0"
# make install
在gdb里啟動 # gdb /usr/local/memcached/bin/memcached
給gdb傳參數(shù)
帶精靈模式
# set args -d -m 100 -uroot -l 0.0.0.0 -p 11211 -c 512
不帶精靈模式
# set args? -m 100 -uroot -l 0.0.0.0 -p 11211 -c 512
后面都是走正常的調(diào)試流程 # r
# break main
# break slabs_init
后面都是走正常的調(diào)試流程
# s? 下一步 跟進函數(shù)
# n? 下一步 不跟進函數(shù)
# c? 下一個斷點
修改變量值?
修改do_daemonize,這樣就不用進入daemon了
#p do_daemonize=0
調(diào)試線程
# info threads
顯示進程中所有的線程的概要信息。gdb按順序顯示:
1.線程號(gdb設(shè)置)
2.目標系統(tǒng)的線程標識。
3.此線程的當前堆棧。
一前面打*的線程表示是當前線程。
#thread THREADNO
把線程號為THREADNO的線程設(shè)為當前線程。命令行參數(shù)THREADNO是gdb內(nèi)定的
線程號。你可以用info threads命令來查看gdb內(nèi)設(shè)置的線程號。gdb顯示該線程
的系統(tǒng)定義的標識號和線程對應的堆棧。比如:
#thread apply [THREADNO] [ALL] ARGS
此命令讓你對一個以上的線程發(fā)出相同的命令ARGS,[THREADNO]的含義同上。
如果你要向你進程中的所有的線程發(fā)出命令使用[ALL]選項。
無論gdb何時中斷了你的程序(因為一個斷點或是一個信號),它自動選擇信號或
斷點發(fā)生的線程為當前線程。gdb將用一個格式為[Switching to SYSTAG]的消息來向你報告。
總結(jié)
以上是生活随笔為你收集整理的Memcached安装使用和源码调试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10月份去甘南有什么好玩的,10月甘南的
- 下一篇: 《Java: The Complete