Nginx-包教包會-進階

前言

Nginx-包教包會-入門 一文中介紹了怎麼使用 Nginx 搭建 web 服務器。

但有的時候呢,我們需要對資源進行訪問控制。比如說需要登錄才能訪問,訪問鏈接具有時間段限制。

又比如說防止惡意攻擊,使用限流,限制帶寬等等

我們也會使用 Nginx 作為代理服務器,將我們的動態內容的請求轉發到應用服務器去處理。

下一期,總結一下 Nginx 相關的配置,給出一個配置模板

本文內容

  • 基於 ngx_http_auth_basic_module模塊,使用用戶名和密碼限制資源的訪問
  • 基於 ngx_http_auth_request_module 集成已有的授權驗證
  • 基於 ngx_http_secure_link_module 限制連接的時效性和訪問控制
  • 基於請求的限流、基於併發鏈接數限流,限制每個鏈接的帶寬
  • 為什麼要使用 Nginx 作為代理服務器及代理的配置,及獲取用戶的真實 ip 。
  • 基於代理的負載均衡

有的時候我們想簡單限制用戶的訪問。可以使用 ngx_http_auth_basic_module 模塊,我們預先設置好賬號和密碼,用戶需要使用特定的用戶和密碼才能訪問。在網站沒有用戶登錄管理功能的時候,可以作為一個替代品。

| Syntax: | auth_basic string | off; | | :------- | -------------------------------------------- | | Default: | auth_basic off; | | Context: | http, server, location, limit_except |

Syntax:auth_basic_user_file file;Default:—Context:http, server, location, limit_except

Nginx 自帶登錄驗證

密碼生成

可以使用 htpasswd 生成密碼,也可以使用 OpenSSL 生成密碼。

<code>yum install httpd-tools -y
# htpasswd --h 可以查看幫助命令

# 在指定文件位置生成,用戶zhang1 和它的密碼,輸入之後,會讓你設置你的密碼
htpasswd -c /etc/nginx/mypasswd zhang1

# 在已有的文件中添加用戶 zhang2
htpasswd /etc/nginx/mypasswd zhang2/<code>

mypasswd 中文件的內容

<code>zhang1:$apr1$5dvJBg5z$aY.ncM55O8caHgyOvd.G0/
zhang2:$apr1$3YUp0G3g$agIpFCfS4K3rfqn.F29VB1/<code>

配置訪問控制

然後再 nginx 中添加這個配置

<code>location / {
auth_basic "sdaf";
auth_basic_user_file /etc/nginx/mypasswd;
}/<code>

nginx -s reload 刷新配置,然後再訪問資源就需要輸入預先設置好的用戶名和密碼。

ngx_http_auth_basic_module 儘管可以限制訪問,但是作用太雞肋了,它相當於另一套登錄邏輯。它不能集成我們已有的授權功能。

Nginx 中的模塊 ngx_http_auth_request_module 也支持第三方的授權的驗證的。

nginx -V 看你的編譯的模塊中是否包含此模塊。

-說明語法auth_request uri默認auth_request off;上下文http、server、location

auth_request 啟用基於子請求 (uri) 結果的授權。子請求返回一個 2xx 響應嗎,則允許訪問。如果返回 401 和 403 則拒絕訪問。

下面模擬一個場景進行實現。

子請求(/auth)的驗證基於 cookie 中的 Authorization ,存在返回 200 狀態碼。不存在返回 403 狀態碼。

在 nginx 配置 403 狀態碼跳轉到我們的登錄頁面。

http://localhost:9090 下的資源都需要限制訪問。

<code>server {
listen 9090 default_server;
server_name "$host";
root /usr/local/var/www;
index index.html;
location / {
# 9090 下的請求,都去訪問 /auth 看看有沒有權限訪問
auth_request /auth;
}
location =/auth {
# 代理去訪問我們已有的登錄授權
proxy_pass http://localhost:8087/auth;
proxy_pass_request_body off;

proxy_set_header Content-Length "";
}

# 403 狀態碼,跳轉我們已有的授權登錄功能
error_page 403 = @login;

location @login {
# oriUrl 使我們用於登錄成功之後的跳轉鏈接
return 302 http://localhost:8087/login.html?oriUrl=$scheme://$http_host$request_uri;
}
}/<code>

用戶訪問資源,如果鑑權失敗會跳轉到登錄頁面,在登錄頁面登錄之後,重新跳轉到用戶訪問的資源路徑。

登錄頁面實現邏輯:點擊登錄,地址欄刷新地址,請求接口 http://localhost:8087/login?oriUrl=xxx,訪問成功,接口會設置 cookie 並跳轉到 oriUrl 指定的資源。

login.html 內容,這裡我不想在寫 ajax 去請求接口飯後進行跳轉,所以改變瀏覽器地址欄

<code>



<title> 登錄 /<title>


登錄頁面,點擊登錄之後跳轉到訪問的頁面.





/<code>

服務端代碼,http://localhost:8087

服務端會鑑權接口只判斷有沒有 Authorization cookie。

登錄接口也比較簡單,沒有進行賬號密碼驗證,訪問既返回 cookie。並跳轉。

<code>@RestController
public class AuthController {
// 用於資源鑑權,邏輯比較簡單,就看有沒有 cookie
@GetMapping("/auth")
public ResponseEntity<string> res(HttpServletRequest request) {
Cookie[] cookies = Optional.ofNullable(request.getCookies()).orElse(new Cookie[0]);
Optional<cookie> authorization1 = Stream.of(cookies).filter(item -> {
String value = item.getName();
return Objects.equals("Authorization", value);
}).findFirst();
if (authorization1.isPresent()){
return ResponseEntity.status(200).body("success");
}
return ResponseEntity.status(403).body("fail");
}

// 登錄邏輯,也比較簡單,訪問就會設置 cookie 及跳轉
@GetMapping("/login")
public RedirectView request(HttpServletRequest request, HttpServletResponse response){
final Cookie cookie = new Cookie("Authorization", "Authorization");
cookie.setPath("/");
cookie.setDomain("localhost");
response.addCookie(cookie);
final String oriUrl = request.getParameter("oriUrl");
final RedirectView redirectView = new RedirectView();
redirectView.setUrl(oriUrl);
return redirectView;
}
}/<cookie>/<string>/<code>

效果演示,訪問http://localhost:9090/index.html 的時候由於沒有登錄,nginx 錯誤狀態碼 403 跳轉到了登錄頁面,在登錄頁面點擊登錄,跳轉到 http://localhost:9090/index.html

Nginx-包教包會-進階

ngx_http_secure_link_module

有的時候呢,我們希望訪問的鏈接具有時效性。比如微信發佈的文章中,文章路徑有時效性,過了這個時效性就沒有辦法訪問了。或者有的資源必須帶有一些字段我們才讓其訪問。

secure_link

-說明語法secure_link expression;默認-上下文http、server、location

定義從哪裡取到的鏈接的 md5 和 過期時間,以逗號隔開

<code># 從請求參數中取鏈接的 md5 和過期時間
secure_link $arg_md5,$arg_expires;/<code>

secure_link_md5

Syntax:secure_link_md5 expression;Default:—Context:http, server, location

在secure_link_md5 的 expression 中可以通過 $secure_link_expires (只能在 secure_link_md5 expression; 使用)獲取鏈接指定的過期時間。

nginx 會校驗取到的 md5 (secure_link 指定的第一個值)和 secure_link_md5 指定的 expression 計算出來的 md5 是否一致, 不一樣會將 secure_lin 設置為 "" 。校驗 md5 成功,校驗過期時間,過期將 secure_link 設置為 "0” ,校驗成功設置為 "1"。

<code>location /s/ {
secure_link $arg_md5,$arg_expires;

secure_link_md5 "123$secure_link_expires$uri hello";

# md5 不一致返回空
if ($secure_link = "") {
return 403;
}

# secure_link 為 0 標識,鏈接過期了
if ($secure_link = "0") {
return 410;
}
}/<code>

我們需要事先將鏈接計算好,然後將連接發佈出去。

比如說我想限制 /s/a.jpg 訪問。那麼我需要使用算法計算鏈接。比如說

shell 命令生成 md5 的值。

<code>#!/bin/bash
# 服務 IP 端口
IP=localhost:8888
LINK_URL="/s/a.jpg"
NOW=$(date +%s)
TIMESTAMP=$((NOW + 10))
SECRET_STR=hello

md5=$(echo -n "123${TIMESTAMP}${LINK_URL} ${SECRET_STR}" | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)

echo "http://${IP}${LINK_URL}?md5=${md5}&expires=${TIMESTAMP}"/<code>

上述腳本會打印出訪問鏈接。

java 生成 md5 的值

一般我們都會在服務端進行生成鏈接。

<code>public class HttpSecureLink {
public static final String site = "http://localhost:8888";

public static final String secret = " hello";
public static String createLink(String path, long expireTime) {
final long l = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) + expireTime;
String time = String.valueOf(l);
String md5 = Base64.encodeBase64URLSafeString(DigestUtils.md5("123" + time + path + secret));
String url = site + path + "?md5=" + md5 + "&expires=" + time;
return url;
}

public static void main(String[] args) {
System.out.println(createLink("/s/a.jpg", 10L));
}
}/<code>

需引入 jar

<code><dependency>
<groupid>commons-codec/<groupid>
<artifactid>commons-codec/<artifactid>
<version>1.14/<version>
/<dependency>/<code>

這樣我們的鏈接就可以限制到哪些用戶可以訪問,還可以具有一定的時效性。

基於請求限流

ngx_http_limit_req_module 採用 漏桶算法 進行限流。

Nginx-包教包會-進階

水滴比作網絡請求,當水滴超過桶的容量,請求會被拒絕。漏桶算法是以勻速掉落水滴(處理請求)。

比如說 rate=3r/m 是 20000ms(20s) 一個勻速處理請求。nginx 是毫秒作計量單位。超過的請求就會被拋棄掉。桶的容量實際是一個隊列,limit_req 中的 burst 配置隊列的大小,burst 可以應對突發請求。

比如 rate=3r/m ,那麼 20s 處理一個請求。這 20s 來兩個請求就會有一個請求被拋棄掉。

rate=3r/m 和 burst=3 可以應對突發請求,20s 內來了五個請求,一個被處理,三個請求放到緩衝隊列等待處理,剩下的一個被拋棄掉。然後勻速處理請求,一個一個消耗掉隊列中的請求,隊列中有空餘位置,又可以應對突發請求了。

設置以什麼為標識限流

-說明語法limit_req_zone key zone=name:size rate=rate;默認-上下文http

key 可以包含文本、變量及組合。設置限制請求的標識。

以下配置相當於根據訪問用戶的 ip 限制訪問,每秒只能 10 個請求。

比如說,我訪問 http://localhost:9091/2.jpg 限流了,我再去訪問http://localhost:9091/1.jpg也是會被限流。

<code>limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;/<code>

下面這個以用戶的 ip +訪問路徑為限制標識。

比如說,我訪問 http://localhost:9091/2.jpg 限流了,但是我可以訪問 http://localhost:9091/1.jpg。

<code>limit_req_zone $binary_remote_addr$uri zone=one11:10m rate=3r/m;/<code>

size 相當於為設置保存 key 的空間,超過這個空間大小,就會使用緩存策略,清楚掉最近最少使用的狀態。

設置哪些地方限流

-說明語法limit_req zone=name [burst=number] [nodelay];默認-上下文http、server、location

一般我們都會配置 limit_req zone=one11 burst=4 nodelay;

nodelay 為配置緩衝隊列中的請求,不延遲執行,但是隊列中的空間還是需要勻速消耗請求去恢復。

###設置限流的響應狀態碼

-說明語法limit_req_status code;默認limit_req_status 503;上下文http、server、location

設置拒絕請求的響應狀態碼。

列子講解

<code>limit_req_zone $binary_remote_addr$uri zone=one:10m rate=3r/m;
server {
listen 9091 default_server;
location / {
limit_req zone=one burst=4 nodelay;
root /Users/zhangpanqin/stduy_app/break2;
}
}/<code>

緩衝隊列為 4。每 20 s 處理一個請求。nodelay 讓隊列中的請求不延遲執行。

第一個 20 s 內,可以處理 5 個請求。隊列和勻速加一塊正好五個。

第二個 20 s 內,就只能處理 1 個請求。因為隊列中的容量沒有回覆。

如果接下來一段時間都沒有請求處理的話,那麼隊列就會每 20 s 回覆一個位置,回覆的位置可以處理請求,這樣慢慢達到 4 個。又可以 20 s 內處理 5 個請求了。

limit_req_zone 配置的是用戶的 ip 和 path 作為限流標識。

比如說,我訪問 http://localhost:9091/2.jpg 五次限流之後,但是我可以訪問 http://localhost:9091/1.jpg五次。

基於鏈接數限流

有的時候我們基於請求限流還不能達到我們的目的,因為瞬間流量控制不了,我上面舉的例子是基於 ip 和 path 限流,如果被惡意攻擊,那麼可能好幾百的請求被處理,這顯然不符合正常用戶的行為。

比如說你有一個文件下載功能,每個文件 1 分鐘只能下載一次,但是惡意攻擊的話,你的 100 個文件我同時下載,這樣的帶寬和流量就被白白消耗了。

針對上述情況,我們可以結合連接數限流,每個 ip 限制併發鏈接 5 個。這樣就沒有辦法一次性下載 100 個文件了。

ngx_http_limit_conn_module 就是針對併發鏈接限制的,服務器處理了請求並讀取了整個請求頭,併發鏈接才會計數。

limit_conn_zone

-說明語法limit_conn_zone key zone=name:size;默認-上下文http

key 用於限流標識。zone 定義存儲的大小和名稱。

<code>limit_conn_zone $binary_remote_addr zone=addr:10m;/<code>

limit_conn 在哪裡限制

-說明語法limit_conn zone number;默認-上下文http、server、location

配置允許的最大併發鏈接數。

<code>limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
location /download/ {

limit_conn addr 1;
}
}/<code>

limit_conn_status 配置限流時的響應狀態碼

-說明語法limit_conn_status code;默認limit_conn_status 503;上下文http、server、location

配置限流時響應狀態碼,我們可以根據狀態碼跳轉到提示頁面。

<code>error_page 503 = @limit2;

location @limit2 {
add_header Content-Type application/json;
return 200 "你被限流了,稍後再試";
}/<code>

基於響應帶寬限制

-說明語法limit_rate rate;默認limit_rate 0;上下文http、server、location、location 中的 if

設置為 0 標識不限制響應。rate 為字節/秒為單位。

<code>
# 每秒 4k 響應
set $limit_rate 4k;
/<code>

代理

ngx_http_proxy_module 允許將一個請求傳遞給另一個服務器。

nginx 的代理有一個好處是,它會將客戶端的請求信息全部讀取之後,客戶端的請求信息比較大的話,會放到臨時文件中去,讀取完之後請求信息之後再轉發至代理服務器。這樣做的好處是,降低了上游服務器的負載,缺點是延長了響應的時間,多佔了內存。

比如我們有一個上傳文件的功能,直接上傳服務器可能比較慢,而且還佔用鏈接,但是我們使用 nginx 代理的話,它會先經過 nginx 上,,讀取請求內容根據內容大小是否保存臨時文件,然後再通過內容傳輸到我們的服務器。這樣應用服務器的鏈接佔用時間就會比較短(nginx 與上游的代理服務器處於內網)。而 nginx 佔用鏈接的內存比較小,而且處理併發能力更強。

nginx 收到代理服務器的響應內容會邊緩存邊發送給客戶端。

我會列舉一些我瞭解並常用的配置。

proxy_buffering

<code># 啟用代理代理服務器緩衝,默認開啟
proxy_buffering on;/<code>

啟用緩存時,nginx 會盡可能接受來自代理服務器響應,將其保存至 proxy_buffer_size 和 proxy_buffers 指令設置的緩衝區中。內存如果放不下整個響應的話,會將一部分內容寫入到臨時文件中。

proxy_buffer_size

-說明語法proxy_buffer_size size;默認proxy_buffer_size 4k | 8k;上下文http、server、location

設置從代理服務器讀取的響應頭的緩衝區大小。默認情況下等於一個系統內存頁大小。建議設置成內存頁的整數倍,如果響應頭比較大,可以修改此部分

<code># 獲取內存頁大小
getconf PAGESIZE/<code>

第一次測試,我返回 10m響應體。響應頭很小,低於 4k。服務端的端口為 8087。

<code>@GetMapping("/proxy")
public ResponseEntity<string> proxy(){
final String collect = Stream.generate(() -> {
return "a";
}).limit(1024*1024*10).collect(Collectors.joining());
return ResponseEntity.status(200).header("a","collect1").body(collect);
}/<string>/<code>

nginx 配置如下,瀏覽器請求 http://localhost:9092/test/proxy,請求成功。

<code>    server {
listen 9092 default_server;
location /test/ {
proxy_pass http://localhost:8087/;
}
}/<code>

第二次測試,我返回 10m 響應體,外加大於 4k 的響應頭。請求失敗。

<code>@GetMapping("/proxy")
public ResponseEntity<string> proxy(){

final String collect = Stream.generate(() -> {
return "a";
}).limit(1024*1024*10).collect(Collectors.joining());
final String collect1 = Stream.generate(() -> "b").limit(1024 * 5).collect(Collectors.joining());
return ResponseEntity.status(200).header("a",collect1).body(collect);
}/<string>/<code>

將註釋打開,才能訪問成功

<code>server {
listen 9092 default_server;
location /test/ {
proxy_pass http://localhost:8087/;
#proxy_buffer_size 8k;
}
}/<code>

proxy_buffers

-說明語法proxy_buffers number size;默認proxy_buffers 8 4k | 8k;上下文http、server、location

設置單個連接從代理服務器讀取響應的緩衝區的 number (數量)和 size (大小)。

默認情況下,緩衝區大小等於一個內存頁。為 4K 或 8K,因平臺而異。

避免設置 number 小,size 大的。比如 proxy_buffers 10 1m;

只需要滿足緩衝區 number 乘 size 可以容納響應體即可。

從上游的代理服務器讀取的響應內容,會存到 proxy_buffers 設置的緩衝區中,寫滿一個緩衝區,繼續寫下一個。當緩衝區總大小容納不下的時候,會寫到臨時文件中去。已經寫過的緩衝區 (size)不會被操作,除非發送給客戶端。

proxy_busy_buffers_size

-說明語法proxy_busy_buffers_size size;默認proxy_buffer_size 8k | 16k;上下文http、server、location

proxy_busy_buffers_size 用於指定緩衝區(proxy_buffers 和 proxy_buffer_size)寫入多大內容的時候往客戶端發送。默認為 proxy_buffers 中 size 的兩倍。

proxy_temp_file_write_size 一次寫入臨時文件的數據大小

-說明語法proxy_temp_file_write_size size;默認proxy_temp_file_write_size 8k | 16k;上下文http、server、location

當緩衝區沒法容納從代理服務器返回的響應內容時,需要按照 proxy_temp_file_write_size 配置的 size 寫入臨時文件中

proxy_temp_path 定義臨時文件的目錄

需要注意的是,worker 進程要有讀寫臨時目錄的權限,否則會丟失數據。

-說明語法proxy_temp_path path [level1 [level2 [level3] ] ]默認proxy_temp_path proxy_temp;上下文http、server、location

<code>proxy_temp_path /spool/nginx/proxy_temp 1 2;/<code>

proxy_pass

-說明語法proxy_pass URL;默認-上下文http、server、location

默認情況下,反向代理不會轉發請求頭 Host,如果需要轉發需要配置

<code>proxy_set_header Host $host;/<code>

設置代理的 URL。會將匹配的 location 路徑替換成指定的 URL。

注意這裡 proxy_pass 是否以 / 結尾,處理是不一樣的。

<code>server {
listen 80;
location /api/flyyou/ {
proxy_pass http://localhost:8080;
}
}/<code>

訪問 http://localhost:80/api/flyyou/a 會轉發到 http://localhost:8080/api/flyyou/a

proxy_pass 不以 / 結尾,會將匹配的路徑追加到代理去。

都以 / 就是替換,就是替換處理。

<code>server {
listen 81;
location /api/flyyou/ {
proxy_pass http://localhost:8081/;
}
}/<code>

訪問 http://localhost:81/api/flyyou/a 會轉發到 http://localhost:8081/a

proxy_set_header 傳遞請求頭到代理服務器

-說明語法proxy_pass_header name value;默認-上下文http、server、location

<code>proxy_set_header test1 $remote_addr;
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;/<code>

proxy_pass_request_body 設置是否傳遞請求體到代理服務器

-說明語法proxy_pass_request_body on | off;默認proxy_pass_request_body on;上下文http、server、location

proxy_pass_request_headers 是否將原始請求的請求頭傳遞給代理服務器

-說明語法proxy_pass_request_headers on | off;默認proxy_pass_request_headers on;上下文http、server、location

ngx_http_proxy_module 模塊支持內嵌變量

  • $proxy_host

proxy_pass 指令中指定的代理服務器的名稱和端口

  • $proxy_port

proxy_pass 指令中指定的代理服務器的端口或協議的默認端口

  • $proxy_add_x_forwarded_for

X-Forwarded-For 客戶端請求頭字段,其中附加了 $remote_addr 變量,以逗號分割。

如果客戶端請求頭中不存在 X-Forwarded-For 字段,則變量等於 $remote_addr 變量。

總結

nginx 作為代理服務器的時候,併發大的時候還是比較佔用內存的。但是服務器的內存還要預留一部分給系統調用。

以下設置是針對每一個請求的。

<code># 大於響應頭即可,設置為內存頁大小的倍數,getconf PAGESIZE 獲取內存頁大小
proxy_buffer_size 4k;
# 設置大於響應體內容大小即可,在日誌記錄中看發送響應大小或估算,注意 size 不要設置的太大
proxy_buffers 32 8k;
# 設置為 proxy_buffers 中 size 的 2 倍
proxy_busy_buffers_size 16k;
# 設置和 proxy_busy_buffers_size 一樣大小
proxy_temp_file_write_size 16k;
# 為了便於查找文件,可以設置臨時文件目錄
proxy_temp_path /var/nginx/proxy_temp;/<code>

獲取用戶真實 ip

當我們訪問一個資源的時候,可以使用命令 traceroute mflyyou.cn 查看經過了哪些網關。網絡運營商不會為每一個用戶分配公網 ip,會有一個內網路由將一部分用戶的請求分發到一個公網 ip 上去。我們能獲取到的就是這個 公網 ip。

有的時候我們不單單要知道用戶從哪個 ip 訪問的,還想知道,中間經過了哪些代理 ip。

我使用了兩個 nginx 和一個 java 後端服務。

本地 Nginx => 公網 Nginx => 後端服務。

本地 nginx 配置

<code>server {
listen 9092 default_server;
location /test/ {
proxy_pass http://mflyyou.cn/mytest/;
proxy_buffer_size 8k;
# 記錄的是用戶經過了哪些 ip
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}/<code>

公網 nginx 配置

<code>    location /mytest/api/{
# 記錄的是用戶建立公網鏈接時的 ip
proxy_set_header X-REAL-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:8087/;

}/<code>

後端 java 服務

<code>@GetMapping("/ip")
public IpData getIPData(HttpServletRequest request){
final String header = request.getHeader("X-Forwarded-For");
final String realIp = request.getHeader("X-REAL-IP");
final IpData ipData = new IpData();
ipData.setXForwardFor(header);
ipData.setXRealIp(realIp);
return ipData;
}/<code>

當我本地訪問 http://localhost:9092/test/api/ip

<code>{"xforwardFor":"127.0.0.1, 155.10.116.110","xrealIp":"155.10.116.110"}/<code>

基於代理的負載均衡

簡單負載均衡

nginx 支付的負載均衡策略有:

  • 輪詢(round-robin) - 發送給應用服務器的請求以輪詢的方式分發
  • 最少連接(least_conn) - 下一個請求被分配給具有最少數量活動連接的服務器
  • ip 哈希(ip_hash) - 使用哈希函數確定下一個請求應該選擇哪一個服務器(基於客戶端 的 IP 地址)

默認輪訓策略。

以下配置可以作為研究使用,實際生產不會這樣配置的,一般都會轉發到不同的服務器上去。

<code>upstream passserver2 {
# ip_hash;
# least_conn;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}

server {
listen 9088 default_server;
server_name localhost;
location / {
proxy_pass http://passserver2;
}
}


server {
listen 8081 default_server;
server_name localhost;
location =/api {
add_header Content-Type application/json;
return 200 "我是 8081 服務器";
}
}
server {
listen 8082 default_server;
server_name localhost;
location =/api {
add_header Content-Type application/json;
return 200 "我是 8082 服務器";
}
}
server {
listen 8083 default_server;
server_name localhost;
location =/api {
add_header Content-Type application/json;
return 200 "我是 8083 服務器";
}
}/<code>

server

-說明語法server address [parameters];默認-上下文upstream

我們也可以通過 parameters 給應用服務器設置更細粒度的控制。

有一些參數需要商用 nginx 才能使用,我就沒有列出來。

weight 控制權重

weight=number;

weight 默認為 1。通過設置權重,會讓某個服務有更多的概率處理請求。

通常可以將服務器配置比較高的服務器設置的權重更大。

8081 會有 3/6 的概率。

8082 會有 2/6 的概率。

8083 會有 1/6 的概率。

<code>upstream passserver2 {
server 127.0.0.1:8081 weight=3;
server 127.0.0.1:8082 weight=2;
server 127.0.0.1:8083;
}/<code>

max_fails 配置允許的失敗次數

max_fails=number

默認為 1。需要與 fail_timeout 配合使用。表示 fail_timeout 內允許的失敗次數,超過之後,就不會分配請求。

<code>upstream passserver2 {
server 127.0.0.1:8081 weight=3 max_fails=3 fail_timeout=15;
server 127.0.0.1:8082 weight=2;
server 127.0.0.1:8083;
}/<code>

fail_timeout

fail_timeout=time

默認 10 秒。

<code>upstream passserver2 {
server 127.0.0.1:8081 weight=3 max_fails=3 fail_timeout=15;
server 127.0.0.1:8082 weight=2;
server 127.0.0.1:8083;
}/<code>

backup 設置備用機

當別的服務器都掛了之後才會啟動服務。

8081 和 8082 都掛掉之後,8083 才開始提供服務。

<code>upstream passserver2 {
server 127.0.0.1:8081 weight=3 max_fails=3 fail_timeout=15;
server 127.0.0.1:8082 weight=2;
server 127.0.0.1:8083 backup;
}/<code>

max_conns 限定服務器的最大連接數

max_conns=number

指定某個服務器的最大連接數,超過這個數,不會分配新的請求,除非低於這個數。

<code>upstream passserver2 {
server 127.0.0.1:8081 weight=3 max_fails=3 fail_timeout=15;
server 127.0.0.1:8082 weight=2 max_conns=1000;
server 127.0.0.1:8083 backup;
}/<code>


Nginx-包教包會-進階

點資料


分享到:


相關文章: