Nginx 優化及原理

JaneWorld發表於2019-06-17

~nginx原理了解~

server_name的優先順序
Nginx 優化及原理

總入口:http://tengine.taobao.org/nginx_docs/cn/do...
白名單配置:(http://tengine.taobao.org/nginx_docs/cn/do...)
連線限制跟請求限制,會對所有的ip進行限制,如果希望自己的測試的ip,或者搜尋引擎蜘蛛受到限制。
ngx_http_geo_module 模組建立變數,並根據客戶端IP地址對變數賦值。
geo就判斷當前這些IP地址屬不屬於白名單列表裡面。

白名單會用到對映:http://tengine.taobao.org/nginx_docs/cn/do...
map也是把geo給的變數,去匹配,匹配到了返回1,並賦值給$limit
返回為0,是屬於白名單,不做限制。其餘的惡意攻擊IP,限制頻率和訪問。

ab -c10 -n200 http://127.0.0.1 (壓測白名單的IP,進行測試)配置中,127.0.0.1在白名單內,壓測全部請求成功。
-n requests     在測試會話中所執行的請求總個數,預設一個
-c concurrency  一次產生的請求個數,預設一個

//判斷客戶端地址是否在白名單列表,如果在返回0在白名單列表,否則返回1
127.0.0.1-127.0.0.255
geo $white {
default 1;
//include '/conf/ip.conf';
127.0.0.1/32 0;
192.168.1.0/24 0;
}

//如果滿足條件返回二進位制ip地址
map $white $limit {
1 $binary_remote_addr;
0 "";
}

limit_req_zone $limit zone=two:10m rate=1r/s;
limit_req_status 503;
limit_req_log_level info;

rewrite的主要功能是實現URL地址的重定向。Nginx的rewrite功能需要PCRE軟體(perl 相容的正規表示式庫)的支援,即通過perl相容正規表示式語句進行規則匹配的。預設引數編譯nginx就會支援rewrite的模組,但是也必須要PCRE的支援。
使用場景:
1、可以調整使用者瀏覽的URL,看起來更規範,合乎開發及產品人員的需求。
2、為了讓搜尋引擎搜錄網站內容及使用者體驗更好,企業會將動態URL地址偽裝成靜態地址提供服務。
3、網址換新域名後,讓舊的訪問跳轉到新的域名上。例如,訪問京東的360buy.com會跳轉到jd.com。
4、根據特殊變數、目錄、客戶端的資訊進行URL調整等。

匹配路徑不存在,代理到另一個404的頁面裡去。

rewrite模組語法:
location /if {
if ( $http_user_agent ~ (mobile|nokia|iphone|ipad|android|samsung|htc|blackberry) ) {
rewrite ^(.
) http://peter.23673.com$1 permanent;
}
//匹配檔案不存在
if (!-e $request_filename) {
proxy_pass http://127.0.0.1:9501;
}
}

隱藏index.php:
(真實訪問地址)xxxx/api/public/index.php-->(匹配後訪問的地址)xxxx/api/aa/bb
location /api {
//匹配檔案不存在
if (!-e $request_filename) {
}
rewrite ^/api/(.)$ /api/public/index.html/$1 break;//如果只是匹配一次就不要用last,否則會重複匹配10次報500
//框架根據請求地址,路由
rewrite ^/api/(.
)$ /abc/public/index.html/$1 last; 隱藏了真實的路徑
}

偽靜態(靜態形式訪問動態網頁):
location /ecshop {
root /www;
//商品頁面
// /ecshop/goods-3.html ---->/ecshop/goods.php?id=3
rewrite goods-(\d+).html$ /ecshop/goods.php?id=$1 break;
//欄目頁面
// /ecshop/category-2-b1.html -> /ecshop/category.php?id=3&brand=1
}

nginx提供了expires、etag、if-modified-since指令來進行瀏覽器快取控制
瀏覽器圖片快取設定(web快取機制)

location ~ (.)(.gif|jpeg|jpg|mp3)$ {
alias /www/img/$1$2;

expires 10s;
access_log off;
}

Nginx 優化及原理
expires 30s;#30秒
expires 30m;#30分鐘
expires 2h;#2個小時
expires 30d;#30天

Gzip指令
nginx中gzip的主要作用就是用來減輕伺服器的頻寬問題,經過gzip壓縮後的頁面大小可以變為原來的30%甚至更小,這樣使用者瀏覽頁面時的速度會快很多。gzip的壓縮頁面需要瀏覽器和伺服器雙方都支援,實際上就是伺服器端壓縮,傳到瀏覽器後瀏覽器解壓縮並解析。目前的大多數瀏覽器都支援解析gzip壓縮過的頁面。
引數說明:
gzip
語法:gzip on | off;
預設值:gzip off;
作用域:http, server, location, if in location

說明:
啟用或禁用gzip壓縮模組,on表示啟用,off表示禁用
gzip_min_length
語法:gzip_min_length length;
預設值:gzip_min_length 20;
作用域:http, server, location

gzip on;
gzip_comp_level 6;
gzip_types application/javascript text/css;

靜態檔案,讓客戶端快取或者放置在本機的nginx某個目錄下面;
動態檔案,就代理到後端的某一個伺服器下面去;動態請求看是否快取它。fastcgi也是一種代理快取。

快取細節:
熱點新聞,1W次訪問,開始幾個使用者,從客戶端通過nginx代理,到源伺服器訪問後,快取到nginx設定的快取目錄裡。其它客戶端都是從快取目錄裡獲取。

inactive 快取時間10m;max_size:快取大小100m

map $request_uri $no_cache {
default 0;
~*/admin 1; #uri當中包含了admin
}

某些時候我們如果不想等待快取的過期,想要主動清除快取,可以採用第三方的快取清除模組清除快取nginx_ngx_cache_purge。

location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge my_cache $host$1$is_args$args;
//default_type text/html;
//return 200 $host$1$is_args$args;\ #error_page 404 /404.html;
}

location ^~ /cache {
proxy_http_version 1.1;
proxy_pass http://127.0.0.1:9502;
//設定當前請求是否快取
//proxy_cache_bypass $no_cache;#0不快取 1快取
//default_type text/html;
//return 200 $host$uri$is_args$args;
//請求頭設定
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header connection keep-alive;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

//時間設定
proxy_connect_timeout 30;
proxy_send_timeout 30;
proxy_read_timeout 60;

proxy_cache my_cache; #開啟快取了
proxy_cache_valid 200 302 10s; #不同的響應頭設定不同快取時間
proxy_cache_valid 404 1s;

//設定快取key(注意:#設定快取key,要在proxy_cache 指令下方。)
proxy_cache_key $host$uri$is_args$args;
//proxy_ignore_headers Cache-Control;

proxy_cache_min_uses 3; #至少3次之後才會快取(不經常訪問的,生成快取會佔用空間)
proxy_cache_lock on; #如果說是併發情況下,只會有一個請求落到後端伺服器
}

半自動平滑升級:
所謂半自動,其實就是在最後遷移的時候使用原始碼自帶的升級命令:make upgrade 來自動完成。
先軟連線-->在二進位制安裝(不停止客服端訪問,不重啟nginx伺服器來安裝我們的模組)
1、需要下載對應的需要載入的第三方的擴充套件,或者是需要附加設定的引數  (注意:之前的配置引數要保留)
--add_module=PATH   新增第三方擴充套件
2、執行make不要執行make install
3、重新命名 nginx 舊版本二進位制檔案,即 sbin 目錄下的 nginx(期間 nginx 並不會停止服務)
4、然後拷貝一份新編譯的二進位制檔案到安裝目錄
5、在原始碼目錄執行 make upgrade 開始升級:

nginx負載均衡:
upstream這個指令會自動選擇訪問的地址。
在nginx配置檔案裡,配置多個用於負載的伺服器地址,設定好後預設採取輪訓,挨個訪問。
upstream backend {
//ip_hash; #雜湊
//least_conn; #最少連線數
server nginx.23673.com:9502 max_fails=3 fail_timeout=5s;
//server nginx.23673.com:9503 backup max_fails=3 fail_timeout=5s;
//server nginx.23673.com:9503 down max_fails=3 fail_timeout=5s;
server nginx.23673.com:9502 max_fails=3 fail_timeout=5s;
server nginx.23673.com:9502 max_fails=3 fail_timeout=5s;
}

location /up {
//proxy_next_upstream timeout; #超時切換到下一臺伺服器,注意備用伺服器切換問題
//超時時間
proxy_connect_timeout 20;
proxy_send_timeout 30;
proxy_read_timeout 30;

proxy_next_upstream_tries 1; #代理請求的重試次數
proxy_next_upstream_timeout 1; #重試的超時時間

proxy_pass http://backend;#代理到上游伺服器裡面來
}
可以定義下面的引數:
weight=number 設定伺服器的權重,預設是1,權重越大被訪問機會越大,要根據機器的配置情況來配置

max_fails=number 設定Nginx與伺服器通訊的嘗試失敗的次數。在fail_timeout引數定義的時間段內,如果失敗的次數達到此值,Nginx就認為伺服器不可用。在下一個fail_timeout時間段,伺服器不會再被嘗試。 失敗的嘗試次數預設是1。

可以通過指令proxy_next_upstream 和memcached_next_upstream來配置什麼是失敗的嘗試。 預設配置時,http_404狀態不被認為是失敗的嘗試。

fail_timeout=time
統計失敗嘗試次數的時間段。在這段時間中,伺服器失敗次數達到指定的嘗試次數,伺服器就被認為不可用。預設情況下,該超時時間是10秒。

當訪問Nginx時,會將請求反向代理到backend配置的upstream server。

負載均衡的方法
nginx支援以下負載均衡機制:
1、 輪詢
預設輪訓方式
每一個來自網路中的請求,輪流分配給內部的伺服器,從1到N然後重新開始。此種負載均衡演算法適合伺服器組內部的伺服器都具有相同的配置並且平均服務請求相對均衡的情況。

2、加權輪詢
通過weight引數控制權重。
根據伺服器的不同處理能力,給每個伺服器分配不同的權值,使其能夠接受相應權值數的服務請求。例如:伺服器A的權值被設計成1,B的權值是3,C的權值是6,則伺服器A、B、C將分別接受到10%、30%、60%的服務請求。此種均衡演算法能確保高效能的伺服器得到更多的使用率,避免低效能的伺服器負載過重。

3、IP Hash(處理會話機制)
在upstream當中配置ip_hash;
這種方式通過生成請求源IP的雜湊值,並通過這個雜湊值來找到正確的真實伺服器。這意味著對於同一主機來說他對應的伺服器總是相同。使用這種方式,你不需要儲存任何源IP。
將客戶端會話"沾住"或者"持久化",以便總是能選擇特定伺服器,那麼可以使用ip-hash負載均衡機制。

使用ip-hash時,客戶端IP地址作為hash key使用,用來決策選擇伺服器叢集中的哪個伺服器來處理這個客戶端的請求。這個方法保證從同一個客戶端發起的請求總是定向到同一臺伺服器,除非伺服器不可用。

4、最少連線數
在upstream當中配置least_conn實現最少連線數。
客戶端的每一次請求服務在伺服器停留的時間可能會有較大的差異,隨著工作時間加長,如果採用簡單的輪循或隨機均衡演算法,每一臺伺服器上的連線程式可能會產生極大的不同,並沒有達到真正的負載均衡。最少連線數均衡演算法對內部中需負載的每一臺伺服器都有一個資料記錄,記錄當前該伺服器正在處理的連線數量,當有新的服務連線請求時,將把當前請求分配給連線數最少的伺服器,使均衡更加符合實際情況,負載更加均衡。

注意網路請求環境不能變:手機網路和連線的WiFi是2個網路,不同的IP地址。會造成IP地址的切換。(這裡用Session入庫來解決!!)

失敗重試:
通過配置上游伺服器max_fails和 fail_timeout,指定每個上游伺服器,當fail_timeout時間內失敗了max_fails次請求,則認為該上游伺服器不可用/不存活,然後這段時間將不會訪問這臺上遊伺服器,fail_timeout時間後會再次進行重試。

max_fails=2  fail_timeout=30s  這2個一起搭配使用,表示:當失敗2次的時候,就停止使30秒。

好處:既可以避免重複請求,不能訪問或者暫時不能訪問的服務,增大伺服器的壓力,也可以靈活的做到當伺服器可用時再次訪問。

location /up {

proxy_connect_timeout 20;
proxy_send_timeout 30;
proxy_read_timeout 30;

proxy_next_upstream_tries 1; #代理請求的重試次數
proxy_next_upstream_timeout 1; #重試的超時時間

proxy_pass http://backend;#代理到上游伺服器裡面來
}

故障轉移:
backup(故障轉移)
標記為備用伺服器。當主伺服器不可用以後,請求會被傳給這些伺服器。

down
標記伺服器永久不可用,可以跟ip_hash指令一起使用。

動態負載均衡:增加減少伺服器
https://github.com/weibocom/nginx-upsync-m...
nginx-upsync-module提供了動態的負載均衡,動態更新上游的伺服器不需要reload nginx,它的功能是拉取 consul 的後端 server 的列表,並更新 Nginx 的路由資訊。此模組不依賴於任何第三方模組。consul 作為 Nginx 的 db,利用 consul 的 KV 服務,每個 Nginx work 程式獨立的去拉取各個 upstream 的配置,並更新各自的路由。

2、安裝consul(分散式和微服務架構用consul)

 對於consul的介紹,先通過docker的方式pull一個consul。
基於映象執行容器:docker run -itd -p 8700:8500 --name upstream consul
docker exec -it upstream sh
wget  https://github.com/weibocom/nginx-upsync-m...
--add-module=/root/nginx-upsync-module-2.1.0

示例:
upstream swoole_test {
        upsync  127.0.0.1:8700/v1/kv/upstreams/swoole_test upsync_timeout=6m upsync_interval=500ms  upsync_type=consul  strong_dependency=off;
        upsync_dump_path /usr/local/nginx/conf/servers_test.conf;
        include /usr/local/nginx/conf/servers_test.conf;
    }

location = /upstream_show {
upstream_show;
}

upsync模組會去consul拉取最新的upstream資訊並存到本地的檔案中;
upsync_timeout 配置從consul拉取上游伺服器的超時時間;
upsync_interval 配置從consul拉取上游伺服器的間隔時間;
upsync_type 指定使用配置伺服器的型別,當前是consul;
strong_dependency 啟動時是否強制依賴配置伺服器,如果配置為on,則拉取失敗,nginx同樣會啟用失敗;
upsync_dump_path 指定從consul拉取的上游伺服器後持久化到的位置,這樣即使Consul伺服器出問題了,本地同樣會有備份。
Nginx 優化及原理

    curl -X PUT -d '{"weight":1, "max_fails":2, "fail_timeout":10}' http://$consul_ip:$port/v1/kv/$dir1/$upstream_name/$backend_ip:$backend_port

   curl -X PUT -d '{"weight":1,"max_fails":2,"fail_timeout":10}' http://127.0.0.1:8700/v1/kv/upstreams/swoo...

檢視所有已經儲存的k/v:curl  http://127.0.0.1:8700/v1/kv/?recurse

刪除:curl  -X  DELETE http://127.0.0.1:8700/v1/kv/upstreams/swoo...

etcd叢集(Java用居多)

https://www.runoob.com/lua/lua-tutorial.ht...

 1、安裝lua

wget  http://luajit.org/download/LuaJIT-2.0.5.ta... 
tar -zxvf  LuaJIT-2.0.5.tar.gz
cd  LuaJIT-2.0.5
make install PREFIX=/usr/local/LuaJIT

2、/etc/profile 檔案中加入環境變數

export LUAJIT_LIB=/usr/local/LuaJIT/lib      
export LUAJIT_INC=/usr/local/LuaJIT  #路徑是上面luajit實際安裝路徑,路徑錯誤安裝nginx的lua模組時會報錯很找不到luajit庫

3、下載ngx_devel_kit模組

wget  https://github.com/simpl/ngx_devel_kit/arc...
NDK(nginx development kit)模組是一個擴充nginx伺服器核心功能的模組,第三方模組開發可以基於它來快速實現。  NDK提供函式和巨集處理一些基本任務,減輕第三方模組開發的程式碼量。

4、下載lua-nginx-module模組
wget https://github.com/openresty/lua-nginx-mod...
lua-nginx-module模組使nginx中能直接執行lua指令碼

5、~再次編譯nginx~

增加這兩個模組
--add-module=/root/download/lua-nginx-module-0.10.9rc7
--add-module=/root/download/ngx_devel_kit-0.3.0

相應的api在這裡可以找到:
https://github.com/openresty/lua-nginx-mod...

編寫一個lua指令碼實現流量的分發,按照自己的規則來分發商品的id

需求:
做商品詳情頁的快取

問題:
為了解決相同的內容重複的快取,並且為了降低redis的壓力

需求:基於商品的id進行流量分發
1、獲取請求引數商品id
2、獲取id的雜湊值,取模做負載均衡,獲取到一個地址
3、利用http請求,請求應用層伺服器
4、響應趕回給客戶端
local uri_args=ngx.req.get_uri_args()
local id=uri_args["id"]
local server={"47.98.147.49:9502","47.98.147.49:9503"}
local hash=ngx.crc32_long(id)
local index=(hash % table.getn(server))+1
url="http://"..server[index]
local http=require("resty.http")
local httpClient=http.new()
local resp,err = httpClient:request_uri(url,{method="GET"})
if not resp then
ngx.say(err)
return
end

ngx.say(resp.body)

httpClient:close()

index = server[0] (2nil)或者 server[1](47.98.147.49:9502)或者(47.98.147.49:9503)這個陣列不是從0開始的,所以加1

相應的lua模組,載入一些模組
https://www.nginx.com/resources/wiki/modul...
Nginx API for Lua:
https://github.com/pintsized/lua-resty-htt...

/------------------------------------------------------------------------------------------------------------------------------------------------------/

~1、什麼是nginx?~

Nginx是一款自由的、開源的、高效能的HTTP伺服器和反向代理伺服器;同時也是一個IMAP、POP3、SMTP代理伺服器;Nginx可以作為一個HTTP伺服器進行網站的釋出處理,另外nginx可以作為反向代理進行負載均衡的實現。

正向代理:服務端明確,客戶端來源不明確(客戶翻牆通過正向代理伺服器請求Google)
反向代理:客服端明確,具體請求哪一個服務端不明確

~2、為什麼選擇nginx?~

(1)更快
這表現在兩個方面:一方面,在正常情況下,單次請求會得到更快的響應;另一方面,
在高峰期(如有數以萬計的併發請求),Nginx可以比其他Web伺服器更快地響應請求。
實際上,

(2)高擴充套件性
Nginx的設計極具擴充套件性,它完全是由多個不同功能、不同層次、不同型別且耦合度極低的模組組成。因此,當對某一個模組修復Bug或進行升級時,可以專注於模組自身,無須在意其他。而且在HTTP模組中,還設計了HTTP過濾器模組:一個正常的HTTP模組在處理完請求後,會有一串HTTP過濾器模組對請求的結果進行再處理。這樣,當我們開發一個新的HTTP模組時,不但可以使用諸如HTTP核心模組、events模組、log模組等不同層次或者不同型別的模組,還可以原封不動地複用大量已有的HTTP過濾器模組。這種低耦合度的優秀設計,造就了Nginx龐大的第三方模組,當然,公開的第三方模組也如官方釋出的模組一樣容易使用。

Nginx的模組都是嵌入到二進位制檔案中執行的,無論官方釋出的模組還是第三方模組都是如此。這使得第三方模組一樣具備極其優秀的效能,充分利用Nginx的高併發特性,因此,許多高流量的網站都傾向於開發符合自己業務特性的定製模組。

(3)高可靠性
高可靠性是我們選擇Nginx的最基本條件,因為Nginx的可靠性是大家有目共睹的,很多家高流量網站都在核心伺服器上大規模使用Nginx。Nginx的高可靠性來自於其核心框架程式碼的優秀設計、模組設計的簡單性;另外,官方提供的常用模組都非常穩定,每個worker程式相對獨立,master程式在1個worker程式出錯時可以快速“拉起”新的worker子程式提供服務。

(4)低記憶體消耗
一般情況下,10000個非活躍的HTTP Keep-Alive連線在Nginx中僅消耗2.5MB的記憶體,這是Nginx支援高併發連線的基礎。

(5)單機支援10萬以上的併發連線
這是一個非常重要的特性!隨著網際網路的迅猛發展和網際網路使用者數量的成倍增長,各大公司、網站都需要應付海量併發請求,一個能夠在峰值期頂住10萬以上併發請求的Server,無疑會得到大家的青睞。理論上,Nginx支援的併發連線上限取決於記憶體,當然,能夠及時地處理更多的併發請求,是與業務特點緊密相關的

(6)熱部署
master管理程式與worker工作程式的分離設計,使得Nginx能夠提供熱部署功能,即可以在7×24小時不間斷服務的前提下,升級Nginx的可執行檔案。當然,它也支援不停止服務就更新配置項、更換日誌檔案等功能。

(7)最自由的BSD許可協議
這是Nginx可以快速發展的強大動力。BSD許可協議不只是允許使用者免費使用Nginx,它還允許使用者在自己的專案中直接使用或修改Nginx原始碼,然後釋出。這吸引了無數開發者繼續為Nginx貢獻自己的智慧。

3、~Nginx高效的原因及原理解析~

nginx的基本架構如下:

3.1、web伺服器的請求處理機制

web伺服器和客戶端是一對多的關係,Web伺服器必須有能力同時為多個客戶端提供服務。一般來說完成並行處理請求工作有三種方式:
1、多程式方式
  多程式方式指,伺服器每當收到一個客戶端請求時,就有伺服器主程式生成一個子程式出來和客戶端建立連線進行互動,直到連線斷開該子程式就結束了。
多程式方式的優點是設計簡單,各個子程式相對獨立,處理客戶端請求時彼此不受干擾;

缺點是作業系統生成一個子程式需要進行記憶體複製等操作,在資源和時間上會產生一定的開銷;當有大量請求時,會導致系統效能下降;
例如:即時聊天程式,一臺伺服器可能要維持數十萬的連線,那麼就要啟動數十萬的程式來維持。這顯然不可能

2、多執行緒方式
多執行緒方式指每當伺服器接收到一個請求後,會由伺服器主程式派生出一個執行緒出來和客戶端進行互動。由於作業系統產生出一個執行緒的開銷遠遠小於一個程式的開銷。故多執行緒方式在很大程度上減輕了Web伺服器對系統資源的要求。

缺點:穩定性!假設某個程式突然關閉會造成整個程式中的所有執行緒都崩潰。

3、非同步方式
使用非阻塞方式處理請求,是三種方式中開銷最小的。但非同步方式雖然效率高,但要求也高,因為多工之間的排程如果出現問題,就可能出現整體故障,因此使用非同步工作的,一般是一些功能相對簡單,但卻符合伺服器任務排程、且程式碼中沒有影響排程的錯誤程式碼存在的程式。

優點:效能最好!一個程式或執行緒處理多個請求,不需要額外開銷,效能最好,資源佔用最低。

缺點:穩定性!某個程式或執行緒出錯,可能導致大量請求無法處理,甚至導致整個服務當機。

同步和非同步:

同步與非同步的重點在訊息通知的方式上,也就是呼叫結果通知的方式。
同步:當一個同步呼叫發出去後,呼叫者要一直等待呼叫結果的通知,直到得到呼叫結果。

非同步:當一個非同步呼叫發出去後,呼叫者不能立即得到呼叫結果的返回。
非同步呼叫,要想獲得結果,一般有兩種方式:
1、主動輪詢非同步呼叫的結果;
2、被呼叫方通過callback來通知呼叫方呼叫結果。

~ IO複用/EventLoop~

1、IO複用是什麼?

IO多路複用是指核心一旦發現程式指定的一個或者多個IO條件準備讀取,它就通知該程式,目前支援I/O多路複用的系統呼叫有 select,poll,epoll,I/O多路複用就是通過一種機制,一個程式可以監視多個描述符(socket),一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。

2、Select跟poll

Select介紹:
監視並等待多個檔案描述符的屬性變化(可讀、可寫或錯誤異常)。select函式監視的檔案描述符分 3 類,分別是writefds、readfds、和 exceptfds。呼叫後 select會阻塞,直到有描述符就緒(有資料可讀、可寫、或者有錯誤異常),或者超時( timeout 指定等待時間),函式才返回。當 select()函式返回後,可以通過遍歷 fdset,來找到就緒的描述符,並且描述符最大不能超過1024

poll 介紹:
poll的機制與select類似,與select在本質上沒有多大差別,管理多個描述符也是進行輪詢,根據描述符的狀態進行處理,但是poll沒有最大檔案描述符數量的限制。poll和select同樣存在一個缺點就是,包含大量檔案描述符的陣列被整體複製於使用者態和核心的地址空間之間,而不論這些檔案描述符是否就緒,它的開銷隨著檔案描述符數量的增加而線性增大。

 問題:
select/poll問題很明顯,它們需要迴圈檢測連線是否有事件。如果伺服器有上百萬個連線,在某一時間只有一個連線向伺服器傳送了資料,select/poll需要做迴圈100萬次,其中只有1次是命中的,剩下的99萬9999次都是無效的,白白浪費了CPU資源。

 epoll:
epoll是在2.6核心中提出的,是之前的select和poll的增強版本。相對於select和poll來說,epoll更加靈活,沒有描述符限制,無需輪詢。epoll使用一個檔案描述符管理多個描述符,將使用者關係的檔案描述符的事件存放到核心的一個事件表中。

簡單點來說就是當連線有I/O流事件產生的時候,epoll就會去告訴程式哪個連線有I/O流事件產生,然後程式就去處理這個程式。

 這裡可以多加一個選擇nginx的原因,因為Nginx是基於epoll的非同步非阻塞的伺服器程式。自然,Nginx能夠輕鬆處理百萬級的併發連線,也就無可厚非了。

例項:

       那麼我們也可以基於epoll,實現 IO複用非同步非阻塞(eventloop或者叫Reactor),Event 是核心,Loop 是機制,Loop 可以用 select/poll/epoll/中的任意方式,實現。

IO複用非同步非阻塞程式使用經典的Reactor模型,Reactor顧名思義就是反應堆的意思,它本身不處理任何資料收發。只是可以監視一個socket(也可以是管道、eventfd、訊號)控制程式碼的事件變化。

注:什麼是控制程式碼?控制程式碼英文為handler,可以形象的比喻為鍋柄、勺柄。也就是資源的唯一識別符號、資源的ID。通過這個ID可以操作資源。

Reactor只是一個事件發生器,實際對socket控制程式碼的操作,如connect/accept、send/recv、close是在callback中完成的。

負載均衡裝置通過心跳檢測等手段監控到某臺伺服器不可用時,就將其從叢集列表中剔除,並將請求分發到叢集中其他可用的伺服器上,使整個叢集保持可用,從而實現高可用。

nginx相關命令:
檢視nginx服務:netstat -apn|grep 80

安裝pcntl模組
http://cn2.php.net/distributions/php-7.1.1...
tar xf php-7.1.14.tar.xz\
cd php-7.1.14\
cd ext/pcntl\
phpize\
./configure --with-php-config=/usr/bin/php-config\
make\
make install\
echo "extension=pcntl.so" >> /etc/php.ini

ngx.say(resp.body)
httpClient:close()

nginx:
https://www.nginx.com/resources/wiki/
https://www.nginx.com/resources/wiki/modul...
https://www.nginx.com/resources/wiki/modul...

sockets:
https://www.php.net/sockets

workerman:
http://doc.workerman.net/

三、快取優化
k8s或swarm可以更好的管理叢集和服務

docker-compose.yaml
啟動編排工具:docker-compose up -d

常遇錯誤:
502 Bad GateWay 報錯
https://server.zzidc.com/fwqcjwt/729.html

php.ini中memory_limit設低了會出錯,修改了php.ini的memory_limit為64M,重啟nginx,發現好了,原來是PHP的記憶體不足了。如果頻繁出現502 bad gateway ,可以點選這裡擴容或者更換伺服器。
網站打不開,出現錯誤程式碼“502 bad gateway”,一般都是php-cgi程式數不夠用、php執行時間長、或者是php-cgi程式死掉。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章