1. 程式人生 > >使用Nginx post_action配置 & filter模組中新增定時器 導致的coredump

使用Nginx post_action配置 & filter模組中新增定時器 導致的coredump

開發環境使用nginx + lua;一次使用nginx 的post_action功能,掛在某模組的新增定時器事件的介面上。

首先說下post_action功能,它會在http請求結束時產生一個新請求,產生一個內部跳轉。

server {
        listen  80;
        server_name www.a.com;


        location / {
                proxy_set_header Host "www.a-upstream.com";
                proxy_pass http://127.0.0.1:8000;
                post_action @action;
        }


        location @action {
                proxy_set_header Host "www.a-post-action.com";
                proxy_pass http://127.0.0.1:8001;
        }
}

這樣,http://www.a.com/訪問結束時,將產生一個內部跳轉請求,跳轉到@action,訪問上游www.a-post-action.com。檢視網上資料,這種方式可以用來統計伺服器的資料。

假設產生問題的filter模組為A,A的filter函式中,主要完成以下幾件事情:

1. 如果沒有ctx,則建立ctx;

2. 初始化ctx,ctx中包含一個定時器,定時器回撥用來定時統計一個數據;定時器的記憶體從r->pool中分配;

3. ctx新增cleanup回撥;

4.掛載ctx;

在我的測試環境中使用post_action功能,發現訪問幾次post_action後,產生了coredump資訊。

剛開始懷疑r的記憶體出現了問題,就配置單個worker程序,gdb worker,p了下r的記憶體是沒有任務問題的。這個假設推翻了。

後來有懷疑A模組中定時器的使用方式,檢視nginx中其他地方,也是沒有問題的。

突然,就給A模組的定時器新增函式和cleanup函式添加了列印資訊,分別列印定時器的新增和消費,以及清除事件,發現居然有一個主請求的定時器事情既沒有消費,也沒有銷燬。所以就推斷,可能這個定時器使用的記憶體空間,也就是原來的主請求已經銷燬了,記憶體也非法了。當然後續請求的定時器操作介面遍歷時出現了問題。

那麼確認下到底什麼地方直接退出了定時器的消費或者回收?

進一步新增列印資訊,原來是進入cleanup函式中,判斷A模組的ctx為空,直接退出了。無法從ctx中獲取定時器,並銷燬。

進一步通過gdb的watch命令觀察A模組的ctx什麼時候被清空,發現原來是post_action請求執行前,會首先清空主請求的ctx,才導致了之前的主請求定時器沒有銷燬。但是主請求釋放了,定時器的記憶體已經非法了。