nginx中共享內(nèi)存的使用詳解
在nginx的進(jìn)程模型下,類似流量統(tǒng)計(jì)、流量控制、數(shù)據(jù)共享、等需要多個(gè)工作進(jìn)程共同配合完成任務(wù),共享內(nèi)存是一個(gè)重要的進(jìn)程通訊的方案。本文介紹在nginx的代碼中與共享內(nèi)存相關(guān)的功能,包括ngx_shmem與ngx_slab的使用與注意事項(xiàng),但不包括ngx_slab中實(shí)現(xiàn)的內(nèi)存管理算法。
ngx_shmem的使用
ngx_shmem.c/h文件只是對(duì)mmap()/munmap()系統(tǒng)調(diào)用或者shmget()/shmdt()的一個(gè)很簡(jiǎn)單的封裝。實(shí)現(xiàn)了ngx風(fēng)格的基礎(chǔ)庫(kù),可以申請(qǐng)和釋放一段連續(xù)的共享內(nèi)存空間。一般用于固定長(zhǎng)度的共享數(shù)據(jù)使用,使用過(guò)程中數(shù)據(jù)長(zhǎng)度固定不會(huì)伸縮。
typedef struct { u_char *addr; size_t size; ... } ngx_shm_t; ngx_int_t ngx_shm_alloc(ngx_shm_t *shm); void ngx_shm_free(ngx_shm_t *shm);
在ngxin中共享內(nèi)存的使用流程,一般是由master進(jìn)程創(chuàng)建,worker進(jìn)程通過(guò)繼承的方式獲得內(nèi)存指針。
關(guān)于ngx_shmem的使用,可以參考ngx_event_module_init()中部分片段,這部分代碼在共享內(nèi)存中創(chuàng)建了若干個(gè)變量,用于記錄各個(gè)狀態(tài)(accepted/reading/writing...)的請(qǐng)求數(shù)量,并在ngx_event_module中的幾個(gè)關(guān)鍵事件入口對(duì)這幾個(gè)變量進(jìn)行加減統(tǒng)計(jì)操作。實(shí)現(xiàn)統(tǒng)計(jì)所有worker進(jìn)程當(dāng)前的請(qǐng)求狀態(tài)。
shm.size = size; ngx_str_set(&shm.name, "nginx_shared_zone"); shm.log = cycle->log; if (ngx_shm_alloc(&shm) != NGX_OK) { return NGX_ERROR; } shared = shm.addr; ... ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl); ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl); ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl); ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl); ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl); ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl); ngx_stat_waiting = (ngx_atomic_t *) (shared + 9 * cl);
關(guān)于這個(gè)功能的更多細(xì)節(jié),可以查看代碼中的NGX_STAT_STUB宏定義相關(guān)代碼與ngx_http_stub_status_module。
ngx_slab的使用
ngx_shmem是一層極簡(jiǎn)的封裝,實(shí)現(xiàn)了共享內(nèi)存的基本功能。但我們程序中大部分的場(chǎng)景共享數(shù)據(jù)并不會(huì)一個(gè)固定大小的結(jié)構(gòu),而更多是像ngx_array、ngx_list、ngx_queue、ngx_rbtree這類大小可以變化的數(shù)據(jù)結(jié)構(gòu)。
我們期望能有像ngx_pool_t一樣可以動(dòng)態(tài)申請(qǐng)釋放空間一個(gè)內(nèi)存池。ngx_slab正是一個(gè)這樣的結(jié)構(gòu)體,原理上與系統(tǒng)的malloc()有相識(shí)之處都是通過(guò)一系列算法實(shí)現(xiàn)對(duì)一段段內(nèi)存片段的申請(qǐng)與釋放。只不過(guò)ngx_slab操作的對(duì)象是基于ngx_shmem的共享內(nèi)存。
先看一下ngx_slab的接口
typedef struct { ngx_shmtx_t mutex; ... void *data; /* 一般存放從pool中申請(qǐng)獲得的根數(shù)據(jù)地址(pool中第一個(gè)申請(qǐng)的數(shù)據(jù)接口) */ void *addr; /* 使用ngx_shmem申請(qǐng)獲得的共享內(nèi)存基地址 */ } ngx_slab_pool_t; void ngx_slab_init(ngx_slab_pool_t *pool); void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size); void ngx_slab_free(ngx_slab_pool_t *pool, void *p); void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);
可以看到接口并不復(fù)雜,alloc與calloc的區(qū)別在于是否對(duì)申請(qǐng)獲得的內(nèi)存段清零,_locked結(jié)尾的接口表示操作的pool已經(jīng)是獲取到鎖的。在ngx_slab_pool_t的結(jié)構(gòu)體有一個(gè)ngx_shmtx_t的互斥鎖用于同步多進(jìn)程同時(shí)訪問(wèn)pool的并發(fā)場(chǎng)景。注意ngx_slab_alloc()會(huì)先獲取鎖、然后申請(qǐng)空間、最后釋放鎖。而ngx_slab_alloc_locked()則直接申請(qǐng)空間,認(rèn)為程序已經(jīng)在其他邏輯中獲得鎖了。
在nginx的開發(fā)中使用ngx_shmem一般需要遵循以下初始化流程:
- 模塊在配置解析過(guò)程中調(diào)用ngx_shared_memory_add()接口,注冊(cè)一段共享內(nèi)存。提供共享內(nèi)存大小與內(nèi)存初始化的回調(diào)函數(shù)。
- 框架在ngx_init_cycle()中使用ngx_shmem申請(qǐng)內(nèi)存,并初始化ngx_slab,然后回調(diào)模塊注冊(cè)的初始化函數(shù)
- 模塊使用ngx_slab的申請(qǐng)/是否接口
在這個(gè)流程中,涉及到ngx_shared_memory_add()接口與對(duì)應(yīng)的ngx_shm_zone_t結(jié)構(gòu)體。
struct ngx_shm_zone_s { void *data; ngx_shm_t shm; ngx_shm_zone_init_pt init; void *tag; void *sync; ngx_uint_t noreuse; /* unsigned noreuse:1; */ }; ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag);
其中值得一提的是noreuse屬性,這個(gè)屬性控制了在nginx的reload過(guò)程中是否會(huì)重新申請(qǐng)共享內(nèi)存。
由于關(guān)于ngx_init_cycle()函數(shù)較長(zhǎng),這個(gè)流程可以通過(guò)查找/* create shared memory */這個(gè)注釋或者cycle->shared_memory這個(gè)對(duì)象查看相關(guān)代碼。
關(guān)于ngx_slab更多細(xì)節(jié)的使用,建議可以參考ngx_http_limit_conn_module,這是通過(guò)共享內(nèi)存實(shí)現(xiàn)連接數(shù)限制的模塊,模塊復(fù)雜度底,是一個(gè)很好的參考范例。
參考資料
深入理解Nginx(第2版) https://book.douban.com/subject/26745255/
ngx_http_limit_conn_module http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
nginx如何實(shí)現(xiàn)配置靜態(tài)資源服務(wù)器及防盜鏈
這篇文章主要為大家介紹了nginx實(shí)現(xiàn)配置靜態(tài)資源服務(wù)器及防盜鏈步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11Nginx列出目錄和文件并用密碼控制訪問(wèn)權(quán)限配置方法
這篇文章主要介紹了Nginx列出目錄和文件并用密碼控制訪問(wèn)權(quán)限配置方法,本文給出了詳細(xì)的安裝配置步驟,需要的朋友可以參考下2015-07-07nginx配置proxy_pass后返回404問(wèn)題以及Nginx host相關(guān)變量的說(shuō)明
這篇文章主要介紹了nginx配置proxy_pass后返回404問(wèn)題以及Nginx host相關(guān)變量的說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01詳解ngx_cache_purge _proxy_cache指令使用
本文主要介紹了詳解ngx_cache_purge _proxy_cache指令使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07nginx 隱藏版本號(hào)與WEB服務(wù)器信息的解決方法
這篇文章主要介紹了nginx 隱藏版本號(hào)與WEB服務(wù)器信息的解決方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-11-11