# 負載均衡
網站發展初期,Nginx 后端往往只代理一臺服務器,但當你的網站名氣大漲訪問的人越來越多一臺服務器實在是頂不住,于是我們就需要多臺服務器,那么多臺服務器又怎么配置代理呢,我們這里以兩臺服務器為案例,為大家做演示。
#### upstream 負載均衡模塊說明
案例:
~~~
upstream test.net{
ip_hash;
server 192.168.10.13:80;
server 192.168.10.14:80 down;
server 192.168.10.15:8009 max_fails=3 fail_timeout=20s;
server 192.168.10.16:8080;
}
server {
location / {
proxy_pass http://test.net;
}
}
~~~
upstream 是 Nginx 的 HTTP Upstream 模塊,這個模塊通過一個簡單的調度算法來實現客戶端 IP 到后端服務器的負載均衡。在上面的設定中,通過 upstream 指令指定了一個負載均衡器的名稱 test.net。這個名稱可以任意指定,在后面需要用到的地方直接調用即可。
#### upstream 支持的負載均衡算法
Nginx的負載均衡模塊目前支持6種調度算法,下面進行分別介紹,其中后兩項屬于第三方調度算法。
- 輪詢(默認)。每個請求按時間順序逐一分配到不同的后端服務器,如果后端某臺服務器宕機,故障系統被自動剔除,使用戶訪問不受影響。Weight 指定輪詢權值,Weight值越大,分配到的訪問機率越高,主要用于后端每個服務器性能不均的情況下。
- ip_hash。每個請求按訪問IP的hash結果分配,這樣來自同一個IP的訪客固定訪問一個后端服務器,有效解決了動態網頁存在的session共享問題。
- fair。這是比上面兩個更加智能的負載均衡算法。此種算法可以依據頁面大小和加載時間長短智能地進行負載均衡,也就是根據后端服務器的響應時間來分配請求,響應時間短的優先分配。Nginx本身是不支持fair的,如果需要使用這種調度算法,必須下載Nginx的upstream_fair模塊。
- url_hash。此方法按訪問url的hash結果來分配請求,使每個url定向到同一個后端服務器,可以進一步提高后端緩存服務器的效率。Nginx本身是不支持url_hash的,如果需要使用這種調度算法,必須安裝Nginx 的hash軟件包。
- least_conn。最少連接負載均衡算法,簡單來說就是每次選擇的后端都是當前最少連接的一個server(這個最少連接不是共享的,是每個worker都有自己的一個數組進行記錄后端server的連接數)。*hash。這個hash模塊又支持兩種模式hash, 一種是普通的hash, 另一種是一致性hash(consistent)。
#### upstream 支持的狀態參數
在HTTP Upstream模塊中,可以通過server指令指定后端服務器的IP地址和端口,同時還可以設定每個后端服務器在負載均衡調度中的狀態。常用的狀態有:
- down,表示當前的server暫時不參與負載均衡。
- backup,預留的備份機器。當其他所有的非backup機器出現故障或者忙的時候,才會請求backup機器,因此這臺機器的壓力最輕。
- max_fails,允許請求失敗的次數,默認為1。當超過最大次數時,返回proxy_next_upstream 模塊定義的錯誤。
- fail_timeout,在經歷了max_fails次失敗后,暫停服務的時間。max_fails可以和fail_timeout一起使用。
*當負載調度算法為ip_hash時,后端服務器在負載均衡調度中的狀態不能是backup。*
#### 配置nginx負載均衡

> Nginx 配置負載均衡
~~~
upstream webservers {
server 192.168.18.201 weight=1;
server 192.168.18.202 weight=1;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://webservers;
proxy_set_header X-Real-IP $remote_addr;
}
}
~~~
注,upstream 是定義在 server{ } 之外的,不能定義在 server{ } 內部。定義好 upstream 之后,用 proxy_pass 引用一下即可。
> 重新加載一下配置文件
~~~
[root@nginx ~]# service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
~~~
~~~
[root@nginx ~]# curl http://192.168.18.208
web1.test.com
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
[root@nginx ~]# curl http://192.168.18.208
web1.test.com
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
~~~
注,大家可以不斷的刷新瀏覽的內容,可以發現web1與web2是交替出現的,達到了負載均衡的效果。
> 查看一下Web訪問服務器日志
Web1:
~~~
[root@web1 ~]# tail /var/log/httpd/access_log
192.168.18.138 - - [04/Sep/2013:09:41:58 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:41:58 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:41:59 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:41:59 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:42:00 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:42:00 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:42:00 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:44:21 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:44:22 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:44:22 +0800] "GET / HTTP/1.0" 200 23 "-"
~~~
Web2:
先修改一下,Web服務器記錄日志的格式。
~~~
[root@web2 ~]# vim /etc/httpd/conf/httpd.conf
LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
[root@web2 ~]# service httpd restart
停止 httpd: [確定]
正在啟動 httpd: [確定]
[root@web2 ~]# tail /var/log/httpd/access_log
192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:50:29 +0800] "GET / HTTP/1.0" 200 23 "-"
192.168.18.138 - - [04/Sep/2013:09:50:29 +0800] "GET / HTTP/1.0" 200 23 "-"
~~~
*注,大家可以看到,兩臺服務器日志都記錄是192.168.18.138訪問的日志,也說明了負載均衡配置成功。*
#### 配置nginx進行健康狀態檢查
max_fails,允許請求失敗的次數,默認為1。當超過最大次數時,返回proxy_next_upstream 模塊定義的錯誤。
fail_timeout,在經歷了max_fails次失敗后,暫停服務的時間。max_fails可以和fail_timeout一起使用,進行健康狀態檢查。
~~~
[root@nginx ~]# vim /etc/nginx/nginx.conf
upstream webservers {
server 192.168.18.201 weight=1 max_fails=2 fail_timeout=2;
server 192.168.18.202 weight=1 max_fails=2 fail_timeout=2;
}
~~~
重新加載一下配置文件:
~~~
[root@nginx ~]# service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新載入 nginx: [確定]
~~~
先停止Web1,進行測試:
~~~
[root@web1 ~]# service httpd stop
停止 httpd: [確定]
~~~
~~~
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
~~~
*注,大家可以看到,現在只能訪問Web2,再重新啟動Web1,再次訪問一下。*
~~~
[root@web1 ~]# service httpd start
正在啟動 httpd: [確定]
~~~
~~~
[root@nginx ~]# curl http://192.168.18.208
web1.test.com
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
[root@nginx ~]# curl http://192.168.18.208
web1.test.com
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
~~~
*注,大家可以看到,現在又可以重新訪問,說明 nginx 的健康狀態查檢配置成功。但大家想一下,如果不幸的是所有服務器都不能提供服務了怎么辦,用戶打開頁面就會出現出錯頁面,那么會帶來用戶體驗的降低,所以我們能不能像配置 LVS 是配置 sorry_server 呢,答案是可以的,但這里不是配置 sorry_server 而是配置 backup。*
#### 配置backup服務器
~~~
[root@nginx ~]# vim /etc/nginx/nginx.conf
server {
listen 8080;
server_name localhost;
root /data/www/errorpage;
index index.html;
}
upstream webservers {
server 192.168.18.201 weight=1 max_fails=2 fail_timeout=2;
server 192.168.18.202 weight=1 max_fails=2 fail_timeout=2;
server 127.0.0.1:8080 backup;
}
[root@nginx ~]# mkdir -pv /data/www/errorpage
[root@nginx errorpage]# cat index.html
Sorry......
~~~
重新加載配置文件:
~~~
[root@nginx errorpage]# service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新載入 nginx: [確定]
~~~
關閉Web服務器并進行測試:
~~~
[root@web1 ~]# service httpd stop
停止 httpd: [確定]
[root@web2 ~]# service httpd stop
停止 httpd: [確定]
~~~
進行測試:
~~~
[root@nginx ~]# curl http://192.168.18.208
Sorry......
[root@nginx ~]# curl http://192.168.18.208
Sorry......
[root@nginx ~]# curl http://192.168.18.208
Sorry......
~~~
*注,大家可以看到,當所有服務器都不能工作時,就會啟動備份服務器。好了,backup服務器就配置到這里,下面我們來配置ip_hash負載均衡。*
#### 配置ip_hash負載均衡
ip_hash,每個請求按訪問IP的hash結果分配,這樣來自同一個IP的訪客固定訪問一個后端服務器,有效解決了動態網頁存在的session共享問題。(一般電子商務網站用的比較多)
~~~
[root@nginx ~]# vim /etc/nginx/nginx.conf
upstream webservers {
ip_hash;
server 192.168.18.201 weight=1 max_fails=2 fail_timeout=2;
server 192.168.18.202 weight=1 max_fails=2 fail_timeout=2;
#server 127.0.0.1:8080 backup;
}
~~~
注,當負載調度算法為ip_hash時,后端服務器在負載均衡調度中的狀態不能有backup。(有人可能會問,為什么呢?大家想啊,如果負載均衡把你分配到backup服務器上,你能訪問到頁面嗎?不能,所以了不能配置backup服務器)
重新加載一下服務器:
~~~
[root@nginx ~]# service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新載入 nginx: [確定]
~~~
測試一下:
~~~
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
[root@nginx ~]# curl http://192.168.18.208
web2.test.com
~~~
注,大家可以看到,你不斷的刷新頁面一直會顯示的民Web2,說明ip_hash負載均衡配置成功。
- 序
- Lua 入門
- Lua簡介
- Lua環境搭建
- 基礎數據類型
- 表達式
- 控制結構
- if/else
- while
- repeat
- for
- break,return
- Lua函數
- 函數的定義
- 函數的參數
- 函數的返回值
- 函數回調
- 模塊
- String庫
- Table庫
- 日期時間函數
- 數學庫函數
- 文件操作
- 元表
- 面向對象編程
- FFI
- 下標從1開始
- 局部變量
- 判斷數組大小
- 非空判斷
- 正則表達式
- 不用標準庫
- 虛變量
- 函數在調用代碼前定義
- 抵制使用module()函數來定義Lua模塊
- 點號與冒號操作符的區別
- Nginx
- Nginx 新手起步
- location 匹配規則
- if 是邪惡的
- 靜態文件服務
- 日志服務
- 反向代理
- 負載均衡
- 陷阱和常見錯誤
- 環境搭建
- Windows平臺
- CentOS平臺
- Ubuntu平臺
- Mac OS X平臺
- Hello World
- 簡單API Server框架
- 獲取Nginx內置綁定變量
- LuaRestyRedisLibrary
- select+set_keepalive組合操作引起的數據讀寫錯誤
- redis接口的二次封裝(簡化建連、拆連等細節)
- redis接口的二次封裝(發布訂閱)
- pipeline壓縮請求數量
- script壓縮復雜請求
- LuaCjsonLibrary
- json解析的異常捕獲
- 稀疏數組
- 空table編碼為array還是object
- 跨平臺的庫選擇
- PostgresNginxModule
- 調用方式簡介
- 不支持事務
- 超時
- 健康監測
- SQL注入
- LuaNginxModule
- 執行階段概念
- 正確的記錄日志
- 熱裝載代碼
- 阻塞操作
- 緩存
- sleep
- 定時任務
- 禁止某些終端訪問
- 請求返回后繼續執行
- 調試
- 調用其他C函數動態庫
- 我的lua代碼需要調優么
- 變量的共享范圍
- 動態限速
- shared.dict 非隊列性質
- 如何添加自己的lua api
- 正確使用長鏈接
- 如何引用第三方resty庫
- 典型應用場景
- LuaRestyDNSLibrary
- 使用動態DNS來完成HTTP請求
- 緩存失效風暴
- 測試
- 單元測試
- API測試
- 性能測試
- 持續集成
- 灰度發布
- Web 服務
- API的設計
- 數據合法性檢測
- 協議無痛升級
- 代碼規范
- 連接池
- C10K編程
- TIME_WAIT問題
- 與Docker使用的網絡瓶頸
- 火焰圖
- 什么時候使用
- 顯示的是什么
- 如何安裝火焰圖生成工具
- 如何定位問題
- 開源文化對360企業安全的影響