Skip to content

深入理解 Nginx 讀書筆記 (第二章)

Tags:

進程間的關係

  • Nginx 支持僅單進程(master)提供服務
  • 常態的部署是使用一個 master 進程來管理多個 worker 進程
  • Worker 數量與 CPU 核心數相等,進程切換代價最小

使用多進程的好處

  1. master 進程僅專注於純管理工作,為管理員提供命令行服務(啟動、停止、重配置、升級)
  2. master 進程需要比較大的權限,通常會以 root 使用者啟動
  3. 一個 worker 進程出錯後,其他 worker 仍然可以正常服務
  4. 充分利用 SMP(Symmetric multiprocessing) 多核架構,實現微觀上真正的多核併發處理
  5. Worker 通常不會進入睡眠狀態:可以同時處理多個請求,不像 Apache 每個進程只能同時處理一個請求,以致進程切換代價大

配置語法

每個模組都有自己感興趣的配置項,大部分模組都必須在 nginx.conf 中讀取到某個配置後才會啟用,例如只有當配置 http {…} 時, ngx_http_module 模組才會啟用,其他依賴的模組也才能正常使用

區塊配置項

  • 由名稱及一對大括號組成,如 http, server, location 都屬於區塊配置項
  • 傳入的參數取決於解析這個區塊配置項的模組
  • 大括號表示包含其中的配置同時生效
  • 可以嵌套,內層配置直接繼承外層
  • 當內外層配置發生衝突,以哪層配置為準,取決於解析這個區塊配置項的模組,例如範例的 gzip 開關

配置項語法格式

  • 名稱必須合法的(是某個 Nginx 模組想要處理的)
  • 傳入的參數取決於解析這個區塊配置項的模組
  • 若任一參數包含空格符,須要用單引號或雙引號包住
  • 以分號結尾

通用計算單位

  • 空間: K | k | M | m
  • 時間: ms | s | m | h | d | w | M | y

前提是解析配置的模組使用了 Nginx 特定的解析方法,才能解析單位

使用變數

  • 許多模組解析請求時都會提供多個變數,如 remote_addr, request
  • 使用要帶上 $ 前綴
  • 在配置項使用這些變數,只有少數模組支援,並非通用的作法

基本配置

  • 配置可以依照功能區分為四種:1) 用來調整進程,定位問題的相關配置 2) 運行相關配置 3)優化性能相關的配置 4) 事件相關的配置
  • 有些配置項即使沒有明確配置,仍會套用默認值,如 daemon

用來調整進程,定位問題的相關配置

  • daemon: 守護進程,脫離終端於背景運行的,避免進程被終端的訊號打斷;在 debug 及研究 Nginx 時設為 off 非常有用
  • master_process: 是否以多進程服務
  • error_log: 設定日誌,須注意磁碟空間是否能應付所選的 level (預設為 error)
  • debug_connection: 實屬事件類配置,參數為 IP 或 CIDR,只有請求來自於批配的地址,才會輸出日誌,在高併發請求下定位特定請求很有幫助

如果日誌級別設為 debug,需要在 ./configure 時加上 –with-debug

  • worker_rlimit_core: 限制可儲存的核心傾印(coredumps)大小
  • working_directory:worker 進程的工作目錄,唯一的用途是用來指定 coredump 的目錄

運行相關配置

  • env:用來直接設置系統的環境變數
  • include: 將其他配置文件引入當前的 nginx.conf,可以是絕對或相對路徑,即 /usr/local/nginx/conf
  • pid: master 進程 ID 的 pid 文件存放路徑
  • user: 定義 worker 進程以哪個 user 及 group 的身份運行
  • worker_rlimit_nofile: 定義一個 worker 能打開最大檔案描述符(file descriptor)數
  • worker_rlimit_sigpending: 限制單一客戶端發送的信號佇列大小

優化性能相關的配置

  • worker_process_number: 定義 worker 數量

每個 worker 都是單執行緒,它會調用各個模組來實現不同功能。如果確認調用這些模組不會出現阻塞,則 worker 數量應該等於 CPU 核心數;如果調用會出現阻塞,應配置稍多一點 worker。例如,如果業務方面會導致使用者請求大量靜態文件,且伺服器內存較小,以致大部分請求都必須訪問磁碟,而不是內存中的磁碟緩存,那麼磁碟 I/O 的調用可能會造成 worker 阻塞
如果 worker 數量大於 CPU 核心數,多個 worker 都在搶同一個 CPU,會增加進程切換帶來的消耗(Linux 是搶佔式內核)

  • worker_cpu_affinity 將 worker 指定到 CPU 內核,僅在 Linux 有效(sched_setaffinity)

  • ssl_engine: 如果伺服器上有 SSL 硬體加速設備,可以透過匹配裝置加快 SSL 處理速度,可以使用 openssl engine -t 查看是否有加速設備
  • timer_resolution: 每次事件調用(epoll, select, pool, kqueue)響應時,都會執行一次 gettimeofday,用內核時鐘來更新 Nginx 的緩存時鐘;這對現今內核來說,只是一次虛擬系統呼叫(vsyscall,代價相對早期來說已經小很多,不太須要動到這個配置
  • worker_priority: 決定 worker 的 nice 優先權

當多個程序都處於可執行狀態時,本次內核執行哪個將按照各自的優先權決定,優先權越高,分配到的時間片段也越大(如最小 5ms 最大 800ms)。nice 值是靜態優先權,真正優先順序還內核還會參考執行情況做動態調整。nice 範圍是 -20(最高) ~ +19(最低),不建議設到比內核進程還優先(通常是 -5)

事件相關的配置

  • accpet_mutex: 是否打開 Nginx 的負載均衡鎖,可以讓多個 worker 輪流且序列化地與新的客戶端建立 TCP 連接;當 worker 建立的連線數接近 worker_connections ,建立新連接的機會減低
  • lock_file: 當編譯程序或作業系統導致 Nginx 不支援原子鎖,會使用文件鎖來實現 accept 鎖
  • accept_mutex_delay: 同一時間只有一個 worker 能取得 accept 鎖,當 worker 取不到,至少要等待多少時間才能再次取鎖
  • multi_accept:每當事件模型通知有新連接,盡可能對本次調度中客戶端發起的所有請求都建立連接
  • use: 使用何種事件模型,Nginx 會自動選擇,性能最高的是 epoll
  • worker_connections: 每個 worker 同時可以處理的最大連接數

靜態 Web 服務器基本配置

  • 主要功能由 ngx_http_core_module 實現
  • 配置可以依照功能區分為八種:1) 虛擬主機與分發請求 2) 文件路徑 3) 分配內存及磁碟 4) 網路連接 5) MIME 類型 6) 對請求的限制 7) 優化文件操作 8) 對請求的特殊處理

虛擬主機與分發請求相關的配置

  • server: 每個 server 塊被視為一台虛擬主機,只處理相對應的主機域名請求(透過附屬的 server_name 配置)
  • listen: 決定如何監聽端口
    • defualt_server: 當請求無法批配文件中所有主機域名,就會選用此默認的 server 區塊
    • backlog: 在建立 TCP 連接的三次握手過程中,會先將連接放置在 backlog;若已滿,往後的請求會建立失敗
    • deferred: 客戶建立完 TCP 連接,內核會等到客戶真的發送請求數據才調度 worker,以減輕 worker 負擔;適用於高併發
    • ssl: 在當前監聽的端口上建立的連接必須基於 ssl
  • server_name: Nginx 取出請求頭部的 Host,與每個 server 進行匹配,決定哪個 server 處理該請求
    • 匹配的優先順序: 1) 完全匹配 2) 前通配符,如 *.example.com 3) 後通配符,如 www.example.* 4) 正則表達式
    • 若無法匹配,則遵循順序: 1) 選擇有指定 default_server 的 server 2) 選擇第一個 server
  • server_names_hash_bucket_size: 定義每個用來存放 server_name 的散列桶的大小,加快匹配速度
  • server_names_hash_max_size: 影響散列表發生衝突的機率,值越大,散列 key 的衝突減少,消耗的內存也越大
  • server_name_in_redirect: 在重定向請求時會使用 server_name 第一個主機名稱來取代請求頭部的 Host
  • location: 根據請求的 URI 來決定哪個 location 處理該請求
    • 可以使用正則表達式
    • = 代表完全匹配; ~ 代表 case sensitive ~* 代表 case insensitive ^~: 代表匹配前段 URI; @ 代表服務內部請求的重定向,不直接處理請求
    • 有順序,第一個被匹配到的 location 優先處理
    • 使用 / 作為參數,表示匹配所有請求,放在最後可用於「如果不匹配,則…」使用情境

文件路徑相關的配置

  • root: 請求 URI 的根目錄,可以用在 http, server, location 區塊
  • alias: 與 root 的差別在於,location 的前段 URI 僅用於匹配,在磁碟映射會被棄用;因此也只能用在 location 區塊

當請求 /these/uri/will/be/discard/nignx.conf 則回傳 /usr/local/nginx/conf/nginx.conf

當請求 /test/nginx.conf 則回傳 /usr/local/nginx/conf/nginx.conf

  • index: 通常 URI 是 / 時表示訪問網站的首頁,可接多個參數,從最後一個參數開始向前匹配
  • error_page: 當某個請求返回錯誤碼,則參考此配置,重定向至新的 URI;也可在重定向後更改錯誤碼

  • try_files: 照順序訪問每一個路徑參數,如果可以有效讀取,則返回;如果找不到,就重定向到最後一個 URI 參數

分配內存及磁碟相關的配置

  • client_body_in_file_only: 請求 body 一律寫入磁碟
  • client_body_in_single_buffer: 請求 body 一律寫入內存 buffer,如果超出 client_body_buffer_size 限制,則寫入磁碟
  • cliebt_header_buffer_size: 請求頭部寫入內存 buffer 的數量及大小,若超出則分配 large_client_header_buffer_size 定義的大小,若再超出則返回 414
    • 請求中一般有多個頭部,單一個 header 不得超出單個 buffer 大小
    • 請求頭部的總和不得超過 buffer 個數 * buffer 大小
  • client_body_temp_path: 請求 body 超出 buffer 須寫入磁碟的臨時目錄,隨著文件數量會遞增子目錄,避免單一目錄文件數量過多導致性能下降
  • connection_pool_size: 每個建立成功的 TCP 連接會分配一個內存池,於連線關閉時回收;須謹慎設置,過大會使內存消耗大,過小會觸發更多次的內存分配,
  • request_pool_size: 每個請求都會分配一個內存池,用於減少內核對於小塊內存的分配次數,於請求結束時回收

網路連接相關的配置

  • client_header_timeout: 接收頭部時若超過一定時間沒有讀取到資料,則返回 408;client_body_timeout 則定義讀取 body 的超時
  • send_timeout: 響應時若客戶端超過一定時間沒有接收,則關閉連接
  • reset_timeout_connection: 超時後項客戶端發送 RST 包來重置連接,非使用正常情形的四次握手關閉,減少 FINWAIT1, FINWAIT2, TIME_WAIT 狀態的連接;使用上會造成一些問題,通常不會開啟
  • lingering_close: 關閉連接前是否處理客戶端發送的數據
  • lingering_time: 對於上傳大文件很有幫助;當用戶請求的 Content-Length 大於 max_client_body_size,會返回 413,但客戶端可能不管此返回仍繼續上傳,而超過此設置時間 Nginx 將會強制關閉連接
  • keepalive_disable: keepalive 功能讓多個請求復用一個 HTTP 長連接,可提高服務性能,但有些瀏覽器如 IE6, Safari 在 keepalive 的 POST 有功能性問題,針對這些瀏覽器默認停用 keepalive
  • keepalive_timeout: 閒置超過一定時間,伺服器關閉連接,照規範這個時間會傳給瀏覽器,瀏覽器如何對待 keepalive(例如也去關閉連接)則視各家瀏覽器而不同
  • keepalive_requests: 一個長連接允許發送的最大請求數
  • tcp_nodelay: 對 keepalive 連接是啟用 TCP_NODELAY
  • tcp_nopush: 在 sendfile 開啟的狀況下,是否啟用 TCP_CORK

MIME 類型相關的配置

  • types: 設定文件副檔名對應到哪種 MIME type
  • default_type: 自 types 匹配不到時套用的預設值
  • types_hash_bucket_size: 意義同 server_names_hash_bucket_size
  • types_hash_max_size: 意義同 server_names_hash_max_size

限制請求的配置

  • limit_expect: 限制請求方法

  • client_max_body_size: 瀏覽器發送的請求含較大的 body 時,頭部附有 Content-Length 字段,Nginx 不用接收完所有 body,若 Content-Length 超出即回傳 413
  • limit_rate: 對請求限速,限制每秒可傳輸多少 bytes,可針對不同客戶端做不同設定
  • limit_rate_after: 當 Nginx 響應速度超過多少微秒才開始限速

優化文件操作的配置

  • sendfile: 啟用 Linux 的 sendfile 系統調用來發送文件,減少了內核態與用戶態之間的兩次內存複製,從磁碟讀取文件後直接在內核態發送到網卡,提高效率
  • aio: 是否啟用 Linux 的異步文件 I/O,與 sendfile 功能是互斥的
  • directio: 是否啟用 Linux 的 O_DIRECT,通常能優化對大文件的讀取
  • directio_alignment: 以 directio 讀取文件時的對齊方式
  • open_file_cache: 在內存儲存三種資訊 1) 文件指標、大小、修改時間 2) 訪問過得目錄結構 3) 遺失的或權限不足的文件資訊;透過 max 參數以 LRU 限制緩存數量;透過 inactive 刪除久未使用的緩存
  • open_file_cache_errors: 是否緩存打開文件時出現的錯誤訊息
  • open_file_cache_min_uses: 與 open_file_cache 的 inactive 搭配使用,若在指定的時段訪問次數不到最小值,則刪除該緩存
  • open_file_cache_valid: 多久檢查一次緩存是否有效

對請求特殊處理的配置

  • ignore_invalid_headers: 當請求頭部不合法,回傳 400
  • underscores_in_headers: 是否禁止在請求頭使用 _
  • if_modified_since: 決定如何處理請求頭的 If-Modified-Since 資訊;瀏覽器會在本地緩存文件,並紀錄取得的時間,下次向伺服器請求時會帶上此資訊,而伺服器會判斷是否回傳新的文件(若有修改)或 304 Not Modified
  • log_not_found: 是否紀錄找不到請求文件的錯誤
  • merge_slashes: 是否合併 URI 中鄰近的 /
  • resolver_address: 設置 DNS 的 IP 位址
  • resolver_timeout: DNS 解析的超時時間
  • server_tokens: 是否在錯誤的響應頭部註明版本資訊

反向代理服務器基本配置

  • 反向代理必須能夠處理大量併發,,將Internet 上的連接請求轉發給內部網路中的上游伺服器
  • 當客戶端發出請求,Nginx 並不會立刻轉發,而是緩存完才向上游伺服器發起連接
  • 先緩存請求的缺點是延長了請求處理的時間,優點是降低了上游伺服器的併發壓力

負載均衡的配置

  • upstream: 定義上游服務器的集群,便於在 proxy_pass 使用
  • server: 上游服務器的名字
    • weight: 轉發的優先權重
    • fail_timeout, max_fails: 在時段內轉發失敗幾次就認定該伺服器暫時為不可用
  • ip_hash:根據客戶端 IP 計算出 key ,並根據集群數量做 mod,來決定總是轉發至哪台伺服器
    • weight 不得同時使用
    • 如果集群有某台伺服器不可用,不該直接刪除配置,而是打上 down 標記,避免破壞原本雜湊的一致性

反向代理的配置

  • proxy_pass: 可以是上游伺服器的 URL,或事先定義的 upstream 區塊名稱
  • proxy_set_header: 轉發 Host 頭部(默認情況下不轉發)
  • proxy_method: 更改轉發時的請求方法
  • proxy_hide_header: 響應時,指定哪些 HTTP 頭部字段不轉發,默認為 Date, Server, X-Pad, X-Accel-*
  • proxy_pass_header: 與 proxy_hide_header 作用相反,指定哪些 http 頭部字段可以轉發
  • proxy_pass_request_body: 是否對上游伺服器發送 HTTP body
  • proxy_pass_request_headers: 是否對上游伺服器發送 HTTP 頭部
  • proxy_redirect: 當上游伺服器響應重定向(301)或刷新(302),重設 HTTP 頭部 的 location 或 refresh 字段
  • proxy_next_upstream: 轉發請求若出現錯誤,繼續換一台上游伺服器處理

2 thoughts on “深入理解 Nginx 讀書筆記 (第二章)”

發佈回覆給「pokai」的留言 取消回覆

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *