五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

一文淺析Nginx線程池!

2023-03-23 21:32 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

Nginx通過使用多路復(fù)用IO(如Linux的epoll、FreeBSD的kqueue等)技術(shù)很好的解決了c10k問題,但前提是Nginx的請求不能有阻塞操作,否則將會導(dǎo)致整個Nginx進(jìn)程停止服務(wù)。

但很多時候阻塞操作是不可避免的,例如客戶端請求靜態(tài)文件時,由于磁盤IO可能會導(dǎo)致進(jìn)程阻塞,所以將會導(dǎo)致Nginx的性能下降。為了解決這個問題,Nginx在1.7.11版本中實現(xiàn)了線程池機(jī)制。

下面我們將會分析Nginx是怎么通過線程池來解決阻塞操作問題。

啟用線程池功能

要使用線程池功能,首先需要在配置文件中添加如下配置項:

上面定義了一個名為“default”,包含32個線程,任務(wù)隊列最多支持65536個請求的線程池。如果任務(wù)隊列過載,Nginx將輸出如下錯誤日志并拒絕請求:

如果出現(xiàn)上面的錯誤,說明線程池的負(fù)載很高,這是可以通過添加線程數(shù)來解決這個問題。當(dāng)達(dá)到機(jī)器的最高處理能力之后,增加線程數(shù)并不能改善這個問題。

一切從“源”開始

下面主要通過剖析Nginx的源碼來了解線程池機(jī)制實現(xiàn)原理?,F(xiàn)在先來了解Nginx線程池的兩個重要數(shù)據(jù)結(jié)構(gòu)ngx_thread_pool_t和ngx_thread_task_t。

ngx_thread_pool_t結(jié)構(gòu)體

下面解釋下每個字段的用途:

  1. mtx: 互斥鎖,用于鎖定任務(wù)隊列,避免競爭狀態(tài)。

  2. queue: 任務(wù)隊列。

  3. waiting: 有多少個任務(wù)正在等待處理。

  4. cond: 用于通知線程池有任務(wù)需要處理。

  5. name: 線程池名稱。

  6. threads: 線程池由多少個線程組成(線程數(shù))。

  7. max_queue: 線程池最大能處理的任務(wù)數(shù)。

ngx_thread_task_t結(jié)構(gòu)體

下面解釋下每個字段的用途:

  1. mtx: 互斥鎖,用于鎖定任務(wù)隊列,避免競爭狀態(tài)。

  2. queue: 任務(wù)隊列。

  3. waiting: 有多少個任務(wù)正在等待處理。

  4. cond: 用于通知線程池有任務(wù)需要處理。

  5. name: 線程池名稱。

  6. threads: 線程池由多少個線程組成(線程數(shù))。

  7. max_queue: 線程池最大能處理的任務(wù)數(shù)。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)??

ngx_thread_task_t結(jié)構(gòu)體

下面解釋下每個字段的用途:

  1. next: 指向下一個任務(wù)。

  2. id: 任務(wù)ID。

  3. ctx: 任務(wù)的上下文。

  4. handler: 處理任務(wù)的函數(shù)句柄。

  5. event: 跟任務(wù)關(guān)聯(lián)的事件對象(當(dāng)線程池處理成任務(wù)之后將會由主線程調(diào)用event對象的handler回調(diào)函數(shù))。

線程池初始化

下面介紹下線程池的初始化過程。

在Nginx啟動的時候,首先會調(diào)用ngx_thread_pool_init_worker()函數(shù)來初始化線程池。ngx_thread_pool_init_worker()函數(shù)最終會調(diào)用ngx_thread_pool_init(),源碼如下:

ngx_thread_pool_init()最終調(diào)用pthread_create()函數(shù)創(chuàng)建線程池中的工作線程,工作線程會從ngx_thread_pool_cycle()函數(shù)開始執(zhí)行。

ngx_thread_pool_cycle()函數(shù)源碼如下:

ngx_thread_pool_cycle()函數(shù)的主要工作是從待處理的任務(wù)隊列中獲取一個任務(wù),然后調(diào)用任務(wù)對象的handler()函數(shù)處理任務(wù),完成后把任務(wù)放置到完成隊列中,并通過ngx_notify()通知主線程。

添加任務(wù)到任務(wù)隊列

通過上面的分析,我們知道了線程池是怎么從任務(wù)隊列獲取任務(wù)并處理。但任務(wù)隊列的任務(wù)從哪里來的呢?因為Nginx的使命是處理客戶端請求,所以可以知道任務(wù)是通過客戶端請求產(chǎn)生的。也就是說,任務(wù)是主線程創(chuàng)建的(主線程負(fù)責(zé)處理客戶端請求)。

主線程通過ngx_thread_task_post()函數(shù)向任務(wù)隊列中添加一個任務(wù),代碼如下:

ngx_thread_task_post()函數(shù)首先調(diào)用ngx_thread_cond_signal()通知線程池的線程有任務(wù)需要處理,然后把任務(wù)添加到任務(wù)隊列中??赡苡腥藭枺韧ㄖ€程池在添加任務(wù)到任務(wù)隊列中會不會有順序問題。其實這樣做是沒問題的,這是因為只要主線程不調(diào)用ngx_thread_mutex_unlock()把互斥鎖解開,線程池中的工作線程是不會從ngx_thread_cond_wait()返回的。

收尾工作

當(dāng)線程池把任務(wù)處理完后會把其放置到完成隊列中(ngx_thread_pool_done),然后調(diào)用ngx_notify()通知主線程有任務(wù)完成了。主線程收到通知后,會在事件模塊中進(jìn)行收尾工作:調(diào)用task.event.handler()。task.event.handler由任務(wù)創(chuàng)建者設(shè)置,例如在ngx_http_copy_filter模塊的ngx_http_copy_thread_handler()函數(shù):

task.event.handler被設(shè)置為ngx_http_copy_thread_event_handler,就是說當(dāng)任務(wù)處理完成后,主線程將會調(diào)用ngx_http_copy_thread_event_handler來進(jìn)行收尾工作。

哪些操作會使用線程池

那么哪些操作會使用線程池去處理。一般來說,磁盤IO會使用線程池來處理。在ngx_http_copy_filter模塊中,會調(diào)用ngx_thread_read()讀取文件的內(nèi)容(當(dāng)啟用了線程池時),而ngx_thread_read()會把讀取文件內(nèi)容的操作讓線程池去處理。ngx_thread_read()代碼如下:

從上面的代碼看到,task的handler被設(shè)置為ngx_thread_read_handler,也就是說在線程池中將會調(diào)用ngx_thread_read_handler()去讀取文件內(nèi)容。而file->thread_handler()將會調(diào)用ngx_thread_task_post(),前面已經(jīng)分析過,ngx_thread_task_post()會把任務(wù)添加到任務(wù)隊列中。

圖解

最后用一張圖來解釋Nginx線程池機(jī)制的原理吧。

原文作者:Linux內(nèi)核那些事


一文淺析Nginx線程池!的評論 (共 條)

分享到微博請遵守國家法律
德令哈市| 福建省| 绍兴市| 黔南| 佛学| 龙门县| 博罗县| 宣恩县| 仪征市| 马关县| 辽中县| 东丽区| 阳曲县| 武安市| 天门市| 麦盖提县| 台安县| 富源县| 西贡区| 尼玛县| 大邑县| 山东省| 思南县| 铜川市| 大田县| 南阳市| 万安县| 兰西县| 平果县| 鹤壁市| 莲花县| 陕西省| 深圳市| 定陶县| 德化县| 南通市| 兴宁市| 定陶县| 兴化市| 昌乐县| 和平区|