企業級高性能web服務器

1 web服務基礎

1.1 正常情況的單次web服務訪問流程:

正常情況下,單次 Web 服務訪問流程從用戶在客戶端發起請求開始,到最終在客戶端展示內容結束,涉及客戶端、網絡傳輸、服務器端等多個環節,以下是詳細過程:

1.1.1 客戶端發起請求

1.用戶操作與URL解析:

用戶在瀏覽器地址欄輸入網址(如https://www.example.com ),或點擊網頁上的鏈接、提交表單等操作,觸發 Web 服務訪問。瀏覽器對輸入的 URL 進行解析,識別出協議(常見的有 HTTP、HTTPS)、域名(www.example.com )、端口號(HTTP 默認 80,HTTPS 默認 443,若 URL 中未明確指定端口,瀏覽器會使用默認端口 )以及資源路徑(如/index.html )。

2.DNS解析:

瀏覽器首先檢查本地的 DNS 緩存,如果緩存中有對應的域名 - IP 地址映射,則直接獲取 IP 地址;若沒有,就向本地 DNS 服務器發送查詢請求。本地 DNS 服務器會先查詢自身緩存,若未找到結果,它會向根 DNS 服務器、頂級 DNS 服務器、權威 DNS 服務器等依次進行遞歸或迭代查詢,最終將域名解析為對應的 IP 地址(例如192.168.1.100 ),并將結果返回給瀏覽器。

1.1.2 建立連接

1.TCP三次握手(以HTTP協議基于tcp傳輸為例):

  • 第一次握手:客戶端向服務器發送一個帶有 SYN(同步序列號)標志的 TCP 報文段,該報文段中包含客戶端隨機生成的初始序列號(假設為 x),表示客戶端請求與服務器建立連接。
  • 第二次握手:服務器接收到客戶端的 SYN 報文后,返回一個帶有 SYN 和 ACK(確認應答)標志的 TCP 報文段。其中,ACK 標志表示對客戶端 SYN 的確認,確認號為客戶端初始序列號 x 加 1(即 x + 1);同時,服務器也生成自己的初始序列號(假設為 y),并將其放入 SYN 標志位中發送給客戶端。
  • 第三次握手:客戶端收到服務器的 SYN + ACK 報文后,向服務器發送一個帶有 ACK 標志的 TCP 報文段,確認號為服務器的初始序列號 y 加 1(即 y + 1),序列號為客戶端的初始序列號 x 加 1(即 x + 1),表示客戶端確認收到服務器的響應并完成連接建立。至此,TCP 連接成功建立。

2.TLS/SSL握手(若使用HTTPS協議):

在 TCP 連接建立后,客戶端和服務器之間會進行 TLS/SSL 握手,以協商加密算法、交換公鑰證書等,確保數據傳輸的安全性。具體步驟如下:

  • 客戶端發送ClientHello消息:包含客戶端支持的 SSL/TLS 版本、加密算法列表、隨機數等信息。
  • 服務器響應ServerHello消息:服務器從客戶端提供的選項中選擇合適的 SSL/TLS 版本和加密算法,并返回自己的證書(包含公鑰)、隨機數等信息。
  • 客戶端驗證服務器證書:客戶端檢查服務器證書的有效性(如證書是否過期、頒發機構是否可信等),并從中提取服務器的公鑰。
  • 客戶端生成預主密鑰:客戶端使用服務器的公鑰加密一個隨機生成的預主密鑰,并發送給服務器。
  • 服務器解密預主密鑰:服務器使用自己的私鑰解密收到的預主密鑰,然后客戶端和服務器雙方使用預主密鑰、之前交換的隨機數等信息,生成會話密鑰,用于后續的數據加密傳輸。

具體加密原理請參考:加密(一)- 阮一峰:RSA算法原理_rsa 阮一峰-CSDN博客https://blog.csdn.net/yiguang_820/article/details/108842637

1.1.3 發送http請求

TCP 連接建立后,客戶端通過該連接向服務器發送 HTTP 請求報文,請求報文主要包括:

  • 請求行:包含請求方法(常見的有 GET、POST、PUT、DELETE 等,例如 GET 方法用于獲取資源,POST 方法用于提交數據 )、請求的資源路徑(如/index.html )以及 HTTP 協議版本(如 HTTP/1.1 )。
  • 請求頭:包含一系列鍵值對,提供了關于客戶端、請求內容等的元信息。
  • 請求體:當請求方法為 POST、PUT 等需要提交數據的方法時,請求體中包含了要發送的數據,例如表單數據(格式如name=John&age=30 )或 JSON 格式的數據(如{"username": "John", "password": "123456"} )。

1.1.4 服務器處理請求

  • Web服務器接收與解析:Web 服務器(如 Apache、Nginx 等)在指定端口(如 80 或 443 )監聽并接收客戶端發送的 HTTP 請求報文,然后對請求報文進行解析,提取請求方法、資源路徑等關鍵信息。
  • 請求分發與處理:
    • 靜態資源請求:如果請求的是靜態資源(如 HTML 文件、CSS 樣式表、圖片、JavaScript 腳本等),Web 服務器會根據資源路徑在本地文件系統中查找對應的文件,并直接將其讀取出來,準備返回給客戶端。
    • 動態資源請求:對于動態資源請求(例如請求一個 PHP 腳本、Python Flask 應用的接口等),Web 服務器會將請求轉發給相應的應用服務器(如 PHP-FPM、Gunicorn、Tomcat 等 )。應用服務器根據請求內容執行相應的業務邏輯,這可能涉及與數據庫進行交互(例如查詢用戶信息、獲取商品列表等 )。應用服務器通過數據庫驅動程序(如 MySQL Connector/Python )連接到數據庫(如 MySQL、PostgreSQL 等 ),執行 SQL 查詢或操作,獲取或更新數據,然后將處理結果返回給 Web 服務器。

1.1.5 服務器返回響應

  • 構建響應報文:Web 服務器接收到應用服務器返回的處理結果(如果是動態請求)或獲取到靜態資源后,構建 HTTP 響應報文。響應報文主要包括:
  1. 狀態行:包含 HTTP 協議版本、狀態碼(如 200 表示請求成功,404 表示資源未找到,500 表示服務器內部錯誤等 )以及狀態描述(如OK )。
  2. 響應頭:包含一系列鍵值對,提供關于響應的元信息。
  3. 響應體:包含了實際要返回給客戶端的內容,對于靜態資源請求,可能是 HTML 頁面、CSS 文件、圖片等的二進制數據;對于動態請求,可能是 JSON 格式的數據、渲染后的 HTML 頁面等。
  • 發送響應:Web 服務器通過已建立的 TCP 連接,將構建好的 HTTP 響應報文發送回客戶端。

1.1.6 客戶端接收與渲染

  • 接收響應:客戶端通過 TCP 連接接收服務器發送的 HTTP 響應報文,根據響應頭中的Content-Length等信息,確定接收數據的大小,并將數據完整地接收下來。
  • 解析與渲染:
  1. 響應狀態檢測:客戶端首先檢查響應的狀態碼,如果是 200 - 299 范圍內的狀態碼,表示請求成功;如果是其他范圍的狀態碼,可能意味著請求失敗,客戶端會根據狀態碼的含義進行相應的處理,例如顯示錯誤頁面。
  2. 響應頭處理:客戶端解析響應頭中的信息,如Content-Type ,根據內容類型調用相應的渲染引擎。例如,如果是text/html ,則調用 HTML 渲染引擎;如果是image/jpeg ,則調用圖片解碼和顯示模塊。
  3. 響應體渲染:對于 HTML 頁面,瀏覽器會構建 DOM 樹,解析 CSS 樣式表并應用樣式,執行 JavaScript 腳本,最終在瀏覽器窗口中呈現出完整的網頁內容;對于 JSON 數據等,客戶端可能會根據業務邏輯進行數據處理和展示。

1.1.7 關閉連接

TCP四次揮手(默認情況下):

當數據傳輸完成后,客戶端和服務器之間會進行 TCP 四次揮手來關閉連接:

  • 第一次揮手:客戶端發送一個帶有 FIN(結束標志)的 TCP 報文段,表示客戶端不再發送數據,但還可以接收數據。
  • 第二次揮手:服務器接收到客戶端的 FIN 報文后,返回一個帶有 ACK 標志的 TCP 報文段,確認收到客戶端的 FIN 請求。
  • 第三次揮手:服務器發送一個帶有 FIN 標志的 TCP 報文段,表示服務器也不再發送數據。
  • 第四次揮手:客戶端接收到服務器的 FIN 報文后,返回一個帶有 ACK 標志的 TCP 報文段,確認收到服務器的 FIN 請求,至此,TCP 連接完全關閉。

HTTP長連接(若啟用):在 HTTP/1.1 協議中,默認啟用了 HTTP 長連接(通過Connection: keep-alive 頭字段標識 ),這意味著在一次請求 - 響應完成后,TCP 連接不會立即關閉,而是可以被復用,用于后續的 HTTP 請求,這樣可以減少建立和關閉連接的開銷,提高性能。

1.2 web服務介紹

1.2.1 Apache經典的web服務端

Apache起初由美國的伊利諾伊大學香檳分校的國家超級計算機應用中心開發,目前經歷了兩大版本分別是1.X2.X,其可以通過編譯安裝實現特定的功能。
1.2.1.1 Apache prefork模型
  • 預派生模式,有一個主控制進程,然后生成多個子進程,使用select模型,最大并發1024
  • 每個子進程有一個獨立的線程響應用戶請求
  • 相對比較占用內存,但是比較穩定,可以設置最大和最小進程數
優點:穩定
缺點:每個用戶請求需要對應開啟一個進程,占用資源較多,并發性差,不適用于高并發場景
1.2.1.2 Apache worker模型
  • 一種多進程和多線程混合的模型
  • 有一個控制進程,啟動多個子進程
  • 每個子進程里面包含固定的線程
  • 使用線程來處理請求
  • 當線程不夠使用的時候會再啟動一個新的子進程,然后在進程里面再啟動線程處理請求
  • 由于其使用了線程處理請求,因此可以承受更高的并發
優點:相比于prefork占用的內存少,可以同時處理更多的請求
缺點:使用keepalive的長連接方式,某個線程會一直被占據,即使沒有傳輸數據,也需要一直等待到超時才會被釋放。如果過多的線程,被這樣占據,也會導致在高并發場景下的無服務線程可用(該問題在prefork模式下,同樣會發生)
1.2.1.3 Apache event模型
  • Apache中最新的模式,2012年發布的apache 2.4.X系列正式支持event 模型,屬于事件驅動模型(epoll) 每個進程響應多個請求,在現在版本里的已經是穩定可用的模式
  • 它和worker模式很像,最大的區別在于,它解決了keepalive場景下長期被占用的線程的資源浪費問題(某些線程因為被keepalive,空掛在哪里等待,中間幾乎沒有請求過來,甚至等到超時)
  • event MPM中,會有一個專門的線程來管理這些keepalive類型的線程
  • 當有真實請求過來的時候,將請求傳遞給服務線程,執行完畢后,又允許它釋放。這樣增強了高并發場景下的請求處理能力
優點:單線程響應多請求,占據更少的內存,高并發下表現更優秀,會有一個專門的線程來管理keepalive類型的線程,當有真實請求過來的時候,將請求傳遞給服務線程,執行完畢后,又允許它釋放
缺點:沒有線程安全控制

1.2.2 nginx-高性能的web服務端

Nginx歷經十幾年的迭代更新(https://nginx.org/en/CHANGES), 目前功能已經非常完善且運行穩定,另外Nginx的版本分為開發版、穩定版和過期版,nginx以功能豐富著稱,它即可以作為http服務器,也可以作為反向代理服務器或者郵件服務器能夠快速的響應靜態網頁的請求支持FastCGI/SSL/Virtual Host/URL Rwrite /Gzip / HTTP Basic Auth/http或者TCP的負載均衡(1.9版本以上且開啟stream模塊)等功能,并且支持第三方的功能擴展。
天貓 淘寶 京東 小米 163 新浪等一線互聯網公司都在用Nginx或者進行二次開發

1.2.3 用戶訪問體驗和性能

互聯網存在用戶速度體驗的1-3-10原則,即1秒最優,1-3秒較優,3~10秒比較慢,10秒以上用戶無法接受。用戶放棄一個產品的代價很低,只是換一個URL而已。
1.2.3.1 影響用戶體驗的因素

1.客戶端:

  • 客戶端硬件配置
  • 客戶端網絡速率
  • 客戶端與服務端距離

2.服務器:

  • 服務端網絡速率
  • 服務端硬件配置
  • 服務端架構設計
  • 服務端應用程序工作模式
  • 服務端并發數量,服務端響應文件大小及數量
  • 服務端I/O壓力

1.2.4 服務端I/O流程

I/O在計算機中指Input/Output IOPS (Input/Output Per Second)即每秒的輸入輸出量(或讀寫次數),是衡量磁盤性能的主要指標之一。IOPS是指單位時間內系統能處理的I/O請求數量,一般以每秒處理的I/O請求數量為單位,I/O請求通常為讀或寫數據操作請求。
一次完整的I/O用戶空間的進程數據內核空間的內核數據的報文的完整交換,但是由于內核空間與用戶空間是嚴格隔離的,所以其數據交換過程中不能由用戶空間的進程直接調用內核空間的內存數據,而是需要經歷一次從內核空間中的內存數據copy到用戶空間的進程內存當中,所以簡單說I/O就是把數據從內核空間中的內存數據復制到用戶空間中進程的內存當中。
服務器I/O
  • 磁盤I/O
  • 網絡I/O:一切皆文件,本質是對socket文件的讀寫
1.2.4.1 磁盤I/O
磁盤I/O是進程向內核發起系統調用,請求磁盤上的某個資源比如是html 文件或者圖片,然后內核通過相應的驅動程序將目標文件加載到內核的內存空間,加載完成之后把數據從內核內存再復制給進程內存,如果是比較大的數據也需要等待時間
機械磁盤的尋道時間、旋轉延遲和數據傳輸時間:
尋道時間:是指磁頭移動到正確的磁道上所花費的時間,尋道時間越短則I/O處理就越快,目前磁盤的尋道時間一般在3-15毫秒左右。
旋轉延遲:是指將磁盤片旋轉到數據所在的扇區到磁頭下面所花費的時間,旋轉延遲取決于磁盤的轉速,通常使用磁盤旋轉一周所需要時間的1/2之一表示,比如7200轉的磁盤平均訓傳延遲大約為60*1000/7200/2=4.17毫秒,公式的意思為 (每分鐘60*1000毫秒每秒/7200轉每分/2),如果是15000轉的則為60*1000/15000/2=2毫秒。
數據傳輸時間:指的是讀取到數據后傳輸數據的時間,主要取決于傳輸速率,這個值等于數據大小除以傳輸速率,目前的磁盤接口每秒的傳輸速度可以達到600MB,因此可以忽略不計。
常見的機械磁盤平均尋道時間值:
7200/分的磁盤平均物理尋道時間:9毫秒
10000/分的磁盤平均物理尋道時間:6毫秒
15000/分的磁盤平均物理尋道時間:4毫秒
常見磁盤的平均延遲時間:
7200轉的機械盤平均延遲:60*1000/7200/2 = 4.17ms
10000轉的機械盤平均延遲:60*1000/10000/2 = 3ms
15000轉的機械盤平均延遲:60*1000/15000/2 = 2ms
每秒最大IOPS的計算方法:
7200轉的磁盤IOPS計算方式:1000毫秒/(9毫秒的尋道時間+4.17毫秒的平均旋轉延遲時
)=1000/13.13=75.9 IOPS
10000轉的磁盤的IOPS計算方式:1000毫秒/(6毫秒的尋道時間+3毫秒的平均旋轉延遲時
)=1000/9=111IOPS
15000轉的磁盤的IOPS計算方式:15000毫秒/(4毫秒的尋道時間+2毫秒的平均旋轉延遲時
)=1000/6=166.6 IOPS
1.2.4.2 網絡I/O
網絡通信就是網絡協議棧到用戶空間進程的IO就是網絡IO

網絡I/O處理過程

  • 獲取請求數據,客戶端與服務器建立連接發出請求,服務器接受請求
  • 構建響應,當服務器接收完請求,并在用戶空間處理客戶端的請求,直到構建響應完成
  • 返回數據,服務器將已構建好的響應再通過內核空間的網絡I/O發還給客戶端

不論磁盤和網絡I/O

每次I/O,都要經過兩個階段:

  1. 將數據從文件先加載到內核內存空間(緩沖區),等待數據準備完成,時間較長
  2. 將數據從內核緩沖區復制到用戶空間的進程內存中,時間較短

1.3 I/O模型

1.3.1 I/O模型概念

同步/異步:關注的是消息通信機制,即調用者在等待一件事情的處理結果時,被調用者是否提供完成狀態的通知。

  • 同步:synchronous,被調用者并不提供事件的處理結果相關的通知消息,需要調用者主動詢問事情是否處理完成
  • 異步:asynchronous,被調用者通過狀態、通知或回調機制主動通知調用者被調用者的運行狀態

阻塞/非阻塞:關注調用者在等待結果返回之前的狀態

  • 阻塞:blocking,指IO操作需要徹底完成后才返回到用戶空間,調用結果返回之前,調用者被掛起,干不了別的事情。
  • 非阻塞:nonblocking,指IO操作被調用后立即返回給用戶一個狀態值,而無需等到IO操作徹底完成,在最終的調用結果返回之前,調用者不會被掛起,可以去做別的事情

1.3.2 網絡I/O模型

阻塞型、非阻塞型、復用型、信號驅動型、異步
1.3.2.1 阻塞型I/O模型(blocking IO)

  • 用戶線程在內核進行IO操作時被阻塞
  • 用戶線程通過系統調用read發起I/O讀操作,由用戶空間轉到內核空間。內核等到數據包到達后,然后將接收的數據拷貝到用戶空間,完成read操作
  • 用戶需要等待read將數據讀取到buffer后,才繼續處理接收的數據。整個I/O請求的過程中,用戶線程是被阻塞的,這導致用戶在發起IO請求時,不能做任何事情,對CPU的資源利用率不夠
優點:程序簡單,在阻塞等待數據期間進程/線程掛起,基本不會占用 CPU 資源
缺點:每個連接需要獨立的進程/線程單獨處理,當并發請求量大時為了維護程序,內存、線程切換開銷較大,apache preforck使用的是這種模式。
同步阻塞:程序向內核發送I/O請求后一直等待內核響應,如果內核處理請求的IO操作不能立即返回,則進程將一直等待并不再接受新的請求,并由進程輪詢查看I/O是否完成,完成后進程將I/O結果返回給Client,在IO沒有返回期間進程不能接受其他客戶的請求,而且是有進程自己去查看I/O是否完成,這種方式簡單,但是比較慢,用的比較少。
1.3.2.2 非阻塞型I/O模型(nonblocking IO)

用戶線程發起IO請求時立即返回。但并未讀取到任何數據,用戶線程需要不斷地發起IO請求,直到數據到達后,才真正讀取到數據,繼續執行。即 “輪詢機制存在兩個問題:如果有大量文件描述符都要等,那么就得一個一個的read。這會帶來大量的Context Switchread是系統調用,每調用一次就得在用戶態和核心態切換一次)。輪詢的時間不好把握。這里是要猜多久之后數據才能到。等待時間設的太長,程序響應延遲就過大;設的太短,就會造成過于頻繁的重試,干耗CPU而已,是比較浪費CPU的方式,一般很少直接使用這種模型,而是在其他IO模型中使用非阻塞IO這一特性。
非阻塞:程序向內核發送請I/O求后一直等待內核響應,如果內核處理請求的IO操作不能立即返回IO結果,進程將不再等待,而且繼續處理其他請求,但是仍然需要進程隔一段時間就要查看內核I/O是否完成。
查看上圖可知,在設置連接為非阻塞時,當應用進程系統調用 recvfrom 沒有數據返回時,內核會立即返回一個 EWOULDBLOCK 錯誤,而不會一直阻塞到數據準備好。如上圖在第四次調用時有一個數據報準備好了,所以這時數據會被復制到 應用進程緩沖區 ,于是 recvfrom 成功返回數據
當一個應用進程這樣循環調用 recvfrom 時,稱之為輪詢 polling 。這么做往往會耗費大量CPU時間,實際使用很少
1.3.2.3 多路復用I/O型(I/O multiplexing)
  • 上面的模型中,每一個文件描述符對應的IO是由一個線程監控和處理
  • 多路復用IO指一個線程可以同時(實際是交替實現,即并發完成)監控和處理多個文件描述符對應各自的IO,即復用同一個線程
  • 一個線程之所以能實現同時處理多個IO,是因為這個線程調用了內核中的SELECT,POLLEPOLL等系統調用,從而實現多路復用IO
I/O multiplexing 主要包括:selectpollepoll三種系統調用,select/poll/epoll的好處就在于單個
process就可以同時處理多個網絡連接的IO
它的基本原理就是select/poll/epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有數據到達了,就通知用戶進程。
當用戶進程調用了select,那么整個進程會被block,而同時,kernel監視所有select負責的socket,當任何一個socket中的數據準備好了,select就會返回。這個時候用戶進程再調用read操作,將數據從kernel拷貝到用戶進程。
Apache prefork是此模式的selectworker是poll模式。
IO多路復用(IO Multiplexing) :是一種機制,程序注冊一組socket文件描述符給操作系統,表示“我要監視這些fd是否有IO事件發生,有了就告訴程序處理”,IO多路復用一般和NIO一起使用的。NIOIO多路復用是相對獨立的。NIO僅僅是指IO API總是能立刻返回,不會被Blocking;IO多路復用僅僅是操作系統提供的一種便利的通知機制。操作系統并不會強制這倆必須得一起用,可以只用IO多路復用 + BIO,這時還是當前線程被卡住。IO多路復用和NIO是要配合一起使用才有實際意義
IO多路復用是指內核一旦發現進程指定的一個或者多個IO條件準備讀取,就通知該進程多個連接共用一個等待機制,本模型會阻塞進程,但是進程是阻塞在select或者poll這兩個系統調用上,而不是阻塞在真正的IO操作上用戶首先將需要進行IO操作添加到select中,同時等待select系統調用返回。當數據到達時,IO被激活,select函數返回。用戶線程正式發起read請求,讀取數據并繼續執行從流程上來看,使用select函數進行IO請求和同步阻塞模型沒有太大的區別,甚至還多了添加監視IO,以及調用select函數的額外操作,效率更差。并且阻塞了兩次,但是第一次阻塞在select上時,select可以監控多個IO上是否已有IO操作準備就緒,即可達到在同一個線程內同時處理多個IO請求的目的。而不像阻塞IO那種,一次只能監控一個IO雖然上述方式允許單線程內處理多個IO請求,但是每個IO請求的過程還是阻塞的(在select函數上阻塞),平均時間甚至比同步阻塞IO模型還要長。如果用戶線程只是注冊自己需要的IO請求,然后去做自己的事情,等到數據到來時再進行處理,則可以提高CPU的利用率IO多路復用是最常使用的IO模型,但是其異步程度還不夠“徹底,因它使用了會阻塞線程的select系統調用。因此IO多路復用只能稱為異步阻塞IO模型,而非真正的異步IO
優缺點:
  • 優點:可以基于一個阻塞對象,同時在多個描述符上等待就緒,而不是使用多個線程(每個文件描述符一個線程),這樣可以大大節省系統資源
  • 缺點:當連接數較少時效率相比多線程+阻塞 I/O 模型效率較低,可能延遲更大,因為單個連接處理需要 2 次系統調用,占用時間會有增加
IO多路復用使用場景:
  • 當客戶端處理多個描述符時(一般是交互式輸入和網絡套接口),必須使用I/O復用
  • 當一個客戶端同時處理多個套接字時,此情況可能的但很少出現
  • 當一個服務器既要處理監聽套接字,又要處理已連接套接字,一般也要用到I/O復用
  • 當一個服務器即要處理TCP,又要處理UDP,一般要使用I/O復用
  • 當一個服務器要處理多個服務或多個協議,一般要使用I/O復用
1.3.2.4 信號驅動式I/O模型(signal-drven IO)

信號驅動I/O的意思就是進程現在不用傻等著,也不用去輪詢。而是讓內核在數據就緒時,發送信號通知進程。
調用的步驟是,通過系統調用 sigaction ,并注冊一個信號處理的回調函數,該調用會立即返回,然后主程序可以繼續向下執行,當有I/O操作準備就緒,即內核數據就緒時,內核會為該進程產生一個 SIGIO信號,并回調注冊的信號回調函數,這樣就可以在信號回調函數中系統調用 recvfrom 獲取數據,將用戶進程所需要的數據從內核空間拷貝到用戶空間
此模型的優勢在于等待數據報到達期間進程不被阻塞。用戶主程序可以繼續執行,只要等待來自信號處理函數的通知。
在信號驅動式 I/O 模型中,應用程序使用套接口進行信號驅動 I/O,并安裝一個信號處理函數,進程繼續運行并不阻塞
當數據準備好時,進程會收到一個 SIGIO 信號,可以在信號處理函數中調用 I/O 操作函數處理數據。
優點:線程并沒有在等待數據時被阻塞,內核直接返回調用接收信號,不影響進程繼續處理其他請求因此可以提高資源的利用率
缺點:信號 I/O 在大量 IO 操作時可能會因為信號隊列溢出導致沒法通知
異步阻塞:程序進程向內核發送IO調用后,不用等待內核響應,可以繼續接受其他請求,內核收到進程請求后進行的IO如果不能立即返回,就由內核等待結果,直到IO完成后內核再通知進程。

1.3.2.5 異步I/O模型(asynchronous IO)

異步I/O 與 信號驅動I/O最大區別在于,信號驅動是內核通知用戶進程何時開始一個I/O操作,而異步I/O是由內核通知用戶進程I/O操作何時完成,兩者有本質區別,相當于不用去飯店場吃飯,直接點個外賣,把等待上菜的時間也給省了
相對于同步I/O,異步I/O不是順序執行。用戶進程進行aio_read系統調用之后,無論內核數據是否準備好,都會直接返回給用戶進程,然后用戶態進程可以去做別的事情。等到socket數據準備好了,內核直接復制數據給進程,然后從內核向進程發送通知。IO兩個階段,進程都是非阻塞的。
信號驅動IO當內核通知觸發信號處理程序時,信號處理程序還需要阻塞在從內核空間緩沖區拷貝數據到用戶空間緩沖區這個階段,而異步IO直接是在第二個階段完成后,內核直接通知用戶線程可以進行后續操作了
優點:異步 I/O 能夠充分利用 DMA 特性,讓 I/O 操作與計算重疊
缺點:要實現真正的異步 I/O,操作系統需要做大量的工作。目前 Windows 下通過 IOCP 實現了真正的異步 I/O,在 Linux 系統下,Linux 2.6才引入,目前 AIO 并不完善,因此在 Linux 下實現高并發網絡編程時以 IO 復用模型模式+多線程任務的架構基本可以滿足需求
Linux提供了AIO庫函數實現異步,但是用的很少。目前有很多開源的異步IO庫,例如libeventlibev、libuv。
異步非阻塞:程序進程向內核發送IO調用后,不用等待內核響應,可以繼續接受其他請求,內核調用的IO如果不能立即返回,內核會繼續處理其他事物,直到IO完成后將結果通知給內核,內核在將IO完成的結果返回給進程,期間進程可以接受新的請求,內核也可以處理新的事物,因此相互不影響,可以實現較大的同時并實現較高的IO復用,因此異步非阻塞使用最多的一種通信方式。

1.3.3 五種IO對比

這五種 I/O 模型中,越往后,阻塞越少,理論上效率也是最優,前四種屬于同步 I/O,因為其中真正的 I/O操作(recvfrom)將阻塞進程/線程,只有異步 I/O 模型才與 POSIX 定義的異步 I/O 相匹配

1.3.4 I/O的具體實現方式

1.3.4.1 I/O常見實現
Nginx支持在多種不同的操作系統實現不同的事件驅動模型,但是其在不同的操作系統甚至是不同的系統版本上面的實現方式不盡相同,主要有以下實現方式:
  • select:select庫是在linuxwindows平臺都基本支持的 事件驅動模型庫,并且在接口的定義也基本相同,只是部分參數的含義略有差異,最大并發限制1024,是最早期的事件驅動模型。
  • poll:在Linux 的基本驅動模型,windows不支持此驅動模型,是select的升級版,取消了最大的并發限制,在編譯nginx的時候可以使用--with-poll_module--without-poll_module這兩個指定是否編譯select庫。
  • epoll:epoll是庫是Nginx服務器支持的最高性能的事件驅動庫之一,是公認的非常優秀的事件驅動模型,它和select和poll有很大的區別,epollpoll的升級版,但是與poll有很大的區別.epoll的處理方式是創建一個待處理的事件列表,然后把這個列表發給內核,返回的時候在去輪詢檢查這個表,以判斷事件是否發生,epoll支持一個進程打開的最大事件描述符的上限是系統可以打開的文件的最大數,同時epoll庫的I/O效率不隨描述符數目增加而線性下降,因為它只會對內核上報的活躍的描述符進行操作。
  • kqueue:用于支持BSD系列平臺的高校事件驅動模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0級以上版本NetBSD級以上版本及Mac OS X 平臺上,該模型也是poll庫的變種,因此和epoll沒有本質上的區別,都是通過避免輪詢操作提供效率。
  • Iocp:Windows系統上的實現方式,對應第5種(異步I/O)模型。
  • rtsig:不是一個常用事件驅動,最大隊列1024,不是很常用
  • /dev/poll:用于支持unix衍生平臺的高效事件驅動模型,主要在Solaris 平臺、HP/UX,該模型是sun公司在開發Solaris系列平臺的時候提出的用于完成事件驅動機制的方案,它使用了虛擬的/dev/poll設備,開發人員將要見識的文件描述符加入這個設備,然后通過ioctl()調用來獲取事件通知,因此運行在以上系列平臺的時候請使用/dev/poll事件驅動機制。
  • eventport:該方案也是sun公司在開發Solaris的時候提出的事件驅動庫,只是Solaris 10以上的版本,該驅動庫看防止內核崩潰等情況的發生。
1.3.4.2 常用I/O模型比較
selectpollepoll
操作方式遍歷遍歷回調
底層實現數組鏈表哈希表
IO效率每次調回都進行線性遍歷,時間復雜度為O(n)同左事件通知方式,每當fd就緒,系統注冊的回調函數就會被調用,將就緒的fd放到rdlist里,時間復雜度O(1)
最大連接數

1024(x86)

2048(x64)

無上限無上限
fd拷貝每次調用select都需要把fd集合從用戶拷貝到內核態每次調用poll,都需要把fd集合從用戶態拷貝到內核態調用epoll_ct時拷貝進內核并保存,之后每次epoll_wait不拷貝
Select:POSIX所規定,目前幾乎在所有的平臺上支持,其良好跨平臺支持也是它的一個優點,本質上是通過設置或者檢查存放fd標志位的數據結構來進行下一步處理
缺點:單個進程能夠監視的文件描述符的數量存在最大限制,在Linux上一般為1024,可以通過修改宏定FD_SETSIZE,再重新編譯內核實現,但是這樣也會造成效率的降低單個進程可監視的fd數量被限制,默認是1024,修改此值需要重新編譯內核對socket是線性掃描,即采用輪詢的方法,效率較低select 采取了內存拷貝方法來實現內核將 FD 消息通知給用戶空間,這樣一個用來存放大量fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構時復制開銷大
poll:本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然后查詢每個fd對應的設備狀態其沒有最大連接數的限制,原因是它是基于鏈表來存儲的大量的fd的數組被整體復制于用戶態和內核地址空間之間,而不管這樣的復制是不是有意義poll特點是水平觸發,如果報告了fd后,沒有被處理,那么下次poll時會再次報告該fd select是邊緣觸發即只通知一次
epoll:在Linux 2.6內核中提出的selectpoll的增強版本支持水平觸發LT和邊緣觸發ET,最大的特點在于邊緣觸發,它只告訴進程哪些fd剛剛變為就需態,并且只會通知一次使用事件的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內核就會采用類似callback的回調機制來激活該fdepoll_wait便可以收到通知
優點: 沒有最大并發連接的限制:能打開的FD的上限遠大于1024(1G的內存能監聽約10萬個端口),具體查看/proc/sys/fs/file-max,此值和系統內存大小相關
效率提升:非輪詢的方式,不會隨著FD數目的增加而效率下降;只有活躍可用的FD才會調用callback函數,即epoll最大的優點就在于它只管理活躍的連接,而跟連接總數無關內存拷貝,利用mmap(Memory Mapping)加速與內核空間的消息傳遞;epoll使用mmap減少復制開銷
總結:
1epoll只是一組API,比起select這種掃描全部的文件描述符,epoll只讀取就緒的文件描述符,再加入基于事件的就緒通知機制,所以性能比較好
2、基于epoll的事件多路復用減少了進程間切換的次數,使得操作系統少做了相對于用戶任務來說的無用功。
3epollselect等多路復用方式來說,減少了遍歷循環及內存拷貝的工作量,因為活躍連接只占總并發連接的很小一部分。

1.4 零拷貝

1.4.1 零拷貝介紹

1.4.1.1 傳統Linux中I/O的問題

傳統的 Linux 系統的標準 I/O 接口(readwrite)是基于數據拷貝的,也就是數據都是 copy_to_user或者 copy_from_user,這樣做的好處是,通過中間緩存的機制,減少磁盤 I/O 的操作,但是壞處也很明顯,大量數據的拷貝,用戶態和內核態的頻繁切換,會消耗大量的 CPU 資源,嚴重影響數據傳輸的性能,統計表明,在Linux協議棧中,數據包在內核態和用戶態之間的拷貝所用的時間甚至占到了數據包整個處理流程時間的57.1%
1.4.1.2 什么是零拷貝
零拷貝就是上述問題的一個解決方案,通過盡量避免拷貝操作來緩解 CPU 的壓力。零拷貝并沒有真正做到“0”拷貝,它更多是一種思想,很多的零拷貝技術都是基于這個思想去做的優化

1.4.2 零拷貝相關技術

1.4.2.1 MMAP(Memory Mapping)

mmap()系統調用使得進程之間通過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間后,進程可以向訪問普通內存一樣對文件進行訪問。
mmap是一種內存映射文件的方法,即將一個文件或者其它對象映射到進程的地址空間,實現文件磁盤地址和進程虛擬地址空間中一段虛擬地址的一一對映關系。
實現這樣的映射關系后,進程就可以采用指針的方式讀寫操作這一段內存,而系統會自動回寫臟頁面到對應的文件磁盤上,即完成了對文件的操作而不必再調用read,write等系統調用函數。相反,內核空間對這段區域的修改也直接反映用戶空間,從而可以實現不同進程間的文件共享。
內存映射減少數據在用戶空間和內核空間之間的拷貝操作,適合大量數據傳輸
1.4.2.2 SENDFILE

1.4.2.3 DMA輔助的SENDFILE

2 Nginx架構和安裝

2.1 Nginx概述

2.1.1 nginx介紹

Nginx是免費的、開源的、高性能的HTTP和反向代理服務器、郵件代理服務器、以及TCP/UDP代理服務器
解決C10K問題(10K Connections
nginx官網:http://nginx.org
nginx其它的二次發行版:
  • Tengine:由淘寶網發起的Web服務器項目。它在Nginx的基礎上,針對大訪問量網站的需求,添加了很多高級功能和特性。Tengine的性能和穩定性已經在大型的網站如淘寶網,天貓商城等得到了很好的檢驗。它的最終目標是打造一個高效、穩定、安全、易用的Web平臺。從201112月開始,Tengine成為一個開源項目官網: http://tengine.taobao.org/
  • OpenResty:基于 Nginx Lua 語言的高性能 Web 平臺, 章亦春團隊開發,官網:http://openresty.org/cn/

2.1.2 nginx功能介紹

  • 靜態web資源服務器html,圖片,js,css,txt等靜態資源
  • http/https協議的反向代理
  • 結合FastCGI/uWSGI/SCGI等協議反向代理動態資源請求
  • tcp/udp協議的轉發請求轉發(反向代理)
  • imap4/pop3協議的反向代理

2.2.3 基礎特性

  • 模塊化設計,較好的擴展性
  • 高可靠性
  • 支持熱部署:不停機更新配置文件,升級版本,更換日志文件
  • 低內存消耗:10000個keep-alive連接模式下的非活動連接,僅需2.5M內存
  • event-driven,aio,mmap,sendfile

2.2.4 web服務相關的功能

2.2 nginx架構和進程

  • 虛擬主機(server)
  • 支持keep-alive和管道連接(利用一個連接做多次請求)
  • 訪問日志(支持基于日志緩沖提高其性能)
  • url rewirte
  • 路徑別名
  • 基于IP及用戶的訪問控制
  • 支持速率限制及并發數限制
  • 重新配置和在線升級而無需中斷客戶的工作進程

2.2.2 nginx進程結構

web請求處理機制:

  • 多進程方式:服務器每接收到一個客戶端請求就有服務器的主進程生成一個子進程響應客戶端,直到用戶關閉連接,這樣的優勢是處理速度快,子進程之間相互獨立,但是如果訪問過大會導致服務器資源耗盡而無法提供請求
  • 多線程方式:與多進程方式類似,但是每收到一個客戶端請求會有服務進程派生出一個線程和此客戶端進行交互,一個線程的開銷遠遠小于一個進程,因此多線程方式在很大程度減輕了web服務器對系統資源的要求,但是多線程也有自己的缺點,即當多個線程位于同一個進程內工作的時候,可以相互訪問同樣的內存地址空間,所以他們相互影響,一旦主進程掛掉則所有子線程都不能工作了,IIS服務器使用了多線程的方式,需要間隔一段時間就重啟一次才能穩定。
Nginx是多進程組織模型,而且是一個由Master主進程和Worker工作進程組成。

主進程(master)的功能:

  • 對外接口:接收外部的操作(信號)
  • 對內轉發:根據外部的操作的不同,通過信號管理worker
  • 監控:監控worker進程的運行狀態,worker進程異常終止后,自動重啟worker進程
  • 讀取nginx配置文件并驗證其有效性和正確性
  • 建立、綁定和關閉socker連接
  • 按照配置生成、管理和結束工作進程
  • 接收外界指令,如重啟、升級及退出服務器等指令
  • 不中斷服務,實現平滑升級,重啟服務并應用新的配置
  • 開啟日志文件,獲取文件描述符
  • 不中斷服務,實現平滑升級,升級失敗進行回滾處理
  • 編譯和處理perl腳本

工作進程(worker)的功能:

  • 所有worker進程都是平等的
  • 實際處理:網絡請求,由worker進程處理
  • worker進程數量:一般設置為核心數,充分利用CPU資源,同時避免進程數量過多,導致進程競爭CPU資源
  • 增加上下文切換的損耗
  • 接受處理客戶的請求
  • 將請求依次送入各個功能模塊進行處理
  • I/O調用,獲取響應數據
  • 與后端服務器通信,接收后端服務器的處理結果
  • 緩存數據,訪問緩存索引,查詢和調用緩存數據
  • 發送請求結果,響應客戶的請求
  • 接收主程序指令,比如重啟、升級和退出等

2.2.3 nginx進程間通信

工作進程是由主進程生成的,主進程使用fork()函數,在Nginx服務器啟動過程中主進程根據配置文件決定啟動工作進程的數量,然后建立一張全局的工作表用于存放當前未退出的所有的工作進程,主進程生成工作進程后會將新生成的工作進程加入到工作進程表中,并建立一個單向的管道并將其傳遞給工作進程,該管道與普通的管道不同,它是由主進程指向工作進程的單向通道,包含了主進程向工作進程發出的指令、工作進程ID、工作進程在工作進程表中的索引和必要的文件描述符等信息。
主進程與外界通過信號機制進行通信,當接收到需要處理的信號時,它通過管道向相關的工作進程發送正確的指令,每個工作進程都有能力捕獲管道中的可讀事件,當管道中有可讀事件的時候,工作進程就會從管道中讀取并解析指令,然后采取相應的執行動作,這樣就完成了主進程與工作進程的交互。
worker進程之間的通信原理基本上和主進程與worker進程之間的通信是一樣的,只要worker進程之間能夠取得彼此的信息,建立管道即可通信,但是由于worker進程之間是完全隔離的,因此一個進程想要知道另外一個進程的狀態信息,就只能通過主進程來實現。
為了實現worker進程之間的交互,master進程在生成worker進程之后,在worker進程表中進行遍歷,將該新進程的PID以及針對該進程建立的管道句柄傳遞給worker進程中的其他進程,為worker進程之間的通信做準備,當worker進程1worker進程2發送指令的時候,首先在master進程給它的其他worker進程工作信息中找到2的進程PID,然后將正確的指令寫入指向進程2的管道,worker進程2捕獲到管道中的事件后,解析指令并進行相關操作,這樣就完成了worker進程之間的通信。
worker進程可以通過共享內存來通訊的,比如upstream中的zone,或者limit_reqlimit_conn中的zone等。操作系統提供了共享內存機制。

2.2.4 nginx啟動和HTTP連接建立

2.3 nginx模塊介紹

nginx有多種模塊:

  • nginx啟動時,master進程加載配置文件
  • master進程,初始化監聽的socket
  • master進程,fork出多個worker進程
  • worker進程,競爭新的連接,獲勝方通過三次握手,建立socket連接,并處理請求
  • 核心模塊:是 Nginx 服務器正常運行必不可少的模塊,提供錯誤日志記錄 、配置文件解析 、事件驅動機制 、進程管理等核心功能
  • 標準HTTP模塊:提供 HTTP 協議解析相關的功能,比如: 端口配置 、 網頁編碼設置 、 HTTP響應頭設置等
  • 可選HTTP模塊:主要用于擴展標準的 HTTP 功能,讓 Nginx 能處理一些特殊的服務,比如: Flash多媒體傳輸 、解析 GeoIP 請求、 網絡傳輸壓縮 、 安全協議 SSL 支持等
  • 郵件服務模塊:主要用于支持 Nginx 的 郵件服務 ,包括對 POP3 協議、 IMAP 協議和 SMTP協議的支持
  • Stream服務模塊: 實現反向代理功能,包括TCP協議代理
  • 第三方模塊:是為了擴展 Nginx 服務器應用,完成開發者自定義功能,比如: Json 支持、 Lua 持等
nginx高度模塊化,但其模塊早期不支持DSO機制;1.9.11 版本支持動態裝載和卸載
核心模塊:core module
標準模塊:HTTP模塊:ngx_http_*HTTP Core modulesHTTP Optional modules    # 需編譯時指定Mail模塊:ngx_mail_*Stream模塊:ngx_stream_*

參考:勿忘初心,進無止盡!https://www.cnblogs.com/Soy-technology/p/11355597.html

2.4 nginx安裝

2.4.1 nginx版本和安裝方式

nginx版本:

  • Mainline version 主要開發版本,一般為奇數版本號,如1.19
  • Stable version 當前最穩定版本,一般為偶數版本,如1.20
  • Legacy version 舊的穩定版,一般為偶數版本,如1.18

nginx安裝可以使用yum或源碼安裝,但是推薦使用源碼編譯安裝

2.4.2 nginx編譯安裝

編譯器介紹:

  • yum的版本比較舊
  • 編譯安裝可以更方便自定義相關路徑
  • 使用源碼編譯可以自定義相關功能,更方便業務上的使用
源碼安裝需要提前準備標準的編譯器,GCC的全稱是(GNU Compiler collection),其有GNU開發,并以GPL即LGPL許可,是自由的類UNIX即蘋果電腦Mac OS X操作系統的標準編譯器,因為GCC原本只能處理C語言,所以原名為GNU C語言編譯器,后來得到快速發展,可以處理C++,Fortranpascalobjective C,java以及Ada等其他語言,此外還需要Automake工具,以完成自動創建Makefile的工作,Nginx的一些模塊需要依賴第三方庫,比如: pcre(支持rewrite),zlib(支持gzip模塊)和openssl(支持ssl模塊)等。
2.4.2.1 編譯安裝nginx

官方源碼包下載地址:

nginx: downloadhttps://nginx.org/en/download.html

編譯安裝示例:

注意:編譯安裝前請確保SELinux和防火墻為關閉狀態,本地yum或網絡yum配置正常,網絡通暢

[root@Nginx ~]# yum install gcc pcre-devel zlib-devel openssl-devel -y
[root@Nginx ~]# tar zxf nginx-1.24.0.tar.gz
[root@Nginx ~]# cd nginx-1.24.0
[root@Nginx nginx-1.24.0]# useradd -s /sbin/nologin -M nginx
[root@Nginx nginx-1.24.0]# ls # 查看是否有下面類似的文件
auto CHANGES.ru configure html Makefile objs src
CHANGES conf contrib LICENSE man README[root@Nginx nginx-1.24.0]# ./configure --prefix=/usr/local/nginx \ # 指定 Nginx 的安裝目錄為 /usr/local/nginx
--user=nginx \ # 指定nginx運行用戶
--group=nginx \ # 指定nginx運行組
--with-http_ssl_module \ # 支持https://
--with-http_v2_module \ # 支持http版本2
--with-http_realip_module \ # 支持ip透傳
--with-http_stub_status_module \ # 支持狀態頁面
--with-http_gzip_static_module \ # 支持壓縮
--with-pcre \ # 支持正則
--with-stream \ # 支持tcp反向代理
--with-stream_ssl_module \ # 支持tcp的ssl加密
--with-stream_realip_module # 支持tcp的透傳ip[root@Nginx nginx-1.24.0]# make && make install

nginx完成安裝后有四個主要目錄

[root@Nginx nginx-1.24.0]# ls /usr/local/nginx/
conf html logs sbinconf:保存nginx所有的配置文件,其中nginx.conf是nginx服務器的最核心最主要的配置文件,其他
的.conf則是用來配置nginx相關的功能的,例如fastcgi功能使用的是fastcgi.conf和fastcgi_params
兩個文件,配置文件一般都有一個樣板配置文件,是以.default為后綴,使用時可將其復制并將default后綴
去掉即可。html目錄中保存了nginx服務器的web文件,但是可以更改為其他目錄保存web文件,另外還有一個50x的web
文件是默認的錯誤頁面提示頁面。logs:用來保存nginx服務器的訪問日志錯誤日志等日志,logs目錄可以放在其他路徑,比
如/var/logs/nginx里面。sbin:保存nginx二進制啟動腳本,可以接受不同的參數以實現不同的功能。
2.4.2.2 驗證版本及編譯參數
# 將 Nginx 的可執行程序目錄(/usr/local/nginx/sbin)添加到系統環境變量 PATH 中
[root@Nginx ~]# vim ~/.bash_profile
export PATH=$PATH:/usr/local/nginx/sbin
[root@Nginx ~]# source ~/.bash_profile # 使剛修改的環境變量配置立即生效[root@Nginx ~]# nginx -V # 查看 Nginx 的版本信息和編譯配置參數
nginx version: nginx/1.24.0
built by gcc 11.4.1 20231218 (Red Hat 11.4.1-3) (GCC)
built with OpenSSL 3.0.7 1 Nov 2022
TLS SNI support enabled
configure arguments: --group=nginx --with-http_ssl_module --with-http_v2_module -
-with-http_realip_module --with-http_stub_status_module --withhttp_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --
with-stream_realip_module
2.4.2.3 使用安裝完成的二進制文件nginx
[root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf # 編輯 Nginx 的主配置文件
[root@Nginx ~]# nginx -g "worker_processes 4;" # 啟動 Nginx 服務并臨時指定工作進程數為4
[root@Nginx ~]# ps aux | grep nginx # 查看當前系統中與 nginx 相關的進程狀態
2.4.2.4 nginx啟動文件

為 Nginx 創建一個 systemd 服務配置文件,以便通過系統服務管理器來管理 Nginx(啟動、停止、開機自啟等)

[root@Nginx ~]# vim /lib/systemd/system/nginx.service
[Unit]
# 服務描述信息,說明這是 Nginx HTTP 服務器和反向代理服務
Description=The NGINX HTTP and reverse proxy server
# 指定 Nginx 啟動的依賴順序,需在這些服務(系統日志、網絡、遠程文件系統、DNS 解析)啟動之后再啟動 Nginx
After=syslog.target network-online.target remote-fs.target nss-lookup.target
# 期望網絡就緒后再啟動nginx
Wants=network-online.target
[Service]
Type=forking # Nginx 是fork模式啟動(主進程會創建子進程,主進程退出后子進程繼續運行)
PIDFile=/usr/local/nginx/logs/nginx.pid # 指定Nginx主進程PID文件路徑(與nginx.conf中pid配置一致)
ExecStartPre=/usr/local/nginx/sbin/nginx -t # 啟動前執行的命令,nginx -t用于檢查配置文件語法是否正確,確保配置無誤后才啟動
ExecStart=/usr/local/nginx/sbin/nginx # 啟動Nginx的命令(執行 Nginx 二進制文件)
ExecReload=/usr/local/nginx/sbin/nginx -s reload # 重載配置的命令(nginx -s reload 平滑重啟,不中斷服務)
ExecStop=/bin/kill -s QUIT $MAINPID # 停止服務的命令
PrivateTmp=true # 為Nginx分配獨立的臨時目錄
[Install]
WantedBy=multi-user.target
[root@Nginx ~]# systemctl daemon-reload # 重新加載systemd服務配置,使新創建的nginx.service生效
[root@Nginx ~]# systemctl start nginx # 啟動Nginx服務

2.6 平滑升級和回滾

    有時候我們需要對Nginx版本進行升級以滿足對其功能的需求,例如添加新模塊,需要新功能,而此時Nginx又在跑著業務無法停掉,這時我們就可能選擇平滑升級

    2.6.1 平滑升級流程

    1. 將舊Nginx二進制文件換成新Nginx程序文件(注意先備份)
    2. master進程發送USR2信號
    3. master進程修改pid文件名加上后綴.oldbin,成為nginx.pid.oldbin
    4. master進程用新Nginx文件啟動新master進程成為舊master的子進程,系統中將有新舊兩個Nginx進程共同提供Web服務,當前新的請求仍然由舊Nginxworker進程進行處理,將新生成的master程的PID存放至新生成的pid文件nginx.pid
    5. 向舊的Nginx服務進程發送WINCH信號,使舊的Nginx worker進程平滑停止
    6. 向舊master進程發送QUIT信號,關閉老master,并刪除Nginx.pid.oldbin文件
    7. 如果發現升級有問題,可以回滾∶向老master發送HUP,向新master發送QUIT

    2.6.2 平滑升級和回滾案例

    [root@Nginx nginx]# tar zxf nginx-1.26.1.tar.gz
    [root@Nginx nginx]# cd nginx-1.26.1/
    #開始編譯新版本
    [root@Nginx nginx-1.26.1]# ./configure --with-http_ssl_module --with_http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module
    #只要make不需要make install
    [root@Nginx nginx-1.26.1]# make
    #查看兩個版本
    [root@Nginx nginx-1.26.1]# ll objs/nginx /usr/local/nginx/sbin/nginx
    -rwxr-xr-x 1 root root 1239416 Jul 18 15:08 objs/nginx
    -rwxr-xr-x 1 root root 5671488 Jul 18 11:41 /usr/local/nginx/sbin/nginx
    #把之前的舊版的nginx命令備份
    [root@Nginx ~]# cd /usr/local/nginx/sbin/
    [root@Nginx sbin]# cp nginx nginx.24
    #把新版本的nginx命令復制過去
    [root@Nginx sbin]# cp -f /root/nginx/nginx-1.26.1/objs/nginx /usr/local/nginx/sbin
    #檢測一下有沒有問題
    [root@Nginx sbin]# nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful[root@Nginx sbin]# ps aux | grep nginx # 查看進程ID
    root 48732 0.0 0.1 9868 2436 ? Ss 14:17 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 48733 0.0 0.2 14200 4868 ? S 14:17 0:00 nginx: worker
    process
    root 52075 0.0 0.3 9876 6528 ? S 15:41 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 52076 0.0 0.2 14208 4868 ? S 15:41 0:00 nginx: worker
    process[root@Nginx sbin]# kill -USR2 48732 #nginx worker ID
    #USR2 平滑升級可執行程序,將存儲有舊版本主進程PID的文件重命名為nginx.pid.oldbin,并啟動新的nginx
    #此時兩個master的進程都在運行,只是舊的master不在監聽,由新的master監聽80
    #此時Nginx開啟一個新的master進程,這個master進程會生成新的worker進程,這就是升級后的Nginx進
    #程,此時老的進程不會自動退出,但是當接收到新的請求不作處理而是交給新的進程處理。[root@Nginx sbin]# curl -I localhost
    HTTP/1.1 200 OK
    Server: nginx/1.24.0 # 此時依舊是舊版本生生效
    Date: Thu, 18 Jul 2025 07:45:58 GMT
    Content-Type: text/html
    Content-Length: 615
    Last-Modified: Thu, 18 Jul 2025 03:41:13 GMT
    Connection: keep-alive
    ETag: "66988ed9-267"
    Accept-Ranges: bytes#回收舊版本
    [root@Nginx sbin]# kill -WINCH 48732 # 減少工作進程數量,主進程保持運行,跟舊主進程ID
    [root@Nginx sbin]# ps aux | grep nginx
    root 48732 0.0 0.1 9868 2436 ? Ss 14:17 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    root 52075 0.0 0.3 9876 6528 ? S 15:41 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 52076 0.0 0.2 14208 4868 ? S 15:41 0:00 nginx: worker
    process
    #檢測版本信息
    [root@Nginx sbin]# curl -I localhost
    HTTP/1.1 200 OK
    Server: nginx/1.26.1 #新版本生效
    Date: Thu, 18 Jul 2025 07:59:45 GMT
    Content-Type: text/html
    Content-Length: 615
    Last-Modified: Thu, 18 Jul 2025 03:41:13 GMT
    Connection: keep-alive
    ETag: "66988ed9-267"
    Accept-Ranges: bytes#回滾
    #如果升級的版本發現問題需要回滾,可以重新拉起舊版本的worker
    [root@Nginx sbin]# cp nginx nginx.26
    [root@Nginx sbin]# ls
    nginx nginx.24 nginx.26
    [root@Nginx sbin]# mv nginx.24 nginx
    mv: overwrite 'nginx'? y# kill -HUP ID
    # 檢查新配置文件的語法是否正確(若錯誤則不重載,保持舊配置運行)。
    # 用新配置啟動新的工作進程。
    # 逐步關閉舊工作進程(等待它們處理完當前請求)。
    [root@Nginx sbin]# kill -HUP 48732
    [root@Nginx sbin]# ps aux | grep nginx
    root 48732 0.0 0.1 9868 2436 ? Ss 14:17 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    root 52075 0.0 0.3 9876 6528 ? S 15:41 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 52076 0.0 0.2 14208 5124 ? S 15:41 0:00 nginx: worker
    process
    nobody 52130 0.0 0.2 14200 4868 ? S 16:30 0:00 nginx: worker
    process
    [root@Nginx sbin]# kill -WINCH 52075
    [root@Nginx sbin]# ps aux | grep nginx
    root 48732 0.0 0.1 9868 2436 ? Ss 14:17 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    root 52075 0.0 0.3 9876 6528 ? S 15:41 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 52130 0.0 0.2 14200 4868 ? S 16:30 0:00 nginx: worker
    process
    root 52137 0.0 0.1 221664 2176 pts/0 S+ 16:31 0:00 grep --
    color=auto nginx
    [root@Nginx sbin]# curl -I localhost
    HTTP/1.1 200 OK
    Server: nginx/1.24.0 ##版本回滾完成
    Date: Thu, 18 Jul 2025 08:31:51 GMT
    Content-Type: text/html
    Content-Length: 615
    Last-Modified: Thu, 18 Jul 2025 03:41:13 GMT
    Connection: keep-alive
    ETag: "66988ed9-267"
    Accept-Ranges: bytes

    3 nginx核心配置詳解

    3.1 配置文件說明

    nginx官方幫助文檔:nginx documentationhttp://nginx.org/en/docs/

    nginx配置文件的組成部分:

    • 主配置文件:nginx.conf
    • 子配置文件:include conf.d/*.conf
    • fastcgi,uwsgi,scgi等協議相關的配置文件
    • mime.types:支持的mime類型,MIME(Multipurpose Internet Mail Extensions)多用途互聯網郵件擴展類型,MIME消息能包含文本、圖像、音頻、視頻以及其他應用程序專用的數據,是設定某種擴展名的文件用一種應用程序來打開的方式類型,當該擴展名文件被訪問的時候,瀏覽器會自動使用指定應用程序來打開。多用于指定一些客戶端自定義的文件名,以及一些媒體文件打開方式。

    nginx配置文件格式說明:

    • 配置文件由指令與指令塊構成
    • 每條指令以;分號結尾,指令與值之間以空格符號分隔
    • 可以將多條指令放在同一行,用分號分隔即可,但可讀性差,不推薦
    • 指令塊以{ }大括號將多條指令組織在一起,且可以嵌套指令塊
    • include語句允許組合多個配置文件以提升可維護性
    • 使用#符號添加注釋,提高可讀性
    • 使用$符號使用變量
    • 部分指令的參數支持正則表達式

    nginx主配置文件的配置指令方式:

    指令必須以分號結尾
    支持使用配置變量
    內建變量:由Nginx模塊引入,可直接引用
    自定義變量:由用戶使用set命令定義,格式: set variable_name value;
    引用變量:$variable_name
    主配置文件結構:四部分
    main block:主配置段,即全局配置段,對http,mail都有效
    #事件驅動相關的配置
    event {
    ...
    }#http/https 協議相關配置段
    http {
    默認的nginx.conf 配置文件格式說明
    ...
    }#默認配置文件不包括下面兩個塊
    #mail 協議相關配置段
    mail {
    ...
    }#stream 服務器相關配置段
    stream {
    ...
    }

    默認的nginx.conf配置文件格式說明:

    # 全局配置端,對全局生效,主要設置nginx的啟動用戶/組,啟動的工作進程數量,工作模式,Nginx的PID路
    徑,日志路徑等。
    user  nobody; # 這里使用nginx
    worker_processes  1; # 指定工作進程數量,一般設置為auto# error_log  文件路徑  日志級別;
    #error_log  logs/error.log; 
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;#pid        logs/nginx.pid; # 指定主進程PID文件路徑# events塊專門用于設置Nginx與客戶端連接相關的底層參數,決定了Nginx如何處理網絡事件(如接收連接、處理請求等),這些配置直接影響 Nginx 的并發處理能力
    events {worker_connections  1024; # 設置單個nginx工作進程可以接受的最大并發# 作為web服務器的時候最大并發數為# worker_processes * worker_connections# 作為反向代理的時候最大并發數為# (worker_connections * worker_processes)/2
    }# http塊是Nginx服務器配置中的重要部分,緩存、代理和日志格式定義等絕大多數功能和第三方模塊都
    # 可以在這設置,http塊可以包含多個server塊,而一個server塊中又可以包含多個location塊,
    # server塊可以配置文件引入、MIME-Type定義、日志自定義、是否啟用sendfile、連接超時時間和
    # 單個鏈接的請求上限等。
    http {include       mime.types;default_type  application/octet-stream;#log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '#                  '$status $body_bytes_sent "$http_referer" '#                  '"$http_user_agent" "$http_x_forwarded_for"';#access_log  logs/access.log  main;sendfile        on; # 作為web服務器的時候打開sendfile加快靜態文件傳輸,# 數據傳輸路徑為:磁盤 → 內核緩存 → 網絡協議棧 → 網卡,# 省略了用戶態與內核態之間的拷貝,減少 CPU 占用,提升傳輸速度,# 被稱之為零拷貝。#tcp_nopush     on;#keepalive_timeout  0;keepalive_timeout  65; # 長連接超時時間,單位是秒# 當客戶端(如瀏覽器)發起請求時,若雙方支持長連接,# 連接不會在單次請求后立即關閉,而是保持一段時間,供后續請求復用。# 避免每次請求都重新進行 TCP 三次握手,降低網絡延遲和服務器資源消耗# 際配置時需根據業務場景(并發量、請求頻率)調整,# 靜態資源多的服務可適當延長,高并發動態服務可適當縮短。#gzip  on;# server:設置一個虛擬機主機,可以包含自己的全局塊,同時也可以包含多個location模塊
    # 比如本虛擬機監聽的端口、本虛擬機的名稱和IP配置,多個server可以使用一個端口
    # 比如都使用80端口提供web服務server {listen       80; # 配置server監聽的端口server_name  localhost; # 本server的名稱,當訪問此名稱的時候# nginx會調用當前serevr內部的配置進程匹配#charset koi8-r;#access_log  logs/host.access.log  main;# location是Nginx配置中用于匹配客戶端請求URL路徑的核心指令,
    # 主要作用是根據請求的URL路徑,定義不同的處理規則(如返回靜態文件、反向代理到后端服務、
    # 重定向等)。它必須嵌套在 server 塊或其他 location 塊中,是實現 URL 路由的關鍵。location / {root   html; # 相當于默認頁面的目錄名稱,默認是安裝目錄的相對路徑,# 可以使用絕對路徑配置。index  index.html index.htm; # 默認的頁面文件名稱}#error_page  404              /404.html;# redirect server error pages to the static page /50x.html# 當服務器返回 500、502、503、504 這些服務器端錯誤狀態碼時,# Nginx 會自動將請求重定向到 /50x.html 頁面error_page   500 502 503 504  /50x.html; location = /50x.html { # location處理對應的不同錯誤碼的頁面定義到/50x.htmlroot   html; # 定義默認頁面所在的目錄}# proxy the PHP scripts to Apache listening on 127.0.0.1:80##location ~ \.php$ {#    proxy_pass   http://127.0.0.1;#}# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000##location ~ \.php$ {#    root           html;#    fastcgi_pass   127.0.0.1:9000;#    fastcgi_index  index.php;#    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;#    include        fastcgi_params;#}# deny access to .htaccess files, if Apache's document root# concurs with nginx's one##location ~ /\.ht {#    deny  all;#}}# another virtual host using mix of IP-, name-, and port-based configuration##server {#    listen       8000;#    listen       somename:8080;#    server_name  somename  alias  another.alias;#    location / {#        root   html;#        index  index.html index.htm;#    }#}# HTTPS server##server {#    listen       443 ssl;#    server_name  localhost;#    ssl_certificate      cert.pem;#    ssl_certificate_key  cert.key;#    ssl_session_cache    shared:SSL:1m;#    ssl_session_timeout  5m;#    ssl_ciphers  HIGH:!aNULL:!MD5;#    ssl_prefer_server_ciphers  on;#    location / {#        root   html;#        index  index.html index.htm;#    }#}
    # include /usr/local/nginx/conf.d/*.conf # 導入其他路徑的配置文件
    }

    3.2 全局配置

    • main全局配置段常見的配置指令分類:
    • 正常運行必備的配置
    • 優化性能相關的配置
    • 用于調試及定位問題相關的配置
    • 事件驅動相關的配置

    全局配置說明:

    user nginx nginx; # 啟動Nginx工作進程的用戶和組
    worker_processes [number | auto]; # 啟動Nginx工作進程的數量,一般設為和CPU核心數相同
    worker_cpu_affinity 00000001 00000010 00000100 00001000 | auto ;
    # 將Nginx工作進程綁定到指定的CPU核心,默認Nginx是不進行進程綁定的,綁定并不是意味著當前nginx進
    # 程獨占以一核心CPU,但是可以保證此進程不運行在其他核心上,這就極大減少了nginx的工作進程在不同的
    # cpu核心上的來回跳轉,減少了CPU對進程的資源分配與回收以及內存管理等,因此可以有效的提升nginx服務
    # 器的性能。
    # CPU MASK:00000001:0號CPU
    #           00000010:1號CPU
    #           10000000:7號CUP
    # 示例:
    # worker_cpu_affinity 0001 0010 0100 1000;第0號至第3號CPU
    # worker_cpu_affinity 01 10;第0號至第1號cpu
    # 查看配置
    [root@centos8 ~]# ps axo pid,cmd,psr | grep nginx
    31093 nginx: master process /apps 1
    34474 nginx: worker process 1
    34475 nginx: worker process 3
    34476 nginx: worker process 5
    34477 nginx: worker process 7
    # a:顯示所有用戶的進程
    # x:顯示沒有控制終端的進程(如后臺服務進程)
    # o pid,cmd,psr:自定義輸出格式,僅顯示三個字段
    # pid:進程 ID。
    # cmd:啟動進程的命令(包括參數)。
    # psr:進程當前運行的 CPU 核心編號error_log /usr/local/nginx/logs/error.log error; # 指定錯誤日志路徑和錯誤級別pid /usr/local/nginx/logs/nginx.pid; # pid文件的保存路徑worker_priority 0; # 工作進程的優先級,進程優先級范圍通常為-20到19,通常保持默認0即可# 數值越小,優先級越高(如 -20 是最高優先級)# 數值越大,優先級越低(如 19 是最低優先級)# 默認值通常為 0(與系統中其他普通進程優先級相同)# 若服務器專門用于 Nginx 服務,且需要優先保障其響應速度,# 可適當降低數值(提高優先級),如 worker_priority -5;# 若 Nginx 并非服務器核心服務(如同時運行高優先級的計算任務),# 可提高數值(降低優先級),如 worker_priority 5;
    worker_rlimit_nofile 65536; # 所有worker進程能打開的文件數量上限,# 包括:Nginx的所有連接(例如與代理服務器的連接等)# 而不僅僅是與客戶端的連接# 另一個考慮因素是實際的并發連接數不能超過# 系統級別的最大打開文件數的限制# 最好與ulimit -n 或者limits.conf的值保持一致
    # 修改pam限制
    [root@Nginx ~]# sudo -u nginx ulimit -n
    1024
    [root@Nginx ~]# vim /etc/security/limits.conf
    * - nofile 100000
    [root@Nginx ~]# sudo -u nginx ulimit -n
    100000daemon off; #前臺運行Nginx服務用于測試、docker等環境
    master_process off|on; # 是否開啟Nginx的master-worker工作模式,僅用于開發調試場景,默認為onevents {worker_connections 65535; # 設置單個工作進程的最大并發連接數use epoll;                # 使用epoll事件驅動(Linux推薦epoll,性能最優),# Nginx支持眾多的事件驅動,# 比如:select、poll、epoll,只能設置在events模塊中accept_mutex on; # 驚群問題:當多個 Nginx 工作進程同時監聽同一端口時,新連接到達時,# 所有工作進程會被同時喚醒競爭連接,但最終只有一個進程能獲取連接,# 其余進程被喚醒后發現無連接可處理,造成 CPU 資源浪費# on時,同一時間只允許一個工作進程嘗試接收新連接,避免多進程同時競爭,# 減少 CPU 無效消耗,提高連接處理效率,建議設置為onmulti_accept on; # 允許單個工作進程(worker process)一次性接收多個新連接# 減少accept()調用次數和進程喚醒頻率,降低CPU上下文切換開銷# 建議開啟
    }

    3.2.1 實現nginx的高并發配置

    注意:測試環境由于硬件問題,并發量寫小一點(對硬件要求較高)

    1.修改nginx默認配置文檔

    [root@server2 conf]# vim /usr/local/nginx/conf/nginx.conf

    2.修改pam限制

    [root@server2 conf]# vim /etc/security/limits.conf

    3.查看pam是否生效

    [root@server2 ~]# sudo -u nginx ulimit -n
    50000

    4.測試并發性能

    [root@server2 ~]# ab -c 1500 -n 50000 http://192.168.36.136/index.html

    ?-n:請求總量

    -c:并發量

    總共50000個請求,每次發送1500個并發

    3.3 http配置塊

    # 在響應報文中將指定的文件擴展名映射至MIME對應的類型
    include /etc/nginx/mime.types;
    default_type application/octet-stream; # 除mime.types中的類型外# 指定其它文件的默認MIME類型,瀏覽器一般會提示下載
    types {
    text/html html;
    image/gif gif;
    image/jpeg jpg;
    }

    示例:

    [root@Nginx ~]# vim /usr/local/nginx/html/lee.php
    <?php
    phpinfo();
    ?>
    [root@Nginx ~]# curl -I 192.168.36.136/lee.php
    HTTP/1.1 200 OK
    Server: nginx/1.26.1
    Content-Type: application/octet-stream
    Content-Length: 24
    Last-Modified: Fri, 19 Jul 2025 09:38:52 GMT
    Connection: keep-alive
    ETag: "669a342c-18"
    Accept-Ranges: bytes
    [root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf
    default_type text/html;
    [root@Nginx ~]# nginx -s reload
    [root@Nginx ~]# curl -I 192.168.36.136/lee.php
    HTTP/1.1 200 OK
    Server: nginx/1.26.1
    Date: Fri, 19 Jul 2025 09:49:49 GMT
    Content-Type: text/html
    Content-Length: 24
    Last-Modified: Fri, 19 Jul 2025 09:38:52 GMT
    Connection: keep-alive
    ETag: "669a342c-18"
    Accept-Ranges: bytes

    3.4 核心配置示例

    基于不同的IP、不同的端口以及不用得域名實現不同的虛擬主機,依賴于核心模塊
    ngx_http_core_module實現。

    3.4.1?新建一個 PC web 站點

    1.添加子配置文件路徑(在配置文件的最后面添加此行,不要放在最前面,會導致前面的命令無法

    生效
    [root@server2 sbin]# vim /usr/local/nginx/conf/nginx.conf

    2.創建虛擬主機網站配置

    [root@server2 sbin]# mkdir -p /usr/local/nginx/conf.d/
    [root@server2 sbin]# vim /usr/local/nginx/conf.d/vhosts.conf
    [root@server2 sbin]#

    3.重新讀取配置文件

    [root@server2 sbin]# nginx -s reload

    3.添加域名映射

    [root@server2 sbin]# vim /etc/hosts

    4.測試域名訪問效果

    [root@server2 ~]# mkdir -p /web/html
    [root@server2 ~]# vim /web/html/index.html
    web_html
    [root@server2 ~]# curl www.timinglee.org
    web_html

    3.4.2 root與alias

    location中使用root指令和alias指令的意義不同?

    1.root查找路徑方式?

    location /dirtest {root /mnt;}
    

    ?客戶實請求路徑:curl www.timinglee.org/dirtest/index.html

    Nginx 實際查找的文件路徑:/nmt/dirtest/index.html(root路徑 + location路徑 + 請求資源

    2.alias查找路徑方式

    location /alias {alias /mnt/dirtest;}
    

    客戶請求路徑:curl www.timinglee.org/dirtest/

    nginx實際查找文件路徑:/nmt/dirtest/index.html(alias路徑 + 請求資源,忽略location路徑)

    3.4.3 location的詳細使用

    • 在一個serverlocation配置段可存在多個,用于實現從uri到文件系統的路徑映射;
    • ngnix會根據用戶請求的URI來檢查定義的所有location,按一定的優先級找出一個最佳匹配, 而后應用其配置在沒有使用正則表達式的時候,nginx會先在server中的多個location選取匹配度最高的一個uri
    • uri是用戶請求的字符串,即域名后面的web文件路徑
    • 然后使用該location模塊中的正則url和字符串,如果匹配成功就結束搜索,并使用此location處理此請求。
    #語法規則:
    location [ = | ~ | ~* | ^~ ] uri { ... }=     # 用于標準uri前,需要請求字串與uri精確匹配,大小敏感,如果匹配成功就停止向下匹配并立即處理請求
    ^~    # 用于標準uri前,表示包含正則表達式,并且匹配以指定的正則表達式開頭# 對uri的最左邊部分做匹配檢查,不區分字符大小寫
    ~     # 用于標準uri前,表示包含正則表達式,并且區分大小寫
    ~*    # 用于標準uri前,表示包含正則表達式,并且不區分大寫
    不帶符號 #匹配起始于此uri的所有的uri
    \     # 用于標準uri前,表示包含正則表達式并且轉義字符。可以將 . * ?等轉義為普通符號#匹配優先級從高到低:
    =, ^~, ~/~*, 不帶符號
    3.4.3.1 匹配案例-精準匹配
    server部分使用location配置一個web界面,例如:當訪問nginx 服務器的/logo.jpg的時候要顯示指定html文件的內容,精確匹配一般用于匹配組織的logo等相對固定的URL,匹配優先級最高
    1.精確匹配logo
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/images -p
    [root@Nginx ~]# ls /webdata/nginx/timinglee.org/lee/images
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location = /logo.png {root /webdata/nginx/timinglee.org/lee/images;}
    }
    #上傳logo.jpg圖片到/webdata/nginx/timinglee.org/lee/images,重啟Nginx并訪問測試
    #訪問測試:http://www.timinglee.org/logo.png
    3.1.3.2 匹配案例-區分大小寫
    ~ 實現區分大小寫的模糊匹配. 以下案例中, 如果訪問uri中包含大寫字母的logo.PNG,則以下location匹配logo.png條件不成功,因為 ~ 區分大小寫,當用戶的請求被執行匹配時發現location中定義的是小寫的png,本次訪問的uri匹配失敗,后續要么繼續往下匹配其他的location(如果有),要么報錯給客戶端
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ~ /logo.PNG {root /webdata/nginx/timinglee.org/lee/images;}
    }
    #重啟Nginx并訪問測試
    #http://www.timinglee.org/logo.PNG #訪問失敗,系統中沒有logo.PNG文件
    3.4.3.3 匹配案例-不區分大小寫
    ~* 用來對用戶請求的uri做模糊匹配,uri中無論都是大寫、都是小寫或者大小寫混合,此模式也都會匹配,通常使用此模式匹配用戶request中的靜態資源并繼續做下一步操作,此方式使用較多
    注意: 此方式中,對于Linux文件系統上的文件仍然是區分大小寫的,如果磁盤文件不存在,仍會提示404
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ~* /logo.PNG {root /webdata/nginx/timinglee.org/lee/images;}
    }
    #重啟Nginx并訪問測試
    #http://www.timinglee.org/logo.png
    3.4.3.4 匹配案例-URI開始
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/images/images{1,2}
    [root@Nginx ~]# echo image1 > /webdata/nginx/timinglee.org/lee/images/images1/index.html
    [root@Nginx ~]# echo image1 > /webdata/nginx/timinglee.org/lee/images/images2/index.html
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ^~ /images {root /webdata/nginx/timinglee.org/lee/images;index index.html;}location /images1 {root /webdata/nginx/timinglee.org/lee/images;}
    }
    #重啟Nginx并訪問測試,實現效果是訪問/images1和/images2返回內容一樣
    [root@node100 ~]# curl 192.168.36.100/images1/
    image1
    [root@node100 ~]# curl 192.168.36.100/images2/
    image1
    3.4.3.5 匹配案例-文件名后綴
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/images
    #上傳一個圖片到/webdata/nginx/timinglee.org/lee/images
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ~* \.(gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js|css)$ {root /webdata/nginx/timinglee.org/lee/images;index index.html;}
    }
    #重啟Nginx并訪問測試
    192.168.36.200/logo.png
    3.4.3.6 匹配案例-優先級
    server {
    listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ^~ /images {root /webdata/nginx/timinglee.org/lee/images;index index.html;}location /images1 {root /webdata/nginx/timinglee.org/lee/images;}location ~* \.(gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js)$ {root /data/nginx/static3;index index.html;}
    }
    #匹配優先級:=, ^~, ~/~*,/
    location優先級:(location =) > (location ^~ 路徑) > (location ~,~* 正則順序) >
    (location 完整路徑) > (location 部分起始路徑) > (/)
    3.4.3.7 生產使用案例
    #直接匹配網站根會加速Nginx訪問處理
    location = /index.html {......;
    }
    location / {......;
    }#靜態資源配置方法1
    location ^~ /static/ {......;
    }#靜態資源配置方法2,應用較多
    location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {......;
    }#多應用配置
    location ~* /app1 {......;
    }
    location ~* /app2 {......;
    }

    3.4.4 Nginx 賬戶認證功能

    ngx_http_auth_basic_module 模塊提供此功能
    示例:
    [root@Nginx ~]# htpasswd -cmb /usr/local/nginx/conf/.htpasswd admin lee #-b 表
    示非交互建立用戶認證
    Adding password for user admin
    [root@Nginx ~]# htpasswd -mb /usr/local/nginx/conf/.htpasswd lee lee
    Adding password for user lee
    [root@Nginx ~]# cat /usr/local/nginx/conf/.htpasswd
    admin:$apr1$haGCKgCT$myogggALmqNecTyNupsWQ/
    lee:$apr1$H97AyQPF$kGU.Tc4zn1E4Zkp/M4R6G.
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/login
    [root@Nginx ~]# echo login > /webdata/nginx/timinglee.org/lee/login/index.html
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {
    listen 80;
    server_name lee.timinglee.org;
    location /login {
    root /webdata/nginx/timinglee.org/lee;
    index index.html;
    auth_basic "login password";
    auth_basic_user_file "/usr/local/nginx/conf/.htpasswd";
    }
    }
    #重啟Nginx并訪問測試
    [root@node100 ~]# curl lee.timinglee.org/login/ -u lee:lee
    login
    [root@node100 ~]# curl lee.timinglee.org/login/ -u admin:lee
    login

    實驗驗證:

    基于用戶的訪問

    [root@server2 ~]# mkdir -p /web/login/
    [root@server2 ~]# touch index.html
    [root@server2 ~]# echo "login" > /web/login/index.html
    [root@server2 ~]# cat /web/login/index.html 
    login
    [root@server2 ~]#
    [root@server2 conf.d]# htpasswd -cm /usr/local/nginx/.htpasswd admin # 創建nginx所需認證文件和用戶
    # -c創建新的文件會覆蓋舊文件
    New password: 
    Re-type new password: 
    Adding password for user admin
    [root@server2 conf.d]# htpasswd -m /usr/local/nginx/.htpasswd lee
    New password: 
    Re-type new password: 
    Adding password for user lee
    [root@server2 conf.d]# cat /usr/local/nginx/.htpasswd 
    admin:$apr1$.0fUA3Pl$e6CqYByBBLgDfrZAps32y/
    lee:$apr1$pPwPp51g$/PBcT9Xl293rX5ciMdaE4.
    [root@server2 conf.d]# 
    
    [root@server2 conf.d]# vim vhosts.conf 
    [root@server2 conf.d]# pwd
    /usr/local/nginx/conf.d
    

    驗證是否成功

    [root@server2 ~]# nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
    [root@server2 ~]# nginx -s reload
    [root@server2 ~]# curl www.timinglee.org/login/
    <html>
    <head><title>401 Authorization Required</title></head>
    <body>
    <center><h1>401 Authorization Required</h1></center>
    <hr><center>nginx/1.24.0</center>
    </body>
    </html>
    [root@server2 ~]# curl -uadmin:lee www.timinglee.org/login/
    login
    [root@server2 ~]#

    3.4.5 自定義錯誤頁面和錯誤日志

    自定義錯誤和日志

    [root@server2 web]# mkdir errorpage
    [root@server2 web]# echo "錯誤" > error.html
    [root@server2 web]# cat error.html 
    錯誤
    

    [root@server2 logs]# touch timinglee.org.err
    [root@server2 logs]# touch timinglee.org.acc
    [root@server2 logs]# pwd
    /usr/local/nginx/logs
    [root@server2 logs]#

    ?驗證

    3.4.7 檢測文件是否存在

    try_files會按順序檢查文件是否存在,返回第一個找到的文件或文件夾(結尾加斜線表示為文件夾),如果所有文件或文件夾都找不到,會進行一個內部重定向到最后一個參數。只有最后一個參數可以引起一個內部重定向,之前的參數只設置內部URI的指向。最后一個參數是回退URI且必須存在,否則會出現內部500錯誤。
    示例:如果不存在頁面,就轉到default.html頁面
    [root@Nginx ~]# echo "index.html is not exist" >
    /webdata/nginx/timinglee.org/lee/error/default.html
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;root /webdata/nginx/timinglee.org/lee;error_page 404 /40x.html;access_log /var/log/nginx/access.log;error_log /var/log/nginx/error.log;try_files $uri $uri.html $uri/index.html /error/default.html;location = /40x.html {root /webdata/nginx/timinglee/lee/errors;}
    }

    實驗驗證:

    [root@server2 conf.d]# echo default > /web/errorpage/default.html
    [root@server2 conf.d]# cat /web/errorpage/default.html 
    default
    

    測試

    3.4.8 長連接配置

    keepalive_timeout timeout [header_timeout]; # 設定保持連接超時時長,0表示禁止長連接,默認為75s# 通常配置在http字段作為站點全局配置
    keepalive_requests 數字;                     # 在一次長連接上所允許請求的資源的最大數量# 默認為100次,建議適當調大,比如:500

    示例:

    keepalive_requests 3;
    keepalive_timeout 65 60;
    #開啟長連接后,返回客戶端的會話保持時間為60s,單次長連接累計請求達到指定次數請求或65秒就會被斷
    開,第二個數字60為發送給客戶端應答報文頭部中顯示的超時時間設置為60s:如不設置客戶端將不顯示超時時
    間。
    Keep-Alive:timeout=60 #瀏覽器收到的服務器返回的報文
    #如果設置為0表示關閉會話保持功能,將如下顯示:
    #Connection:close 瀏覽器收到的服務器返回的報文
    #使用命令測試:
    [root@node100 ~]# telnet lee.timinglee.org 80
    Trying 172.25.254.200...
    Connected to lee.timinglee.org.
    Escape character is '^]'.
    GET / HTTP/1.1 ##輸入動作
    HOST: lee.timinglee.org ##輸入訪問HOST
    ##輸入回車
    HTTP/1.1 200 OK
    Server: nginx/1.24.0
    Date: Sat, 20 Jul 2024 12:54:16 GMT
    Content-Type: text/html
    Content-Length: 15
    Last-Modified: Sat, 20 Jul 2024 08:49:12 GMT
    Connection: keep-alive
    ETag: "669b7a08-f"
    Accept-Ranges: bytes
    172.25.254.200
    GET / HTTP/1.1 #第二次操作
    HOST: lee.timinglee.org #第二次操作
    #第二次操作
    HTTP/1.1 200 OK
    Server: nginx/1.24.0
    Date: Sat, 20 Jul 2024 12:54:25 GMT
    Content-Type: text/html
    Content-Length: 15
    Last-Modified: Sat, 20 Jul 2024 08:49:12 GMT
    Connection: close
    ETag: "669b7a08-f"
    Accept-Ranges: bytes
    172.25.254.200
    Connection closed by foreign host. #自動斷開鏈接

    實驗驗證

    [root@server2 conf]# vim nginx.conf # 長鏈接位于nginx主配置文件
    [root@server2 conf]# pwd
    /usr/local/nginx/conf
    [root@server2 conf]# 

    [root@server2 ~]# yum install telnet -y

    3.4.9 作為下載服務器配置

    ngx_http_autoindex_module 模塊處理以斜杠字符 "/" 結尾的請求,并生成目錄列表,可以做為下載服務配置使用
    相關指令:
    autoindex on | off; # 自動文件索引功能,默為off
    autoindex_exact_size on | off; # 計算文件確切大小(單位bytes),off 顯示大概大小(單位K、M),默認on
    autoindex_localtime on | off ; # 顯示本機時間而非GMT(格林威治)時間,默認off
    autoindex_format html | xml | json | jsonp; # 顯示索引的頁面文件風格,默認html
    limit_rate rate; # 限制響應客戶端傳輸速率(除GET和HEAD以外的所有方法),單位B/s,bytes/second,# 默認值0,表示無限制,此指令由ngx_http_core_module提供
    set $limit_rate 4k; # 也可以通變量限速,單位B/s,同時設置,此項優級高.

    示例:實現下載站點

    #注意:download不需要index.html文件
    [root@Nginx ~]# mkdir -p /webdata/nginx/timinglee.org/lee/download
    [root@Nginx ~]# cp /root/anaconda-ks.cfg /webdata/nginx/timinglee.org/lee/download
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;root /webdata/nginx/timinglee.org/lee;access_log /var/log/nginx/access.log;error_log /var/log/nginx/error.log;try_files $uri $uri.html $uri/index.html /error/default.html;location = /40x.html {root /webdata/nginx/timinglee/lee/errors;}location /download {autoindex on; #自動索引功能autoindex_exact_size on; #計算文件確切大小(單位bytes),此為默認值,off只顯示大概大小(單位kb、mb、gb)autoindex_localtime on; #on表示顯示本機時間而非GMT(格林威治)時間,默為為off顯示GMT時間limit_rate 1024k; #限速,默認不限速 }
    }
    #重啟Nginx并訪問測試下載頁面

    實驗實現:

    1.建立實驗素材?

    2.下載服務器?

    ?3.測試

    4 nginx高級配置

    4.1 nginx狀態頁

    • 基于nginx 模塊 ngx_http_stub_status_module 實現,
    • 在編譯安裝nginx的時候需要添加編譯參數 --with-http_stub_status_module
    • 否則配置完成之后監測會是提示法錯誤
    注意: 狀態頁顯示的是整個服務器的狀態,而非虛擬主機的狀態
    #配置示例:
    location /nginx_status {
    stub_status;
    auth_basic "auth login";
    auth_basic_user_file /apps/nginx/conf/.htpasswd;
    allow 192.168.0.0/16;
    allow 127.0.0.1;
    deny all;
    }
    # 狀態頁用于輸出nginx的基本狀態信息:
    # 輸出信息示例:
    Active connections: 291
    server accepts handled requests
    16630948 16630948 31070465
    上面三個數字分別對應accepts,handled,requests三個值
    Reading: 6 Writing: 179 Waiting: 106
    Active connections: # 當前處于活動狀態的客戶端連接數# 包括連接等待空閑連接數=reading+writing+waiting
    accepts:           # 統計總值,Nginx自啟動后已經接受的客戶端請求連接的總數。
    handled:            # 統計總值,Nginx自啟動后已經處理完成的客戶端請求連接總數# 通常等于accepts,除非有因worker_connections限制等被拒絕的連接
    requests:           # 統計總值,Nginx自啟動后客戶端發來的總的請求數
    Reading:            # 當前狀態,正在讀取客戶端請求報文首部的連接的連接數# 數值越大,說明排隊現象嚴重,性能不足
    Writing:            # 當前狀態,正在向客戶端發送響應報文過程中的連接數,數值越大,說明訪問量很大
    Waiting:            # 當前狀態,正在等待客戶端發出請求的空閑連接數開啟 keep-alive的情況下,這個值                等于active –(reading+writing)

    4.1 nginx壓縮功能

    Nginx支持對指定類型的文件進行壓縮然后再傳輸給客戶端,而且壓縮還可以設置壓縮比例,壓縮后的文件大小將比源文件顯著變小,樣有助于降低出口帶寬的利用率,降低企業的IT支出,不過會占用相應的CPU資源。
    Nginx對文件的壓縮功能是依賴于模塊 ngx_http_gzip_module,默認是內置模塊
    配置指令如下:
    #啟用或禁用gzip壓縮,默認關閉
    gzip on | off;#壓縮比由低到高從1到9,默認為1,值越高壓縮后文件越小,但是消耗cpu比較高。基本設定未4或者5
    gzip_comp_level 4;#禁用IE6 gzip功能,早期的IE6之前的版本不支持壓縮
    gzip_disable "MSIE [1-6]\.";#gzip壓縮的最小文件,小于設置值的文件將不會壓縮
    gzip_min_length 1k;#啟用壓縮功能時,協議的最小版本,默認HTTP/1.1
    gzip_http_version 1.0 | 1.1;#指定Nginx服務需要向服務器申請的緩存空間的個數和大小,平臺不同,默認:32 4k或者16 8k;
    gzip_buffers number size;#指明僅對哪些類型的資源執行壓縮操作;默認為gzip_types text/html,不用顯示指定,否則出錯
    gzip_types mime-type ...;#如果啟用壓縮,是否在響應報文首部插入“Vary: Accept-Encoding”,一般建議打開
    gzip_vary on | off;#預壓縮,即直接從磁盤找到對應文件的gz后綴的式的壓縮文件返回給用戶,無需消耗服務器CPU
    #注意: 來自于ngx_http_gzip_static_module模塊
    gzip_static on | off;

    示例:

    #重啟nginx并進行訪問測試壓縮功能
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/data
    [root@Nginx ~]# cp /usr/local/nginx/logs/access.log
    /webdata/nginx/timinglee.org/lee/data/data.txt
    [root@Nginx ~]# echo test > /webdata/nginx/timinglee.org/lee/data/test.html #
    小于1k的文件測試是否會壓縮
    [root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf
    @@@@省略內容@@@@
    gzip on;
    gzip_comp_level 5;
    gzip_min_length 1k;
    gzip_types text/plain application/javascript application/x-javascript text/css
    application/xml text/javascript application/x-httpd-php image/gif image/png;
    gzip_vary on;
    #重啟Nginx并訪問測試:
    [root@client ~]# curl --head --compressed lee.timinglee.org/data/test.html
    HTTP/1.1 200 OK
    Server: nginx/1.26.1
    Date: Sun, 21 Jul 2024 15:42:46 GMT
    Content-Type: text/html
    Content-Length: 5
    Last-Modified: Sun, 21 Jul 2024 15:40:35 GMT
    Connection: keep-alive
    ETag: "669d2bf3-5"
    Accept-Ranges: bytes
    [root@client ~]# curl --head --compressed lee.timinglee.org/data/data.txt
    HTTP/1.1 200 OK
    Server: nginx/1.26.1
    Date: Sun, 21 Jul 2024 15:43:17 GMT
    Content-Type: text/plain
    Last-Modified: Sun, 21 Jul 2024 15:40:13 GMT
    Connection: keep-alive
    Vary: Accept-Encoding
    ETag: W/"669d2bdd-3e25b5"
    Content-Encoding: gzip

    實驗驗證:

    1.準備壓縮材料

    [root@server2 conf.d]# cp /usr/local/nginx/logs/timinglee.org.acc /web/html/big.html
    [root@server2 conf.d]# echo hello > /web/html/small.html
    [root@server2 conf.d]# cat /web/html/small.html 
    hello
    

    2.編輯配置文件

    測試壓縮效果

    [root@server2 conf.d]# cp /usr/local/nginx/logs/timinglee.org.acc /web/html/big.html

    [root@server2 conf.d]# curl --head --compressed www.timinglee.org/small.html

    4.3 nginx的版本隱藏

    用戶在訪問nginx的時候,我們可以從報文中獲得nginx的版本,相對于裸漏版本號的nginx,我們把其隱藏起來更安全
    [root@Nginx nginx-1.26.1]# vim src/core/nginx.h
    #define nginx_version 1026001
    #define NGINX_VERSION "1.0"
    #define NGINX_VER "HAHA/" NGINX_VERSION

    4.4 nginx變量使用

    • nginx的變量可以在配置文件中引用,作為功能判斷或者日志等場景使用
    • 變量可以分為內置變量和自定義變量
    • 內置變量是由nginx模塊自帶,通過變量可以獲取到眾多的與客戶端訪問相關的值。

    4.4.1 內置變量

    官方文檔:Alphabetical index of variableshttp://nginx.org/en/docs/varindex.html

    常用內置變量:

    $remote_addr;
    #存放了客戶端的地址,注意是客戶端的公網IP$args;
    #變量中存放了URL中的所有參數
    #例如:https://search.jd.com/Search?keyword=手機&enc=utf-8
    #返回結果為: keyword=手機&enc=utf-8$is_args
    #如果有參數為? 否則為空$document_root;
    #保存了針對當前資源的請求的系統根目錄,例如:/webdata/nginx/timinglee.org/lee。$document_uri;
    #保存了當前請求中不包含參數的URI,注意是不包含請求的指令
    #比如:http://lee.timinglee.org/var?\id=11111會被定義為/var
    #返回結果為:/var$host;
    #存放了請求的host名稱limit_rate 10240;
    echo $limit_rate;
    #如果nginx服務器使用limit_rate配置了顯示網絡速率,則會顯示,如果沒有設置, 則顯示0$remote_port;
    #客戶端請求Nginx服務器時隨機打開的端口,這是每個客戶端自己的端口$remote_user;
    #已經經過Auth Basic Module驗證的用戶名$request_body_file;
    #做反向代理時發給后端服務器的本地資源的名稱$request_method;
    #請求資源的方式,GET/PUT/DELETE等$request_filename;
    #當前請求的資源文件的磁盤路徑,由root或alias指令與URI請求生成的文件絕對路徑,
    #如:webdata/nginx/timinglee.org/lee/var/index.html$request_uri;
    #包含請求參數的原始URI,不包含主機名,相當于:$document_uri?$args,
    #例如:/main/index.do?id=20190221&partner=search$scheme;
    #請求的協議,例如:http,https,ftp等$server_protocol;
    #保存了客戶端請求資源使用的協議的版本,例如:HTTP/1.0,HTTP/1.1,HTTP/2.0等$server_addr;
    #保存了服務器的IP地址$server_name;
    #虛擬主機的主機名$server_port;
    #虛擬主機的端口號$http_user_agent;
    #客戶端瀏覽器的詳細信息$http_cookie;
    #客戶端的所有cookie信息$cookie_<name>
    #name為任意請求報文首部字部cookie的key名
    $http_<name>
    #name為任意請求報文首部字段,表示記錄請求報文的首部字段,name的對應的首部字段名需要為小寫,如果有
    橫線需要替換為下劃線
    #示例:
    echo $http_user_agent;
    echo $http_host;$sent_http_<name>
    #name為響應報文的首部字段,name的對應的首部字段名需要為小寫,如果有橫線需要替換為下劃線,此變量有
    問題echo $sent_http_server;
    $arg_<name>
    #此變量存放了URL中的指定參數,name為請求url中指定的參數
    echo $arg_id;

    示例:

    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;root /webdata/nginx/timinglee.org/lee;location /var {default_type text/html;echo $remote_addr;echo $args;echo $document_root;echo $document_uri;echo $host;echo $http_user_agent;echo $request_filename;echo $scheme;echo $scheme://$host$document_uri?$args;echo $http_cookie;echo $cookie_key2;echo $http_Accept;}
    }[root@client ~]# curl -b "title=lee;key1=lee,key2=timinglee"
    "lee.timinglee.org/var?search=lee&&id=666666"
    172.25.254.20
    search=lee&&id=666666
    /webdata/nginx/timinglee.org/lee
    /var
    lee.timinglee.org
    curl/7.29.0
    /webdata/nginx/timinglee.org/lee/var
    http
    http://lee.timinglee.org/var?search=lee&&id=666666
    title=lee;key1=lee,key2=timinglee
    timinglee
    */*
    實驗驗證:
    1.實驗前需要導入echo-nginx-module-0.63模塊(前面并沒有安裝此模塊)
    [root@server2 ~]# rm -rf /usr/local/nginx/
    [root@server2 ~]# cd /usr/local/
    [root@server2 local]# rm -rf nginx-1.26.3/
    [root@server2 ~]# cd /usr/local/
    [root@server2 local]# tar zxf /root/nginx-1.26.3.tar.gz
    [root@server2 local]# tar zxf /root/echo-nginx-module-0.63.tar.gz
    [root@server2 nginx-1.26.3]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/usr/local/echo-nginx-module-0.63
    [root@server2 nginx-1.26.3]# make && make install

    ?驗證

    [root@server2 conf.d]# nginx -s reload
    [root@server2 conf.d]# curl -A "timinglee" -b "lee=a,key1=2" -ulee:lee www.timinglee.org/vars?name=lee

    4.4.2 自定義變量

    假如需要自定義變量名稱和值,使用指令set $variable value;
    示例:
    set $name timinglee;
    echo $name;
    set $my_port $server_port;
    echo $my_port;
    echo "$server_name:$server_port";
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;root /webdata/nginx/timinglee.org/lee;location /var {default_type text/html;set $name timinglee;echo $name;set $web_port $server_port;echo $web_port;}
    }
    測試輸出
    [root@client ~]# curl lee.timinglee.org/var
    timinglee
    80

    5 Nginx Rewrite 相關功能

    • Nginx服務器利用 ngx_http_rewrite_module 模塊解析和處理rewrite請求
    • 此功能依靠 PCRE(perl compatible regular expression),因此編譯之前要安裝PCRE
    • rewritenginx服務器的重要功能之一,用于實現URL的重寫,URL的重寫是非常有用的功能
    • 比如它可以在我們改變網站結構之后,不需要客戶端修改原來的書簽,也無需其他網站修改我們的鏈接,就可以設置為訪問
    • 另外還可以在一定程度上提高網站的安全性。

    5.1?ngx_http_rewrite_module 模塊指令

    官方文檔:Module ngx_http_rewrite_modulehttps://nginx.org/en/docs/http/ngx_http_rewrite_module.html

    5.2?rewrite 案例: break last

    ?rewrite中break與last區別

    [root@server2 ~]# mkdir /web/html/{test1,test2,break,last}
    [root@server2 ~]# echo test1 > /web/html/test1/index.html
    [root@server2 ~]# echo test2 > /web/html/test2/index.html
    [root@server2 ~]# echo break > /web/html/break/index.html
    [root@server2 ~]# echo last > /web/html/last/index.html
    [root@server2 ~]#

    ?測試

    5.2.1?rewrite案例: 自動跳轉 https

    案例:基于通信安全考慮公司網站要求全站 https,因此要求將在不影響用戶請求的情況下將http請求全部自動跳轉至 https,另外也可以實現部分 location 跳轉https加密基本配置及全站加密策略

    [root@server2 conf.d]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /usr/local/nginx/certs/timinglee.org.key -x509 -days 365 -out /usr/local/nginx/certs/timinglee.org.crt
    

    ?

    測試

    5.2.2?rewrite 案例: 判斷文件是否存在

    案例:當用戶訪問到公司網站的時輸入了一個錯誤的URL,可以將用戶重定向至官網首頁

    [root@centos8 ~]#vim /apps/nginx/conf.d/pc.conf
    location / {root /data/nginx/html/pc;index index.html;if (!-e $request_filename) {rewrite .* http://www.timinglee.org/index.html; #實現客戶端瀏覽器的302跳轉#rewrite .* /index.html; #web服務器內部跳轉}
    }
    #重啟Nginx并訪問測試

    ?判斷文件是否存在

    5.3 nginx防盜鏈

    防盜鏈基于客戶端攜帶的referer實現,referer是記錄打開一個頁面之前記錄是從哪個頁面跳轉過來的標記信息,如果別人只鏈接了自己網站圖片或某個單獨的資源,而不是打開了網站的整個頁面,這就是盜鏈,referer就是之前的那個網站域名,正常的referer信息有以下幾種:
    none:             # 請求報文首部沒有referer首部,# 比如用戶直接在瀏覽器輸入域名訪問web網站,就沒有referer信息。
    blocked:          # 請求報文有referer首部,但無有效值,比如為空。
    server_names:     # referer首部中包含本主機名及即nginx 監聽的server_name。
    arbitrary_string: # 自定義指定字符串,但可使用*作通配符。示例: *.timinglee.org
    www.timinglee.*
    regular expression: # 被指定的正則表達式模式匹配到的字符串,要使用~開頭,例如:
    ~.*\.timinglee\.com

    5.3.1 實現盜鏈

    在一個web 站點盜鏈另一個站點的資源信息,比如:圖片、視頻等
    示例:
    #新建一個主機172.25.254.20,盜取另一臺主機lee.timinglee.org/images/lee.png的圖片
    [root@client ~]# yum install httpd -y
    [root@client html]# vim /var/www/html/index.html
    #準備盜鏈web頁面:
    <html>
    <head>
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
    <title>盜鏈</title>
    </head>
    <body>
    <img src="http://www.timinglee.org/images/lee.png" >
    <h1 style="color:red">歡迎大家</h1>
    <p><a href=http://www.timinglee.org>狂點老李</a>出門見喜</p>
    </body>
    </html>
    ~
    #重啟apache并訪問http://172.25.254.20 測試
    #驗證兩個域名的日志,是否會在被盜連的web站點的日志中出現以下盜鏈日志信息:
    [root@Nginx ~]# cat /usr/local/nginx/logs/access.log
    172.25.254.1 - - [22/Jul/2024:09:50:01 +0800] "GET /images/logo.png HTTP/1.1" 304
    0 "http://172.25.254.20/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)
    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
    Edg/126.0.0.0"
    172.25.254.1 - - [22/Jul/2024:09:50:18 +0800] "GET / HTTP/1.1" 304 0
    "http://172.25.254.20/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)
    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
    Edg/126.0.0.0"

    5.3.2?實現防盜鏈

    基于訪問安全考慮,nginx支持通過ngx_http_referer_module模塊,檢查訪問請求的referer信息是否有效實現防盜鏈功能
    官方文檔:Module ngx_http_referer_modulehttps://nginx.org/en/docs/http/ngx_http_referer_module.html

    示例:定義防盜鏈

    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name www.timinglee.org;root /data/web/html;index index.html;location / {valid_referers none blocked server_names *.timinglee.org ~/.baidu/.;if ($invalid_referer){return 404;}
    }location /images {valid_referers none blocked server_names *.timinglee.org ~/.baidu/.;if ($invalid_referer){rewrite ^/ http://www.timinglee.org/daolian.png permanent; #注意此圖片不能和正常圖片放在一個目錄中}}
    }
    #重啟Nginx并訪問測試
    http://172.25.254.20

    6 nginx反向代理功能

    反向代理:reverse proxy,指的是代理外網用戶的請求到內部的指定的服務器,并將數據返回給用戶的一種方式,這是用的比較多的一種方式。
    Nginx 除了可以在企業提供高性能的web服務之外,另外還可以將 nginx 本身不具備的請求通過某種預定義的協議轉發至其它服務器處理,不同的協議就是Nginx服務器與其他服務器進行通信的一種規范,主要在不同的場景使用以下模塊實現不同的功能
    ngx_http_proxy_module:         # 將客戶端的請求以http協議轉發至指定服務器進行處理
    ngx_http_upstream_module       # 用于定義為proxy_pass,fastcgi_pass,uwsgi_pass# 等指令引用的后端服務器分組
    ngx_stream_proxy_module:       # 將客戶端的請求以tcp協議轉發至指定服務器處理
    ngx_http_fastcgi_module:       # 將客戶端對php的請求以fastcgi協議轉發至指定服務器助理
    ngx_http_uwsgi_module:         # 將客戶端對Python的請求以uwsgi協議轉發至指定服務器處理
    邏輯調用關系:

    訪問邏輯圖:
    • 同構代理:用戶不需要其他程序的參與,直接通過http協議或者tcp協議訪問后端服務器
    • 異構代理:用戶訪問的資源時需要經過處理后才能返回的,比如phppython,等等,這種訪問資源需要經過處理才能被訪問

    6.1 實現http反向代理

    官方文檔:Module ngx_http_proxy_modulehttps://nginx.org/en/docs/http/ngx_http_proxy_module.html

    6.1.1 http 協議反向代理

    6.1.1.1 反向代理配置參數
    #官方文檔:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
    proxy_pass;         # 用來設置將客戶端請求轉發給的后端服務器的主機# 可以是主機名(將轉發至后端服務做為主機頭首部)、IP地址:端口的方式# 也可以代理到預先設置的主機群組,需要模塊ngx_http_upstream_module支持
    #示例:
    location /web {index index.html;proxy_pass http://172.25.254.30:8080; # 8080后面無uri,即無 / 符號,# 需要將location后面url 附加到proxy_pass指定的url后面# 此行為類似于root# proxy_pass指定的uri不帶斜線將訪問的/web# 等于訪問后端服務器
    proxy_pass http://172.25.254.40:8080/;     # 8080后面有uri,即有 / 符號# 相當于置換,即訪問/web時實際返回proxy_pass后面uri內容
    # 此行為類似于alias
    # proxy_pass指定的uri帶斜線
    # 等于訪問后端服務器的
    # http://172.25.254.40:8080/index.html
    # 內容返回給客戶端
    } # http://nginx/web/index.html ==> http://1:8080# 重啟Nginx測試訪問效果:
    # curl -L http://www.timinglee.org/web
    # 如果location定義其uri時使用了正則表達式模式(包括~,~*,但不包括^~),則proxy_pass之后必須不能使用uri
    # 即不能有/ ,用戶請求時傳遞的uri將直接附加至后端服務器之后
    server {
    ...
    server_name HOSTNAME;
    location ~|~* /uri/ {
    proxy_pass http://host:port; #proxy_pass后面的url 不能加/
    }
    ...
    }
    http://HOSTNAME/uri/ --> http://host/uri/
    proxy_hide_header field; # 用于nginx作為反向代理的時候
    # 在返回給客戶端http響應時
    # 隱藏后端服務器相應頭部的信息
    # 可以設置在http,server或location塊
    # 示例: 隱藏后端服務器ETag首部字段
    location /web {index index.html;proxy_pass http://10.0.0.18:8080/;proxy_hide_header ETag;
    }
    proxy_pass_header field; # 透傳
    # 默認nginx在響應報文中不傳遞后端服務器的首部字段Date, Server, X-Pad, X-Accel等參數
    # 如果要傳遞的話則要使用 proxy_pass_header field聲明將后端服務器返回的值傳遞給客戶端
    # field 首部字段大小不敏感
    # 示例:透傳后端服務器的Server和Date首部給客戶端,同時不再響應報中顯示前端服務器的Server字段
    proxy_pass_header Server;
    proxy_pass_header Date;
    proxy_pass_request_body on | off;# 是否向后端服務器發送HTTP實體部分,可以設置在http,server或location塊,默認即為開啟
    proxy_pass_request_headers on | off;
    # 是否將客戶端的請求頭部轉發給后端服務器,可以設置在http,server或location塊,默認即為開啟
    proxy_set_header;# 可更改或添加客戶端的請求頭部信息內容并轉發至后端服務器,比如在后端服務器想要獲取客戶端的真實IP的時候,就要更改每一個報文的頭部
    #示例:
    location ~ /web {proxy_pass http://172.25.254.20:80;proxy_hide_header ETag;proxy_pass_header Server;proxy_pass_request_body on;proxy_pass_request_headers on;proxy_set_header X-Forwarded-For $remote_addr;
    }[root@apache20 ~]# vim /etc/httpd/conf/httpd.conf
    LogFormat "\"%{X-Forwarded-For}i\" %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%
    {User-Agent}i\"" combined訪問后看后端服務器日志proxy_connect_timeout time;
    # 配置nginx服務器與后端服務器嘗試建立連接的超時時間,默認為60秒用法如下:proxy_connect_timeout 6s;
    # 60s為自定義nginx與后端服務器建立連接的超時時間,超時會返回客戶端504響應碼proxy_read_timeout time;
    # 配置nginx服務器向后端服務器或服務器組發起read請求后,等待的超時時間,默認60sproxy_send_timeout time;
    # 配置nginx項后端服務器或服務器組發起write請求后,等待的超時 時間,默認60sproxy_http_version 1.0;
    # 用于設置nginx提供代理服務的HTTP協議的版本,默認http 1.0proxy_ignore_client_abort off;
    # 當客戶端網絡中斷請求時,nginx服務器中斷其對后端服務器的請求。即如果此項設置為on開啟,則服務器、
    會忽略客戶端中斷并一直等著代理服務執行返回,如果設置為off,則客戶端中斷后Nginx也會中斷客戶端請求
    并立即記錄499日志,默認為off。
    6.1.1.2 實戰案例: 反向代理單臺 web 服務器
    要求:將用戶對域 www.timinglee.org 的請求轉發給后端服務器處理
    [root@centos8 ~]# cat /apps/nginx/conf/conf.d/pc.conf
    server {listen 80;server_name www.timinglee.org;location / {proxy_pass http://172.25.254.30;}
    }
    #重啟Nginx 并訪問測試
    6.1.1.3 實戰案例: 指定 location 實現反向代理
    6.1.1.3.1 針對指定的 location
    server {
    listen 80;server_name www.timinglee.org;location / {proxy_pass http://172.25.254.30;}location ~ /static {proxy_pass http://172.25.254.20:8080;}
    }
    # 后端web服務器必須要有相對于的訪問URL
    [root@apache20 ~]# mkdir /var/www/html/static
    [root@apache20 ~]# echo static 172.25.254.20 > /var/www/html/static/index.html
    [root@apache30 ~]# echo 172.25.254.30 > /var/www/html/index.html
    # 重啟Nginx并訪問測試:
    [2025-07-25 17:09.35] ~
    [Administrator.DESKTOP-P19CNDN] ? curl www.timinglee.org/static/
    static 172.25.254.20
    [2025-07-25 17:09.39] ~
    [Administrator.DESKTOP-P19CNDN] ? curl www.timinglee.org
    172.25.254.30
    6.1.1.3.2 針對特定的資源實現代理

    [root@Nginx ~]# vim /apps/nginx/conf.d/vhost.conf
    server {listen 80;server_name www.timinglee.org;location / {proxy_pass http://172.25.254.30;}location ~ \.(png|jpg|gif) {proxy_pass http://172.25.254.20:8080;}
    }
    6.1.1.4 反向代理示例: 緩存功能
    緩存功能默認關閉狀態,需要先動配置才能啟用
    proxy_cache zone_name | off; 默認off
    # 指明調用的緩存,或關閉緩存機制;Context:http, server, location
    # zone_name 表示緩存的名稱.需要由proxy_cache_path事先定義proxy_cache_key string;
    # 緩存中用于“鍵”的內容,默認值:proxy_cache_key $scheme$proxy_host$request_uri;proxy_cache_valid [code ...] time;
    # 定義對特定響應碼的響應內容的緩存時長,定義在http{...}中
    示例:
    proxy_cache_valid 200 302 10m;
    proxy_cache_valid 404 1m;
    proxy_cache_path;
    # 定義可用于proxy功能的緩存;Context:http
    proxy_cache_path path [levels=levels] [use_temp_path=on|off]
    keys_zone=zone_name:size [inactive=time] [max_size=size] [manager_files=number]
    [manager_sleep=time] [manager_threshold=time] [loader_files=number]
    [loader_sleep=time] [loader_threshold=time] [purger=on|off]
    [purger_files=number] [purger_sleep=time] [purger_threshold=time];
    # 示例:在http配置定義緩存信息
    proxy_cache_path /var/cache/nginx/proxy_cache # 定義緩存保存路徑,proxy_cache會自動創建
    levels=1:2:2 # 定義緩存目錄結構層次
    # 1:2:2可以生成
    2^4x2^8x2^8=2^20=1048576個目錄
    keys_zone=proxycache:20m # 指內存中緩存的大小,主要用于存放key和metadata
    (如:使用次數)
    # 一般1M可存放8000個左右的key
    inactive=120s # 緩存有效時間
    max_size=10g; # 最大磁盤占用空間,磁盤存入文件內容的緩存空間最大值
    # 調用緩存功能,需要定義在相應的配置段,如server{...};或者location等
    proxy_cache proxycache;
    proxy_cache_key $request_uri; # 對指定的數據進行MD5的運算做為緩存的key
    proxy_cache_valid 200 302 301 10m; # 指定的狀態碼返回的數據緩存多長時間
    proxy_cache_valid any 1m; # 除指定的狀態碼返回的數據以外的緩存多長時間,必須設置,否則不會緩存
    proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 |
    http_502 | http_503 | http_504 | http_403 | http_404 | off ; #默認是off
    # 在被代理的后端服務器出現哪種情況下,可直接使用過期的緩存響應客戶端
    # 示例
    proxy_cache_use_stale error http_502 http_503;
    proxy_cache_methods GET | HEAD | POST ...;
    # 對哪些客戶端請求方法對應的響應進行緩存,GET和HEAD方法總是被緩存
    6.1.1.4.1 非緩存場景壓測
    # 準備后端httpd服務器
    [root@apache20 app1]# pwd
    /var/www/html/static
    [root@apache20 static]# cat /var/log/messages > ./log.html # 準備測試頁面
    [root@apache30 ~]# ab -n1000 -c100 http://www.timinglee.org/static/index.html
    Concurrency Level: 100
    Time taken for tests: 23.238 seconds
    Complete requests: 1000
    Failed requests: 0
    Total transferred: 2011251000 bytes
    HTML transferred: 2010991000 bytes
    Requests per second: 43.03 [#/sec] (mean)
    Time per request: 2323.789 [ms] (mean)
    Time per request: 23.238 [ms] (mean, across all concurrent requests)
    Transfer rate: 84521.97 [Kbytes/sec] received
    6.1.1.4.2 準備緩存配置
    [root@Nginx ~]# vim /apps/nginx/conf/nginx.conf
    @@@@內容省略@@@@
    # gzip on;
    proxy_cache_path /apps/nginx/proxy_cache levels=1:2:2 keys_zone=proxycache:20m
    inactive=120s max_size=1g; #配置在nginx.conf http配置段
    [root@Nginx ~]# vim /apps/nginx/conf.d/vhost.conf
    location ~ /static { # 要緩存的URL 或者放在server配置項對所有URL都進行緩存proxy_pass http://172.25.254.20:8080;proxy_cache proxycache;proxy_cache_key $request_uri;proxy_cache_valid 200 302 301 10m;proxy_cache_valid any 1m; # 必須指定哪些響應碼的緩存
    }
    # /data/nginx/proxycache/ 目錄會自動生成
    [root@Nginx ~]# ll /apps/nginx/proxy_cache/ -d
    drwx------ 3 nginx root 4096 7月 25 20:07 /apps/nginx/proxy_cache/
    [root@Nginx ~]# tree /apps/nginx/proxy_cache/
    /data/nginx/proxycache/
    0 directories, 0 files
    6.1.1.4.3 訪問并驗證緩存文件
    #訪問web并驗證緩存目錄
    [root@apache30 ~]# ab -n1000 -c100 http://www.timinglee.org/static/index.html
    [root@centos8 ~]# ab -n 2000 -c200 http://www.timinglee.org/static/log.html
    Concurrency Level: 100
    Time taken for tests: 10.535 seconds
    Complete requests: 1000
    Failed requests: 0
    Total transferred: 2011251000 bytes
    HTML transferred: 2010991000 bytes
    Requests per second: 94.92 [#/sec] (mean)
    Time per request: 1053.507 [ms] (mean)
    Time per request: 10.535 [ms] (mean, across all concurrent requests)
    Transfer rate: 186435.60 [Kbytes/sec] received# 驗證緩存目錄結構及文件大小
    [root@Nginx ~]# tree /apps/nginx/proxy_cache/
    /apps/nginx/proxy_cache/
    └── e
    └── 50
    └── 99
    └── 319432ef3663735a9d3cb4e0c1d9950e
    3 directories, 0 files

    6.1.2 http 反向代理負載均衡

    在上一個節中Nginx可以將客戶端的請求轉發至單臺后端服務器但是無法轉發至特定的一組的服務器,而且不能對后端服務器提供相應的服務器狀態監測,Nginx 可以基于·ngx_http_upstream_module模塊提 供服務器分組轉發、權重分配、狀態監測、調度算法等高級功能nginx做反向代理
    官方文檔:Module ngx_http_upstream_modulehttps://nginx.org/en/docs/http/ngx_http_upstream_module.html
    6.1.2.1 http upstream配置參數
    # 自定義一組服務器,配置在http塊內
    upstream name {
    server .....
    ......
    }
    # 示例
    upstream backend {
    server backend1.example.com weight=5;
    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;
    server backup1.example.com backup;
    }
    server address [parameters];
    # 配置一個后端web服務器,配置在upstream內,至少要有一個server服務器配置。
    # server支持的parameters如下:
    weight=number             # 設置權重,默認為1,實現類似于LVS中的WRR,WLC等
    max_conns=number          # 給當前后端server設置最大活動鏈接數,默認為0表示沒有限制
    max_fails=number          # 后端服務器的下線條件,當客戶端訪問時,對本次調度選中的后端服務器連續進        行檢測多少次,如果都失敗就標記為不可用,默認為1次,當客戶端訪問時,才會利用TCP觸發對探測后端服務器健康性檢查,而非周期性的探測fail_timeout=time         # 后端服務器的上線條件,對已經檢測到處于不可用的后端服務器,每隔此時間間隔再次進行檢測是否恢復可用,如果發現可用,則將后端服務器參與調度,默認為10秒
    backup                    # 設置為備份服務器,當所有后端服務器不可用時,才會啟用此備用服務器
    down                      # 標記為down狀態,可以平滑下線后端服務器resolve                   # 當server定義的是主機名的時候,當A記錄發生變化會自動應用新IP而不用重啟Nginx
    hash KEY [consistent];
    # 基于指定請求報文中首部字段或者URI等key做hash計算,使用consistent參數,將使用ketama一致性
    hash算法,適用于后端是Cache服務器(如varnish)時使用,consistent定義使用一致性hash運算,一致
    性hash基于取模運算
    hash $request_uri consistent; # 基于用戶請求的uri做hash
    hash $cookie_sessionid # 基于cookie中的sessionid這個key進行hash調度,實現會話綁定
    ip_hash;
    # 源地址hash調度方法,基于的客戶端的remote_addr(源地址IPv4的前24位或整個IPv6地址)做hash計
    算,以實現會話保持
    least_conn;
    # 最少連接調度算法,優先將客戶端請求調度到當前連接最少的后端服務器,相當于LVS中的WLC
    6.1.2.2 反向代理示例: 后端多臺 web服務器
    環境說明:
    172.25.254.10 # Nginx 代理服務器
    172.25.254.20 # 后端web A,Apache部署
    172.25.254.30 # 后端web B,Apache部署
    部署后端 Apache服務器
    [root@apache20 ~]# yum install httpd -y
    [root@apache20 ~]# echo "web1 172.25.254.20" > /var/www/html/index.html
    [root@apache20 ~]# systemctl enable --now httpd
    [root@apache30 ~]# yum install httpd -y
    [root@apache30 ~]# echo "web2 172.25.254.30" >> /var/www/html/index.html
    [root@apache30 ~]# systemctl enable --now httpd# 訪問測試
    [root@centos8 ~]# curl http://172.25.254.20
    web1 172.25.254.20
    [root@centos8 ~]# curl http://172.25.254.30
    web2 172.25.254.30
    配置 nginx 反向代理
    注意: 本節實驗過程中先關閉緩存
    [root@centos8 ~]# cat /apps/nginx/conf/conf.d/pc.conf
    upstream webserver {# ip_hash;# hash $request_uri consistent;# hash $cookie_lee# least_conn;server 172.25.254.20:8080 weight=1 fail_timeout=15s max_fails=3;server 172.25.254.30:80 weight=1 fail_timeout=15s max_fails=3;server 172.25.254.10:80 backup;
    }
    server {listen 80;server_name www.timinglee.org;location ~ / {proxy_pass http://webserver;}
    }# 重啟Nginx 并訪問測試
    [Administrator.DESKTOP-P19CNDN] ? curl www.timinglee.org
    172.25.254.20 web
    [Administrator.DESKTOP-P19CNDN] ? curl www.timinglee.org
    172.25.254.30 web
    #關閉172.25.254.20和172.25.254.30,測試nginx backup服務器可用性:
    [Administrator.DESKTOP-P19CNDN] ? while true;do curl
    http://www.timinglee.org;sleep 1;done
    實戰案例: 基于Cookie 實現會話綁定
    [root@Nginx ~]# vim /apps/nginx/conf.d/vhost.conf
    http {upstream websrvs {hash $cookie_hello; # hello是cookie的key的名稱server 10.0.0.101:80 weight=2;server 10.0.0.102:80 weight-1;}
    }[root@centos8 ~]# vim /apps/nginx/conf/conf.d/pc.conf
    upstream webserver {# ip_hash;# hash $request_uri consistent;hash $cookie_lee;# least_conn;server 172.25.254.20:8080 weight=1 fail_timeout=15s max_fails=3;server 172.25.254.30:80 weight=1 fail_timeout=15s max_fails=3;# server 172.25.254.10:80 backup;
    }
    server {listen 80;server_name www.timinglee.org;location ~ / {proxy_pass http://webserver;}
    }
    #測試
    [Administrator.DESKTOP-P19CNDN] ? curl -b lee=1 www.timinglee.org

    6.2 實現 Nginx 四層負載均衡

    Nginx1.9.0版本開始支持tcp模式的負載均衡,在1.9.13版本開始支持udp協議的負載,udp主要用于DNS的域名解析,其配置方式和指令和http 代理類似,其基于ngx_stream_proxy_module模塊實現tcp負載,另外基于模塊ngx_stream_upstream_module實現后端服務器分組轉發、權重分配、狀態監測、調度算法等高級功能。
    如果編譯安裝,需要指定 --with-stream 選項才能支持ngx_stream_proxy_module模塊

    6.2.1 tcp負載均衡配置參數

    注意:tcp的負載均衡要卸載http語句塊之外
    stream { # 定義stream相關的服務;
    Context:mainupstream backend { # 定義后端服務器hash $remote_addr consistent; # 定義調度算法server backend1.example.com:12345 weight=5; # 定義具體serverserver 127.0.0.1:12345 max_fails=3 fail_timeout=30s;server unix:/tmp/backend3;}upstream dns { # 定義后端服務器server 10.0.0.1:53; #定義具體serverserver dns.example.com:53;}
    server { # 定義serverlisten 12345; # 監聽IP:PORTproxy_connect_timeout 1s; # 連接超時時間proxy_timeout 3s; # 轉發超時時間proxy_pass backend; # 轉發到具體服務器組
    }
    server {listen 127.0.0.1:53 udp reuseport;proxy_timeout 20s;proxy_pass dns;
    }
    server {listen [::1]:12345;proxy_pass unix:/tmp/stream.socket;}
    }

    6.2.2 負載均衡實例: MySQL

    1.后端服務器安裝 MySQL
    #在apache20中安裝mysql
    [root@apache20 ~]# yum install mariadb-server -y
    [root@apache20 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
    [mysqld]
    server-id=20
    [root@apache20 ~]# systemctl start mariadb
    [root@apache20 ~]# mysql -e "grant all on *.* to lee@'%' identified by 'lee';"
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.20 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 20 |
    +-------------+
    #在apache30重復以上步驟并在apache20上測試
    2.nginx配置
    [root@Nginx ~]# vim /apps/nginx/conf/tcp/tcp.conf
    stream {
    upstream mysql_server {
    server 172.25.254.20:3306 max_fails=3 fail_timeout=30s;
    server 172.25.254.30:3306 max_fails=3 fail_timeout=30s;
    }
    server {
    listen 172.25.254.10:3306;
    proxy_pass mysql_server;
    proxy_connect_timeout 30s;
    proxy_timeout 300s;
    }
    }
    # 重啟nginx并訪問測試:
    [root@Nginx ~]# nginx -s reload
    # 測試通過nginx負載連接MySQL:
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 20 |
    +-------------+
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 30 |
    +-------------+
    # 在10.0.0.28停止MySQL服務
    [root@apache20 ~]# systemctl stop mariadb
    # 再次測試訪問,只會看到mysql-server1.timinglee.org進行響應
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 30 |
    +-------------+
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 30 |
    +-------------+

    6.2.3 udp 負載均衡實例: DNS

    stream {upstream dns_server{server 172.25.254.20:53 max_fails=3 fail_timeout=30s;server 172.25.254.30:53 max_fails=3 fail_timeout=30s;}server {listen 172.25.254.10:53 udp;proxy_pass dns_server;proxy_timeout 1s;proxy_responses 1; # 使用UDP協議時,設置代理服務器響應客戶端期望的數據報文數# 該值作為會話的終止條件error_log logs/dns.log;}
    }測試:
    [root@apache30 named]# dig www.timinglee.org @172.25.254.10
    ; <<>> DiG 9.16.23 <<>> www.timinglee.org @172.25.254.10
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33888
    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 1232
    ; COOKIE: 701447f1bdd8acea0100000066a27b465426b2b4bc7f1dc3 (good)
    ;; QUESTION SECTION:
    ;www.timinglee.org. IN A
    ;; ANSWER SECTION:
    www.timinglee.org. 86400 IN A 172.25.254.20
    ;; Query time: 2 msec
    ;; SERVER: 172.25.254.10#53(172.25.254.10)
    ;; WHEN: Fri Jul 26 00:20:22 CST 2024
    ;; MSG SIZE rcvd: 90
    [root@apache30 named]# dig www.timinglee.org @172.25.254.10
    ; <<>> DiG 9.16.23 <<>> www.timinglee.org @172.25.254.10
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8932
    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 1232
    ; COOKIE: 8ecb61bbfe2716df0100000066a27b47a3bb0c3d8e537858 (good)
    ;; QUESTION SECTION:
    ;www.timinglee.org. IN A
    ;; ANSWER SECTION:
    www.timinglee.org. 86400 IN A 172.25.254.30
    ;; Query time: 1 msec
    ;; SERVER: 172.25.254.10#53(172.25.254.10)
    ;; WHEN: Fri Jul 26 00:20:23 CST 2024
    ;; MSG SIZE rcvd: 90

    6.3 實現 FastCGI

    CGI的由來:
    最早的Web服務器只能簡單地響應瀏覽器發來的HTTP請求,并將存儲在服務器上的HTML文件返回給瀏覽器,也就是靜態html文件,但是后期隨著網站功能增多網站開發也越來越復雜,以至于出現動態技術,比如像php(1995)java(1995)python(1991)語言開發的網站,但是nginx/apache服務器并不能直接運行 phpjava這樣的文件,apache實現的方式是打補丁,但是nginx缺通過與第三方基于協議實現,即通過某種特定協議將客戶端請求轉發給第三方服務處理,第三方服務器會新建新的進程處理用戶的請求,處理完成后返回數據給Nginx并回收進程,最后nginx在返回給客戶端,那這個約定就是通用網關接口(common gateway interface,簡稱CGI)CGI(協議) 是web服務器和外部應用程序之間的接口 標準,是cgi程序和web服務器之間傳遞信息的標準化接口。

    為什么會有FastCGI

    CGI協議雖然解決了語言解析器和 Web Server 之間通訊的問題,但是它的效率很低,因為 Web Server 每收到一個請求都會創建一個CGI進程,PHP解析器都會解析php.ini文件,初始化環境,請求結束的時候再關閉進程,對于每一個創建的CGI進程都會執行這些操作,所以效率很低,而FastCGI是用來提高CGI性能的,FastCGI每次處理完請求之后不會關閉掉進程,而是保留這個進程,使這個進程可以處理多個請求。這樣的話每個請求都不用再重新創建一個進程了,大大提升了處理效率。

    什么是PHP-FPM
    PHP-FPM(FastCGI Process Manager
    • FastCGI進程管理器)是一個實現了Fastcgi的程序,并且提供進程管理的功能。
    • 進程包括master進程和worker進程。master進程只有一個,負責監聽端口,接受來自web server
    • 的請求worker進程一般會有多個,每個進程中會嵌入一個PHP解析器,進行PHP代碼的處理。

    6.3.1 FastCGI配置指令

    Nginx基于模塊ngx_http_fastcgi_module實現通過fastcgi協議將指定的客戶端請求轉發至php-fpm處理,其配置指令如下:
    fastcgi_pass address:port;
    # 轉發請求到后端服務器,address為后端的fastcgi server的地址,可用位置:location, if in
    location
    fastcgi_index name;
    # fastcgi默認的主頁資源,示例:fastcgi_index index.php;
    fastcgi_param parameter value [if_not_empty];
    # 設置傳遞給FastCGI服務器的參數值,可以是文本,變量或組合,可用于將Nginx的內置變量賦值給自定義key
    fastcgi_param REMOTE_ADDR $remote_addr; # 客戶端源IP
    fastcgi_param REMOTE_PORT $remote_port; # 客戶端源端口
    fastcgi_param SERVER_ADDR $server_addr; # 請求的服務器IP地址
    fastcgi_param SERVER_PORT $server_port; # 請求的服務器端口
    fastcgi_param SERVER_NAME $server_name; # 請求的server nameNginx默認配置示例:
    location ~ \.php$ {root /scripts;fastcgi_pass 127.0.0.1:9000;fastcgi_index index.php;fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # 默認腳本路徑# fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;include fastcgi_params; # 此文件默認系統已提供,存放的相對路徑為prefix/conf
    }

    6.3.2 FastCGI實戰案例 : Nginxphp-fpm在同一服務器

    編譯安裝更方便自定義參數或選項,所以推薦使用源碼編譯
    官方網站:www.php.net
    1.源碼編譯php
    # 利用yum解決php依賴
    [root@Nginx ~]# yum install -y bzip2 systemd-devel libxml2-devel sqlite-devel libpng-devel libcurl-devel oniguruma-devel
    # 解壓源碼并安裝
    [root@Nginx ~]# ./configure \
    --prefix=/usr/local/php \                     # 安裝路徑
    --with-config-file-path=/usr/local/php/etc \  # 指定配置路徑
    --enable-fpm \                                # 用cgi方式啟動程序
    --with-fpm-user=nginx \                       # 指定運行用戶身份
    --with-fpm-group=nginx \
    --with-curl \                                 # 打開curl瀏覽器支持
    --with-iconv \                                # 啟用iconv函數,轉換字符編碼
    --with-mhash \                                # mhash加密方式擴展庫
    --with-zlib \                                 # 支持zlib庫,用于壓縮http壓縮傳輸
    --with-openssl \                              # 支持ssl加密
    --enable-mysqlnd \                            # mysql數據庫
    --with-mysqli \
    --with-pdo-mysql \
    --disable-debug \                             # 關閉debug功能
    --enable-sockets \                            # 支持套接字訪問
    --enable-soap \                               # 支持soap擴展協議
    --enable-xml \                                # 支持xml
    --enable-ftp \                                # 支持ftp
    --enable-gd \                                 # 支持gd庫
    --enable-exif \                               # 支持圖片元數據
    --enable-mbstring \                           # 支持多字節字符串
    --enable-bcmath \                             # 打開圖片大小調整,用到zabbix監控的時候用到了這個模塊
    --with-fpm-systemd                            # 支持systemctl 管理cgi
    2.php相關配置優化
    [root@Nginx ~]# cd /usr/local/php/etc
    [root@Nginx etc]# cp php-fpm.conf.default php-fpm.conf
    [root@Nginx etc]# vim php-fpm.conf
    去掉注釋
    pid = run/php-fpm.pid # 指定pid文件存放位置
    [root@Nginx etc]# cd php-fpm.d/
    [root@Nginx php-fpm.d]# cp www.conf.default www.conf
    # 生成主配置文件
    [root@Nginx php-fpm.d]# cd /root/php-8.3.9/
    [root@Nginx php-8.3.9]# cp php.ini-production /usr/local/php/etc/php.ini
    [root@Nginx ~]# vim /usr/local/php/etc/php.ini
    [Date]
    ; Defines the default timezone used by the date functions
    ; https://php.net/date.timezone
    date.timezone = Asia/Shanghai # 修改時區
    # 生成啟動文件
    [root@Nginx ~]# cd /root/php-8.3.9/
    [root@Nginx php-8.3.9]# cp sapi/fpm/php-fpm.service /lib/systemd/system/
    # Mounts the /usr, /boot, and /etc directories read-only for processes invoked by
    this unit.
    # ProtectSystem=full # 注釋該內容
    [root@Nginx php-8.3.9]# systemctl start php-fpm.service
    [root@Nginx php-8.3.9]# netstat -antlupe | grep php
    tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 0
    820758 176202/php-fpm: mas
    3.準備php測試頁面
    [root@Nginx ~]# mkdir /data/php -p
    [root@centos8 ~]# cat /data/php/index.php # php測試頁面
    <?php
    phpinfo();
    ?>
    4.Nginx配置轉發
    Nginx安裝完成之后默認生成了與fastcgi的相關配置文件,一般保存在nginx的安裝路徑的conf目錄當中,比如/apps/nginx/conf/fastcgi.conf/apps/nginx/conf/fastcgi_params
    [root@Nginx ~]# vim /apps/nginx/conf.d/php.conf
    server {listen 80;server_name php.timinglee.org;root /data/php;location ~ \.php$ {fastcgi_pass 127.0.0.1:9000;fastcgi_index index.php;include fastcgi.conf;}
    }
    # 重啟Nginx并訪問web測試
    [root@Nginx ~]# nginx -s reload
    5.訪問驗證php測試頁面

    6.添加php環境變量
    [root@Nginx ~]# vim .bash_profile
    # .bash_profile
    # Get the aliases and functions
    if [ -f ~/.bashrc ]; then
    . ~/.bashrc
    fi
    # User specific environment and startup programs
    PATH=$PATH:$HOME/bin:/apps/nginx/sbin:/usr/local/php/bin
    export PATH
    [root@Nginx ~]# source .bash_profile

    6.3.3 php的動態擴展模塊(php的緩存模塊)

    1.軟件下載:http://pecl.php.net/package/memcache

    2.安裝memcache模塊
    [root@Nginx ~]# tar zxf memcache-8.2.tgz
    [root@Nginx ~]# cd memcache-8.2/
    [root@Nginx memcache-8.2]# yum install autoconf
    [root@Nginx memcache-8.2]# phpize
    [root@Nginx memcache-8.2]# ./configure && make && make install
    Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-nonzts-20230831/
    [root@Nginx memcache-8.2]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts-
    20230831/
    memcache.so opcache.so
    3.復制測試文件到nginx發布目錄中
    [root@Nginx ~]# cd memcache-8.2/
    [root@Nginx memcache-8.2]# ls
    autom4te.cache config.log configure.ac example.php Makefile.fragments
    README
    build config.m4 config.w32 include Makefile.objects runtests.php
    config9.m4 config.nice CREDITS libtool memcache.la src
    config.h config.status docker LICENSE memcache.php
    tests
    config.h.in configure Dockerfile Makefile modules
    [root@Nginx memcache-8.2]# cp example.php memcache.php /data/php/
    [root@Nginx ~]# vim /data/php/memcache.php
    define('ADMIN_USERNAME','admin'); // Admin Username
    define('ADMIN_PASSWORD','lee'); // Admin Password
    define('DATE_FORMAT','Y/m/d H:i:s');
    define('GRAPH_SIZE',200);
    define('MAX_ITEM_DUMP',50);
    $MEMCACHE_SERVERS[] = 'localhost:11211'; // add more as an array
    #$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array
    4.配置php加載memcache模塊
    [root@Nginx ~]# vim /usr/local/php/etc/php.ini
    ;extension=zip
    extension=memcache
    ;zend_extension=opcache
    [root@Nginx ~]# systemctl reload php-fpm
    [root@Nginx no-debug-non-zts-20230831]# php -m | grep mem
    memcache
    5.部署memcached
    [root@Nginx ~]# yum install memcached -y
    [root@Nginx ~]# systemctl enable --now memcached.service
    [root@Nginx ~]# netstat -antlupe | grep memcache
    tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN
    976 1037243 186762/memcached
    [root@Nginx ~]# cat /etc/sysconfig/memcached
    PORT="11211"
    USER="memcached"
    MAXCONN="1024"
    CACHESIZE="64"
    OPTIONS="-l 127.0.0.1,::1"
    6.測試
    訪問 http://php.timinglee.org/example.php 不斷刷新
    訪問 http://php.timinglee.org/memcache.php 查看命中效果

    7.性能對比
    [root@apache20 ~]# ab -n500 -c10 http://php.timinglee.org/index.php
    @@@內容忽略@@@
    Concurrency Level: 10
    Time taken for tests: 0.514 seconds
    Complete requests: 500
    Failed requests: 44
    (Connect: 0, Receive: 0, Length: 44, Exceptions: 0)
    [root@apache20 ~]# ab -n500 -c10 http://php.timinglee.org/example.php
    @@@內容忽略@@@
    Concurrency Level: 10
    Time taken for tests: 0.452 seconds
    Complete requests: 500
    Failed requests: 0

    6.3.4 php高速緩存

    1.部署方法
    在我們安裝的nginx中默認不支持memcsrcache功能,需要借助第三方模塊來讓nginx支持此功能,所以nginx需要重新編譯
    [root@Nginx ~]# rm -fr /apps/nginx/
    [root@Nginx ~]# tar zxf srcache-nginx-module-0.33.tar.gz
    [root@Nginx ~]# tar zxf memc-nginx-module-0.20.tar.gz
    [root@Nginx ~]# cd nginx-1.26.1/
    [root@Nginx nginx-1.26.1]# ./configure --prefix=/apps/nginx --user=nginx --
    group=nginx --with-http_ssl_module --with-http_v2_module --withhttp_realip_module --with-http_stub_status_module --with-http_gzip_static_module
    --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --
    add-module=/root/memc-nginx-module-0.20 --add-module=/root/srcache-nginx-module-
    0.33
    [root@Nginx nginx-1.26.1]# make && make install
    [root@Nginx ~]# vim /apps/nginx/conf.d/php.conf
    upstream memcache {
    server 127.0.0.1:11211;
    keepalive 512;
    }
    server {
    listen 80;
    server_name php.timinglee.org;
    root /data/php;
    location /memc {
    internal;
    memc_connect_timeout 100ms;
    memc_send_timeout 100ms;
    memc_read_timeout 100ms;
    set $memc_key $query_string; #使用內置變量$query_string來作為key
    set $memc_exptime 300; #緩存失效時間300秒
    memc_pass memcache;
    }
    location ~ \.php$ {
    set $key $uri$args; #設定key的值
    srcache_fetch GET /memc $key; #檢測mem中是否有要訪問的php
    srcache_store PUT /memc $key; #緩存為加載的php數據
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    include fastcgi.conf;
    }
    }
    [root@Nginx ~]# systemctl start nginx.service
    2.測試結果:
    [root@apache20 ~]# ab -n500 -c10 http://php.timinglee.org/index.php
    Concurrency Level: 10
    Time taken for tests: 0.255 seconds
    Complete requests: 500
    Failed requests: 0

    7?nginx 二次開發版本

    7.1 openresty

    Nginx 是俄羅斯人發明的, Lua 是巴西幾個教授發明的,中國人章亦春把 LuaJIT VM 嵌入到 Nginx 中,實現了 OpenResty 這個高性能服務端解決方案
    OpenResty? 是一個基于 Nginx Lua 的高性能 Web 平臺,其內部集成了大量精良的 Lua 庫、第三方模塊以及大多數的依賴項。用于方便地搭建能夠處理超高并發、擴展性極高的動態 Web 應用、Web 服務和動態網關。
    OpenResty? 通過匯聚各種設計精良的 Nginx 模塊(主要由 OpenResty 團隊自主開發),從而將Nginx有效地變成一個強大的通用 Web 應用平臺。這樣,Web 開發人員和系統工程師可以使用 Lua 腳本語言調動 Nginx 支持的各種 C 以及 Lua 模塊,快速構造出足以勝任 10K 乃至 1000K 以上單機并發連接的高性能 Web 應用系統。
    OpenResty 由于有功能強大且方便的的API,可擴展性更強,如果需要實現定制功能,OpenResty是個不錯的選擇
    官網: http://openresty.org/cn/

    7.2 編譯安裝 openresty

    [root@Nginx ~]#dnf -yq install gcc pcre-devel openssl-devel perl
    [root@Nginx ~]#useradd -r -s /sbin/nologin nginx
    [root@Nginx ~]#cd /usr/local/src
    [root@Nginx src]#wget https://openresty.org/download/openresty-1.17.8.2.tar.gz
    [root@Nginx src]#tar xf openresty-1.17.8.2.tar.gz
    [root@Nginx src]#cd openresty-1.17.8.2/
    [root@Nginx openresty-1.17.8.2]#./configure \
    --prefix=/apps/openresty \
    --user=nginx --group=nginx \
    --with-http_ssl_module \
    --with-http_v2_module \
    --with-http_realip_module \
    --with-http_stub_status_module \
    --with-http_gzip_static_module
    --with-pcre --with-stream \
    --with-stream_ssl_module \
    --with-stream_realip_module
    [root@Nginx openresty-1.17.8.2]#make && make install
    [root@Nginx openresty-1.17.8.2]#ln -s /apps/openresty/bin/* /usr/bin/
    [root@Nginx openresty-1.17.8.2]#openresty -v
    nginx version: openresty/1.17.8.2
    [root@Nginx openresty-1.17.8.2]#openresty
    [root@Nginx openresty-1.17.8.2]#ps -ef |grep nginx
    [root@Nginx ~]#curl 10.0.0.18

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/bicheng/92693.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92693.shtml
    英文地址,請注明出處:http://en.pswp.cn/bicheng/92693.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    免費PDF編輯軟件 pdf24-creator 及其安裝包

    最近發現了一款還算是不錯的PDF編輯和閱讀軟件 pdf24-creator&#xff0c;官方下載網站為&#xff1a;https://tools.pdf24.org/zh/creator&#xff0c;但是官方下載如果沒有魔法的話&#xff0c;下載速度很慢&#xff0c;比百度網盤下載還滿&#xff0c;因此我把它分享到網盤。…

    openvela之ADB

    ADB&#xff08;Android Debug Bridge&#xff09;是一款功能豐富的命令行工具&#xff0c;旨在實現開發工作站與設備&#xff08;如模擬器、實體設備&#xff09;之間的通信。通過 ADB&#xff0c;開發者可以便捷地在設備上執行命令、傳輸文件、調試應用等。本文將詳細介紹 AD…

    如何控制需求交付節奏

    有效控制需求的交付節奏&#xff0c;其核心在于將產品開發過程從一個不可預測的、時快時慢的混亂狀態&#xff0c;轉變為一套產出穩定、流程順暢、步調可持續的系統化交付機制。要成功構建這套機制&#xff0c;實現有節奏的價值交付&#xff0c;必須綜合運用五大關鍵策略&#…

    匯編中常用寄存器介紹

    X86-32位寄存器 4個數據寄存器&#xff1a;EAX、EBX、ECX和EDX; 2個變址和指針寄存器&#xff1a;ESI和EDI; 2個指針寄存器&#xff1a;ESP和EBP; 1個指令指針寄存器&#xff1a;EIP; 6個段寄存器&#xff1a;ES、CS、SS、DS、FS和GS; 1個標志寄存器&#xff1a;EFlags。 在X8…

    SOMGAN:用自組織映射改善GAN的模式探索能力

    論文信息 論文題目:Improving mode exploring capability ofgenerative adversarial nets by self-organizing map(利用自組織映射提高生成對抗網絡的模式探索能力) 期刊:Neurocomputing 摘要:生成對抗網絡(GANs)的出現將生成模型的研究推向了一個新的高潮。支持這一進步…

    《匯編語言:基于X86處理器》第12章 復習題和練習

    本篇記錄了《匯編語言&#xff1a;基于X86處理器》第12章 復習題和練習的筆記。12.6復習題和練習12.6.1 簡答題1.假設有二進制浮點數1101.01101&#xff0c;如何將其表示為十進制分數之和?答&#xff1a;1101.01101(1x)(1x)(0x)(1x)(0x)(1x)(1x)(1x)(1x) 13.406252.為什么十進…

    ApacheCon Asia 2025 中國開源年度報告:Apache Doris 國內第一

    上周剛落下帷幕的 ApacheCon Asia 2025 中&#xff0c;一個數據讓所有人都為之震撼&#xff1a;全球 Apache 基金會項目 OpenRank 排行榜中&#xff0c;Apache Doris 位居第二&#xff0c;在中國 Apache 項目中更是穩居第一。 這個排名意味著什么&#xff1f;在 Apache 基金會管…

    Pytest中實現自動生成測試用例腳本代碼

    &#x1f345; 點擊文末小卡片&#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快在Python的測試框架中&#xff0c;我們通常會針對某個系統進行測試用例的維護&#xff0c;在對龐大系統進行用例維護時&#xff0c;往往會發現很多測試用例是差不多…

    一周學會Matplotlib3 Python 數據可視化-標注 (Annotations)

    鋒哥原創的Matplotlib3 Python數據可視化視頻教程&#xff1a; 2026版 Matplotlib3 Python 數據可視化 視頻教程(無廢話版) 玩命更新中~_嗶哩嗶哩_bilibili 課程介紹 本課程講解利用python進行數據可視化 科研繪圖-Matplotlib&#xff0c;學習Matplotlib圖形參數基本設置&…

    安全合規1--實驗:ARP欺騙、mac洪水攻擊、ICMP攻擊、TCP SYN Flood攻擊

    一、實驗環境 (思科的云實驗平臺)攻擊機&#xff1a;Kali Linux&#xff08;IP&#xff1a;192.168.234.128&#xff0c;MAC&#xff1a;00:00:29:35:64:EC&#xff09;目標1&#xff1a;網關&#xff08;IP&#xff1a;192.168.234.2&#xff0c;MAC&#xff1a;00:50:56:ED:D…

    Linux下GCC的C++實現Hive到Snowflake數據遷移

    程序結構 ├── main.cpp ├── config.json ├── hive_export/ ├── parquet_data/ ├── sql_scripts/ └── logs/核心代碼實現 (main.cpp) #include <iostream> #include <fstream> #include <vector> #include <thread> #include <mut…

    drippingblues靶機教程

    一、信息搜集首先將其在VirtualBOX中安裝&#xff0c;并將kali與靶機都設置為橋接模式緊接著我們掃描IP&#xff0c;來發現靶機地址&#xff0c;經過搜集&#xff0c;發現IP是192.168.1.9&#xff0c;我們去訪問一下緊接著我們掃一下開放了哪些端口。發現開放了21、22以及80端口…

    39.【.NET8 實戰--孢子記賬--從單體到微服務--轉向微服務】--擴展功能--調整發布腳本

    這篇文章&#xff0c;我們要調整發布腳本。之所以要調整發布腳本&#xff0c;是因為現在我們的項目有三個環境&#xff1a;本地&#xff08;Local&#xff09;、開發&#xff08;Development&#xff09;、生產&#xff08;Production&#xff09;。Tip&#xff1a;我們的項目雖…

    商品、股指及ETF期權五檔盤口Tick級與分鐘級歷史行情數據多維解析

    在金融數據分析領域&#xff0c;本地CSV文件是存儲高頻與低頻數據的常用載體。本文以期權市場數據為例&#xff0c;探討如何基于CSV格式處理分鐘級行情、高頻Tick數據、日頻數據、逐筆委托記錄、五檔訂單簿及歷史行情數據&#xff0c;并提供專業的技術實現方案。以下將從數據預…

    云端軟件工程智能代理:任務委托與自動化實踐全解

    云端軟件工程智能代理&#xff1a;任務委托與自動化實踐全解 背景與未來趨勢 隨著軟件工程復雜度不斷提升&#xff0c;開發者對自動化工具的依賴也日益增強。我們正進入一個“人機協作”的新時代&#xff0c;開發者可以專注于核心創新&#xff0c;將重復性、繁瑣的任務委托給智…

    making stb style lib(1): do color print in console

    col.h: see origin repo // origin repo: https://github.com/resyfer/libcol #ifndef _COL_HOL_H_ #define _COL_HOL_H_#include <stdlib.h> #include <stdio.h> #include <stdbool.h> #include <string.h> #include <math.h> // 新增&#xf…

    llm本地部署+web訪問+交互

    要實現基于llm的web訪問和交互&#xff0c;需支持對llm的訪問和對網絡搜索的調用。 這里使用ollama llm兼容openai sdk訪問&#xff1b;使用proxyless-llm-websearch模擬網絡搜索。 1 ollama本地部署 假設ollama已經部署&#xff0c;具體過程參考 在mac m1基于ollama運行dee…

    自動駕駛數據閉環

    自動駕駛的數據閉環是支撐算法持續迭代的核心機制&#xff0c;其本質是通過“數據采集-處理-訓練-部署-反饋”的循環&#xff0c;不斷優化模型對復雜場景的適應性。由于自動駕駛數據量極大&#xff08;單車日均TB級&#xff09;、場景多樣&#xff08;從常規道路到極端邊緣場景…

    二十、MySQL-DQL-條件查詢

    DQL-條件查詢代碼&#xff1a; DQL-條件查詢 -- 1.查詢 姓名 為 楊逍 的員工 select * from tb_emp where name 楊逍; -- 2.查詢 id小于等于5 的員工信息 select * from tb_emp where id < 5; -- 3.查詢 沒有分配職位 的員工信息 select * from tb_emp where job is null; …

    Mac下安裝Conda虛擬環境管理器

    Conda 是一個開源的包、環境管理器&#xff0c;可以用于在同一個機器上創建不同的虛擬環境&#xff0c;安裝不同Python 版本的軟件包及其依賴&#xff0c;并能夠在不同的虛擬環境之間切換 Conda常通過安裝Anaconda/Miniconda來進行使用。一般使用Miniconda就夠了。Miniconda 是…