轉載自:http://chenlinux.com/2010/03/02/loadbalance-in-nginx-using-url_hash/
nginx是著名的非專職全七層負載均衡器,在用慣了四層LVS后,終於碰上了麻煩:LVS后端的4台RS磁盤都較小(20G),跑不到一天就塞滿了東西;而根據預估,實際上一天時間該節點也就只有20G的文件增長。很顯然,因為lvs轉發的輪詢算法,導致RS重復緩存了相同的文件。
針對這個情況,可以有兩個辦法(我只想到兩個,歡迎大家補充):
- 架構拆分,把不同的幾個域名分別指向不同的server,這個在DNS上就能完成,不過就喪失了lvs的冗余;也可以用nginx的upstream+server配置,分別指向不通的RS,不過不同域名文件數量如果相差比較大的話,RS的負載就不均衡了……
- url_hash,采用HAproxy的loadbalance uri或者nginx的upstream_hash模塊,都可以做到針對url進行哈希算法式的負載均衡轉發。
那么,就開始試試nginx的url_hash負載均衡吧:
安裝部署:
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.01.tar.gz tar zxvf pcre-8.01.tar.gz wget http://wiki.nginx.org/images/7/78/Nginx_upstream_hash-0.3.tar.gz tar zxvf Nginx_upstream_hash-0.3.tar.gz wget http://sysoev.ru/nginx/nginx-0.7.65.tar.gz tar zxvf nginx-0.7.65.tar.gz
vi nginx-0.7.65/src/http/ngx_http_upstream.h
struct ngx_http_upstream_srv_conf_s { ngx_http_upstream_peer_t peer; void **srv_conf; ngx_array_t *servers; /* ngx_http_upstream_server_t */ +ngx_array_t *values; +ngx_array_t *lengths; +ngx_uint_t retries; ngx_uint_t flags; ngx_str_t host; u_char *file_name; ngx_uint_t line; in_port_t port; in_port_t default_port; };
為了安全,可以修改一下nginx的version信息:vi nginx-0.7.65/src/core/nginx.h
#define NGINX_VERSION "2.6.STABLE21" #define NGINX_VER "squid/" NGINX_VERSION
vi nginx-0.7.65/src/http/ngx_http_header_filter_module.c
static char ngx_http_server_string[] = "Server: squid/2.6.STABLE21" CRLF;
vi nginx-0.7.65/src/http/ngx_http_special_response.c
static u_char ngx_http_error_tail[] = "<hr><center>squid/2.6.STABLE21</center>" CRLF "</body>" CRLF "</html>" CRLF
cd pcre-8.01 ./configure --prefix=/usr make && make install cd nginx-0.7.65 ./configure --prefix=/home/nginx --with-pcre --with-http_stub_status_module --with-http_ssl_module --without-http_rewrite_module --add-module=/tmp/nginx_upstream_hash-0.3
vi auto/cc/gcc
# debug #CFLAGS="$CFLAGS -g"
make && make install
這樣就安裝完成了。
2、配置文件
upstream images6.static.com { server 11.11.11.11:80; server 11.11.21.12:80; server 11.11.21.13:80; server 11.11.21.14:80; hash $request_uri; } server { listen 80; server_name images6.static.com; access_log /dev/null main; location / { proxy_pass http://images6.static.com; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
以上配置的問題:
- RS中不能設置nginx本機的其他端口,我本來設定的server 11.11.11.10:3128,希望能把nginx本機也開上squid,省出一台機器來。結果在確認配置了DNS的情況下,返回狀態碼全是503……
- RS一旦有宕機的,nginx不會重算hash,導致部分url返回錯誤信息;而啟用hash_again標簽的話,其他RS就都亂了。
- RS中默認logformat中將顯示nginx的IP。
解決辦法: 1. 不知道 2. 不采用hash_again標簽而采用error_page重定向到專門的備份服務器保障訪問 3. 修改RS的logformat,把%>a改成%{X-Real_IP}>h即可。
最后的根本性問題:
對nginx下的RS集群進行增減操作,是否會對hash表產生影響?nginx_upstream_hash目錄中的CHANGES有如下三條:
Changes with upstream_hash 0.3 06 Aug 2008 *) Bugfix: infinite loop when retrying after a 404 and the "not_found" flag of *_next_upstream was set. *) Change: no more "hash_method" directive. Hash method is always CRC-32. *) Change: failover strategy is compatible with PECL Memcache.
nginx的wiki上,關於hash_again的doc這么寫到:
Number of times to rehash the value and choose a different server if the backend connection fails. Increase this number to provide high availability.
關於PECL Memcache,請參考下列鏈接:
http://www.surfchen.org/archives/348 http://tech.idv2.com/2008/07/24/memcached-004/
尤其是第二個鏈接,其中關於rehash的解釋,很好的解釋了為什么大家都不推薦使用hash_again標簽。 由此可知,upstream_hash模塊,使用的是余數計算standard+CRC32方式,10+2的存活率是17%,3+1的存活率是23%! 而存活率最高的是consistent+CRC32方式,存活率是n/(n+m)*100%,10+2是83%,3+1是75%。
nginx的wiki中,還有另一個3rd模塊upstream_consistent_hash,下回可以試試; 網上還有針對upstream_hash模塊的補丁http://www.sanotes.net/wp-content/uploads/2009/06/nginx_upstream_hash.pdf,好模塊就是有人研究呀~~