在nginx的進程模型下,類似流量統計、流量控制、數據共享、等需要多個工作進程共同配合完成任務,共享內存是一個重要的進程通訊的方案。本文介紹在nginx的代碼中與共享內存相關的功能,包括ngx_shmem與ngx_slab的使用與注意事項,但不包括ngx_slab中實現的內存管理算法。
ngx_shmem的使用
ngx_shmem.c/h文件只是對mmap()/munmap()系統調用或者shmget()/shmdt()的一個很簡單的封裝。實現了ngx風格的基礎庫,可以申請和釋放一段連續的共享內存空間。一般用于固定長度的共享數據使用,使用過程中數據長度固定不會伸縮。
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中共享內存的使用流程,一般是由master進程創建,worker進程通過繼承的方式獲得內存指針。
關于ngx_shmem的使用,可以參考ngx_event_module_init()中部分片段,這部分代碼在共享內存中創建了若干個變量,用于記錄各個狀態(accepted/reading/writing...)的請求數量,并在ngx_event_module中的幾個關鍵事件入口對這幾個變量進行加減統計操作。實現統計所有worker進程當前的請求狀態。
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);
關于這個功能的更多細節,可以查看代碼中的NGX_STAT_STUB宏定義相關代碼與ngx_http_stub_status_module。
ngx_slab的使用
ngx_shmem是一層極簡的封裝,實現了共享內存的基本功能。但我們程序中大部分的場景共享數據并不會一個固定大小的結構,而更多是像ngx_array、ngx_list、ngx_queue、ngx_rbtree這類大小可以變化的數據結構。
我們期望能有像ngx_pool_t一樣可以動態申請釋放空間一個內存池。ngx_slab正是一個這樣的結構體,原理上與系統的malloc()有相識之處都是通過一系列算法實現對一段段內存片段的申請與釋放。只不過ngx_slab操作的對象是基于ngx_shmem的共享內存。
先看一下ngx_slab的接口
typedef struct { ngx_shmtx_t mutex; ... void *data; /* 一般存放從pool中申請獲得的根數據地址(pool中第一個申請的數據接口) */ void *addr; /* 使用ngx_shmem申請獲得的共享內存基地址 */} 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);
新聞熱點
疑難解答