第三十六讲:用好共享内存工具:Slab管理器
? 剛剛我們談到nginx不同的worker進(jìn)程間需要共享信息的時候,需要通過共享內(nèi)存;我們也談到了共享內(nèi)存上可以使用鏈表或者紅黑樹這樣的數(shù)據(jù)結(jié)構(gòu);但是每一個紅黑樹上有許多節(jié)點(diǎn);每一個節(jié)點(diǎn)你需要分配內(nèi)存去存放;那么怎么樣把一整塊共享內(nèi)存切割成一小塊給紅黑樹上的每一個節(jié)點(diǎn)使用呢???
? 下面我們來看下Slab內(nèi)存分配管理是怎么樣應(yīng)用于共享內(nèi)存上的;首先我們來看下Slab內(nèi)存管理是怎么樣的一種形式;
? 它首先會把整塊的共享內(nèi)存分為很多頁面;那么每個頁面例如4k;會切分為很多slot; 比如32字節(jié)是一種slot; 64字節(jié)又是一種slot; 128字節(jié)又是一種slot; 那么這些slot是以乘2的方式向上增長的; 如果現(xiàn)在有一個51字節(jié)需要分配的內(nèi)存會放到哪里呢?會放于小于它最大的一個slot的一個環(huán)節(jié); 比如說64字節(jié);所以上圖中slot就是指向不同大小的塊;所以這樣的一種數(shù)據(jù)結(jié)構(gòu)呢?它有一個特點(diǎn);會有內(nèi)存的浪費(fèi)的。 就像我們剛剛所說的: 51字節(jié)它會用64字節(jié)來存放;那么其他的13字節(jié)就浪費(fèi)了;那么最多會有多少消耗呢?還有兩倍: 這種使用的方式叫做Bestfit; Bestfit這種分配內(nèi)存的方式有什么好處呢? 它適合小對象; 如果我們要分配的對象的內(nèi)存非常小, 比如小于一個頁面的大小,就非常合適;因?yàn)樗苌儆兴槠?#xff0c;那么每分配一塊內(nèi)存,就會沿著還未分配的空白的地方繼續(xù)使用就可以了;當(dāng)一個頁面使用滿以后,我再拿一個空白的頁面繼續(xù)給此類slot大小的內(nèi)存繼續(xù)使用就可以。那么有時候我分配在某段內(nèi)存上的數(shù)據(jù)結(jié)構(gòu)它是固定的,甚至需要初始化;那么這樣的話,原先的數(shù)據(jù)結(jié)構(gòu)都還在;當(dāng)我重復(fù)使用的話,也避免了初始化;Slab內(nèi)存管理中,我們怎么做數(shù)據(jù)的監(jiān)控和統(tǒng)計(jì)呢?
? 那么tng上有一個模塊叫做slab_stat; slab_stat可以幫我們看不同的slot:
比如說: 8字節(jié) 16字節(jié) ......等等
一共目前分配了多少,使用了多少,有多少個請求在訪問,失敗了多少次,這個對我們來監(jiān)控Slab是非常有用處的;
?下面我們來看下怎么樣在openresty的場景下去使用tng上的slab_stat這個模塊;
首先我們打開tengine的頁面??http://tengine.taobao.org/document/ngx_slab_stat.html
但是會發(fā)現(xiàn)在這個模塊上沒有g(shù)ithub的地址;也就是說它沒有作為一個獨(dú)立的模塊提供出來;那這個時候該怎么辦呢?
那么tengine怎么下載下來?從download里:
解壓后進(jìn)入目錄查看多個modules目錄:
modules里有個ngx_slab_stat
再進(jìn)入查看
可以看到
這是一個標(biāo)準(zhǔn)的nginx第三方模塊;因?yàn)槊恳粋€nginx第三方模塊會通過一個c文件定義好我們之前所說的ngx_module_t這么一個結(jié)構(gòu)體;
以及處理哪些配置項(xiàng) ,提供哪些變量;并有一個config來幫助他編譯到我們的目標(biāo)nginx中 ;現(xiàn)在我們再回到 openresty中,讓openresty編譯的時候,把tengine的slab_stat模塊編譯進(jìn)去;然后再使用openresty上的share_direct去分配共享內(nèi)存;再用slab_stat查看我們共享內(nèi)存的使用情況;
我們執(zhí)行configure的時候,可以添加一個參數(shù)叫 --add-module=;--add-module=這個命令尼 可以將一個目錄下具備config的這樣一個配置項(xiàng)或者目錄添加到我們的nginx中,它的方式尼 也就是將這個模塊的nginx源碼能夠使我們的./configure 識別到;所以這里的configure和我們的官方configure是一樣的,那么我們現(xiàn)在開始編譯openresty;
編譯完成以后開始執(zhí)行make命令:
如果之前已經(jīng)安裝了openresty或者(nginx)
執(zhí)行編譯make 好以后不需要make install
(1). 備份原來的nginx 可執(zhí)行文件
cd /usr/local/openresty/nginx/sbin
cp nginx nginx.old
(2) 將編譯好的nginx可執(zhí)行二進(jìn)制文件復(fù)制到原始nginx的sbin目錄
cp /home/web/openresty-1.13.6.2/build/nginx-1.13.6/objs/nginx /usr/local/openresty/nginx/sbin/ -f
(3) 驗(yàn)證是否成功安裝ngx_slab_stat
cd /usr/local/openresty/nginx/sbin
./nginx -V
現(xiàn)在openresty已經(jīng)安裝完成了,這個openresty中,已經(jīng)包含了ngx_slab_stat模塊;
我們以上一節(jié)中l(wèi)ua_shared_dict 那段代碼的例子,來講解下slab_stat是怎么使用的?
首先我們用 lua_shared_dict_dogs 10m; 分配了一個10m的共享內(nèi)存,名字叫dogs;
使用的話,我們有一個set的url下;設(shè)置了一個key-value: Jim-8;設(shè)置在我們的共享內(nèi)存下,并返回給用戶一個字符串叫STORED;
當(dāng)收到get這個url請求時,會從dogs共享內(nèi)存中取出Jim的值;也就是這里設(shè)置的8返回給用戶:
然后我們又增加了一個location,這個location叫做slab_stat,它里面的內(nèi)容就是tengine中slab_stat提供的slab_stat配置項(xiàng),這個配置項(xiàng)叫做slab_stat.
它會返回我們slab的所有的統(tǒng)計(jì)狀況:
nginx.conf 配置文件代碼:
lua_shared_dict dogs 10m;
??? server {
??????? listen 8080;
??????? server_name? localhost;
??????? #charset koi8-r;
??????? #access_log? logs/host.access.log? main;
??????? location = /slab_stat{
???????? slab_stat;
??????? }
??????? location /set{
??????????????? content_by_lua_block{
??????????????????????? local dogs=ngx.shared.dogs
??????????????????????? dogs:set("Jim",8)
??????????????????????? ngx.say("STORED");
??????????????? }
??????? }
??????? location /get {
??????????????? content_by_lua_block{
??????????????????????? local dogs=ngx.shared.dogs
??????????????????????? ngx.say(dogs:get("Jim"))
??????????????? }
??????? }
??????? location / {
??????????? #proxy_set_header Host?host;?????????????#proxy_set_header?X-Real-IPhost;?????????????#proxy_set_header?X-Real-IPremote_addr;
??????????? #proxy_set_header X-Forwarded-For?proxy_add_x_forwarded_for;?????????????#proxy_cache?my_cache;?????????????#proxy_cache_keyproxy_add_x_forwarded_for;?????????????#proxy_cache?my_cache;?????????????#proxy_cache_keyhosturiuriis_args&args;
??????????? #proxy_cache_valid 200 304 302 1d;
??????????? #proxy_pass http://local;
??????? }
?
配置項(xiàng)寫完,把ngixn啟動看看它的執(zhí)行效果;
每一個slot及其slot對應(yīng)的大小;分配了多少個,使用了多少個,失敗了多少個;
所謂分配就是10m是一個非常大的共享內(nèi)存,它會劃分很多個頁面;對于比較小的比如32字節(jié),一個頁面可以有128個;這里127可用,已經(jīng)使用了一個;
總結(jié):以上我們介紹了Slab內(nèi)存的使用方法:slab使用了Bestfit思想,它也是Linux操作系統(tǒng)經(jīng)常使用的內(nèi)存分配方式;
那么通常我們在使用共享內(nèi)存時,都需要使用slab_stat去分配相應(yīng)的內(nèi)存給對象,再使用上層的數(shù)據(jù)結(jié)構(gòu)來維護(hù)這些數(shù)據(jù)對象;
總結(jié)
以上是生活随笔為你收集整理的第三十六讲:用好共享内存工具:Slab管理器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 记一次糟心的内网靶场实战
- 下一篇: nginx+lua+redis 灰度发布