日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Memcached安装使用和源码调试

發布時間:2023/11/27 生活经验 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Memcached安装使用和源码调试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

memcached官網: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官網?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


啟動參數

memcached 1.4.2
-p <num>      監聽的TCP端口(默認: 11211)
-U <num>      監聽的UDP端口(默認: 11211, 0表示不監聽)
-s <file>     用于監聽的UNIX套接字路徑(禁用網絡支持)
-a <mask>     UNIX套接字訪問掩碼,八進制數字(默認:0700)
-l <ip_addr>  監聽的IP地址。(默認:INADDR_ANY,所有地址)
-d            作為守護進程來運行。
-r            最大核心文件限制。
-u <username> 設定進程所屬用戶。(只有root用戶可以使用這個參數)
-m <num>      單個數據項的最大可用內存,以MB為單位。(默認:64MB)
-M            內存用光時報錯。(不會刪除數據)
-c <num>      最大并發連接數。(默認:1024)
-k            鎖定所有內存頁。注意你可以鎖定的內存上限。試圖分配更多內存會失敗的,所以留意啟動守護進程時所用的用戶可分配的內存上限。(不是前面的 -u <username> 參數;在sh下,使用命令"ulimit -S -l NUM_KB"來設置。)
-v            提示信息(在事件循環中打印錯誤/警告信息。)
-vv           詳細信息(還打印客戶端命令/響應)
-vvv          超詳細信息(還打印內部狀態的變化)
-h            打印這個幫助信息并退出。
-i            打印memcached和libevent的許可。
-P <file>     保存進程ID到指定文件,只有在使用 -d 選項的時候才有意義。
-f <factor>   塊大小增長因子。(默認:1.25)
-n <bytes>    分配給key+value+flags的最小空間(默認:48)
-L            嘗試使用大內存頁(如果可用的話)。提高內存頁尺寸可以減少"頁表緩沖(TLB)"丟失次數,提高運行效率。為了從操作系統獲得大內存頁,memcached會把全部數據項分配到一個大區塊。
-D <char>     使用 <char> 作為前綴和ID的分隔符。這個用于按前綴獲得狀態報告。默認是":"(冒號)。如果指定了這個參數,則狀態收集會自動開啟;如果沒指定,則需要用命令"stats detail on"來開啟。
-t <num>      使用的線程數(默認:4)
-R            每個連接可處理的最大請求數。
-C            禁用CAS。
-b            設置后臺日志隊列的長度(默認:1024)
-B            綁定協議 - 可能值:ascii,binary,auto(默認)
-I            重寫每個數據頁尺寸。調整數據項最大尺寸。


查看詳情

#ps aux|grep mem???

輸出pid

#cat /usr/local/memcached/memcached.pid

?

狀態

#?telnet 127.0.0.1 11211


STAT limit_maxbytes就是最大內存是100M。


增加內存到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次查看內存使用

# 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字節=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間隔越小,可以減少內存的浪費
# /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狀態

# stats slabs?? 顯示各個slab的信息,包括chunk的大小、數目、使用情況等


# 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 最后一個參數就是value字符的長度


下面是故意構造多個不同chunk的字符存儲效果



# stats

# stats items



調整slab參數
slab對于memcached的空間利用率占有決定因素.
1:比較重要的幾個啟動參數:-f:增長因子,chunk的值會按照增長因子的比例增長(chunk size growth factor).-n:每個chunk的初始大小(minimum space allocated for key+value+flags),chunk大小還包括本身結構體大小.-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數量total_pages:page數量total_chunks:chunk數量*page數量used_chunks:已被分配的chunk數量free_chunks:曾經被使用,但是目前被回收的chunk數.free_chunks_end:從來沒被使用的chunk數mem_requested:請求存儲的字節數active_slabs:活動的slabs.total_malloced:實際已分配的內存數.
3:重要的結構體和常量typedef struct {? ?unsigned int size; ? ? ?? ?unsigned int perslab; ?? ?void **slots; ? ? ? ? ?? ?unsigned int sl_total; ?? ?unsigned int sl_curr; ?? ?void *end_page_ptr; ? ? ? ?? ?unsigned int end_page_free;? ?unsigned int slabs; ? ?? ?void **slab_list; ? ? ?? ?unsigned int list_size;} slabclass_t;
static slabclass_t slabclass[MAX_NUMBER_OF_SLAB_CLASSES];
4:slabs_init函數slabs_init(const size_t limit, const double factor, const bool prealloc)?
unsigned int size = sizeof(item) + settings.chunk_size; ?//計算一個chunk的大小,包括item結構體本身的大小,key和value和flags的大小.mem_base = malloc(mem_limit); //一次性分配mem_limit大小的內存,并指向到mem_base指針中.memset(slabclass, 0, sizeof(slabclass));//初始化為0while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) {? ? ? ?if (size % CHUNK_ALIGN_BYTES)? ? ? ? ? ?size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES); //字節對齊? ? ? ?slabclass[i].size = size; //這個slabs的大小? ? ? ?slabclass[i].perslab = settings.item_size_max / slabclass[i].size; //一共含有多少個chunk? ? ? ?size *= factor; //增長因子? ?}power_largest = i; //最后一個slabs.最多可以有MAX_NUMBER_OF_SLAB_CLASSES個slabclass[power_largest].size = settings.item_size_max;slabclass[power_largest].perslab = 1;
#ifndef DONT_PREALLOC_SLABS? ?{? ? ? ?char *pre_alloc = getenv("T_MEMD_SLABS_ALLOC");? ? ? ?if (pre_alloc == NULL || atoi(pre_alloc) != 0) {? ? ? ? ? ?slabs_preallocate(power_largest);? ? ? ?}? ?}#endif
5:do_slabs_newslab 初始化slabsdo_slabs_newslab(const unsigned int id) {? ?slabclass_t *p = &slabclass[id]; //對應第幾個slabs? ?int len = p->size * p->perslab;? ?char *ptr;? ?if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) || (grow_slab_list(id) == 0) || ((ptr = memory_allocate((size_t)len)) == 0)) {? ? ? ?return 0;? ?}? ?memset(ptr, 0, (size_t)len); //初始化大小? ?p->end_page_ptr = ptr; //指向下一個空閑的page指針? ?p->end_page_free = p->perslab;//沒有使用的chunk個數? ?p->slab_list[p->slabs++] = ptr;? ?mem_malloced += len; //對mem_base指針的移動? ?return 1;}

//重新分配slabs個數,默認是分配16個頁,后續按照2倍增加static int grow_slab_list (const unsigned int id) {? ?slabclass_t *p = &slabclass[id];? ?if (p->slabs == p->list_size) {? ? ? ?size_t new_size = ?(p->list_size != 0) ? p->list_size * 2 : 16;? ? ? ?void *new_list = realloc(p->slab_list, new_size * sizeof(void *)); //重新realloc? ? ? ?if (new_list == 0) return 0;? ? ? ?p->list_size = new_size;? ? ? ?p->slab_list = new_list;? ?}? ?return 1;}
6:slabs_clsid根據指定大小的數據,確定應該放入到那個桶unsigned int slabs_clsid(const size_t size) {? ?int res = POWER_SMALLEST;? ?if (size == 0)? ? ? ?return 0;? ?while (size > slabclass[res].size)? ? ? ?if (res++ == power_largest) ?? ? ? ? ? ?return 0;? ?return res;}
7:do_slabs_alloc//從class中分配chunk.static void *do_slabs_alloc(const size_t size, unsigned int id) {? ?slabclass_t *p;? ?void *ret = NULL;??? //假如slabs標記號不對,則發揮錯誤? ?if (id < POWER_SMALLEST || id > power_largest) {? ? ? ?return NULL;? ?}
? ?p = &slabclass[id];? ?assert(p->sl_curr == 0 || ((item *)p->slots[p->sl_curr - 1])->slabs_clsid == 0);
#ifdef USE_SYSTEM_MALLOC? ?if (mem_limit && mem_malloced + size > mem_limit) {? ? ? ?return 0;? ?}? ?mem_malloced += size;? ?ret = malloc(size);? ?return ret;#endif? ?if (! (p->end_page_ptr != 0 || p->sl_curr != 0 ||? ? ? ? ? do_slabs_newslab(id) != 0)) {?? ? ? ?ret = NULL;? ?} else if (p->sl_curr != 0) {? ? ? ?ret = p->slots[--p->sl_curr]; ?//直接使用? ?} else {? ? ? ?assert(p->end_page_ptr != NULL);? ? ? ?ret = p->end_page_ptr;? ? ? ?if (--p->end_page_free != 0) {? ? ? ? ? ?p->end_page_ptr = ((caddr_t)p->end_page_ptr) + p->size;? ? ? ?} else {? ? ? ? ? ?p->end_page_ptr = 0;? ? ? ?}? ?}? ?return ret;}?


 slab,是一個邏輯概念。它是在啟動memcached實例的時候預處理好的,每個slab對應一個chunk size,也就是說不同slab有不同的chunk size。具體分配多少個slab由參數 -f (增長因子)和 -n (chunk最小尺寸)決定的。page,可以理解為內存頁。大小固定為1m。slab會在存儲請求時向系統申請page,并將page按chunk size進行切割。 chunk,是保存用戶數據的最小單位。用戶數據item(包括key,value)最終會保存到chunk內。chunk規格是固定的,如果用戶數據放進來后還有剩余則這剩余部分不能做其他用途。
工作流程:memcahed實例啟動,根據 -f 和 -n 進行預分配slab。以 -n 為最小值開始,以 -f 為比值生成等比數列,直到1m為止(每個slab的chunk size都要按8的倍數進行補全,比如:如果按比值算是556的話,會再加4到560成為8的整倍數)。然后每個slab分配一個page。當用戶發來存儲請求時(key,value),memcached會計算key+value的大小,看看屬于哪個slab。確定slab后看里面的是否有空閑 chunk放key+value,如果不夠就再向系統申請一個page(如果此時已經達到 -m 參數設置的內存使用上限,則看是否設置了 -M 。如果設置了 -M 則返回錯誤提示,否則按LRU算法刪除數據)。申請后將該page按本slab的chunk size 進行切割,然后分配一個來存放用戶數據。
注意: 1,chunk是在page里面劃分的,而page固定為1m,所以chunk最大不能超過1m。 2,chunk實際占用內存要加48B,因為chunk數據結構本身需要占用48B。 3,如果用戶數據大于1m,則memcached會將其切割,放到多個chunk內。 4,已分配出去的page不能回收。
優化建議 1,-n 參數的設置,注意將此參數設置為1024可以整除的數(還要考慮48B的差值),否則余下來的部分就浪費了。 2,不要存儲超過1m的數據。因為要拆成多個chunk,計算和時間成本都成倍增加。 3,善用stats命令查看memcached狀態。 4,消滅eviction(被刪除的數據)。造成eviction是因為內存不夠,有三個思路:一是在CPU有余力的情況下開啟壓縮(PHP擴展);二是增加內存;三是調整 -f 參數,減少內存浪費。5,調整業務代碼,提高命中率。 6,緩存小數據。省帶寬,省網絡I/O時間,省內存。 7,根據業務特點,為數據尺寸區間小的業務分配專用的memcached實例。這樣可以調小 -f 參數,使數據集中存在少數幾個slab上,內存浪費較少。 
Memcached的內存分配以page為單位,默認情況下一個page是1M?,可以通過-I參數在啟動時指定。如果需要申請內存 時,memcached會劃分出一個新的page并分配給需要的slab區域。Memcached并不是將所有大小的數據都放在一起的,而是預先將數據空間劃分為一系列slabs,每個slab只負責一定范圍內的數據存儲,其大小可以通過啟動參數設置增長因子,默認為1.25,即下一個slab的大小是上一個的1.25倍。 
Memcached在啟動時通過-m指定最大使用內存,但是這個不會一啟動就占用,是隨著需要逐步分配給各slab的。
?? ? ? ? 如果一個新的緩存數據要被存放,memcached首先選擇一個合適的slab,然后查看該slab是否還有空閑的chunk,如果有則直接存放進去;如 果沒有則要進行申請。slab申請內存時以page為單位,所以在放入第一個數據,無論大小為多少,都會有1M大小的page被分配給該slab。申請到 page后,slab會將這個page的內存按chunk的大小進行切分,這樣就變成了一個chunk的數組,在從這個chunk數組中選擇一個用于存儲 數據。如下圖,slab 1和slab 2都分配了一個page,并按各自的大小切分成chunk數組。
  默認情況下memcached把slab分為42類(class1~class42),在class 1中,chunk的大小為96字節,由于一個slab的大小是固定的1048576字節(1M),因此在class1中最多可以有10922個chunk:13107×80 + 16 = 1048576在class1中,剩余的16字節因為不夠一個chunk的大小(80byte),因此會被浪費掉。每類chunk的大小有一定的計算公式的,假定i代表分類,class i的計算公式如下:chunk size(class i) : ?(default_size+item_size)*f^(i-1)+?CHUNK_ALIGN_BYTES
  • default_size: 默認大小為48字節,也就是memcached默認的key+value的大小為48字節,可以通過-n參數來調節其大小;
  • item_size: item結構體的長度,固定為32字節。default_size大小為48字節,item_size為32,因此class1的chunk大小為48+32=80字節;
  • f為factor,是chunk變化大小的因素,默認值為1.25,調節f可以影響chunk的步進大小,在啟動時可以使用-f來指定;
  • CHUNK_ALIGN_BYTES是一個修正值,用來保證chunk的大小是某個值的整數倍(在32位機器上要求chunk的大小是4的整數倍)。
從上面的分析可以看到,我們實際可以調節的參數有-f、-n,在memcached的實際運行中,我們還需要觀察我們的數據特征,合理的調節f,n的值,使我們的內存得到充分的利用減少浪費。
?Memcached 采用slab+page+chunk 方式管理內存
–Slab,特定大小的一組chunk
–Page,每次分配給slab的內存空間,會按照slab大小切分為chunk(默認1MB)–Chunk,存儲記錄的內存空間
下面是我畫的memcached的slab結構圖

下面是:http://wenku.baidu.com/view/3e858ff09e314332396893fe.html存儲一個value的大體過程存儲一個value的大體過程
1.先根據要存儲的key、value和flags計算item的大小
item長度=item結構大小 + 鍵長 + 后綴長 + 存儲值長度
2.如果這個item對應的slab還沒有創建,則申請1個page(默認1MB),將這個page按照這個slab類chunk的大寫進行分割,然后將這個 item 存入
3.如果存在,且對應的slab沒用完,存儲
4.如果存在,且對應的slab用完了,則看內存是否用完,用完則啟用LRU,否則申請新的page,存儲

三.調試(帶參數+線程)


在make的時候增加參數:

如果之前已經安裝需要清理,
必須加上編譯選項-O0,不然在gdb內打印變量時提示"<value optimized out>"

# make uninstall
# make CFLAGS="-g -O0"
# make install

在gdb里啟動
# gdb /usr/local/memcached/bin/memcached

給gdb傳參數

帶精靈模式
# 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

后面都是走正常的調試流程 # r
# break main
# break slabs_init
后面都是走正常的調試流程
# s? 下一步 跟進函數
# n? 下一步 不跟進函數
# c? 下一個斷點 

修改變量值
?
修改do_daemonize,這樣就不用進入daemon了
#p do_daemonize=0


調試線程
# info threads
顯示進程中所有的線程的概要信息。gdb按順序顯示:
1.線程號(gdb設置)
2.目標系統的線程標識。
3.此線程的當前堆棧。
一前面打*的線程表示是當前線程。

#thread THREADNO
把線程號為THREADNO的線程設為當前線程。命令行參數THREADNO是gdb內定的
線程號。你可以用info threads命令來查看gdb內設置的線程號。gdb顯示該線程
的系統定義的標識號和線程對應的堆棧。比如:


#thread apply [THREADNO] [ALL] ARGS
此命令讓你對一個以上的線程發出相同的命令ARGS,[THREADNO]的含義同上。
如果你要向你進程中的所有的線程發出命令使用[ALL]選項。
無論gdb何時中斷了你的程序(因為一個斷點或是一個信號),它自動選擇信號或
斷點發生的線程為當前線程。gdb將用一個格式為[Switching to SYSTAG]的消息來向你報告。

 

總結

以上是生活随笔為你收集整理的Memcached安装使用和源码调试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。