1. 程式人生 > 實用技巧 >【Codeforces Round #669 (Div. 2) D】Discrete Centrifugal Jumps

【Codeforces Round #669 (Div. 2) D】Discrete Centrifugal Jumps

Nginx

Nginx 概述

Nginx ("engine x") 是一個高效能的 HTTP 和反向代理伺服器,特點是佔有記憶體少,併發能力強,事實上nginx的併發能力確實在同類型的網頁伺服器中表現較好,中國大陸使用nginx網站使用者有:百度、京東、新浪、網易、騰訊、淘寶等。

Nginx 可以作為靜態頁面的 web 伺服器,同時還支援 CGI 協議的動態語言,比如 perl、php 等。但是不支援 java。Java 程式只能通過與 tomcat 配合完成。Nginx 專為效能優化而開發, 效能是其最重要的考量,實現上非常注重效率 ,能經受高負載的考驗,有報告表明能支援高 達 50,000 個併發連線數。

正向代理與反向代理

正向代理:如果把區域網外的 Internet 想象成一個巨大的資源庫,則區域網中的客戶端要訪問 Internet,則需要通過代理伺服器來訪問,這種代理服務就稱為正向代理。

反向代理:其實客戶端對代理是無感知的,因為客戶端不需要任何配置就可以訪問,我們只需要將請求傳送到反向代理伺服器,由反向代理伺服器去選擇目標伺服器獲取資料後,再返回給客戶端,此時反向代理伺服器和目標伺服器對外就是一個伺服器,暴露的是代理伺服器 地址,隱藏了真實伺服器 IP 地址。

負載均衡

​ 客戶端傳送多個請求到伺服器,伺服器處理請求,有一些可能要與資料庫進行互動,伺服器處理完畢後,再將結果返回給客戶端。 這種架構模式對於早期的系統相對單一,併發請求相對較少的情況下是比較適合的,成本也低。但是隨著資訊數量的不斷增長,訪問量和資料量的飛速增長,以及系統業務的複雜度增加,這種架構會造成伺服器相應客戶端的請求日益緩慢,併發量特別大的時候,還容易造成伺服器直接崩潰。很明顯這是由於伺服器效能的瓶頸造成的問題,那麼如何解決這種情況呢?
​ 我們首先想到的可能是升級伺服器的配置,比如提高 CPU 執行頻率,加大記憶體等提高機器的物理效能來解決此問題,但是我們知道摩爾定律的日益失效,硬體的效能提升已經不能 滿足日益提升的需求了。最明顯的一個例子,天貓雙十一當天,某個熱銷商品的瞬時訪問量是極其龐大的,那麼類似上面的系統架構,將機器都增加到現有的頂級物理配置,都是不能 夠滿足需求的。那麼怎麼辦呢?上面的分析我們去掉了增加伺服器物理配置來解決問題的辦法,也就是說縱向解決問題的辦法行不通了,那麼橫向增加伺服器的數量呢?這時候叢集的概念產生了,單個伺服器解決不了,我們增加伺服器的數量,然後將請求分發到各個伺服器上,將原先請求集中到單個伺服器上的情況改為將請求分發到多個伺服器上,將負載分發到不同的伺服器,也就是我們所說的負載均衡。

動靜分離

為了加快網站的解析速度,可以把動態頁面和靜態頁面由不同的伺服器來解析,加快解析速度。降低原來單個伺服器的壓力。

常用命令

  1. 檢視版本號。
nginx -v
  1. 啟動nginx
nginx
  1. 關閉nginx
nginx -s  stop  
  1. 重新載入配置檔案
nginx -s  reload 

配置檔案

/etc/nginx/nginx.conf

  1. 全域性塊

從配置檔案開始到 events 塊之間的內容,主要會設定一些影響nginx 伺服器整體執行的配置指令,主要包括配 置執行 Nginx 伺服器的使用者(組)、允許生成的 worker process 數,程序 PID 存放路徑、日誌存放路徑和型別以 及配置檔案的引入等。

user  nginx;
worker_processes  1; # 設定worker的數量(建議與CPU的核心數一致)
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
  1. events塊

events 塊涉及的指令主要影響 Nginx 伺服器與使用者的網路連線,常用的設定包括是否開啟對多 work process 下的網路連線進行序列化,是否允許同時接收多個網路連線,選取哪種事件驅動模型來處理連線請求,每個 word process 可以同時支援的最大連線數等。

events {
    worker_connections  1024; # 每個worker最大的連線數,每個併發會佔用2個(請求靜態資源)或者4個(反向代理)連線數。
}
  1. http塊

這算是 Nginx 伺服器配置中最頻繁的部分,代理、快取和日誌定義等絕大多數功能和第三方模組的配置都在這裡。

http {
    include       /etc/nginx/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  /var/log/nginx/access.log  main;
    sendfile        on;
    keepalive_timeout  65;
    include /etc/nginx/conf.d/*.conf;
}

http 塊也可以包括 http全域性塊、server 塊。

  • http全域性塊

http全域性塊配置的指令包括檔案引入、MIME-TYPE 定義、日誌自定義、連線超時時間、單鏈接請求數上限等。

  • server 塊

這塊和虛擬主機有密切關係,虛擬主機從使用者角度看,和一臺獨立的硬體主機是完全一樣的,該技術的產生是為了節省網際網路伺服器硬體成本。
每個 http 塊可以包括多個 server 塊,而每個 server 塊就相當於一個虛擬主機。
而每個 server 塊也分為全域性 server 塊,以及可以同時包含多個 locaton 塊。

​ * 全域性 server 塊

最常見的配置是本虛擬機器主機的監聽配置和本虛擬主機的名稱或IP配置。

​ * location 塊

一個 server 塊可以配置多個 location 塊。
這塊的主要作用是基於 Nginx 伺服器接收到的請求字串(例如 server_name/uri-string),對虛擬主機名稱 (也可以是IP 別名)之外的字串(例如 前面的 /uri-string)進行匹配,對特定的請求進行處理。地址定向、資料緩 存和應答控制等功能,還有許多第三方模組的配置也在這裡進行。

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

nginx配置反向代理

實現效果:使用 nginx 反向代理,訪問 123.56.168.21 nginx伺服器 直接跳轉到 123.56.168.21:8080 tomcat伺服器 。

  1. 修改nginx.conf,新增 proxy_pass
server {
    listen       80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
		proxy_pass http://123.56.168.21:8080;
        index  index.html index.htm;
    }
  1. 重新載入配置檔案
nginx -s  reload 
  1. 訪問123.56.168.21 測試。

location 指令說明

該指令用於匹配 URL。

語法如下:

location [ = | ~ | ~* | ^~ ] uri {
}

1、= :用於不含正則表示式的 uri 前,要求請求字串與 uri 嚴格匹配,如果匹配成功,就停止繼續向下搜尋並立即處理該請求。
2、~:用於表示 uri 包含正則表示式,並且區分大小寫。
3、~*:用於表示 uri 包含正則表示式,並且不區分大小寫。
4、^~:用於不含正則表示式的 uri 前,要求 Nginx 伺服器找到標識 uri 和請求字串匹配度最高的 location 後,立即使用此 location 處理請求,而不再使用 location 塊中的正則 uri 和請求字串做匹配。
注意:如果 uri 包含正則表示式,則必須要有 ~ 或者 ~* 標識。

nginx配置負載均衡

實現效果:利用nginx負載均衡,多次訪問同一個網址,用不同的伺服器來響應。

  1. 在nginx.conf的http塊中新增 upstream ,裡面放要負載均衡的伺服器列表。
http {
    include       /etc/nginx/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  /var/log/nginx/access.log  main;
    sendfile        on;
    keepalive_timeout  65;

    upstream myserver{
		server 123.56.168.21:9090;
		server 123.56.168.21:8080; 
    }
    
    include /etc/nginx/conf.d/*.conf;
}

  1. 在nginx.conf的server塊中新增 proxy_pass 。
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;
    
    location / {
        root   /usr/share/nginx/html;
		proxy_pass http://myserver;
        index  index.html index.htm;
    }
    
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
  1. 重新載入配置檔案
nginx -s  reload 

負載均衡的策略

隨著網際網路資訊的爆炸性增長,負載均衡(load balance)已經不再是一個很陌生的話題, 顧名思義,負載均衡即是將負載分攤到不同的服務單元,既保證服務的可用性,又保證響應 足夠快,給使用者很好的體驗。快速增長的訪問量和資料流量催生了各式各樣的負載均衡產品, 很多專業的負載均衡硬體提供了很好的功能,但卻價格不菲,這使得負載均衡軟體大受歡迎, nginx 就是其中的一個,在 linux 下有 Nginx、LVS、Haproxy 等等服務可以提供負載均衡服 務,而且 Nginx 提供了幾種分配方式(策略):

  1. 輪詢(預設)

每個請求按時間順序逐一分配到不同的後端伺服器,如果後端伺服器 down 掉,能自動剔除。

upstream myserver{
	server 192.168.5.21;
	server 192.168.5.22; 
}
  1. weight

weight 代表權重,預設為 1,權重越高被分配的客戶端越多 。用於後端伺服器效能不均的情況

upstream server_pool{    
	server 192.168.5.21 weight=5;     
	server 192.168.5.22 weight=10;     
}
  1. ip_hash

每個請求按訪問 ip 的 hash 結果分配,這樣每個訪客固定訪問一個後端伺服器,可以解決 session 的問題。相同ip一定訪問相同的伺服器。

upstream server_pool{    
	ip_hash;     
	server 192.168.5.21:80;     
	server 192.168.5.22:80;     
}
  1. fair

按後端伺服器的響應時間來分配請求,響應時間短的優先分配。 哪臺伺服器響應時間短,就先訪問它。

upstream server_pool{    
	server 192.168.5.21:80;     
	server 192.168.5.22:80;     
	fair;     
}

nginx 配置動靜分離

Nginx 動靜分離簡單來說就是把動態跟靜態請求分開,不能理解成只是單純的把動態頁面和 靜態頁面物理分離。嚴格意義上說應該是動態請求跟靜態請求分開,可以理解成使用 Nginx 處理靜態頁面,Tomcat 處理動態頁面。動靜分離從目前實現角度來講大致分為兩種,
一種是純粹把靜態檔案獨立成單獨的域名,放在獨立的伺服器上,也是目前主流推崇的方案;另外一種方法就是動態跟靜態檔案混合在一起釋出,通過nginx來分開。

通過 location 指定不同的字尾名實現不同的請求轉發。通過 expires 引數設定,可以使瀏覽器快取過期時間,減少與伺服器之前的請求和流量。具體 Expires 定義:是給一個資 源設定一個過期時間,也就是說無需去服務端驗證,直接通過瀏覽器自身確認是否過期即可,所以不會產生額外的流量。此種方法非常適合不經常變動的資源。(如果經常更新的檔案, 不建議使用 Expires 來快取),設定 3d,表示在這 3 天之內訪問這個 URL,傳送 一個請求,比對伺服器該檔案最後更新時間沒有變化,則不會從伺服器抓取,返回狀態碼 304,如果有修改,則直接從伺服器重新下載,返回狀態碼 200。

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    location /images/ {
        root   /data/;
        autoindex  on;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

nginx原理

有一個主程序master和若干個worker程序。master程序主要用來管理worker程序,包括:接受訊號,將訊號分發給worker程序,監聽worker程序工作狀態,當worker程序退出時(非正常),啟動新的worker程序。

多個worker程序之間是對等的,他們同等競爭來自客戶端的請求,各程序互相之間是獨立的 。一個請求,只可能在一個worker程序中處理,一個worker程序,不可能處理其它程序的請求。

master-workers 的機制的好處 :

  • 可以使用 nginx –s reload 熱部署,利用 nginx 進行熱部署操作

  • 每個 woker 是獨立的程序,如果有其中的一個 worker 出現問題,其他 worker 是獨立的, 繼續進行爭搶,實現請求過程,不會造成服務中斷 。