當前位置:首頁 » 操作系統 » nginx源碼分析

nginx源碼分析

發布時間: 2023-04-07 22:31:21

Ⅰ nginx host$1指的是什麼

是這樣衫茄子或沒察的,nginx的ngx_http_variables.c文件中對於nginx內置的http變數進行了定義。
從nginx的源碼來分析,修改headers_in中的host成員是不察含會修改$host變數的值的。
如下是nginx的代碼:
{
ngx_string("http_host"),
NULL,
ngx_http_variable_...

Ⅱ 從剛剛「簡書」平台的短暫異常,談Nginx An error occurred報錯~

An error occurred.

Sorry, the page you are looking for is currently unavailable.

Please try again later.

If you are the system administrator of this resource then you should check theerror log for details.

Faithfully yours, nginx.

如上,剛老徐正打算上平台,寫文章,出現如上錯誤,應該持續了幾分鍾~不知道有多少用戶有感知,平台響應還不錯,幾分鍾後已恢復正常~

一般nginx的此類報錯,原因如下(當然,老徐對nginx了解不深,如下都是一些可能原因)

出現問題,首先是去分析nginx的日誌,得到一些線索~

可能的常見原因:

/ 1 /

很明顯這是一個nginx的錯誤,查看nginx.conf的文件過程中分析可能是以下行族的問題,在nginx.xml中胡帶悶有如下配置:

標紅的部分是很大的嫌疑,恰好應用中在提交數據的一瞬間和伺服器有多次交互,這些交互都要過nginx。再加上用戶IP來做key,假如多個用戶訪問在網上的最後一跳是同一個路由器,很顯然會被伺服器當成是一台電腦,從而出現判斷錯誤。那麼又一個新問題來了,出現503錯誤後為啥返回的是那個錯誤頁面呢?

帶著這個問題在nginx.conf中又發現了一段配置,如下圖:

這個配置的意思是當出現500、502、503、504的錯誤時返回50x.html頁面,這個頁面在nginx安裝目錄的html文件夾下,內容如下:

這個頁面經過瀏覽器解析就是開頭第一幅圖的樣子。

分析到這褲彎里,就大概估計出原因了,把之前的rate值該大一點即可。那麼到底改多大?這個要根據不同的業務而定,甚至去掉這個配置,所以這個是個經驗值,通過多次試驗可以得到一個相對於應用合理的值,這里就不說了。

實際nginx出現這個錯誤原因應該有很多,這里提供一種可能原因,以供網友參考。

/ 2 /

日誌記錄中HTTP狀態碼出現499錯誤有多種情況,我遇到的一種情況是nginx反代到一個永遠打不開的後端,就這樣了,日誌狀態記錄是499、發送位元組數是0。

老是有用戶反映網站系統時好時壞,因為線上的產品很長時間沒有修改,所以前端程序的問題基本上可以排除,於是就想著是Get方式調用的介面不穩定,問了相關人員,說沒有問題,為了拿到確切證據,於是我問相關人員要了nginx伺服器的日誌文件(awstats日誌),分析後發現日誌中很多錯誤碼為499的錯誤,約占整個日誌文件的1%,而它只佔全部報錯的70%左右(全部報錯見下圖),那麼所有報錯加起來就要超過1%了,這個量還是特別大的。

499錯誤是什麼?讓我們看看NGINX的源碼中的定義:

ngx_string(ngx_http_error_495_page), /* 495, https certificate error */

ngx_string(ngx_http_error_496_page), /* 496, https no certificate */

ngx_string(ngx_http_error_497_page), /* 497, http to https */

ngx_string(ngx_http_error_404_page), /* 498, canceled */

ngx_null_string,                    /* 499, client has closed connection */

可以看到,499對應的是 「client has closed connection」。這很有可能是因為伺服器端處理的時間過長,客戶端「不耐煩」了。

Nginx 499錯誤的原因及解決方法

打開Nginx的access.log發現在最後一次的提交是出現了HTTP1.1 499 0 -這樣的錯誤,在網路搜索nginx 499錯誤,結果都是說客戶端主動斷開了連接。

但經過我的測試這顯然不是客戶端的問題,因為使用埠+IP直接訪問後端伺服器不存在此問題,後來測試nginx發現如果兩次提交post過快就會出現499的情況,看來是nginx認為是不安全的連接,主動拒絕了客戶端的連接.

但搜索相關問題一直找不到解決方法,最後終於在google上搜索到一英文論壇上有關於此錯誤的解決方法:

proxy_ignore_client_abort on;

Don』t know if this is safe.

就是說要配置參數 proxy_ignore_client_abort on;

表示代理服務端不要主要主動關閉客戶端連接。

以此配置重啟nginx,問題果然得到解決。只是安全方面稍有欠缺,但比總是出現找不到伺服器好多了。

還有一種原因是 我後來測試發現 確實是客戶端關閉了連接,或者說連接超時 ,無論你設置多少超時時間多沒用 原來是php進程不夠用了 改善一下php進程數 問題解決

/ 3 /

今天網站突然出現如下錯誤:

The page you are looking for is temporarily unavailable.Please try again later.

很奇怪,我對伺服器端的技術不是很熟悉,於是查詢了下google,在https://wiki.archlinux.org/index.php/Nginx

上面的解決方法:

Error: The page you are looking for is temporarily unavailable. Please try again later.

This is because the FastCGI server has not been started.

如何解決呢?

剛開始我懷疑是不是nginx掛了,我首先通過 ps aux | grep nginx ,結果出現:

root      3769  0.0  0.0   5760   692 ?        Ss   Apr21   0:00 nginx: master process /usr/local/nginx/sbin/nginx

www       3770  0.0  0.1  18680 14252 ?        S    Apr21   0:03 nginx: worker process

www       3771  0.0  0.1  18680 14252 ?        S    Apr21   0:03 nginx: worker process

www       3772  0.0  0.1  18712 14276 ?        S    Apr21   0:03 nginx: worker process

www       3774  0.0  0.1  18680 14248 ?        S    Apr21   0:03 nginx: worker process

www       3776  0.0  0.1  18712 14240 ?        S    Apr21   0:03 nginx: worker process

www       3777  0.0  0.1  18680 14252 ?        S    Apr21   0:03 nginx: worker process

www       3778  0.0  0.1  18680 14232 ?        S    Apr21   0:02 nginx: worker process

root     24068  0.0  0.0   5196   756 pts/1    S+   14:33   0:00 grep nginx

可見nginx是正常的,本來打算重啟nginx的:

/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf的,

突然覺得有沒有其他方法,有同事提示先在一個目錄下運行下test.html和test.php,結果html可以運行,php無法運行。

證實是php沒有啟動,我剛才也檢測過php的進程,的確是沒有php進程,這台伺服器我不熟悉,同事幫忙查看了下

cd /etc/init.d,就是web管理員經常看的地方,是隨著系統自動啟動的服務,程序等。可以看看:

http://blog.wgzhao.com/2008/12/27/talk-about-rc-local.html的《 說說? /etc/rc.d/rc.local 》

找到:

/usr/local/php/sbin/php-fpm start,首先什麼是php-fpm呢?

就是FastCGI Process Manager,是一種可選的PHP FastGCI執行模式,有一點很有特點的應用,尤其是一個繁忙的網站中:

(1)可適應的進行再生(NEW!)

(2)基本的統計功能(Apache's mod_status)

(3)高級進程管理功能,能夠優雅的停止/開始

(4)能夠使用不同的工作用戶和不同的php.ini

(5)輸入,輸出日誌記錄...

開啟後,一切恢復正常!自己的伺服器端技術還是有很多地方使用的不夠。需要多學習使用!

總結:

1、試檢查一下nginx.conf的設置,是不是有limit的設置,比如limit_zone、limit_conn,這些參數也是有影響的。

2、檢查一下防火牆,是不是有相關的設置限制。

3、檢查一下nginx.conf的設置,看看有沒有valid_referers none blocked的防鏈設置。

4、看下訪問靜態文件是否正常,錯誤排除~

OK,如上只是一些猜測~

具體原因,具體分析~

越來越多的系統,採用nginx,大家有必要了解些nginx的知識~

Ⅲ 伺服器程序源代碼分析之二:php-fpm

php作為排名top2 互聯網開發工具,非常流行,可以參考:中國最大的25個網站採用技術選型方案

php這個名稱實際上有兩層含義

直接定義:

php-fpm從php5.3.3開始已經進入到php源代碼包,之前是作為patch存在的

很少人會去讀php本身源代碼,我6年前解決php內存泄露問題的時候做了些研究,最近再查看了一番,發現php的開發者很有誠意,這是一款非常出色的伺服器軟體,支持如下

在linux伺服器上,如果不設置 events.mechanism ,那麼默認就是採用epoll,所以

php-fpm的IO模型&並發處理能力和nginx是完全一致

nginx以性能卓越聞名,大部分程序員都認為php效率低下,看了源代碼,才知道這是傳奇啊

在高性能部署的時候,大家往往會針對性的優化nginx 。我自己之前部署php程序也犯了錯誤,8G內存的server,php-fpm的max children都會設置128+,現在看來太多了,參考nginx的部署:

php-fpm配置為 3倍 cpu core number就可以了

php-fpm穩定性比nginx稍差 這是因為php-fpm內置了一個php解析器,php-fpm進程就和php程序捆綁了,如果php腳本寫得不好,有死循環或者阻塞在某個遠端資源上,會拖累載入它的php-fpm進程

而nginx和後端應用伺服器之間通過網路連接,可以設置timeout,不容易堵死的

php-fpm的fastcgi是短連接 我原以為是長連接的,看了代碼才知道也是短連接,處理一個request就關閉掉

php-fpm介面採用fastcgi 非常遺憾,php-fpm和fastcgi完全綁定了,無法獨立使用 。只能部署在支持http-fcgi協議轉換程序背後(nginx)。其實可以考慮在php-fpm代碼包裡面引入http協議支持,這樣php-fpm可以獨立運行,讓nodejs無話可說

php-fpm等同於OpenResty OpenResty是一個國人開發的nginx模塊,就是在nginx引入lua解釋器. 實際上,它和php-fpm的唯一差別就是一個採用php語法,一個用lua,所以OpenResty要作為nginx增強包使用還可以,要選擇它作為一個主要編程工具,沒有任何必要

從架構上來說,php-fpm已經做到最好,超過大多數 python部署工具,我再也不黑它了

Ⅳ nginx 源代碼分析 (一)

ngx_pool_t提供內存分配介面。

ngx_pool_t對大塊內存和小塊內存的分配使用不同的策略。

對於大塊內存(超過指定閾值,一般是內存的頁大小4096),調用malloc()動態分配。

對於小塊內存,則是先預分配大的內存塊,然後根據需要從中動態分配小塊的。

ngx_create_pool()創建這個單向鏈表的第一個元素。

ngx_palloc()從指定的ngx_pool_t實例中分配內存。如果要求大塊內存,則調用ngx_palloc_large(),否則調用ngx_palloc_small()。

對於ngx_palloc_small(),

對於ngx_palloc_large(),

ngx_free()負責釋放內存。它只是調用free()釋放大塊嫌肆叢內存。實際上小塊內存是不能一個一個釋放的,nginx的策略是釋放就釋放全部。

ngx_reset_pool()釋放所有大塊內存,將ngx_pool_t鏈表置於未使用狀態。

ngx_destroy_pool()釋放所有大塊內存,雹信也釋芹櫻放ngx_pool_t鏈表自身佔用的內存。

nginx_pool_t還用於保存「待清理的任務」,這個任務保存在ngx_pool_cleanup_t結構中,從預分配內存中分配。這也是一個單向鏈表,保存在ngx_pool_t的成員cleanup中。

ngx_pool_cleanup_t的成員handler是任務的處理函數,成員data是處理函數的參數。

ngx_array_t實現了數組。

ngx_array_create()創建數組。

ngx_array_push()從數組中得到一個可用的元素。

ngx_list_create()實現單向鏈表。與一般鏈表不同的是,它的鏈表中每一個元素中保存的是一個數組。下圖是包含兩個ngx_list_part_t元素的鏈表。

ngx_list_create()創建一個鏈表。

ngx_list_push()從鏈表中得到一個可用的位置。

ngx_queue_t是一個雙向鏈表。

使用ngx_queue_t的方式是,在結構中包含ngx_queue_t,就可以把結構串聯起來。如下面的示意圖。

ngx_queue_data()可以根據ngx_queue_t成員在結構中的位置偏移,從成員地址計算結構地址。

ngx_rbtree_t實現紅黑樹,ngx_rbtree_node_t是樹上的節點。

對於ngx_rbtree_node_t,

對於ngx_rbtree_t,

Ⅳ nginx-rtmp模塊簡介

1:  Mole Configuration Struct(s)模塊配置結構

這個結構的命名規則為ngx_http_[mole-name]_[main|srv|loc]_conf_t。

main,srv,loc表示這個模塊的作用范圍是配置文件中的main/server/location三種范圍(這個需要記住,後面會經常用到)

2: Mole Directives模塊命令結構

static ngx_command_t ngx_http_echo_commands[] = {

{

ngx_string("echo"), //命令名字

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, //代表是local配置,帶一個參數

ngx_http_echo, //組裝模塊配置結構

NGX_HTTP_LOC_CONF_OFFSET, //上面的組裝模塊配置獲取完參數後存放到 哪裡?使用這個和下面的offset參數來進行定位

offsetof(ngx_http_echo_loc_conf_t, ed), //同上 

},

ngx_null_command //必須使用ngx_null_command作為commands的結束標記

};

3: The Mole Context模塊內容

static ngx_http_mole_t   ngx_http_circle_gif_mod ule_ctx

主要是定義了一些鉤子函數, nginx會在不同時期會調用

4: The Mole Definition模塊整合

ngx_mole_t ngx_http_<mole name>_mole = {

NGX_MODULE_V1,

&ngx_http__mole_ctx, /* mole context模塊內容 */

ngx_http__commands, /* mole directives模塊命令*/

NGX_HTTP_MODULE, /* mole type模塊類型,HTTP模塊,或者HTTPS*/

5: Mole Installation模塊安裝

1: ngx_rtmp_live_mole

直播模塊:推拉流同點, 不涉及回源

2: ngx_rtmp_relay_mole

中繼模塊:  1:回源pull  2: 轉推: push

一:  建立rtmp連接, 需要握手

      1: ngx_rtmp_handshake_recv()開始握手

      2: NGX_RTMP_HANDSHAKE_DONE()握手完成

      3: ngx_rtmp_cycle()重新設置讀寫handler

二:  建立網路連接

    建立rtmp連接之後, ngx_rtmp_recv函數會利用ngx_event_t結構會獲取推送過來的原始數據, 接受到的數據會存放到ngx_rtmp_stream_t的in鏈表結構中.

1:接受chunk數據

2:分析處理chunk數據, 如果message還沒接受完, 繼續接受數據

3:將chunk組成一個rtmp message, 然後交給ngx_rtmp_receive_message處理, 這個函數根據消息的類型找對應的handle

三:  建立網路流

        在建立網路連接後,就需要建立網路流了, 網路流代表了發送多媒體數據的通道. 伺服器和客戶端只能建立一個網路連接, 且多個網路流可以復用這一個網路連接

1: ngx_rtmp_recv接受數據後交給ngx_rtmp_receive_handler, 它會根據類型區別處理, 此時客戶端發送ngx_rtmp_msg_chunk_size類型的消息

2:接受message後跳轉到處理函數ngx_rtmp_amf_message_handler. 處理客戶端發送的amf控制消息. 此時連續接受3個amf數據.

3:調用ngx_rtmp_cmd_create_stream_init初始化網路流. 利用ngx_rtmp_receive_amf獲取接受的amf數據.

4:調用ngx_rtmp_cmd_create_stream創建網路流, 利用ngx_rtmp_send_amf向客戶端發送amf控制消息

四:  傳輸媒體數據

在客戶端和服務端建立網路流之後,接下來就可以傳輸媒體數據了, 一般來講, 媒體數據分為兩部分, 一部分為meta元信息, 另一部分是音視頻數據, 首先傳送的是meta元信息. 然後推送媒體. 伺服器處理如下:

1:從客戶端接受amf命令信息, 然後服務端會利用ngx_rtmp_cmd_publish_init來初始化發布環境.  函數功能: 會讀取剛接受端amf信息

2:利用ngx_rtmp_auto_push_publish, ngx_rtmp_notify_publish, ngx_rtmp_exec_publish建立發布環境,

3:如果conf配置了record命令記錄媒體文件, 此時會調用ngx_rtmp_record_publish來初始化記錄環境;

4:執行ngx_rtmp_access_publish;

[if !supportLists]l [endif]meta信息:

5:接受客戶端amf, 並調用ngx_rtmp_codec_meta_data獲取meta元信息;

6:結合伺服器的參數, 利用ngx_rtmp_codec_reconstruct_meta介面重構meta元信息, 並調用ngx_rtmp_prepare_message組成消息保存

[if !supportLists]l [endif]媒體數據:

7:接受客戶端推送, 根據類型轉到ngx_rtmp_codec_av來處理音視頻數據; 其中利用函數ngx_rtmp_codec_parse_avc_header來處理頭部信息

8:調用record模塊記錄數據, 介面為ngx_rtmp_codec_av;

9:調用live模塊來廣播發布數據, 介面為ngx_rtmp_live_av, 廣播到所有觀察者, 第一次調用介面ngx_rtmp_live_start創建廣播, 之後直接調用ngx_rtmp_append_shared-bufs

 

rtmp 的 信令交互圖:

1: 播放器端發起play

2: ngx_rtmp_relay_play()

3: ngx_rtmp_relay_pull() --主要建立pull請求, 將遠程拉流的上下文和本地上下文放到鏈表中

    ngx_rtmp_relay_create_local_ctx()創建本地上下文

    ngx_rtmp_relay_create_remote_ctx()創建遠端上下文

4: ngx_rtmp_relay_create_remote_ctx詳解:  創建遠端session, 開始rtmp信令交互

       1: ngx_rtmp_relay_create_connection  

        2: ngx_rtmp_init_session

注意:此時session中的flashver為「ngx-local-relay「

5: rtmp信令交互流程

核心函數: ngx_rtmp_relay_on_result主要用來接收對端服務端發送的amf消息包,而後按正常rtmp協議請求進行下一步交互,這個主要是當前服務端做為客戶端發起遠程rtmp請求流程

例如:   ngx_rtmp_client_handshake(發起握手)

         握手完成後調用回調函數: ngx_rtmp_relay_handshake_done

       ngx_rtmp_relay_send_connect:發起連接請求, 接著參考rtmp信令交互圖

        核心功能:向nginx推送一個直播流,該直播流經 nginx-rtmp 的 ngx_rtmp_live_mole 模塊轉發給 application live 應用,然後使用vlc連接 live,播放該直播流。本質上就是1對多的廣播

參考: http://nginx.org/en/docs/debugging_log.html

1: Nginx-rtmp-mole模塊源碼學習

https://blog.evanxia.com/2017/02/1264

2: nginx_rtmp_relay_mole模塊解讀

https://www.shangmayuan.com/a/d74b78669f804fb5b12cae5a.html

3:開發手冊中文版:包含指令介紹

https://blog.csdn.net/ai2000ai/article/details/55517992

Ⅵ Nginx rtmp 推流(publish) 解析

系列文章:
Nginx rtmp 拉流播放(play)_fdsafwagdagadg6576的專欄-CSDN博客
Nginx rtmp 拉流(轉發pull)_fdsafwagdagadg6576的專欄-CSDN博客
Nginx rtmp 轉推_fdsafwagdagadg6576的專欄-CSDN博客
Nginx rtmp 點播流模攜簡隱渣程_fdsafwagdagadg6576的專欄-CSDN博客

1 整體結構圖:

先建立信令,然後接收媒體

2 流程圖旦褲

4 源碼分析:

**ngx_rtmp_relay_publish(ngx_rtmp_session_t s, ngx_rtmp_publish_t v)

**s->relay **

**接收流媒體 **

Ⅶ 07《Nginx 入門教程》Nginx 的 Http 模塊介紹(上)

本部分內容將詳細介紹 Nginx 中對 Http請求的 11 個處理階段,分成 3 個小節講解並進行相關實驗操作。

Nginx 將一個 Http 請求分成多個階段,以模塊為單位進行處理。其將 Http請求的處理過程分成了 11 個階段,各個階段可以包含任意多個 Http 的模塊並以流水線的方式處理請求。這 11 個 Http 階段如下所示:

網上有人做了一個非常形象的圖片,如下圖所示。我們可以看到 11 個階段的處理順序,以及每個階段中涉及到的相關模塊以及模塊之間的順序。

POST_READ 階段是 Nginx 接收到 Http 請求完整頭部後的處理階段,這里主要使用的是 realip 模塊獲取用戶的真實地址,方便後續對該 IP 進行限速或者過濾其請求等。

SERVER_REWRITE 和後面的 REWRITE 階段一般是使用 rewrite 模塊修改 Http請求的 uri,實現請求的控制。

FIND_CONFIG 階段只是做 location 的匹配項。

PREACCESS、ACCESS 和 POST_ACCESS 是和 Http 請求訪問許可權相關的階段。PREACCESS 階段是在連接之前要做的訪問控制, 這個階段有 limit_conn 和 limit_req 等模塊工作。ACCESS 階段是解決用戶能不能訪問,比如根據用戶名、密碼限制用戶訪問(auth_basic 模塊)、根據 ip 限制用戶訪問(access 模塊)以及第三方模塊認證限制用戶的訪問(auth_request模塊)。POST_ACCESS 是在 ACCESS 之後要做的一些工作。

TRY_FILES 階段為訪問靜態文件資源而設置的。有時候又稱之為 PRECONTENT 階段,即在 CONTENT 階段之前做的事情。主要是 try_files 模塊在此階段工作。

最重要的 CONTENT 是處理 Http 請求內容的階段,大部分 HTTP 模塊介入這個階段,比如 index、autoindex、concat 以及反向代理的模塊都是在這里生效的。

LOG 是處理完請求後的日誌記錄階段,如 access_log 模塊。

realip 模塊是在 postread 階段生效的,它的作用是: 當本機的 nginx 處於一個反向代理的後端時獲取到真實的用戶 ip。 如果沒有 realip 模塊,Nginx 中的 $remote_addr 可能就不是客戶端的真實 ip 了,而是代理主機的 ip。
realip模塊的配置實例如下:

set_real_ip_from 是指定我們信任的後端代理伺服器,real_ip_header 是告訴 nginx 真正的用戶 ip 是存在 X-Forwarded-For 請求頭中的。

當 real_ip_recursive 設置為 off 時,nginx 會把 real_ip_header 指定的 Http頭中的最後一個 ip 當成真實 ip;

而當 real_ip_recursive 為 on 時,nginx 會把 real_ip_header 指定的 Http頭中的最後一個不是信任伺服器的 ip (前面設置的set_real_ip_from)當成真實 ip。通過這樣的手段,最後拿到用戶的真實 ip。

rewrite 模塊可以看到它在 SERVER_REWRITE 和 REWRITE 階段都有介入。rewrite 模塊的主要功能是改寫請求的 uri。它是 Nginx 默認安裝的模塊。rewrite 模塊會根據正則匹配重寫 uri,然後發起內部跳轉再匹配 location, 或者直接做30x重定向返回客戶端。rewrite 模塊的指令有 break, if, return, rewrite, set 等,這些都是我們常用到的。

return 指令返回後,Http 請求將在 return 的階段終止,後續階段將無法進行,所以許多模塊得不到執行。

1、將 regex 指定的 url 替換成 replacement 這個新的 url,可以使用正則表達式及變數提取。

2、當 replacement 以 http:// 或者 https:// 或者 $schema 開頭,則直接返回 302 重定向

3、替換後的 url 根據 flag 指定的方式進行處理

if 指令的條件表達式:

location 匹配是在 FIND_CONFIG 階段進行的,我們需要掌握 location 的匹配規則和匹配順序。

有一個簡單總結如下:

即:

realip 模塊默認沒有被編譯進 Nginx 的,我們需要在源碼編譯階段使用–with-http_realip_mole,將 realip 模塊編譯進來後方可使用。接下來,我們做個簡單測試,首先准備一個 server 塊如下:

首先,我們將 real_ip_recursive 設置為 off,然後做一次請求:

這里返回的是頭部參數 X-Forwarded-For 中最後一個 ip,如果將 real_ip_recursive 設置為 on,此時,由於 set_real_ip_from 中設置218.19.206.164為信任的方向代理 ip,那麼 Nginx 會往前找一位,認為 1.1.1.1 是用戶的真實ip。

我們寫一個簡單配置如下:

先測試if指令,當請求方法為 POST 時,我們能得到 『post request!』 這樣的字元串輸出。GET 請求時候,針對 404 情況,會跳轉到/403.html,我們准備一個 403.html 頁面,裡面寫上』403, forbidden!』 這一行內容,開始下面的 Http 請求:

如果我們打開 return 405 這行指令,則 error_page 將不會生效,連同後面的 location 匹配也不會生效。無論我們發送如何請求,都會返回405的錯誤信息。這是因為 server 中的 return 指令是在 SERVER_REWRITE中執行的,而 location 匹配則是在下一個階段 FIND_CONFIG 中執行的,所以上一個階段在 return 後,根本不會進入後面的階段執行。

首先,我們准備環境,首先是新建一個目錄 third(全路徑為/root/test/third),再該目錄下新建一個文件 3.txt, 裡面只有一行內容 『hello, world』。接下來,我們准備一個 server 塊,加到 Http 指令塊中:

上述配置中,要打開 rewrite_log指令,這樣我們可以看到 rewrite 指令的相應日誌,方便查看結果。

當我們在 /second 配置中,使用 break 時,請求命令:

如果是不使用 break 標識,則請求結果如下:

首先是 /first/3.txt 請求在 /first 中匹配,並被替換為 /second/3.txt, last 標識表示將繼續進行匹配,在 /second 中,uri 又被 rewrite 成 /third/3.txt, 如果後面跟了 break 標識,表示 rewrite 到此結束,不會執行後面的 return 指令,直接請求靜態資源 /third/3.txt,得到其內容』hello, world』;如果是沒有 break 標識,則會在執行 return 指令後直接返回,並不會繼續執行下去,最後返回』second!'字元串。

我們按照這樣的 location 規則,進行匹配實驗,結果如下:

這里介紹了 Nginx 處理 Http 請求的 11 個階段,並重點介紹了 前三個階段POST_READ、REWRITE以及FIND_CONFIG以及這些階段中涉及到的模塊和指令。前面講到的指令都是 Nginx 中的高頻指令,必須要熟練掌握。

Ⅷ nginx動態域名解析

原文鏈接:
https://priesttomb.github.io/%E6%8A%80%E6%9C%AF/2020/05/17/nginx-cached-dns-server-resolvered-answer/

接 上篇文章 中提到的 Nginx 解析域名地址的問題,用一句話描述就是「proxy_pass 中如果配置的是域名地址,Nginx 只有在 start / restart / reload 時,才會連接一次域名伺服器解析域名,緩存解析的結果,後續則 不會根據解析結果的 TTL 進行自動更新 」,如果遇到了域名地址配置有多個 IP ,且還在動態變化,那就會出現 Nginx 把請求轉發到一個過期的 IP 地址的情況,連接超時的報錯日誌類似這樣:

這個說法在 官方的一篇 2016 年的博客 中有提到:

除此之外,除了一些分析源碼的網路文章,暫時還沒有找到其他的官方文檔中說到這個細節

在 upstream 中可以對上游的伺服器進行更詳細的設置,解決 DNS 緩存的問題可以在 upstream 中指定需要的負載均衡演算法,比如 least_conn ,並指定 max_fails ,以實現調用失敗 N 次之後判定該服務異常,暫停轉發該服務

註:

這個配置的示例是官方博客中的,看到這個配置時覺得有點鬧明奇怪,自己進行了模擬測試,測試的方案是在 hosts 文件中配置一個模擬的域名與三個 IP 地址,其中兩個 IP 是正確的,另一個是內網不存在的 IP,測試的結果就是 Nginx 始終會將請求轉發到那個錯誤的 IP 去,日誌中一直能看到超時的報錯,配置的 max_fails 彷彿沒有任何作用(有補充配置了 fail_timeout ,也嘗試配置了 proxy_next_upstream 、 proxy_next_upstream_timeout 和 proxy_next_upstream_tries )

不清液者告楚用 hosts 配置的方式是不是必然會出現這樣的情況,因為目前沒條件測試真正想要的場景,所以不敢說博客中的這種配置是錯的【如果以後碰巧有條件能測試驗證,再回頭來更新

最初學習 Nginx 的時候測試過 max_fails 這個配置,當時在 upstream 里配置的都是一些 IP 地址的上游服務。再次按 IP 地址進行測試,在 upstream 中配置兩個正確的 IP 地址 和一個錯誤的 IP 地址,發現這樣的配置就是能生效的,失敗一定次數之後(實際失敗的次數比設置的 max_fails 多,不清楚什麼原因),Nginx 在 fail_timeout 時間內就不再轉發請求到那個錯誤的 IP

resolver 的配置詳情可看 官方文檔 ,示例的配置是指定 DNS 伺服器 10.0.0.2,指定 DNS 解析的有效時間為 10 秒,按博客 《Nginx動態解析upstream域名》 中博主的測試,不是說 Nginx 每過 10 秒會自己重新調一次 DNS 解析,而是嫌埋有請求轉發時才檢驗一次有效期是否過期

不配置 valid 選項時,V1.1.9 之後的 Nginx 默認會使用 DNS 解析結果中的 TTL

在 proxy_pass 中使用變數,帶來的作用就是在 TTL 過期時能再次調用 DNS 解析,從而解決一直使用緩存結果的問題

這大概是目前官方原版唯一解決 DNS 緩存的解決方案了,帶來的弊端也如 《Nginx動態解析upstream域名》 的博主所說,不能使用 upstream 模塊特有的相關配置

Nginx Plus 版有更好的配置解決這些問題,另外使用 Lua 插件或許也能更完美的解決這個問題,暫時就沒什麼研究了

Ⅸ [code.nginx] Nginx的時間管理

在Linux平台上獲取系統時間的方法有很多,比如使用time()函數、gettimeofday()函數和localtime()函數等,大部分函數本質上都是通過系統調用來獲取時間的。但是使用系統調用時,有一個問題需要特別關注,就是系統調用開銷的問題。

Nginx伺服器程序在獲取系統時間時,本質上使用的是gettimeofday函數,該函數是C語言庫提供的函數,從嚴格意義上來講,該函數不也是系統調用,但它是對系統調用sys_gettimeofday()的封裝,因此一般也就認為它是一個系統調用了。
大家都知道,Linux平台上程序函數調用可以分為庫調用和系統調用兩大類,這里不過多的解釋這兩種機制的不同,主要是明確系統調用與庫調用相比,時間成本是相當巨大的。程序執行一次系統調用將至少經過一下步驟:

在Linux平台上使用C語言進行程序設計時,為了精確獲取系統時間,我們經常會使用gettimeofday()這個函數。該函數的原型為:

調用該函數後,當前的時間將用timeval結構體返回,時間可以精確到微秒。當地時區的信息則放在timezone結構體中。timeval結構體的定義為:

gettimeofday()函數在執行過程中,一般情況下實際上是調用了另一個函數sys_gettimeofday(),該函數才是名副其實的系統調用,通過該調用就可以獲取保存在系統內核中的時間信息。在實際程序設計中是不提倡頻繁使用gettimeofday()函數的。
vsyscall方式在內存中創建了一個內核態的共享頁面,它的數據由內核來維護,但這塊區域用戶態也有許可權訪問,通過這樣的機制,不經過系統中斷和陷入內核也能獲取一些內核信息。x86_64體繫上使用vsyscall方式實現了gettimeofday()的功能,這樣系統開銷比普通的系統調用要小的多。

Nginx伺服器重視程序的高效運行,Nginx程序採取緩存時間的方法來減少對gettimeofday()的調用,並且每個工作進程會自行維護時間緩存。Nginx的時間緩存一般會賦值給一下四種變數,更新緩存時是同步更新的。

Nginx伺服器更新時間緩存的兩個函數是ngx_time_update()和ngx_time_sigsafe_update(),具體的實現的源碼都在/nginx/src/core/ngx_time.c中可以找到。我們分別來分析一下它們的源碼。
1.ngx_time_update()
該函數是Nginx伺服器時間管理的核心函數。更新時間緩存的過程實際上是一個寫緩存的過程,Nginx伺服器為了解決信號處理過程中更新時間緩存產生的數據一致性的問題,需要使用原子變數ngx_time_lock進行寫加鎖。

2.ngx_time_update()的調用
該函數的調用時機主要有三個:一是在Nginx伺服器主進程捕捉、處理完一個信號返回的時候。二是在緩存索引管理進程中調用該函數,用於標記緩存數據的時間屬性。三是在Nginx伺服器工作進程中在進行事件處理時調用了該函數。主要是第三種情況對該函數的調用頻率較高。
epoll_wait()函數用於等待事件的產生,執行epoll_wait()函數返回後會調用ngx_time_update()函數更新時間緩存。當epoll機制通知有事件到達或者epoll機制超時退出時,Nginx伺服器程序就會更新一次緩存時間。然後調用各個事件對應的處理函數處理事件。

指令timer_resolution用於設置執行兩次緩存時間更新工作之間的間隔時間。該參數設置的越大,則對系統調用gettimeofday()的使用頻率就越低,但緩存時間的精度也就越低。該指令的語法結構為:

其中的Interval參數就是更新時間間隔,默認值為100ms。該指令只能在Nginx配置文件的全局塊中進行設置。

熱點內容
內置存儲卡可以拆嗎 發布:2025-05-18 04:16:35 瀏覽:336
編譯原理課時設置 發布:2025-05-18 04:13:28 瀏覽:378
linux中進入ip地址伺服器 發布:2025-05-18 04:11:21 瀏覽:612
java用什麼軟體寫 發布:2025-05-18 03:56:19 瀏覽:32
linux配置vim編譯c 發布:2025-05-18 03:55:07 瀏覽:107
砸百鬼腳本 發布:2025-05-18 03:53:34 瀏覽:944
安卓手機如何拍視頻和蘋果一樣 發布:2025-05-18 03:40:47 瀏覽:741
為什麼安卓手機連不上蘋果7熱點 發布:2025-05-18 03:40:13 瀏覽:803
網卡訪問 發布:2025-05-18 03:35:04 瀏覽:511
接收和發送伺服器地址 發布:2025-05-18 03:33:48 瀏覽:372