論Nginx作為Web服務器的應用在Linux上的實現 ( Blog 18)

Nginx…

博客十八:論Nginx作為Web服務器的應用在Linux上的實現;

Alphabetical index of variables
Core functionality
ngx_http_core_module
ngx_http_access_module
ngx_http_auth_basic_module
ngx_http_fastcgi_module
ngx_http_gzip_module
ngx_http_headers_module
ngx_http_log_module
ngx_http_proxy_module
ngx_http_referer_module
ngx_http_rewrite_module
ngx_http_ssl_module
ngx_http_status_module
ngx_http_stub_status_module
ngx_http_upstream_module
ngx_stream_core_module

獲取模塊相關指令的幫助: http://nginx.org/en/docs/

主配置文件結構:
main block:主配置段,也即全局配置段;進程配置
event {

}:事件驅動相關的配置;

http {

}:http/https 協議相關的配置段;

mail {

}: 7層負載均衡

stream {

}: 4層負載均衡

http協議相關的配置結構
http {

…:各server的公共配置
server {

}:每個server用于定義一個虛擬主機;
server {

listen defult_server: 主機名虛擬主機時,通過IP訪問此主機響應;
server_name _ 匹配所有主機名
root 相當于DocumentRoot
alias 相當于alias
location [OPERATOR] URL {

if CONDITION {

}:相當于IfModule,為真則運行;

error_page 錯誤頁
}:僅能基于URL定義。http可以基于文件系統、URL定義
}
}

配置文件修改后:
1)語法檢測:nginx -t
2)重載配置:nginx -s reload

Main配置段指令:
1)正常運行必備
user, pid, include, load_module
(1)、user nginx;
workder進程的身份;
(2)、pid /run/nginx.pid;
pid文件
(3)、include /usr/share/nginx/modules/*.conf;
片段化配置
(4)、load_module “/usr/lib64/nginx/modules/ngx_http_geoip_module.so”;
裝載支持動態裝載的模塊

2)性能優化相關
worker_processes, worker_cpu_affinity, worker_priority, worker_rlimit_nofile
(1)、worker_processes auto;
worker進程啟用個數,auto表示當前物理核心數,建議比當前物理核心數小,以避免worker進程間切換;
(2)、worker_cpu_affinity auto [cpumask];
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
綁定worker進程在哪個CPU上;提高緩存命中率;查看進程位置哪個CPU:ps axo pid,comm,psr
(3)、worker_priority number;
worker_priority -10;
worker進程啟動后的優先級,默認是0;查看進程的優先級:ps axo pid,comm,ni
(4)、worker_rlimit_nofile number;
限制打開文件最大數量,應該大于”所有worker進程并發數”;

3)調度定位問題
daemon, master_process, error_log file [level]
(1)、daemon on | off;
nginx是否工作于前臺;off:表示工作于前臺;注意需要重啟進程;
(2)、master_process on | off;
nginx是否僅以master進程工作;off:表示只能master進程;注意需要重啟進程;
(3)、error_log file [level];
Log levels:debug, info, notice, warn, error, crit, alert, or emerg.
錯誤日志記錄級別,從左而右依次遞增,級別越高記錄的越少;

4)事件驅動:event { … }
worker_connections number, use method, accept_mutex
(1)、worker_connections number;
一個worker進程最大并發數;
所有worker進程最大并發數 = worker_connections number X worker_processes
(2)、 use method;
select: 1024
epoll: C10K
(3)、accept_mutex on | off;
on意味著由各worker輪流處理新請求; 必須輪流;
Off意味著每個新請求的到達都會通知所有的worker進程;搶著請求;

http配置段
http {
… …
server {
listen
server_name
root
location [OPERATOR] /uri/ {

}
}
server {

}
}
與套接字相關的配置:

(1)、server { … }
表示定義一個虛擬主機;
server {
listen
server_name
root
}

(2)、listen PORT|address[:port] [ssl]
定義當前虛擬主機監聽的地址加端口,省略時表示所有:例如:listen 800; 監聽在當前主機所有的接口的地址;
listen 127.0.0.1:8000;
listen 127.0.0.1;
listen 8000;
listen *:8000;
listen localhost:8000;
listen 44322 ssl;
ssl: 表示僅能ssl通信;
ssl_certificate “/etc/pki/nginx/server.crt”;
ssl_certificate_key “/etc/pki/nginx/private/server.key”;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

(3)、server_name name …;
定義虛擬主機的主機名稱
server {
server_name example.com *.example.com www.example.* ~^www\d+\.example\.com$;
}
優先級:
(1) 首先是字符串精確匹配;
(2) 左側*通配符;
(3) 右側*通配符;
(4) 正則表達式;

例如:
server {
listen 172.16.0.99:80;
server_name www.a.com;
root /data/nginx/v3;
}
server {
listen 172.16.0.99:80;
server_name *.a.com;
root /data/nginx/v1;
}
server {
listen 172.16.0.99:80;
server_name www.a.*;
root /data/nginx/v2;
}
server {
listen 172.16.0.99:80;
server_name ^www\d+\.a\.com$;
root /data/nginx/v4;
}
瀏覽器中訪問:
www.a.com —> v3:前三個都滿足,精確匹配者為先;
www1.a.com –> v1:二四滿足,正則表達式優先級最低;
www.a.io —> v2:僅3匹配;

(4)、tcp_nodelay on | off; <適用于keepalive啟用時>
on: 在keepalived模式下的連接時, 每個報文單獨發送,提升用戶體驗;
off: 在keepalived模式下的連接時, 將多個報文打包為一個發送,用戶看到有延遲;

(5)、tcp_nopush on | off;
on: 在sendfile模式下,等待應用層首部;
off: 在sendfile模式下,不等待應用層首部,首部隨后到達;

(6)、sendfile on | off;
on: 啟用sendfile時,worker進程被請求一個資源時,其向內核發起系統調用,內核將其加載至”內核內存”中,直接構建響應報文發送;
off: 將加載到內核內存中的數據再復制到進程內存中,由應用程序響應,消耗不必要的時間;

面向客戶端連接的相關配置
(1)、keepalive_timeout timeout [header_timeout];
設定保持連接的超時時長,0表示禁止長連接;默認為75s;
禁用:keepalive_timeout 0;

(2)、keepalive_requests number;
在一次長連接上所允許請求的資源的最大數量,默認為100;

保持連接:多個資源一直請求,第一次建立連接,傳輸完成后再拆除連接;
缺點:建立后不會釋放連接;
折中的方案: 設置長連接,但有限制: 時間, 資源
注意:在高并發場景應該關閉長連接,給每個用戶維持一個連接,可能會阻止新的用戶連接;
建議配置:
keepalive_timeout 15;

(3)、send_timeout time; 發送響應超時時長!
服務端向客戶端發送響應報文時,客戶端突然斷開,超時會重試響應。

(4)、client_body_buffer_size size;
緩沖(讀寫)請求報文的body的buffer大小,默認為16K,超出此大小時,其將被暫存到磁盤上的由client_body_temp_path指令所定義的位置;
1個漢字2個Bytes,1KBytes=1024Bytes /2 –> 512漢字; 16K –> 16*1024/2=接近1萬個漢字;
如果并發1萬:單個buffer 16K ,所有請求:16 X 10^-3 M X 10^4 =16M
client_body_temp_path path [level1 [level2 [level3]]]; 將buffer未能緩存的body部分(>16K),緩存于磁盤上;以便將來快速查找;
path: 緩存的路徑:
level1: 一級子目錄
level2: 兩級子目錄
level3: 三級子目錄
目錄名是URL的hash值(十六進制數字),從右而左截取的字串,如果目錄名為一個字符:則縮小16倍。2個字符:則縮小16X16倍。3個字符:則16^3倍。

對客戶端進行限制的相關配置:
(1)、limit_except method … { … }
限制除了哪些方法(GET, HEAD, PUT, POST, DELETE, TRACE, OPTIONS)之外的方法:
建議配置:GET HEAD POST方法外不允許使用;
limit_except GET HEAD POST {
deny all;
}
GET:不需要ENTITY-BODY;
HEAD:測試測試能否GET;
POST: 提交表單;密碼、提交回復;
PUT: 上傳一個資源至服務器端(服務器要提供DAV)
DELETE:刪除
TRACE: 追蹤web服務器需要經過多少個代理;
traceroute
OPTIONS: 探測資源支持的方法的方法

文件操作優化相關的配置:
(1)aio on | off ; 啟用AIO功能,極大優化訪問時被阻塞在IO上的時間;
(2)open_file_cache max=N [inactive=time];
max=N 緩存多少個信息;(文件描述符、目錄結構、沒有訪問權限的相關信息); 達到MAX值時,以LRU算法找出最近最少使用,刪除緩存;
inactive=time 非活動時長。如果此時間內不命中緩存,就會刪除緩存;

定義路徑相關的配置:
(1)、root path;
URL的根映射到文件系統哪個目錄;用于:http, server, location, if in location;范圍小越最終生效;
http {
server {
location {
if () {

}
}
}
}

(2)、location [ = | ^~ | ~* | ~ ] uri { … }
根據請求報文的的URI來匹配檢查;URI: 在訪問日志中有記錄:http://www.a.com/123 –> “GET /123 HTTP/1.1”
根據匹配優先級遞減列出:
= 精確匹配
^~ 半部分匹配
~* 正則表達式匹配,ignore case;
~ 正則表達式匹配,區分字母大小寫;
直接給出

多個location可以匹配到相同的內容時,則根據此優先級判斷應該運用于哪個location:
例如:
server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;

location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}

location / {
root /web
all all;
}
}

此時,在172.16.0.68主機上訪問一個 http://www.ilinux.io/1920×1080.jpg,的權限匹配法則:
其URI:/1920×1080.jpg ~* 可以匹配;/也可以匹配;優先級 ~* > /,所以匹配 ~* 所在的location;

(3)、alias path;
路徑別名
root: 目錄下存在URI
location /images/ {
root /path/to/somedir;
}
www.ilinux.io/images/ –> server –> location /images/ –> /path/to/somedir/images/

alias:目錄下不存在URI;
location /images/ {
alias /path/to/somedir;
}
www.ilinux.io/images/ –> server –> location /images/ –> /path/to/somedir/
例如:
server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;

location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}
location / {
}

location ^~ /images/ {
alias /data/pictures/;
}
}

訪問:www.ilinux.io/images/1920×1080.jpg –> location (^~ > ~* > 直接給出) –> alias指定的路徑下不存在匹配的URI(/data/pictures/1920×1080.jpg)

(4)、error_page code … uri;
自定義錯誤頁;響應狀態碼為code時,返回URI并重新檢查整個配置文件;
例如:
server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;
location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}
location / {
root /web;
}
location ^~ /images/ {
alias /data/pictures/;
}
error_page 404 /notfound.html;
}
客戶端訪問一個不存在的頁面時,返回/notfound.html,并重新匹配整個配置文件,多個location 只能第二個匹配,是root:表示/notfound.html則為/web目錄下的一個文件;

server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;

location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}

location / {
}

location ^~ /images/ {
alias /data/pictures/;
}

error_page 404 /notfound.html;
location = /notfound.html {
root /data/nginx/error_pages;
}
}
客戶端訪問一個不存在的頁面時,返回/notfound.html,并重新匹配整個配置文件,location優先級最高的是 = ,文件為: /data/nginx/error_pages/notfound.html

(5)、error_page code … [=[response]] uri;
響應狀態碼為指定的code時,返回URI;且修改狀態碼:查看方法:瀏覽器中打開F12 后 F5刷新;

訪問控制:
(1)、ngx_http_access_module
白名單:
allow addr;
deny all;
黑名單:
allow all;
deny addr;

(2)、ngx_http_auth_basic_module
程序包:httpd-tools
location ~* /(admin|login)/ {
auth_basic “admin area”
auth_basic_user_file /etc/nginx/.ngxpasswd
}
不定義root相當于承繼全局root;

狀態:
(1)、ngx_http_stub_status_module
location /NAME {
stub_status;
}
AME必須要與網頁不沖突,惟一;
location /ngxstatus {
stub_status;
}
Active connections: 2
當前的活動連接數;
accepts handled requests
總請求requests中:
accepts:接受進來的請求數;
handled: 處于完成的請求數;
requests > accepts > handled

Reading: 0 Writing: 1 Waiting: 1
處于正在 讀請求報文首部狀態的請求
處于正在 發送響應狀態的請求:
處于正在 等待請求的請求;空閑 <– 長連接,客戶端發送一個請求后,不再請求時,就空閑了;

awk取出:處理過的請求:
# curl –silent http://www.ilinux.io/ngxstatus | awk ‘/^[[:space:]]/{print $2}’

日志:
(1)、ngx_http_log_module
log_format name string …;
access_log path [format [buffer=size] [gzip[=level]];
buffer:定義{緩沖}數據內容的緩沖區大小,元數據由下面的指令字義{緩存},大量的訪問日志先在內存中,一會兒在寫入磁盤。性能提升;默認即可;
access_log off; 表示關閉訪問日志

應用上下文: http, server, location
http: 全局配置
server: 單虛擬主機日志
location: URI匹配到此location時,記錄

combined格式:
log_format main ‘$proxy_add_x_forwarded_for – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent”‘;

示例:記錄自己定義的虛擬主機日志,且admin單獨記錄,status不記錄:
server {
listen 172.16.0.67:80;
server_name www.ilinux.io;
root /data/nginx/vhost1;
access_log /var/log/vhost1_access.log main;

location ~* \.(jpg|png)$ {
deny 172.16.0.68;
allow all;
}

location / {
root /web;
}

location ~* /(admin|login)/ {
auth_basic “admin area”;
auth_basic_user_file /etc/nginx/.ngxpasswd;
access_log /var/log/admin_access.log main;
}

location ^~ /images/ {
alias /data/pictures/;
}

error_page 404 =200 /notfound.html;
location = /notfound.html {
root /data/nginx/error_pages;
}

location /ngxstatus {
stub_status;
access_log off;
}
}

open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
緩存各日志文件相關的元數據信息;

max:緩存的最大文件描述符數量;
min_uses:在inactive指定的時長內訪問大于等于此值方可被當作活動項;
inactive:非活動時長;
valid:驗正緩存中各緩存項是否為活動項的時間間隔;

傳輸壓縮:
(1)、ngx_http_gzip_module
http, server, location, if in location
對所有站點壓縮:http中
對指定站點壓縮:server中;
對匹配的URI壓縮:location

gzip on;
gzip_comp_level 6;
gzip_min_length 64; 啟用壓縮最小大小
gzip_proxied any;
gzip_types text/xml text/css application/javascript; 對哪些mime(mime.types)壓縮;
測試:cp nginx.conf /data/nginx/vhost1/nginx.html
注意:后綴為Html才能壓縮;此項為默認!

SSL:
(1)、ngx_http_ssl_module (單個IP只能做一次SSL)
server {
listen 443 ssl;
server_name www.magedu.com;
root /vhosts/ssl/htdocs;
ssl on;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_session_cache shared:sslcache:20m;
}
shared:sslcache:20m
1M=4000個會話; 20M –> 160萬個會話;
shared: worker進程間的ssl session是共享的;

URL重寫:
(1)、ngx_http_rewrite_module
rewrite pcre擴展正則表達式 替換的內容 (類似于查找替換)
pcre擴展正則表達式: 與擴展正則表達式相同寫法;
替換的內容: 只能是純文本字符,可以使用$1, $2 …后向引用
注意:
替換的內容是相對路徑: 瀏覽器中鍵入的URL不會改變;
替換的內容是絕對路徑: 瀏覽器中鍵入的URL會改變,相當于 301, permanent

例如:
1)找出URI中jpg替換為png:
rewrite /(.*)\.jpg@ /$1.png
2)全棧SSL
rewrite /(.*)$ https://www.ilinux.io/$1

重寫優先級:
last: 重寫后重復檢查;
break: 重寫后不再檢查;
redirect: 臨時重定向;302;
rewrite /(.*)\.jpg /$1.jpg
rewrite /(.*)\.jpg /$1.jpg redirect 即使相對路徑客戶端也會重新請求;
permanent, 永久重定向,301,相當于給出絕對路徑;
rewrite /(.*)\.jpg /$1.jpg permanent;
服務器自己處理:
last,break, 相對路徑;
返回給客戶端:
redirect, permanent, 絕對路徑;
防火鏈:
(1)、ngx_http_referer_module
1)valid_referers none block server_names *.magedu.com *.mageedu.com magedu.* mageedu.* ~\.magedu\.;
none: referer沒有首部: 自己直接鍵入的主頁; –> 合法;
block: 有referer,但沒有值,只要自己委屈的認為合法??赡艽矸掌鲃h除了;
server_names 服務器名 正則表達式:自己定義哪些服務器;
\google\:爬蟲,應該允許,否則表示拒絕了搜索引擎收錄了;
2)if($invalid_referer) {
return http://www.magedu.com/invalid.jpg; 當為真時生效; 返回一個劣圖,假圖;引起用戶注意作用;
}

變量為真:
數字:0假;非0真;
字串:空假,非空真;

3)rewrite_log on | off; 重寫發生是否記錄于日志;
4)set $var :自己定義變量;

例如:
server {
listen 80;
server_name www.iunix.io;
location ~* \.(jpg|png|jpeg|gif)$ {
valid_referers none blocked server_names *.unix.io unix.* ~\.google\.;
if ($invalid_referer) {
return http://web.iunix.io/default.jpg ;
}
}

}
如果返回當前虛擬主機(www.iunix.io)中定義的圖片時,又會匹配到此不可以引用:
解決方法:
1、 valid_referers server_names 后添加可引用的站點;
2、 返回另一個基于名稱或端口或IP的虛擬主機路徑下的一個圖片;
3、 返回另一個站點上的圖片;

總結:與優先級相關:
多個server_name:精確 > *.magedu.com > www.magedu.* > ~ REGEXP;
多個location:精確(=) > ^~(行首) > ~* 不區分大小寫 > ~ 區分大小寫 > 直接給出;
root: 路徑下存在URI;
alias: 路徑下不存在URI;

Nginx 七層代理:
Nginx是應用層的代理:Client與服務端是兩個完全不同的連接;(抓包可分析;)
源地址和源端口會變化;
目標地址和目標端口會變化;Nginx是監聽在一個固定端口;

注意:
同一個主機只能LNMP: Nginx + php-fpm + mariadb

跨主機: 建議使用同一個網段的三個主機,不同網段,反正我是沒有實現出來;
LNMP: Nginx + php-fpm + mariadb
LANMP: Nginx + httpd(php) + mariadb

ngx_http_proxy_module <– 代理http協議,自定義請求首部;(LNAMP)
proxy_pass http://IP:PORT;

proxy_set_header X-Real-IP $remote_addr; 向服務端設定請求首部;
proxy_cache_path 定義緩存空間、大小、磁盤路徑、最大大小、級別;
proxy_cache 調用緩存;
proxy_cache_key 緩存的鍵
proxy_cache_methods 哪些方法緩存
proxy_cache_min_uses 非活動期內最小使用次數;
proxy_cache_valid 哪些狀態碼返回的內容緩存的時間
proxy_cache_use_stale 后端服務器哪些狀態可以以緩存響應;
proxy_connect_timeout 與后端建立連接超時
proxy_read_timeout 讀后端服務器的超時
proxy_send_timeout 向后端服務器發送響應超時

ngx_http_headers_module <– 自定義響應首部
add_header X-Via $server_addr; 代理修改響應給客戶端的報文

ngx_http_fastcgi_module <– 代理fastcgi協議,保持連接;(LNMP)
fastcgi_pass IP:PORT;
fastcgi_cache_path
fastcgi_cache
fastcgi_cache_key
fastcgi_cache_methods
fastcgi_cache_valid
fastcgi_keep_conn nginx要求保持連接;

注意:多個主機協作時,必須要同步時間;
Nginx后是fpm時,fpm的并發連接支撐能力不如httpd;并發管理能力不如httpd

1)將用戶所有請求代理至后端主機;
server {
listen 80;
server_name www.ilinux.io;

location / {
#root /data/nginx/html;
proxy_pass http://192.168.10.11:80;
proxy_set_header X-Real-IP $remote_addr;
add_header X-Via $server_addr;
}
}
注意:需要在后端httpd主機上添加 %h –> %{X-Real-IP}i

2)將用戶對不同的資源請求代理至不同主機;
server {
listen 80;
server_name www.ilinux.io;

proxy_set_header X-Real-IP $remote_addr;
add_header X-Via $server_addr;

location / {
#root /data/nginx/html;
proxy_pass http://192.168.10.11:80;
}

location ~* \.(jpg|gif|png|jpeg)$ {
proxy_pass http://192.168.10.12:80;
}
}

LNAMP:
server {
listen 80;
server_name www.ilinux.io;

proxy_set_header X-Real-IP $remote_addr;
add_header X-Via $server_addr;

location / {
#root /data/nginx/html;
proxy_pass http://192.168.10.11:80;
}

location ~* \.php$ {
proxy_pass http://192.168.10.12:80;
}
}
192.168.10.12
~]# yum -y install php php-mysql mariadb-server php-mbstring php-mcrypt
~]# scp phpMyAdmin-4.0.10.20-all-languages.zip 192.168.10.12:/var/www/html
# unzip phpMyAdmin-4.0.10.20-all-languages.zip
# ln -sv phpMyAdmin-4.0.10.20-all-languages pma
# cp pma/config.sample.inc.php pma/config.inc.php
# vim /etc/my.cnf.d/server.cnf
[mysqld]
skip_name_resolve=ON
innodb_file_per_table=ON
# systemctl start mariadb.service
# mysql_secure_installation
# mysql -uroot -hlocalhost -pmagedu
~]# systemctl restart httpd.service

http://www.ilinux.io/pma/
http://www.ilinux.io/pma/index.php

192.168.10.11
~]# scp phpMyAdmin-4.0.10.20-all-languages.zip 192.168.10.11:/var/www/html
# unzip phpMyAdmin-4.0.10.20-all-languages.zip
# ln -sv phpMyAdmin-4.0.10.20-all-languages pma

# tail /var/log/httpd/access_log
172.16.0.179 – – [17/Dec/2017:07:39:32 +0800] “GET /pma/themes/pmahomme/img/sprites.png HTTP/1.0” 200 61899 “http://www.ilinux.io/pma/phpmyadmin.css.php?server=1&token=d7a0893b2b2b56261eff189d123a25d9&nocache=6008347360ltr” “Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36”

3)靜態內容在本地,動態在后端:
server {
listen 80;
server_name www.ilinux.io;

proxy_set_header X-Real-IP $remote_addr;
add_header X-Via $server_addr;

location / {
root /data/nginx/html;
#proxy_pass http://192.168.10.11:80;
}

location ~* \.php$ {
proxy_pass http://192.168.10.12:80;
}
}
http://www.ilinux.io/pma/index.php

172.16.0.6
~]# cp phpMyAdmin-4.0.10.20-all-languages.zip /data/nginx/html/
~]# cd /data/nginx/html/
# unzip phpMyAdmin-4.0.10.20-all-languages.zip
# ln -sv phpMyAdmin-4.0.10.20-all-languages pma
http://www.ilinux.io/pma/index.php
172.16.0.179 – – [17/Dec/2017:07:44:49 +0800] “GET /pma/themes/pmahomme/img/sprites.png HTTP/1.1” 200 61899 “http://www.ilinux.io/pma/phpmyadmin.css.php?server=1&token=6f042529e089b420daaa96176e8fcbda&nocache=4494879789ltr” “Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36” “-”

4)靜態在后端:動態在后端(amp/p):
~]# yum -y install php php-mysql mariadb-server php-mbstring php-mcrypt
~]# vim /etc/my.cnf.d/server.cnf
~]# systemctl start mariadb.service
~]# mysql_secure_installation
~]# mysql -uroot -pmagedu

server {
listen
server_name

location / {
proxy_pass http://192.168.10.11:80;

}
location ~* \.php$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/apps$fastcgi_script_name;
include fastcgi_params;

proxy_pass http://192.168.10.11:80;
}

}

注意:LNMP可行,LNAMP跨網段搭建不出來;

壓力測試:

注釋fastcgi_cache fcache;
ab -c 100 -n 2000 http://www.ilinux.io/pma/index.php

配置緩存; 后先用curl請求幾次;
Requests per second: 640.58 [#/sec] (mean)

啟用緩存
Requests per second: 2828.87 [#/sec] (mean)

啟用保持連接

http {
fastcgi_cache_path /data/nginx/fcgicache levels=2:2:2 keys_zone=fcache:10m max_size=20g;
}
server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
#proxy_pass http://192.168.10.12:80;
}

location ~* \.php$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name/wp/;
include fastcgi_params;
}
[root@localhost nginx]# ls /data/nginx/fcgicache/
[root@localhost nginx]# <–緩存目錄為空
~]# ab -c 100 -n 20000 www.ilinux.io/phpinfo.php
Requests per second: 3315.66 [#/sec] (mean)

打開緩存:
http {
fastcgi_cache_path /data/nginx/fcgicache levels=2:2:2 keys_zone=fcache:10m max_size=20g;
}
server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
#proxy_pass http://192.168.10.12:80;
}

location ~* \.php$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
include fastcgi_params;

fastcgi_cache fcache;
fastcgi_cache_key $request_uri;
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 301 1h;
fastcgi_cache_valid any 1m;
}
~]# ab -c 100 -n 20000 www.ilinux.io/phpinfo.php
Requests per second: 8747.94 [#/sec] (mean)
# ls /data/nginx/fcgicache/
de
打開保持連接:
http {
fastcgi_cache_path /data/nginx/fcgicache levels=2:2:2 keys_zone=fcache:10m max_size=20g;
}
server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
#proxy_pass http://192.168.10.12:80;
}

location ~* \.php$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
include fastcgi_params;

fastcgi_cache fcache;
fastcgi_cache_key $request_uri;
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 301 1h;
fastcgi_cache_valid any 1m;
fastcgi_keep_conn on
}

~]# ab -c 100 -n 20000 www.ilinux.io/phpinfo.php
Requests per second: 8503.63 [#/sec] (mean)

5) php-fpm狀態頁:
location ~* ^/(status|ping)$ {
fastcgi_pass 192.168.10.11:9000;
fastcgi_param SCRIPT_FILENAME /data/apps$fastcgi_script_name;
include fastcgi_params;
}

Nginx 負載均衡功能
四層調度
七層調度 ngx_http_upstream_module
支持健康狀態檢測;

調度:就會有session丟失的問題:
1) session綁定
SH + FWM
-p + FWM
cookie
2) session 集群
3) session server(memcached, redis)

七層調度: 僅能代理http協議!
http {
upstream {
server
server
}

server {

}
}

拓撲:
外網: 172.16.0.0/16
內網: 192.168.10.0/24
192.168.10.11
192.168.10.12

Nginx

1) 定義組: http { .. } 確保有include指令;
upstream websrvs {
server 192.168.10.11:80;
server 192.168.10.12:80;
}
2) 調用組:
server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
proxy_pass http://websrvs;
}
}
默認是輪循的
[root@localhost nginx]# curl www.ilinux.io
<h1>Upstream Server 2</h1>
[root@localhost nginx]# curl www.ilinux.io
<h1>1Upstream Server 1</h1>
[root@localhost nginx]# curl www.ilinux.io
<h1>Upstream Server 2</h1>
[root@localhost nginx]# curl www.ilinux.io
<h1>1Upstream Server 1</h1>
[root@localhost nginx]# curl www.ilinux.io
<h1>Upstream Server 2</h1>
[root@localhost nginx]#

(1)upstream servername
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80;
}

server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
proxy_pass http://websrvs;
}
}
(2) server address [parameters];

1) weight= 默認為1;rr,有權重時表示wrr;
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80;
}
WRR算法:首輪是WRR的;
~]# for i in {1..100}; do curl www.ilinux.io; done
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>

2) max_conns=number 定義server指定的服務器最大并發連接數;

3)max_fails=number
禁用健康狀態檢測:max_fails=0;
4)fail_timeout=time
每隔多久檢測一次?默認有一個時間間隔
檢測一次fail_timeout時間內沒有響應;就認為失敗;
一共失敗max_fails次就標記此服務器不可用;
例如:
默認情況下:在11主機上使用iptables規則禁止;
~]# iptables -A INPUT -d 192.168.10.11 -p tcp –dport 80 -j REJECT
請求:
# for i in {1..10}; do curl www.ilinux.io; done
<h1>Upstream Server 2</h1> <–
<h1>Upstream Server 2</h1> <-
<h1>Upstream Server 2</h1> <–
<h1>Upstream Server 2</h1> <–
<h1>Upstream Server 2</h1> <-
啟動此服務:~]# iptables -F
請求:
# for i in {1..10}; do curl www.ilinux.io; done
<h1>Upstream Server 1</h1> <–
<h1>Upstream Server 2</h1> <-
<h1>Upstream Server 1</h1> <–
<h1>Upstream Server 1</h1> <–
<h1>Upstream Server 2</h1> <-

自定義:檢測失敗超時1s, 允許失敗3次;
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
}

server {
listen 80;
server_name www.ilinux.io;

location / {
root /data/nginx/html;
proxy_pass http://websrvs;
}
}

在運行過程中宕掉:Upstream Server 2;
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>

5)backup 定義備用主機:所以主機都掛了,才會響應;任何一個主機在線都不會啟用此主機;
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
server 127.0.0.1:80 backup;
}

沒有backup時:
<h1>Maintanance Time</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
<h1>Maintanance Time</h1>
<h1>Upstream Server 1</h1>
/usr/share/nginx/html/index.html
讓全部掛掉:
~]# killall httpd
<h1>Maintanance Time</h1>
<h1>Maintanance Time</h1>
任何一個主機上線:
~]# systemctl start httpd
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>

6)灰度發布時,人為將主機宕機;
upstream websrvs {
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3 down;
server 127.0.0.1:80 backup;
}
默認:
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
人為宕機
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
<h1>Upstream Server 1</h1>
上線時,去掉down 參數:

7)slow_start=time 慢啟動;避免大量請求一下子涌進來; 付費;

3)ip_hash 將來自同一個IP的請求 始終定向到同一個upstream server,粒度很粗糙,因為基于來源IP調度;
upstream websrvs {
ip_hash;
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
#server 127.0.0.1:80 backup; ip hash綁定向,掛了看到的是掛了;
}
for i in {1..100}; do curl www.ilinux.io; done
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
宕機server 2
<h1>Upstream Server 2</h1>
<h1>Upstream Server 1</h1>
宕機server 1
<html>
<head><title>502 Bad Gateway</title></head>
<body bgcolor=”white”>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.12.2</center>
</body>
</html>

4)hash key; 基于cookie調度;hash什么變量 就把 變量中的值 當作鍵;商業版才能使用cookie指令完成基于cookie高效調度;
獲取保存cookie的變量名;Alphabetical index of variables
$cookie_name
1)ip_hash; ip哈希:把源IP綁定,把同一個源IP請求綁定在一個Upstream server.
hash $remote_addr;

upstream websrvs {
hash $remote_addr;
server 192.168.10.11:80 weight=2;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
#server 127.0.0.1:80 backup;
}
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>
<h1>Upstream Server 2</h1>

2)把URI綁定,把對同一個URI請求綁定在一個Upstream server. 后端為緩存服務器非常好用
hash $request_uri;
http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request
$request_uri 完整的URI: /en/docs/http/ngx_http_core_module.html#var_request
$request 不完整的URI:/en/docs/http/ngx_http_core_module.html

3)consistent: 一致性哈希:不使用時是取模法。后端為緩存服務器非常好用
如何將同一個(源IP|URI)綁定至upstream server。
首次對URI請求記錄于內存中的hash表中;鍵是URI;值是后端主機的IP;
以后對URI請求查表,在發到指定主機;速度不快;

換一方式,提高速度:分布式系統均會用到;
1)取模法:URI哈希計算后,對權重取模,根據結果調度;
缺點:一臺服務器離線,算法失效,權重沒了;緩存失效;整個系統不可用;

2)一致性哈希算法:Berkeley大學教授;
將2^32取模結果:[0,2^32-1 ]組成一個環;將后端主機的IP地址做hash計算對2^32取模,因此主機位于環上的某處;
請求來時,hash計算對2^32取模,位于環上的某處;順時針遇到的主機則處理;
缺點:所有ip的hash結果對2^32取模,都位于環上的某處的附近;
避免缺點:對hash值加salt后取模,將一個主機分散為50個節點,因此就分布開了;

示例:
upstream websrvs {
hash $remote_addr consistent;
server 192.168.10.11:80 weight=1;
server 192.168.10.12:80 fail_timeout=1 max_fails=3;
#server 127.0.0.1:80 backup;
}

同一個URI始終調度至同一個服務器;
# for i in {1..20}; do echo “Test Page $i On US1” > /var/www/html/test$i.html; done
# for i in {1..20}; do echo “Test Page $i On US2” > /var/www/html/test$i.html; done

# for i in {1..10}; do curl www.ilinux.io/test1.html; done
Test Page 1 On US2
Test Page 1 On US2
Test Page 1 On US2
Test Page 1 On US2
Test Page 1 On US2
Test Page 1 On US2

對每個頁面請求3次,把每個頁面請求一遍;
for i in {1..20}; do for i in {1..3}; do curl www.ilinux.io/test1.html; done; done

5)keepalive connections; 提高反代服務器的并發能力;每個worker維持長連接個數,每個長連接可承載多個用戶請求,用戶請求被綁定至同一個主機;
upstream memcached_backend {
keepalive 32;
}

6)least_conn; LC算法,weight相同時lc; weight不同時,wlc;

Nginx的4層代理 及 負載均衡:
ngx_stream_core_module
1)驗證此模塊是否可以使用:rpm -qa | grep nginx-mod-stream
stream {
server {
listen 22922;
proxy_pass sshsrvs;
}

server {
listen 80;
proxy_pass websrvs;
}
server {
listen 3306;
proxy_pass mydb;
}
upstream sshsrvs {
server 192.168.10.11:22;
server 192.168.10.12:22;
}
upstream websrvs {
server 192.168.10.11:80;
server 192.168.10.12:80;
}
upstream mydb {
server 192.168.10.11:3306;
server 192.168.10.12:3306;
}
}

結構:
stream {
upstream sshsrvs {
server 192.168.10.130:22;
server 192.168.10.131:22;
hash $remote_addr consistent;
}

server {
listen 172.16.100.6:22202;
proxy_pass sshsrvs;
proxy_timeout 60s;
proxy_connect_timeout 10s;
}
}

listen address:port [ssl] [udp]
監聽的端口;
默認為tcp協議;
udp: 監聽udp協議的端口;

反代的是dns服務,就需要添加udp;

將用戶的請求反代至2個后端主機
1)配置在http { … } 之外;
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
worker_connections 1024;
}
2)不是在本地提供任何服務,不需要server_name和Root;
stream {
server {
listen 10080;
proxy_pass 192.168.10.11:22;
}
}
# nginx -t
# killall nginx
# nginx
# ss -tnlp
~]# ssh -p 10080 root@172.16.0.6
ssh 172.16.0.6 10080

代理80端口:
stream {
server {
listen 10080;
proxy_pass 192.168.10.11:22;
}

server {
listen 80;
proxy_pass 192.168.10.12:80;
}
}
# curl 172.16.0.6
<h1>Upstream Server 2</h1>

輪循22:
stream {
server {
listen 10080;
proxy_pass ssh;
}
upstream ssh {
server 192.168.10.11:22;
server 192.168.10.12:22;
}
}
# for i in {1..10}; do ssh -p 22022 root@172.16.0.6 ‘hostname’; done
ns1
ns2
ns1
ns2
ns1
輪循80:
server {
listen 80;
proxy_pass web;
}

upstream web {
server 192.168.10.12:80;
server 192.168.10.11:80;
}
# for i in {1..10}; do curl 172.16.0.6/test1.html; done
Test Page 1 On US2
Test Page 1 On US1
Test Page 1 On US2
Test Page 1 On US1
Test Page 1 On US2
Test Page 1 On US1

代理3306服務:
server {
listen 3306;
proxy_pass mariadb;
}

upstream mariadb {
server 192.168.10.12:3306;
server 192.168.10.11:3306;
}
*:3306 users:((“nginx”,32605,7),(“nginx”,32231,7))
并在后端主機生成可連接的遠程賬號;
# systemctl start mariadb.service
MariaDB [(none)]> GRANT ALL ON mydb.* TO ‘myuser’@’%’ IDENTIFIED BY ‘mypass’;
MariaDB [(none)]> FLUSH PRIVILEGES;
在第二個主機創建一個庫;
MariaDB [(none)]> CREATE DATABASE mydb;

注意:先在代理服務器手動連接主機,通過再測試;
# mysql -umyuser -h192.168.10.11 -pmypass -e ‘SHOW DATABASES’
# mysql -umyuser -h192.168.10.12 -pmypass -e ‘SHOW DATABASES’

輪循:
# for i in {1..10}; do mysql -umyuser -h172.16.0.6 -pmypass -e ‘SHOW DATABASES’; done

默認支持健康狀態檢測:停止mysql
~]# systemctl stop mariadb.service
# for i in {1..10}; do mysql -umyuser -h172.16.0.6 -pmypass -e ‘SHOW DATABASES’; done
~]# systemctl start mariadb.service
# for i in {1..10}; do mysql -umyuser -h172.16.0.6 -pmypass -e ‘SHOW DATABASES’; done

可以將來自同一IP發自同一個主機:hash 命令

nginx編譯安裝:
默認安裝功能適合,不要編譯安裝;不利于運維、分發
必須得編譯時:
開發環境
仿照官方參數即可;

EPEL:獲取編譯參數:
# nginx -V

開發環境 Development Tools Server Platform Development (僅依賴gcc)
開發組件:pcre-devel(rewrite) openssl-devel 編譯需要頭文件或庫文件;

添加用戶:useradd -r nginx

編譯第三方的模塊:https://www.nginx.com/resources/wiki/modules/
Cache purge:修剪緩存的模塊;自帶的功能需要商業版;
Mogilefs:nginx作為modfilefs的客戶端

注意不需要打補丁,–with指定nginx自動收錄;
–add-module=PATH enable external module 編譯進核心
–add-dynamic-module=PATH enable dynamic external module 支持動態裝載或卸載;
–with 默認沒有啟用;指定時啟用
–without 默認啟用; 指定時禁用

第三方模塊:在編譯參數后添加 –add-module= , 指明module解壓出的路徑即可 ;
unzip ngx_cache_purge-master.zip
–add-module=/root/ngx_cache_purge-master

yum -y install pcre pcre-devel
yum -y install openssl openssl-devel
yum -y install gcc-c++ autoconf automake
yum install -y zlib-devel
yum -y install libxml2 libxml2-dev
yum -y install libxslt-devel
yum -y install gd-devel
yum -y install perl-devel perl-ExtUtils-Embed
yum -y install GeoIP GeoIP-devel GeoIP-data
去掉此選項:
–with-google_perftools_module

make && make install
默認網頁:/etc/nginx/html

提供unit file文件:
vim /usr/lib/systemd/system/nginx.service
基于官方編譯,用官方的Unit; 基于EPEL用EPEL
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target

systemctl daemon-reload

啟用nginx(可能需要創建目錄,nginx用戶,nginx組)

nginx 官方倉庫
只能必要時才編譯安裝;
http://nginx.org/packages
http://nginx.org/packages/centos/7/

SRPMS/ 源碼格式的rpm:安裝–制作;編譯時,應該這樣弄;
# wget http://nginx.org/packages/centos/7/SRPMS/nginx-1.12.0-1.el7.ngx.src.rpm
# rpm -vih nginx-1.12.0-1.el7.ngx.src.rpm
# tree rpmbuild/
rpmbuild/
├── SOURCES
│?? ├── COPYRIGHT
│?? ├── logrotate
│?? ├── nginx-1.12.0.tar.gz
│?? ├── nginx.check-reload.sh
│?? ├── nginx.conf
│?? ├── nginx-debug.service
│?? ├── nginx-debug.sysconf
│?? ├── nginx.init.in
│?? ├── nginx.service
│?? ├── nginx.suse.logrotate
│?? ├── nginx.sysconf
│?? ├── nginx.upgrade.sh
│?? └── nginx.vh.default.conf
└── SPECS
└── nginx.spec <–如何制作 rpm包

~]# vim rpmbuild/SPECS/nginx.spec
%define BASE_CONFIGURE_ARGS $(echo “–prefix=
在其中添加第三方模塊即可;

制作rpm包:
~]# rpmbuild -bb rpmbuild/SPECS/nginx.spec

 

 

本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/90448

(0)
逆神陽逆神陽
上一篇 2017-12-20
下一篇 2017-12-20

相關推薦

  • Find小總結及應用

    Find總結及應用 搜索命令:     locate命令:         在文件系統上查找符合條件的文件         非實時查找( 數據庫查找)…

    Linux干貨 2016-08-16
  • 壓縮與歸檔

    一、壓縮     壓縮:根據一定算法將數據以更加節省空間的形式存放。下面來看一下Linux常見的壓縮工具:     1、gzip/gunzip         后綴名:.gz   …

    Linux干貨 2015-05-04
  • MariaDB日志

    MariaDB日志 查詢日志:query log; 慢查詢日志:slow query log 查詢時長超出指定界限。 錯誤日志:error log 二進制日志:binary log;此中存儲要發生改變或潛在發生改變的語句。 中繼日志:reley log 事務日志:transaction log 1、查詢日志 記錄查詢語句,日志存儲位置:一般不開啟。 文件:f…

    Linux干貨 2016-11-20
  • Linux之啟動和內核管理

     Linux之啟動和內核管理     本文主要包括以下內容一  CentOS 5和6的啟動流程二  服務管理三  Grub管理四  自制Linux五  啟動排錯六  編譯安裝內核   Linux組成Linux: kernel+rootfskernel: 進程管…

    Linux干貨 2016-09-15
  • Linux作業管理和并發執行

    概述 本章將為大家介紹一些進程管理的補充部分作業管理和任務的并發執行,同時也將介紹一下Linux系統上計劃任務的相關內容,具體分為:1、Linux作業管理2、任務的并發執行 第一章 Linxu作業管理 1、前臺作業和后臺作業    前臺作業:通過中斷啟動,且啟動后一直占據終端    后臺作業:可通過終端啟動,但啟動后即…

    Linux干貨 2016-09-28
  • shell編程——讓你又愛又恨的東西

    變量類型:      不同的數據類型在系統中所占資源不同,并且表示的范圍也不同      數值型:          短整型short:      &…

    Linux干貨 2016-08-12

評論列表(1條)

  • 馬哥教育
    馬哥教育 2018-01-07 17:50

    總結的比較全面~~能注意下排版技巧會更好~

欧美性久久久久