Nginx 介紹 Nginx 是一個高性能的 Web 伺服器,從 2001 年發展至今,由於 Nginx 對硬體和操作系統內核特性的深度挖掘,使得在保持高併發的同時還能夠保持高吞吐量。Nginx 還採用了模塊設計,有大量的第三方模塊可以擴展 Nginx 的功能,因此 Nginx 的場景非常豐富,同時 ...
Nginx 介紹
Nginx 是一個高性能的 Web 伺服器,從 2001 年發展至今,由於 Nginx 對硬體和操作系統內核特性的深度挖掘,使得在保持高併發的同時還能夠保持高吞吐量。Nginx 還採用了模塊設計,有大量的第三方模塊可以擴展 Nginx 的功能,因此 Nginx 的場景非常豐富,同時 Nginx 採用的是 BSD 許可證,賦予了 Nginx 最大的靈活性。簡單來說,Nginx 具有以下幾個優點:
- 高併發,高性能
- 可擴展性好
- 高可靠,一年之中停機時間可能只有幾秒
- 熱部署,可以不重啟升級
- 靈活性高,採用BSD 許可證
BSD開源協議是一個給予使用者者很大自由的協議。基本上使用者可以“為所欲為”,可以自由的使用,修改源代碼,也可以將修改後的代碼作為開源或者專有軟體再發佈。
截止 2019 年 9 月份,Nginx 的市場份額已經達到了 33%,且還在持續增長,穩居市場頭把交椅。
背景
Nginx 出現的背景是由於互聯網的快速普及導致數據量的快速增長,同時催生出了海量的連接。傳統的 Apache 等伺服器採用的是單進程模型,這意味著,每處理一個請求就會創建一個進程,這不但存在進程創建的開銷,而且進程之間相互切換產生的上下文開銷也非常耗費 CPU 資源,導致這種傳統的伺服器在面對成千上萬的併發連接時,性能非常低下,而這是快速發展的互聯網所不能夠忍受的。
在這種背景下,Nginx 採用的是進程池和 epoll 處理模型,這二者加起來使得 Nginx 的性能非常優異,一臺 32 核的機器上可以支撐數千萬的併發連接。
Nginx 有一個 master 進程和若幹個 worker 進程,master 進程是用來管理 worker 進程的,worker 進程負責處理具體的請求,worker 進程是 master 進程的子進程。
Nginx 的版本
介紹完 Nginx 的背景,我們就該說說 Nginx 的版本了。目前 Nginx 有三個主要的產品:
- 官方 Nginx。包含開源版(nginx.org)和商業版(nginx.com)
- 阿裡巴巴的 Tengine。Tengine 是由淘寶網發起的 Web 伺服器項目,目前已經開源
- OpenResty。OpenResty 通過 Lua 對 Nginx 進行擴展,使得擴展 Nginx 模塊變得異常輕鬆
針對我們日常學習來說,選擇官方開源版的 Nginx 以及 OpenResty 就可以了。
編譯 Nginx 和 OpenResty
在 Linux 上,當然可以使用 yum、apt-get 等軟體包管理工具來下載 Nginx,但是 Nginx 的很多模塊並不是預設開啟的,第三方模塊很多也並不包含,所以,如果想要開啟內置的模塊或編譯第三方模塊,還是需要編譯 Nginx。
下載 Nginx 源代碼
在 http://nginx.org/en/download.html 裡面可以直接下載 Nginx 源代碼。包含以下目錄:
nginx-1.17.8
├── CHANGES # 每個版本提供的特性和 bugfix
├── CHANGES.ru # 俄羅斯版本的 CHANGES 文件
├── LICENSE
├── Makefile
├── README
├── auto # 自動檢測系統環境以及編譯相關的腳本,輔助 config 腳本執行的時候去判定 nginx 支持哪些模塊,當前操作系統有什麼樣的特性可以供給 nginx 使用
├── conf # 示例文件,方便運維配置,會把 conf 示例文件拷貝到安裝目錄
├── configure # 命令腳本,用來生成中間文件,執行編譯前的一個必備動作
├── contrib # 提供了兩個 pl 腳本和 vim 工具
├── html # 一個 500 錯誤的預設頁面,另一個是預設的 index 頁面
├── man # nginx 對 Linux 的幫助文件,man ./nginx.8
└── src # nginx 源代碼
配置 Vim
如果 Vim 沒有開啟語法高亮的話,最好開啟一下
cp -r contrib/vim/* ~/.vim
# mac 下需要在家目錄下新建 .vimrc 文件並配置
syntax on
編譯 Nginx
./configure --help # --help 命令可以查看配置腳本支持哪些參數
第一類配置參數
--prefix=PATH set installation prefix # 指定這個路徑就可以了,其他文件會在 prefix 目錄下建立相應的文件夾
--sbin-path=PATH set nginx binary pathname
--modules-path=PATH set modules path
--conf-path=PATH set nginx.conf pathname
--error-log-path=PATH set error log pathname
--pid-path=PATH set nginx.pid pathname
--lock-path=PATH set nginx.lock pathname
第二類配置參數
可以配置使用或不使用哪些模塊,首碼通常是 with 和 with out,需要加 with 參數的通常是不會被 Nginx 預設編譯的,without 則是會移出編譯。
--with-http_ssl_module enable ngx_http_ssl_module
--with-http_v2_module enable ngx_http_v2_module
--with-http_realip_module enable ngx_http_realip_module
...
--without-http_charset_module disable ngx_http_charset_module
--without-http_gzip_module disable ngx_http_gzip_module
--without-http_ssi_module disable ngx_http_ssi_module
...
開始編譯
# 1. 使用預設參數,指定編譯安裝目錄
./configure --prefix=/Users/mtdp/myproject/nginx/nginx
# 編譯完成後生成 objs 文件夾中間文件
➜ objs ll
total 176
-rw-r--r-- 1 mtdp staff 40K 3 3 07:23 Makefile
-rw-r--r-- 1 mtdp staff 25K 3 3 07:23 autoconf.err
-rw-r--r-- 1 mtdp staff 5.4K 3 3 07:23 ngx_auto_config.h
-rw-r--r-- 1 mtdp staff 531B 3 3 07:23 ngx_auto_headers.h
-rw-r--r-- 1 mtdp staff 5.7K 3 3 07:23 ngx_modules.c # ngx_modules.c 決定了接下來的編譯會生成哪些模塊
drwxr-xr-x 9 mtdp staff 288B 3 3 07:23 src
2. # 編譯
make # 生成了大量的中間文件。如果是版本升級,就不能直接 makeinstall,需要將 obj 拷貝到安裝目錄。如果生成了動態模塊,編譯後也會放在 objs 目錄下
3. # 安裝
make install
➜ nginx ll # 安裝完成後生成以下文件夾
total 0
drwxr-xr-x 17 mtdp staff 544B 3 3 07:29 conf # 從 Nginx 源碼目錄拷貝的
drwxr-xr-x@ 4 mtdp staff 128B 3 3 07:29 html # 從 Nginx 源碼目錄拷貝的
drwxr-xr-x 2 mtdp staff 64B 3 3 07:29 logs # 日誌文件目錄,包括 access log 和 error log
drwxr-xr-x 3 mtdp staff 96B 3 3 07:29 sbin # Nginx 二進位文件目錄
編譯 OpenResty
OpenResty 的編譯安裝步驟與 Nginx 基本一致
在 https://openresty.org/en/download.html 中下載 OpenResty 的源代碼,然後按照 Nginx 的編譯步驟執行即可。
Nginx 配置文件
配置規則
events {
worker_connections 1024;
}
http {
#incloud 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/geek.access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
gzip_min_length 1;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png multipart/form-data;
server {
listen 8080;
server_name 127.0.0.1;
#charset koi8-r;
access_log logs/geek.access.log main;
location /lua {
default_type text/html;
content_by_lua '
ngx.say("User-Agent: ", ngx.req.get_headers()["User-Agent"])
';
}
}
#error_page 404 /404.html;
}
如上所示,是一個非典型的 Nginx 配置文件,Nginx 的配置文件語法遵循以下規則:
- 配置文件由指令與指令塊構成
- 每條指令以 ; 結尾,指令與指令的參數之間以空格符號分割
- 指令塊以 {} 將多條指令組織在一起
events { # 指令塊
worker_connections 1024; # 指令
}
- include 語句允許組合多個配置文件,以提升可維護性
- 使用 # 添加註釋
- 使用 $ 符號添加變數
- 部分指令的參數支持正則表達式
配置參數
時間單位
- ms:毫秒
- s:秒
- m:分鐘
- h:小時
- d:天
- M:月 = 30 天
- y:年 = 365 天
空間單位
- bytes
- k/K:kilobytes
- m/M:megabytes
- g/G:gigabytes
HTTP 配置的指令塊
- http:表示由 http 模塊來處理請求
- upstream:表示上游伺服器地址
- server:表示站點地址
- location:表示 URL
這些指令塊在接下來都會遇到。
Nginx 命令行
在剛剛編譯完成的 Nginx 目錄下,有一個 sbin 目錄,就是用來存放 Nginx 的二進位文件的
➜ sbin ll
total 1712
-rwxr-xr-x 1 mtdp staff 854K 3 3 07:29 nginx
Nginx 啟動時,有一系列的命令行參數可以指定,下麵分別介紹一下。
./nginx
-h/-? # 打開幫助
-c # 使用指定的配置文件,而不是預設的 conf 文件夾下的配置文件
-g # 指定配置命令,覆蓋掉配置文件中的指令
-p # 指定運行目錄
-s # 發送信號 stop 立刻停止服務;quit 優雅的停止服務;reload 重載配置文件;reopen 重新開始記錄日誌文件
-t/-T # 測試配置文件是否有語法錯誤
-v/-V # 列印 nginx 的版本信息、編譯信息等
熱部署
當配置文件發生變更時,需要重載配置文件:
nginx -s reload
但想要更換 nginx 版本時,就需要採用熱部署的方式:
- 查看現有 master 進程的 pid。可以看出來,worker 進程是 master 進程的子進程
- 拷貝新的二進位文件到安裝目錄,然後 kill 發送信號給現有的 master 進程
# master 進程 pid 為 83308
kill -USR2 61333
查看 Nginx 進程。可以發現,新的 master 進程也是基於老的 master 進程 fork 出來的
- 關閉老的 master 進程下的 worker 進程。這個時候會發現,基於 61333 這個 master 的 worker 進程已經退出了
# 優雅的關閉老的 master 所有的 worker 進程,執行後,老的 master 並不會退出但是 worker 已經沒了,防止新進程有問題,還可以通過 reload 來回滾
kill -WINCH 61333
- 如果沒有問題,那麼就執行退出老的 master 進程,這個時候再查看,老的 master 進程已經不存在了
# 優雅的退出 master
kill -quit 61333
日誌切割
一條命令即可實現日誌切割:
nginx -s reopen # 會重新生成日誌文件
關註公眾號領取二十套技術圖譜