摘要:通過lua-nginx-module中的ngx.thread同時執行多個任務。
ngx_lua中通路多個第三方服務
ngx_lua中提供了ngx.socket API,可以友善的通路第三方網絡服務。如下面的代碼,通過get_response函數從兩個(或者更多)的源伺服器擷取資料,再生成響應發給用戶端。
如果需要10個第三方網絡服務,需要調用get_response 10次。總的響應時間與需要連接配接源的數量成正比。那麼如何縮短源的響應時間呢?ngx.thread就是用來解決這種問題的。
二、lua-nginx-module提供了三個API
1、ngx.thread.spawn
2、ngx.thread.wait
3、ngx.thread.kill
三、詳解
1、ngx.thread.spawn
重點:ngx.thread.spawn生成新的"light thread",這個"light thread"運作優先級比它的父協程高,會優先運作,父協程被迫暫停。"light thread"運作結束或者yield後,再由ngx_http_lua_run_posted_threads去運作父協程。
<a href="https://my.oschina.net/u/2539854/blog/853894" target="_blank">參考:ngx_lua中的協程排程(六)之ngx_http_lua_run_posted_thread</a>
通過ngx.thread.spawn可以生成一個"light thread",一個”light thread“和Lua的協程類似,差別在于"light thread"是由ngx_lua子產品進行排程的,多個"light thread"同時運作。
"light thread",協程 和 程序。"light thread"比Lua中的協程更像作業系統中的程序。
fork生成新的程序,生成的多個程序可以同時運作,而ngx.thread.spawn生成新的協程,多個協程同時在跑。
kill可以殺死不需要的子程序,ngx.thread.kill可以殺死不需要的"light thread"
wait可以等待子程序結束并取得子程序退出狀态,ngx.thread.wait可以等待"light thread"結束并擷取其傳回值。
ngx.thread的使用,用ngx.thread重寫上面的代碼
生成的兩個"light thread"可以同時運作,總的耗時隻相當于通路一個源伺服器的時間,即使需要通路的源伺服器增加,耗時沒有太大的變化。
Linux中的fork生成新的子程序,父程序與子程序誰先運作呢?都有可能,和系統的排程有關。
把調用ngx.thread.spawn的這個Lua協程稱為父協程,生成的"light thread"和父協程誰先運作呢? 在ngx_lua的排程邏輯中,是生成的"light thread"先運作,運作結束或者被挂起後,父協程才會繼續運作。實際的代碼在ngx_http_lua_run_thread函數中,這個函數比較複雜,涉及的東西太多,稍後再細說。
如下面的代碼,沒有調用ngx.thread.wait去等待"light thread"的結束。
由Nginx的日志中可以看到目前的請求一直延遲到t1,t2兩個"light thread"最後退出才會結束。 Nginx中日志的順序也可以看出父協程和兩個"light thread"的執行那個順序。
而如果代碼中主動調用了ngx.exit()結束請求,那麼t1,t2兩個沒有列印出完全的資訊就被kill掉了。
相應的Nginx日志
"light thread"畢竟是基于依附于請求的,如在content_by_lua中建立的"light thread",是完全與目前的請求關聯的,如果"light thread"沒有退出,目前請求也無法結束。同樣如果目前請求因為錯誤退出,或調用ngx.exit強制退出時,處于運作狀态的"light thread"也會被kill掉。不像作業系統的程序,父程序退出後,子程序可以被init程序"收養"。
錯誤代碼:
2017/07/21 09:14:10 [error] 114598#0: *1 failed to load inlined Lua code: content_by_lua(thread.conf:128):2: ')' expected near ',', client: 127.0.0.1, server: 127.0.0.1, request: "GET /thread001 HTTP/1.1", host: "127.0.0.1:8689"