Nginx
1. 基本概念
概述
- Nginx 是一個高效能的 HTTP 和反向代理伺服器
- 特點是佔有記憶體少,併發能力強
- 專為效能優化而開發,效能是其最最要的考量
反向代理
- 談反向代理之前我們先來了解一下正向代理,比如現在我們要訪問
www.google.com
,谷歌大陸目前是不能直接訪問的,那麼我們就可以通過在瀏覽器配置代理伺服器進行訪問(如下圖) - 接下來我們介紹反向代理,客戶端對代理無感知,客戶端不需要任何配置,我們只需要將請求傳送到反向代理伺服器,然後由反向代理伺服器去選擇目標伺服器獲取資料後,再返回給客戶端。此時反向代理伺服器和目標伺服器對外就是一個伺服器。顯然,反向代理對外暴露的是反向代理伺服器,隱藏了真實伺服器
- 比如下圖中,我們想目標伺服器發出請求時,由反向代理伺服器選擇 tomcat 伺服器 8001 埠,獲取資料後,再將資料返回給客戶端
負載均衡
- 客戶端傳送多個請求到伺服器,伺服器與資料庫互動處理請求,處理完畢後,再將結果返回給客戶端
- 這種架構模式適用於早期系統單一簡單,併發較少的情況。隨著資訊數量的不斷增長,訪問量和請求量的飛速增長,伺服器效能就會達到瓶頸,此時我們應該如何解決?
- 首先想到的是提升伺服器的配置,但是隨著摩爾定律的日益失效,硬體的效能提升已經不能滿足日益提升的效能需求。另外一個方法是我們可以增加伺服器的數量,將請求分發到各個伺服器上,這就是我們說的 負載均衡
- 如下圖,將 15 個請求分發到三臺伺服器上,理想狀態是每臺伺服器 3 個請求
動靜分離
- 為了加快網站的解析速度,可以把動態頁面和靜態頁面由不同的伺服器來解析,加快解析速度,降低原來單個伺服器的壓力
2. Nginx 安裝、命令和配置檔案
Linux 中安裝 Nginx
安裝 PCRE
PCRE 作用是讓 Nginx 支援 Rewrite 功能。
cd /usr/src/ wget http://downloads.sourceforge.net/project/pcre/pcre/8.37/pcre-8.37.tar.gz
tar zxvf pcre-8.37.tar.gz
cd pcre-8.37/ ./configure make && make install
pcre-config --version
安裝編譯工具及庫檔案
yum -y install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel
安裝 Nginx
cd /usr/src/ wget http://nginx.org/download/nginx-1.12.2.tar.gz
tar zxvf nginx-1.12.2.tar.gz
cd nginx-1.12.2/ ./configure make && make install
/usr/local/nginx/sbin/nginx -v
- 安裝成功後,在
usr
多出來一個資料夾local/nginx
,啟動指令碼為/nginx/sbin/nginx
測試
cd /usr/local/nginx/sbin ./nginx ps -ef | grep nginx
直接訪問 IP 地址可以看到如下介面
防火牆相關操作
- 檢視開放的埠號:
firewall-cmd --list-all
- 設定開放的埠號:
firewall-cmd --add-service=http --permanent
eg:sudo firewall-cmd --add-port=80/tcp --permanent
- 重啟防火牆:
firewall-cmd --reload
- 關閉防火牆:
systemctl stop firewalld
- 永久關閉防火牆:
systemctl disable firewalld
- 檢視開放的埠號:
Nginx 常用命令
使用 nginx 命令前要進入nginx
目錄:cd /usr/local/nginx/sbin
- 檢視 nginx 版本號:
./nginx -v
- 啟動 nginx:
./nginx
- 關閉 nginx:
./nginx -s stop
- 過載 nginx:
./nginx -s reload
配置 systemctl
配置 systemctl 後的啟動方式
- 狀態:
ssytemctl status nginx
- 啟動:
systemctl start nginx
- 關閉:
systemctl stop nginx
- 重啟:
systemctl restart nginx
配置方法
nginx.service
cd /usr/lib/systemd/system vim nginx.service
將以下內容複製進去<font color="red">(註釋的內容不要放進去!!!)</font>
[Unit] //對服務的說明 Description=nginx - high performance web server //描述服務 After=network.target remote-fs.target nss-lookup.target //描述服務型別 [Service] //服務的一些具體執行引數的設定 Type=forking //後臺執行的形式 PIDFile=/usr/local/nginx/logs/nginx.pid //PID檔案的路徑 ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf //啟動 準備 ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf //啟動命令 ExecReload=/usr/local/nginx/sbin/nginx -s reload //重啟命令 ExecStop=/usr/local/nginx/sbin/nginx -s stop //停止命令 ExecQuit=/usr/local/nginx/sbin/nginx -s quit //快速停止 PrivateTmp=true //給服務分配臨時空間 [Install] WantedBy=multi-user.target //服務使用者的模式
- 賦予許可權:
chmod +x /usr/lib/systemd/system/nginx.service
啟動服務
// 啟動服務之前,需要先過載 systemctl 命令 systemctl daemon-reload systemctl start nginx.service
報錯直接
kill -9
殺死重新拉起即可
- 狀態:
Nginx 配置檔案
Nginx 配置檔案位置:/usr/local/nginx/conf/nginx.conf
配置檔案由三部分組成
第一部分:全域性塊(從配置檔案開始到 events 塊之間的內容)
- 主要設定一些影響 Nginx 伺服器整體執行的配置指令,主要包括配置執行 Nginx 伺服器的使用者(組)、允許生成的 worker process 數、程式 PID 存放路徑、日誌存放路徑和型別以及配置檔案的引入等
worker_processes 1
:Nginx 伺服器併發處理的值,worker_processes 值越大,可以支援的併發處理數量越多
第二部分:events 塊
events { worker_connections 1024; }
- events 塊涉及的指令主要影響 Nginx 伺服器與使用者的網路連線,比如
worker_connections 1024;
表示 Nginx 支援的最大連線數為 1024
- events 塊涉及的指令主要影響 Nginx 伺服器與使用者的網路連線,比如
第三部分:http 塊(http 塊也可以包括 http 全域性塊、server 塊)
- http 全域性塊:http 全域性塊配置的指令包括檔案引入、MIME-TYPE 型別、日誌自定義、連線超時時間、單連結請求數上限等
server 塊:這塊和虛擬主機有密切聯絡,每個 http 塊可以包括多個 server 塊,每個 server 塊就相當於一個虛擬主機,每個 server 塊也分為全域性 server 塊,以及可以同時包含多個 location 塊
- 全域性 server 塊:最常見的配置是本虛擬主機的監聽配置和本虛擬主機的名稱或 IP 配置
- location 塊:主要作用的是基於 Nginx 伺服器接收到的請求字串(eg:server_name/uri-string),對虛擬主機名稱(也可以是 IP 別名)之外的字串(eg:/uri-string)進行匹配,對特定的請求進行處理。地址定向、資料快取和應答控制等功能,還有許多第三方模組的配置也在這裡進行
3. Nginx 配置例項
<0> 準備工作
安裝 tomcat,使用預設埠號 8080
cd /usr/src wget https://mirrors.cnnic.cn/apache/tomcat/tomcat-8/v8.5.73/bin/apache-tomcat-8.5.73.tar.gz tar zxvf apache-tomcat-8.5.73.tar.gz
- 安裝 jdk:可參考此教程 Linux 安裝和配置 JDK13
啟動 tomcat
cd /usr/src/apache-tomcat-8.5.73/bin/ ./startup.sh
訪問 tomcat(伺服器要開放 8080 埠)
<1> 反向代理 • 例項一
- 實現效果:開啟瀏覽器,在瀏覽器地址輸入地址
www.123.com
,跳轉到 Linux 系統 tomcat 主頁面中 - 過程分析:Windows 瀏覽器不能直接訪問t omcat,要通過 nginx 反向代理到 tomcat
具體配置
- 在 Windows 系統的 host 檔案進行域名和 ip 對應關係的配置
C:\Windows\System32\drivers\etc\hosts
在 nginx 進行請求轉發的配置(反向代理)
cd /usr/local/nginx/conf/ vim nginx.conf
測試
//啟動 nginx cd /usr/local/nginx/sbin ./nginx
- 在 Windows 系統的 host 檔案進行域名和 ip 對應關係的配置
<2> 反向代理 • 例項二
實現效果:使用 nginx 反向代理,根據訪問的路徑跳轉到不同埠的服務中,nginx 監聽埠為 9001
- 訪問
http://118.195.179.192:9001/edu/
直接跳轉到127.0.0.1:8080
- 訪問
http://118.195.179.192/vod/
直接跳轉到127.0.0.1:8081
- 訪問
準備工作
準備兩個 tomcat 伺服器,一個 8080 埠,一個 8081 埠
cd /usr/src mkdir tomcat8008 mkdir tomcat8081 cp apache-tomcat-8.5.73.tar.gz tomcat8080 cp apache-tomcat-8.5.73.tar.gz tomcat8081 ps -ef | grep tomcat kill -9 埠號 cd tomcat8080 tar zxvf apache-tomcat-8.5.73.tar.gz cd .. cd tomcat8081 tar zxvf apache-tomcat-8.5.73.tar.gz cd .. cd tomcat8080 cd apache-tomcat-8.5.73/ cd bin/ ./startup.sh cd .. cd .. cd .. cd tomcat8081 cd apache-tomcat-8.5.73/ cd conf vim server.xml
shutdown 埠隨便改一下,我這裡改成 8015
埠改成 8081
啟動 tomcat8081./startup.sh
可以看到我們啟動了兩個 tomcat,一個是 8080,一個是 8081
我們可以訪問看一下
建立資料夾和測試頁面
- 在
/usr/src/tomcat8080/apache-tomcat-8.5.73/webapps
下建立 edu 資料夾,並在資料夾下建立 a.html 檔案,內容為<h1>8080!!!</h1>
- 同樣的,在
/usr/src/tomcat8081/apache-tomcat-8.5.73/webapps
下建立 vod 資料夾,並在資料夾下建立 a.html 檔案,內容為<h1>8081!!!</h1>
- 在
具體配置
找到 nginx 配置檔案進行反向代理配置
cd /usr/local/nginx/conf vim nginx.conf
新增一個 server
server { listen 9001; server_name 118.195.179.192; location ~ /edu/ { proxy_pass http://127.0.0.1:8080; } location ~ /vod/ { proxy_pass http://127.0.0.1:8081; } }
開放埠號 9001、8080、8081
重新載入 nginxcd /usr/local/nginx/sbin ./nginx --s stop ./nginx
- 最終測試
location 指令說明
該指令用於匹配 URL ,語法如下:
location [ = | ~ | ~* | ^~] uri { }
=
:用於不含正規表示式的 uri 前,要求請求字串與 uri 嚴格匹配,如果匹配成功,就停止繼續向下搜尋並立即處理該請求~
:用於表示 url 包含正規表示式,並且區分大小寫~*
:用於表示 uri 包含正規表示式,並且不區分大小寫^~
:用於不含正規表示式的 uri 前,要求 nginx 伺服器找到標識 uri 和請求字串匹配度最高的 location 後,立即使用此 location 處理請求,而不再使用 location 塊中的正則 uri 和請求字串做匹配
<3> 負載均衡
- 實現效果:通過瀏覽器位址列輸入地址
http://118.195.179.192/edu/a.html
,負載均衡效果,平均 8080 和 8081 埠 準備工作
- 準備兩臺 tomcat 伺服器,一臺 8080,一臺 8081(上一個例項已經準備過)
- 在兩臺 tomcat 的 webapps 目錄下,建立名稱為 edu 資料夾,在 edu 資料夾建立 a.html 頁面,用於測試
在 nginx 的配置檔案中進行負載均衡的配置
cd /usr/local/nginx/conf vim nginx.conf
- 測試
負載均衡分配策略
- 輪詢(預設):每個請求按時間順序逐一分配到不同的後端伺服器,如果後端伺服器 down 掉,能自動剔除
weight
- weight 代表權重,預設為1,權重越高被分配的客戶端越多
指定輪詢機率,weight 和訪問比率成正比,用於後端伺服器效能不均的情況
upstream myserver { server 118.195.179.192:8080 weight=5; server 118.195.179.192:8081 weight=10; }
ip_hash :每個請求按訪問 ip 的 hash 結果分配,這樣每個訪問固定訪問一個後端伺服器,可以解決 session 問題,eg
upstream myserver { ip_hash; server 118.195.179.192:8080; server 118.195.179.192:8081; }
fair(第三方):按後端伺服器的響應時間來分配請求,響應時間短的優先分配
upstream myserver { server 118.195.179.192:8080; server 118.195.179.192:8081; fair; }
<4> 動靜分離
動靜分離從目前實現角度來講大致分為兩種
- 一種是純粹把靜態檔案獨立成到單獨的域名,放在獨立的伺服器上
- 另一種方法就是動態跟靜態檔案混合在一起釋出,通過 nginx 來分開
通過 location 指定不同的字尾名實現不同的請求轉發。通過 expires 引數設定,可以使瀏覽器快取過期期間,減少與伺服器之前的請求和流量。具體 expires 定義:是給一個資源設定一個過期時間,也就是說無需去服務端驗證,直接通過瀏覽器自身確認是否過期即可,所以不會產生額外的流量。此種方法非常適合不經常變動的資源。(如果經常更新的檔案,不建議使用 Expires 來快取)。比如:設定 3d,表示在 3 天之內訪問這個 URL,傳送一個請求,比對伺服器該檔案最後更新時間沒有變化,則不會從伺服器抓取,返回狀態碼 304,如果有修改,則直接從伺服器重新下載,返回狀態碼 200
準備工作
在 Linux 系統中準備靜態資源,用於進行訪問
cd / mkdir static cd static mkdir www mkdir image
www
資料夾中建立檔案a.html
,內容為<h1>test html</h1>
image
資料夾中隨便放一張圖片,我這裡放的是01.jpg
- 實現效果:瀏覽器訪問 www 下
a.html
和 image 下01.jpg
(不是通過 tomcat,而是通過 nginx 靜態資源配置訪問) 具體配置
cd /usr/local/nginx/conf vim nginx.conf
啟動/重啟 nginxcd /usr/local/nginx/sbin ./nginx
測試
- 瀏覽器輸入地址
http://118.195.179.192/image/01.jpg
- 瀏覽器輸入地址
http://118.195.179.192/www/a.html
- 瀏覽器輸入地址
<5> 高可用叢集
什麼是高可用?
- 有一臺主伺服器和一臺備份伺服器,一般請求時都是根據主伺服器傳送請求,當主伺服器的 Nginx 掛掉時,會自動切換到備份伺服器,通過備份伺服器進行訪問,此時備份伺服器作為主伺服器的位置來處理請求,這就是高可用
準備工作
- 需要兩臺 Nginx 伺服器
- 在兩臺伺服器安裝 nginx (前面有教程)
- 在兩臺伺服器安裝 keepalived
yum install keepalived -y
安裝目錄為:/etc/keepalived
檢視是否被安裝:rpm -q -a keepalived
完成高可用配置(主備配置)
cd /etc/keepalived vim keepalived.conf
主伺服器
global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id LVS_DEVEL } vrrp_script chk_http_port { script "/usr/local/src/nginx_check.sh" interval 2 # 檢測指令碼執行的間隔 weight 2 } vrrp_instance VI_1 { state MASTER # 備份伺服器上將 MASTER 改為 BACKUP interface eth0 # 網路卡 virtual_router_id 51 # 主、備機的 virtual_router_id 必須相同 priority 100 # 主、備機取不同的優先順序,主機值較大,備機值較小 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.200.16 # VRRP H 虛擬地址 } }
備份伺服器
global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id LVS_DEVEL } vrrp_script chk_http_port { script "/usr/local/src/nginx_check.sh" interval 2 # 檢測指令碼執行的間隔 weight 2 } vrrp_instance VI_1 { state BACKUP # 備份伺服器上將 MASTER 改為 BACKUP interface eth0 # 網路卡 virtual_router_id 51 # 主、備機的 virtual_router_id 必須相同 priority 90 # 主、備機取不同的優先順序,主機值較大,備機值較小 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.200.16 # VRRP H 虛擬地址 } }
在主伺服器和備份伺服器
/usr/local/src
下編寫檔案nginx_check.sh
#!/bin/bash A=`ps -C nginx -no-header |wc -1` if [ $A -eq 0 ];then /usr/local/nginx/sbin/nginx # Nginx 啟動指令碼位置 sleep 2 if [ `ps -C nginx --no-header |wc -1` -eq 0 ];then killall keepalived fi fi
啟動兩臺伺服器的 nginx 和 keepalived
cd /usr/local/nginx/sbin ./nginx systemctl start keepalived
- 測試:兩臺伺服器要在同一區域網,我這裡只是為了演示流程
keepalived 配置檔案詳解
global_defs
:全域性配置(主要是router_id 伺服器名字
在/etc/host
新增主機名稱)vrrp_script
:指令碼配置script "xxx.sh"
interval 2
:檢測指令碼執行的間隔(2s)weight -20
:權重(當指令碼中的條件成立,當前主機的權重降低20)
vrrp_instance
:虛擬 IP 配置state BACKUP
:表示伺服器是主伺服器(MASTER)還是備份伺服器(BACKUP)interface eth0
:繫結的網路卡(通過ifconfig
檢視)virtual_router_id 51
:主備機的id值,相當於唯一標識priority 90
:優先順序,值越大,優先順序越高(一般主伺服器設定為 100,從伺服器小於 100,比如 90)advert_int 1
:每隔多長時間傳送一個心跳,檢測伺服器是否或者,預設每隔 1 s 傳送一個心跳authentication {auth_type PASS auth_pass 1111}
:許可權校驗方式(密碼:1111)vritual_ipaddress
:繫結虛擬 IP(可以繫結多個)
4. Nginx 原理
- nginx 啟動後有兩個程式:master 和 worker
- master 就相當於一個領導,不做具體工作,分配任務給 worker,worker 做具體的任務
worker 如何進行工作?
- 當 client(客戶端)傳送一個請求到 nginx,首先到 master,master 得到請求後,將請求分擔給 worker,一個 master 下面有很多個 worker,worker 獲取任務不是平均分配,也不是輪詢,而是
爭搶
的機制
- 當 client(客戶端)傳送一個請求到 nginx,首先到 master,master 得到請求後,將請求分擔給 worker,一個 master 下面有很多個 worker,worker 獲取任務不是平均分配,也不是輪詢,而是
client 傳送請求 -> master ->worker(爭搶機制) -> 具體操作
一個 master 和多個 worker 有什麼好處?
- 可以使用
nginx -s reload
熱部署,利於 nginx 進行熱部署操作 - 每個 worker 都是獨立的程式,不需要加鎖,一個程式退出後,其他程式可正常工作,降低風險
- 可以使用
設定多少個 worker 合適?
- Nginx 同 redis 類似都採用了 IO 多路複用機制,每個 worker 都是一個獨立的程式,每個程式裡只有一個主執行緒,通過非同步非阻塞方式來處理請求。每個 worker 的執行緒可以把一個 CPU 的效能發揮到極致。因此,
worker 數和伺服器的 CPU 數相等是最為適宜的
。設少了會浪費 CPU,設多了會造成 CPU 頻繁切換上下文帶來的損耗
- Nginx 同 redis 類似都採用了 IO 多路複用機制,每個 worker 都是一個獨立的程式,每個程式裡只有一個主執行緒,通過非同步非阻塞方式來處理請求。每個 worker 的執行緒可以把一個 CPU 的效能發揮到極致。因此,
連線數 worker_connection(每個 worker 程式所能建立連線的最大值)
- 傳送一個請求,佔用了 worker 的幾個連線數?答案:2(client 訪問靜態資源,worker 收到請求後返回) 或者 4 個(worker 本身不支援 Java,worker 要把請求轉發給 tomcat,tomcat 再返回)
nginx 有一個 master,有 4 個 worker,每個 worker 支援的最大連線數為 1024, 支援的最大的併發數為多少?
worker 最大支援的連線數 4*1024 worker 支援的最大併發 4*1024/2=2048 或 4*1024/4=1024
普通的靜態訪問最大併發數是:worker_connections * worker_processes / 2
作為反向代理來說,最大的併發數量是:worker_connections * worker_processes / 4
【注】worker_connections:每個 worker 支援的最大連線數(即上面所說的 1024)
worker_processes:worker 的數量