Nginx負載均衡問題排查

自從用上了Nginx,簡直愛不釋手,感覺太好用了,堪稱神器。不過最近也遇到了一些麻煩,想用它的負載均衡功能,用ip_hash發現總不能如自己所願,現象有兩種:

  1. 用ip_hash負載轉發,但總是發往其中一台機器

  2. 即使將有請求的那個應用undeploy,還是發往這台機器,頁面404

請求是經過硬體負載過來的,為分析問題,設置nginx access日誌信息如下:

log_format main '$remote_addr - $remote_user [$time_local] "$request" '

'$status $body_bytes_sent "$http_referer" "$http_user_agent" '

Advertisements

' "$X-Real-IP" "$X-Forwarded-For" ';

location / {

// ....

set $realip $proxy_add_x_forwarded_for; # 逗號分割的ip地址

if ( $realip ~ (^[^,]+) ) {

set $realip $1;

}

proxy_set_header X-Forwarded-For $realip;

proxy_set_header X-Real-IP $realip;

發現remote_addr倒是有好幾個,但都是一個網段(前三位相同),看上去是內網的地址;X-Forwarded-For和X-Real-IP是外網地址,都不一樣,看上去是請求的真實ip。查了下ip_hash的官方說明:

Advertisements

The first three octets of the client IPv4 address, or the entire IPv6 address, are used as a hashing key.

前三位相同的ip都屬於一個hash key,發往了一個伺服器。看樣子是取的remote_addr做為ip_hash的ip地址,如果能將realip做為hash的ip地址,就能轉發到不同的伺服器了。查了下,是有辦法讓nginx獲取真實的客戶端ip的, 需要重新編譯下nginx,編譯時帶上 增加--with-http_realip_module 即可。然後在http裡面增加以下內容:

http {

real_ip_header X-Forwarded-For;

set_real_ip_from 0.0.0.0/0;

}

經過如此設置,remote_addr日誌列印出來是實際的ip,請求負載分發也正常了, 同一個ip請求,固定發往同一個伺服器,伺服器不用做session同步也不會有問題。

Nginx負載均衡也有其它方式,如輪詢方式(需要考慮session同步問題), hash $X-Forwarded-For, hash $cookie_jsessionid, 需要upstream_hash第三方模塊,沒有試過。

第二個問題,是因為Nginx認為埠開著,服務就是OK的,如果將整個容器停掉,會轉發到另外一台伺服器,但容器中的其中一個應用儘管掛了,還是會往這上面發,就是報404等錯誤狀態。簡單的解決辦法是讓Nginx在遇到服務返回404,504等錯誤響應時,自動轉發到其它伺服器:

proxy_next_upstream http_404 http_502 http_504 timeout invalid_header error;

這樣效率會低,不過一般問題也不大。好的解決辦法是增加Nginx對後端服務節點的健康檢查。

Advertisements

你可能會喜歡