Nginx基於TCP/UDP端口的四層負載均衡(stream模塊)配置梳理


Nginx基於TCP/UDP端口的四層負載均衡(stream模塊)配置梳理

 

 

通過我們會用Nginx的upstream做基於http/https端口的7層負載均衡,由於Nginx老版本不支持tcp協議,所以基於tcp/udp端口的四層負載均衡一般用LVS或Haproxy來做。至於4層負載均衡和7層負載均衡的區別,可以參考:http://www.cnblogs.com/kevingrace/p/6137881.html。然而Nginx從1.9.0版本開始,新增加了一個stream模塊,用來實現四層協議的轉發、代理或者負載均衡等,鑒於Nginx在7層負載均衡和web service上的成功,和Nginx良好的框架,stream模塊前景一片光明。官方文檔:http://nginx.org/en/docs/stream/ngx_stream_core_module.html

Nginx的stream模塊默認不會自帶安裝,需要編譯安裝的時候手動添加上這個模塊。廢話不多說了,下面介紹下一個自己使用stream做四層負載均衡(socket協議代理)的案例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
在此之前已經使用Ningx+Keepalived(主從模式)做了7層負載均衡的LB環境,之前編譯的時候,沒有加上這個stream模塊,所以需要后續手動添加該模塊。
由於Nginx的LB已經有業務跑在上面,可以選擇平滑添加stream模塊,並不會對線上業務造成多大影響。步驟如下:
 
1)先在LB的slave從機上進行平滑添加,然后再將vip切換到從機上,隨即在對master主機進行平滑添加該模塊。
2)平滑添加即是重新configure編譯的時候加上--with-stream,接着 make
3)千萬注意, make 之后,不要 make install ,否則會覆蓋掉之前的配置!!!
 
--------------------------------------------------------------------------------------------------
由於本人的LB環境升級了openssl版本,再添加--with-stream重新編譯的時候報了錯誤,具體可參考:
http: //www .cnblogs.com /kevingrace/p/8058535 .html
--------------------------------------------------------------------------------------------------
 
檢查下,發現nginx沒有安裝stream模塊
[root@external-lb01 ~] # /data/nginx/sbin/nginx -V
nginx version: nginx /1 .12.2
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC)
built with OpenSSL 1.1.0g  2 Nov 2017
TLS SNI support enabled
configure arguments: --prefix= /data/nginx --user=www --group=www --with-http_ssl_module --with-http_flv_module
--with-http_stub_status_module --with-http_gzip_static_module --with-pcre
  
  
操作之前,一定要備份一下之前的nginx安裝目錄,防止操作失敗進行回滾!
[root@external-lb01 ~] # cp -r /data/nginx /mnt/nginx.bak
  
之前的編譯命令是:
[root@external-lb01 vhosts] # cd /data/software/nginx-1.12.2
[root@external-lb01 nginx-1.12.2] # ./configure --prefix=/data/nginx --user=www --group=www --with-http_ssl_module
--with-http_flv_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre
 
現在需要手動添加stream,編譯命令如下:
[root@external-lb01 vhosts] # cd /data/software/nginx-1.12.2
[root@external-lb01 nginx-1.12.2] # ./configure --prefix=/data/nginx --user=www --group=www --with-http_ssl_module
--with-http_flv_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream
  
[root@external-lb01 nginx-1.12.2] # make
 
[root@external-lb01 nginx-1.12.2] # cp -f /data/software/nginx-1.12.2/objs/nginx /data/nginx/sbin/nginx
[root@external-lb01 nginx-1.12.2] # pkill -9 nginx
[root@external-lb01 nginx-1.12.2] # /data/nginx/sbin/nginx
 
檢查下,發現nginx已經安裝了stream模塊了
[root@external-lb01 nginx-1.12.2] # /data/nginx/sbin/nginx -V
nginx version: nginx /1 .12.2
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC)
built with OpenSSL 1.1.0g  2 Nov 2017
TLS SNI support enabled
configure arguments: --prefix= /data/nginx --user=www --group=www --with-http_ssl_module --with-http_flv_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-openssl= /usr/local/ssl
 
======================================================================================================================
stream的4層負載均衡和upstream的7層負載均衡可以共同配置在nginx中,stream模塊用法和http模塊差不多,關鍵的是語法幾乎一致。
具體如下:
 
[root@external-lb01 ~] # cat /data/nginx/conf/nginx.conf
user  www;
worker_processes  8;
  
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
  
#pid        logs/nginx.pid;
  
  
events {
     worker_connections  65535;
}
  
stream {
     upstream kk5 {
         server 10.0.58.22:5100;
         server 10.0.58.23:5100;
     }
    upstream kk5http {
       server 10.0.58.22:8000;
       server 10.0.58.23:8000;
    }
    upstream kk5https {
       server 10.0.58.22:8443;
       server 10.0.58.23:8443;
    }
    server {
       listen 5100;
       proxy_connect_timeout 1s;
       proxy_pass kk5;
     }
    server {
       listen 8000;
       proxy_connect_timeout 1s;
       proxy_pass kk5http;
    }
    server {
       listen 8443;
       proxy_connect_timeout 1s;
       proxy_pass kk5https;
    }
}
  
http {
     include       mime.types;
     default_type  application /octet-stream ;
     charset utf-8;
        
     ######
     ## set access log format
     ######
     log_format  main  '$remote_addr $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" '
                   '$http_user_agent $http_x_forwarded_for $request_time $upstream_response_time $upstream_addr $upstream_status' ;
  
     #######
     ## http setting
     #######
     sendfile       on;
     tcp_nopush     on;
     tcp_nodelay    on;
     keepalive_timeout  65;
     proxy_cache_path /var/www/cache levels=1:2 keys_zone=mycache:20m max_size=2048m inactive=60m;
     proxy_temp_path /var/www/cache/tmp ;
  
     fastcgi_connect_timeout 3000;
     fastcgi_send_timeout 3000;
     fastcgi_read_timeout 3000;
     fastcgi_buffer_size 256k;
     fastcgi_buffers 8 256k;
     fastcgi_busy_buffers_size 256k;
     fastcgi_temp_file_write_size 256k;
     fastcgi_intercept_errors on;
  
     #
     client_header_timeout 600s;
     client_body_timeout 600s;
    # client_max_body_size 50m;
     client_max_body_size 100m;
     client_body_buffer_size 256k;
  
     gzip  on;
     gzip_min_length  1k;
     gzip_buffers     4 16k;
     gzip_http_version 1.1;
     gzip_comp_level 9;
     gzip_types       text /plain application /x-javascript text /css application /xml text /javascript application /x-httpd-php ;
     gzip_vary on;
  
     ## includes vhosts
     include vhosts/*.conf;
}
 
 
 
[root@external-lb01 ~] # cd /data/nginx/conf/vhosts/
[root@external-lb01 vhosts] # ls
-rw-r-xr-- 1 root root  889 12月 26 15:18 bpm.kevin.com.conf
-rw-r-xr-- 1 root root  724 12月 26 14:38 mobi.kevin.com.conf
 
 
[root@external-lb01 vhosts] # cat bpm.kevin.com.conf
upstream os-8080 {
       ip_hash;
       server 10.0.58.20:8080 max_fails=3 fail_timeout=15s;
       server 10.0.58.21:8080 max_fails=3 fail_timeout=15s;
}
           
   server {
       listen      80;
       server_name bpm.kevin.com;
     
       access_log  /data/nginx/logs/bpm .kevin.com-access.log main;
       error_log  /data/nginx/logs/bpm .kevin.com-error.log;
     
  location / {
          proxy_pass http: //os-8080 ;
          proxy_set_header Host $host;
          proxy_redirect  http: //os-8080/ http: //bpm .kevin.com/;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_next_upstream error timeout invalid_header http_502 http_503 http_504;
         }
         error_page   500 502 503 504  /50x .html;
         location = /50x .html {
             root   html;
         }
}
 
[root@external-lb01 vhosts] # cat mobi.kevin.com.conf
upstream mobi_cluster{
     server 10.0.54.20:8080;
     }
 
server {
         listen       80;
         server_name  mobi.kevin.com;
 
       access_log  /data/nginx/logs/mobi .kevin.com-access.log main;
       error_log  /data/nginx/logs/mobi .kevin.com-error.log;
 
     location / {
             proxy_pass http: //mobi_cluster ;
             proxy_set_header Host $host;
             proxy_redirect  http: //mobi_cluster/ http: //mobi .kevin.com/;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         }
         error_page   500 502 503 504  /50x .html;
         location = /50x .html {
             root   html;
         }
}
 
 
 
關閉防火牆,否則要依次打開如上配置中的端口!
[root@external-lb01 vhosts] # /data/nginx/sbin/nginx -s reload
 
重啟nginx后,發現http端口80、8080、8000、8443都起來了( lsof 命令可以查看到),而tcp /udp 端口5100沒有起來,這是正常的。

==========順便總結下Nginx的四大模塊——proxy、headers、upstream、stream模塊梳理=========

一、ngx_http_proxy_module模塊

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
1)proxy_pass URL;
Context: location, if in location, limit_except
 
注意:proxy_pass后面的路徑不帶uri時,其會將location的uri傳遞給后端主機
server {
    
     server_name HOSTNAME;
 
     location /uri/ {
        proxy http: //hos [:port];
        }
 
       
        }
 
http: //HOSTNAME/uri –> http: //host/uri
 
proxy_pass后面的路徑是一個uri時,其會將location的uri替換為proxy_pass的uri
 
server {
    
     server_name HOSTNAME;
 
     location /uri/ {
         proxy http: //host/new_uri/ ;
         }
        
         }
 
http: //HOSTNAME/uri/ –> http: //host/new_uri/
 
如果location定義其uri時使用了正則表達式的模式,則proxy_pass之后必須不能使用uri; 用戶請求時傳遞的uri將直接附加代理到的服務的之后
server {
    
     server_name HOSTNAME;
         location ~|~* /uri/ {
         proxy http: //host ;
         }
        
         }
 
http: //HOSTNAME/uri/ –> http: //host/uri/
 
 
2)proxy_set_header field value;
設定發往后端主機的請求報文的請求首部的值;Context: http, server, location
 
proxy_set_header X-Real-IP  $remote_addr;
$remote_addr:記錄的是上一台主機的IP,而上一台主機有可能也是代理服務器
 
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     $proxy_add_x_forwarded_for:記錄的是源IP地址
 
在http客戶端還有修改 /etc/httpd/conf/httpd .conf文件
LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
通過上述方法則可以在后端主機上記錄真實的httpd資源請求者,而不再是只記錄前端代理服務器的IP地址
 
 
3)proxy_cache_path
定義可用於proxy功能的緩存;Context:    http
 
proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive= time ]
[max_size=size] [manager_files=number] [manager_sleep= time ] [manager_threshold= time ] [loader_files=number]
[loader_sleep= time ] [loader_threshold= time ] [purger=on|off] [purger_files=number] [purger_sleep= time ] [purger_threshold= time ];
 
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2:1 keys_zone=gmtest:20M max_size=1G;
 
4)proxy_cache zone | off;
指明要調用的緩存,或關閉緩存機制;Context: http, server, location
proxy_cache gmtest;
 
5)proxy_cache_key string;
緩存中用於“鍵”的內容;
默認值:proxy_cache_key $scheme$proxy_host$request_uri;
 
建議定義成方法和url
 
6)proxy_cache_valid [code …] time ;
定義對特定響應碼的響應內容的緩存時長;
 
定義在http{…}中;
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:1:1 keys_zone=gmtest:20m max_size=1g;
 
定義在需要調用緩存功能的配置段,例如server{…},或者location中;
proxy_cache gmtest;
proxy_cache_key $request_uri;
proxy_cache_valid 200 302 301 1h;
proxy_cache_valid any 1m;
 
 
7)proxy_cache_use_stale
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403
| http_404 | off …;
 
Determines in which cases a stale cached response can be used when an error occurs during communication with the proxied server.
 
后端服務器的故障在那種情況下,就使用緩存的功能對客戶的進行返回
 
 
8)proxy_cache_methods GET | HEAD | POST …;
If the client request method is listed in this directive then the response will be cached. “GET” and “HEAD” methods are always
added to the list, though it is recommended to specify them explicitly.
 
默認方法就是GET HEAD方法
 
 
9)proxy_hide_header field;
By default, nginx does not pass the header fields “Date”, “Server”, “X-Pad”, and “X-Accel-…” from the response of a proxied server
to a client. The proxy_hide_header directive sets additional fields that will not be passed.
 
10)proxy_connect_timeout time ;
Defines a timeout for establishing a connection with a proxied server. It should be noted that this timeout cannot usually exceed 75
seconds.
 
默認為60s
 
 
11)buffer相關的配置
a:proxy_buffer_size size;
Sets the size of the buffer used for reading the first part of the response received from the proxied server. This part usually contains
a small response header. By default, the buffer size is equal to one memory page.
 
默認為4k|8k
b:proxy_buffering on | off;
Enables or disables buffering of responses from the proxied server.
 
默認為on
c:proxy_buffers number size;
Sets the number and size of the buffers used for reading a response from the proxied server, for a single connection. By default, the buffer size is equal to one memory page.
 
默認為8 4k|8k
d:proxy_busy_buffers_size size;
When buffering of responses from the proxied server is enabled, limits the total size of buffers that can be busy sending a response to the client while the response is not yet fully read .
 
默認為8k|16k

二、ngx_http_headers_module模塊

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
The ngx_http_headers_module module allows adding the “Expires” and “Cache-Control” header fields, and arbitrary fields,
to a response header.
 
向由代理服務器響應給客戶端的響應報文添加自定義首部,或修改指定首部的值;
 
1)add_header name value [always];
添加自定義首部;
 
add_header X-Via  $server_addr;
經由的代理服務器地址
 
add_header X-Accel $server_name;
 
2)expires [modified] time ;
expires epoch | max | off;
 
用於定義Expire或Cache-Control首部的值;
可以把服務器定義的緩存時長修改了;

三、ngx_http_upstream_module模塊

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
The ngx_http_upstream_module module is used to define groups of servers that can be referenced by the proxy_pass, fastcgi_pass,
uwsgi_pass, scgi_pass, and memcached_pass directives.
 
1)upstream name { … }
定義后端服務器組,會引入一個新的上下文;Context: http
 
upstream httpdsrvs {
             server …
             server…
            
}
 
 
2)server address [parameters];
在upstream上下文中server成員,以及相關的參數;Context: upstream
 
address的表示格式:
unix: /PATH/TO/SOME_SOCK_FILE
IP[:PORT]
HOSTNAME[:PORT]
 
parameters:
weight=number
權重,默認為1;默認算法是wrr
 
max_fails=number
失敗嘗試最大次數;超出此處指定的次數時,server將被標記為不可用
 
fail_timeout= time
設置將服務器標記為不可用狀態的超時時長
 
max_conns
當前的服務器的最大並發連接數
 
backup
將服務器標記為“備用”,即所有服務器均不可用時此服務器才啟用
 
down
標記為“不可用”
 
先在nginx前端配置down,然后在下架后端服務器,上架新的web程序,然后上架,在修改配置文件立馬的down
 
 
3)least_conn;
最少連接調度算法,當server擁有不同的權重時其為wlc
要在后端服務器是長連接時,效果才好,比如mysql
 
 
4)ip_hash;
源地址 hash 調度方法
 
 
5) hash key [consistent];
基於指定的key的 hash 表來實現對請求的調度,此處的key可以直接文本、變量或二者的組合
 
作用:將請求分類,同一類請求將發往同一個upstream server
 
If the consistent parameter is specified the ketama consistent hashing method will be used instead.
 
示例:
hash $request_uri consistent;
hash $remote_addr;
hash $cookie_name; 對同一瀏覽器的請求,發往同一個upstream server
 
 
6)keepalive connections;
為每個worker進程保留的空閑的長連接數量
 
nginx的其它的二次發行版:
tengine
OpenResty
 
1.9版本之后可以反代tcp/udp的協議,基於stream模塊,工作與傳輸層

HTTP負載均衡,也就是我們通常所有"七層負載均衡",工作在第七層"應用層"。而TCP負載均衡,就是我們通常所說的"四層負載均衡",工作在"網絡層"和"傳輸層"。例如,LVS(Linux Virtual Server,Linux虛擬服務)和F5(一種硬件負載均衡設備),也是屬於"四層負載均衡"

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
nginx-1.9.0 已發布,該版本增加了stream 模塊用於一般的TCP 代理和負載均衡,ngx_stream_core_module 這個模塊在1.90版本后將被啟用。但是並不會默認安裝,
需要在編譯時通過指定 --with-stream 參數來激活這個模塊。
 
1)配置Nginx編譯文件參數
. /configure --with-http_stub_status_module --with-stream
------------------------------------------------------------------
 
2)編譯、安裝, make && make install
------------------------------------------------------------------
 
3)配置nginx.conf文件
 
stream {
     upstream kevin {
         server 192.168.10.10:8080;     #這里配置成要訪問的地址
         server 192.168.10.20:8081;
         server 192.168.10.30:8081;     #需要代理的端口,在這里我代理一一個kevin模塊的接口8081
     }
     server {
         listen 8081;               #需要監聽的端口
         proxy_timeout 20s;
         proxy_pass kevin;
     }
}
 
創建最高級別的stream(與http同一級別),定義一個upstream組 名稱為kevin,由多個服務組成達到負載均衡 定義一個服務用來監聽TCP連接(如:8081端口),
並且把他們代理到一個upstream組的kevin中,配置負載均衡的方法和參數為每個server;配置些如:連接數、權重等等。
 
首先創建一個server組,用來作為TCP負載均衡組。定義一個upstream塊在stream上下文中,在這個塊里面添加由server命令定義的server,指定他的IP地址和
主機名(能夠被解析成多地址的主機名)和端口號。下面的例子是建立一個被稱之為kevin組,兩個監聽1395端口的server ,一個監聽8080端口的server。
 
upstream kevin {
         server 192.168.10.10:8080;     #這里配置成要訪問的地址
         server 192.168.10.20:8081;
         server 192.168.10.30:8081;     #需要代理的端口,在這里我代理一一個kevin模塊的接口8081
     }
 
 
需要特別注意的是:
你不能為每個server定義協議,因為這個stream命令建立TCP作為整個 server的協議了。
 
配置反向代理使Nginx能夠把TCP請求從一個客戶端轉發到負載均衡組中(如:kevin組)。在每個server配置塊中 通過每個虛擬server的server的配置信息和在
每個server中定義的監聽端口(客戶端需求的代理端口號,如我推流的的是kevin協議,則端口號為:8081)的配置信息和proxy_passs 命令把TCP通信發送到
upstream的哪個server中去。下面我們將TCP通信發送到kevin 組中去。
   
   server {
         listen 8081;    #需要監聽的端口
         proxy_timeout 20s;
         proxy_pass kevin;
     }
 
當然我們也可以采用單一的代理方式:
 
server {
         listen 8081;  #需要監聽的端口
         proxy_timeout 20s;
         proxy_pass  192.168.10.30:8081;  #需要代理的端口,在這里我代理一一個kevin模塊的接口8081
}
------------------------------------------------------------------
 
4)改變負載均衡的方法:
默認nginx是通過輪詢算法來進行負載均衡的通信的。引導這個請求循環的到配置在upstream組中server端口上去。 因為他是默認的方法,這里沒有輪詢命令,
只是簡單的創建一個upstream配置組在這兒stream山下文中,而且在其中添加server。
 
a)least-connected :對於每個請求,nginx plus選擇當前連接數最少的server來處理:
 
 upstream kevin {
    least_conn;
         server 192.168.10.10:8080;     #這里配置成要訪問的地址
         server 192.168.10.20:8081;
         server 192.168.10.30:8081;     #需要代理的端口,在這里我代理一一個kevin模塊的接口8081
     }
 
b)least time :對於每個鏈接,nginx pluns 通過幾點來選擇server的: 最底平均延時:通過包含在least_time命令中指定的參數計算出來的:
connect:連接到一個server所花的時間
first_byte:接收到第一個字節的時間
last_byte:全部接收完了的時間 最少活躍的連接數:
 
 upstream kevin {
    least_time first_byte;
         server 192.168.10.10:8080;     #這里配置成要訪問的地址
         server 192.168.10.20:8081;
         server 192.168.10.30:8081;     #需要代理的端口,在這里我代理一一個kevin模塊的接口8081
     }
 
c)普通的 hash 算法:nginx plus選擇這個server是通過user_defined 關鍵字,就是IP地址:$remote_addr;
 
  upstream kevin {
     hash $remote_addr consistent;
         server 192.168.10.10:8080 weight=5;    #這里配置成要訪問的地址
         server 192.168.10.20:8081 max_fails=2 fail_timeout=30s;
         server 192.168.10.30:8081 max_conns=3;    #需要代理的端口,在這里我代理一一個kevin模塊的接口8081
     }

=================Nginx的TCP負載均衡====================

Nginx的TCP負載均衡的執行原理
當Nginx從監聽端口收到一個新的客戶端鏈接時,立刻執行路由調度算法,獲得指定需要連接的服務IP,然后創建一個新的上游連接,連接到指定服務器。

TCP負載均衡支持Nginx原有的調度算法,包括Round Robin(默認,輪詢調度),哈希(選擇一致)等。同時,調度信息數據也會和健壯性檢測模塊一起協作,為每個連接選擇適當的目標上游服務器。如果使用Hash負載均衡的調度方法,你可以使用$remote_addr(客戶端IP)來達成簡單持久化會話(同一個客戶端IP的連接,總是落到同一個服務server上)。

和其他upstream模塊一樣,TCP的stream模塊也支持自定義負載均和的轉發權重(配置“weight=2”),還有backup和down的參數,用於踢掉失效的上游服務器。max_conns參數可以限制一台服務器的TCP連接數量,根據服務器的容量來設置恰當的配置數值,尤其在高並發的場景下,可以達到過載保護的目的。

Nginx監控客戶端連接和上游連接,一旦接收到數據,則Nginx會立刻讀取並且推送到上游連接,不會做TCP連接內的數據檢測。Nginx維護一份內存緩沖區,用於客戶端和上游數據的寫入。如果客戶端或者服務端傳輸了量很大的數據,緩沖區會適當增加內存的大小。

當Nginx收到任意一方的關閉連接通知,或者TCP連接被閑置超過了proxy_timeout配置的時間,連接將會被關閉。對於TCP長連接,我們更應該選擇適當的proxy_timeout的時間,同時,關注監聽socke的so_keepalive參數,防止過早地斷開連接。

Nginx的TCP負載均衡服務健壯性監控
TCP負載均衡模塊支持內置健壯性檢測,一台上游服務器如果拒絕TCP連接超過proxy_connect_timeout配置的時間,將會被認為已經失效。在這種情況下,Nginx立刻嘗試連接upstream組內的另一台正常的服務器。連接失敗信息將會記錄到Nginx的錯誤日志中。

如果一台服務器,反復失敗(超過了max_fails或者fail_timeout配置的參數),Nginx也會踢掉這台服務器。服務器被踢掉60秒后,Nginx會偶爾嘗試重連它,檢測它是否恢復正常。如果服務器恢復正常,Nginx將它加回到upstream組內,緩慢加大連接請求的比例。

之所"緩慢加大",因為通常一個服務都有"熱點數據",也就是說,80%以上甚至更多的請求,實際都會被阻擋在"熱點數據緩存"中,真正執行處理的請求只有很少的一部分。在機器剛剛啟動的時候,"熱點數據緩存"實際上還沒有建立,這個時候爆發性地轉發大量請求過來,很可能導致機器無法"承受"而再次掛掉。以mysql為例子,我們的mysql查詢,通常95%以上都是落在了內存cache中,真正執行查詢的並不多。

其實,無論是單台機器或者一個集群,在高並發請求場景下,重啟或者切換,都存在這個風險,解決的途徑主要是兩種:
1)請求逐步增加,從少到多,逐步積累熱點數據,最終達到正常服務狀態。
2)提前准備好"常用"的數據,主動對服務做"預熱",預熱完成之后,再開放服務器的訪問。

TCP負載均衡原理上和LVS等是一致的,工作在更為底層,性能會高於原來HTTP負載均衡不少。但是,不會比LVS更為出色,LVS被置於內核模塊,而Nginx工作在用戶態,而且,Nginx相對比較重。另外一點,令人感到非常可惜,這個模塊竟然是個付費功能


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM