《深入剖析ngx》——進程模型


1. 進程工作

ngx是多進程模型:work進程,master進程,cache進程。
ngx還使用 upstream等模塊實現和 其他服務器通信

master和worker進程工作流程如下

可以看出 用戶使用信號控制 監控進程,監控進程 控制工作進程

監控進程主要處理 用戶的信號,

監控進程使用 sigsuspend 阻塞等待信號,信號處理函數設置旗標,根據旗標完成具體動作。
ngx_quit 會進行清理工作再退出。
ngx_terminate 使用 SIGKILL 讓自己退出
ngx_reconfigure 重新加載配置

工作進程主要處理和 客戶端和后端服務器 IO,使用 select epoll 等多路復用實現。

2. 進程通信

2.1 channel

  • 父子通信

    ngx使用 socketpair 分配 兩個互相連接的 Unix套接字,fork后,channel[0] <----> channel[1] 依舊連接,實現血緣關系進程通信。

  • 兄弟通信
    新的子進程會繼承老的子進程的已連接的套接字,但是 老的子進程沒有用於寫給新子進程的套接字,ngx利用 進程間套接字傳遞 實現兄弟通信。

進程間傳遞文件描述符,參考:
https://www.cnblogs.com/yangxinrui/p/16083105.html

  • 總結
    雖然 ngx 實現了 channel 機制,可以完成 父子兄弟互相通信,但只用 channel 進行 控制進程對工作進程的通信。
    而子進程之間使用更好的通信方法,如共享內存。

2.2 共享內存

2.2.1 初始化

ngx的共享內存可以通過 用戶配置 動態申請,如

這里申請一個共享內存,10M,名稱為one,

ngx使用 ngx_shm_zone_s 描述內存塊信息。

 16 typedef struct {
 17     u_char      *addr;
 18     size_t       size;
 19     ngx_str_t    name;
 20     ngx_log_t   *log;
 21     ngx_uint_t   exists;   /* unsigned  exists:1;  */
 22 } ngx_shm_t;

 25 typedef struct ngx_shm_zone_s  ngx_shm_zone_t;
 26
 27 typedef ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, void *data);
 28
 29 struct ngx_shm_zone_s {
 30     void                     *data;
 31     ngx_shm_t                 shm;
 32     ngx_shm_zone_init_pt      init;
 33     void                     *tag;
 34     void                     *sync;
 35     ngx_uint_t                noreuse;  /* unsigned  noreuse:1; */
 36 };

shm.shm.name 是內存塊名稱,是內存塊唯一鍵值
shm.tag 用於區分內存塊的創建和使用,如 模塊A 創建名稱為a的內存塊,之后模塊A再用名稱a從內存池中獲取內存塊,這是可行的,但是若模塊B也創建名稱為a的內存塊,若內存塊只有name做區分,則模塊B也能獲得內存塊a,但這導致沖突,所以需要tag屬性表明該內存塊的owner,如此模塊B再創建名稱為a的內存塊時,還會比較tag是否為模塊B,匹配失敗則報錯,模塊B只能重建其他名稱內存塊。

ngx解析完配置文件時,調用 shared_memory_add() 創建 ngx_shm_zone_s,ngx_shm_zone_s只是內存塊描述,不是真正的內存塊,並將ngx_shm_zone_s 加入 鏈表 cf->cycle->shared_memory ,檢查沖突后,遍歷鏈表 分配共享內存,並格式化內存塊。

ngx_shm_alloc 是對 系統調用的封裝,完成內存塊申請
ngx_init_zone_pool 對內存塊進行格式化
shm_zone[i].init 回調用戶的初始化方法

以 ngx_http_limit_req_module 的初始化方法為例

若舊數據可用(重加載配置情況),則直接返回,否則初始化模塊ctx,用slab方法申請內存。

以上完成內存塊初始化,關於內存塊的使用涉及 互斥和slab

2.2.2 互斥

互斥是使用鎖解決,ngx互斥鎖接口如下

2.2.3 slab

ngx實現的slab是二級頁表,支持分配和釋放內存。

在共享內存的頭部,有頭信息

一級頁表

page[] 是真實用於分配的內存塊,
ngx_slab_page_t[] ngx管理page使用的描述結構,ngx_slab_page_t 和 page 一一對應,獲得 ngx_slab_page_t 地址,就能求得page地址。

ngx 對 ngx_slab_page_t 的管理,是使用 鏈表,鏈表元素為數組。
ngx_slab_page_t 數組的首元素的 slab屬性,表示本數組的長度
當分配空間如下

釋放空間,回收內存塊

二級頁表,
每個 ngx_slab_page_t 的二級頁面粒度不同,對 其對應 page 進行划分。並用位圖方式描述使用情況。
如果粒度能用32bit表示,則使用 ngx_slab_page_t.slab屬性表示

如果粒度用不完32bit,則使用 ngx_slab_page_t.slab屬性的一部分bit位表示
如果粒度用32bit表示不完,則使用 page首部表示

3. 信號

ngx對信號聲明對象

靜態定義信號對象數組

其中涉及的C語言宏

在初始化時,完成信號處理的初始化

ngx處理信號時,根據盡量簡單的原則,只進行少量工作

信號處理完成后,根據旗標進行真正處理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM