Nginx是一款HTTP和反向代理服務器,有關它的介紹可以到網上搜一下,很多很多,不再累述。這裏,我們記錄一下Nginx的安裝過程,以及如何配置Nginx來實現Tomcat集羣的負載均衡。
基本思路
假如現在我們有一個使用Java實現的Web搜索服務器,用戶可以通過Web頁面輸入關鍵詞,搜索服務器處理搜索請求並向用戶展示搜索結果。如果用戶訪問量很大的話,我們的這臺搜索服務器承受的壓力會很大,很可能由於搜索服務器的處理能力達到上限,在某一個時刻無法再處理用戶新到來的請求。所以,我們就考慮將用戶請求的壓力分散開,即在多臺服務器上部署同一套搜索服務器程序,然後通過一個負載均衡策略,將請求的壓力分攤在多臺搜索服務器上,這樣,在用戶請求量很大的情況下,很好解決單臺服務器的無法處理請求的問題。
我們的想法就是,通過一臺服務器做代理,使用負載均衡軟件實現請求的代理轉發,將用戶的請求轉發到多臺搜索服務器上去處理,就能實現多臺搜索服務器的負載均衡,而不致於單一服務器處理所有請求。
假設,我們現在有三臺機器,各臺服務器如下所示:
搜索服務器:192.168.0.174 RHEL 5
搜索服務器:192.168.0.181 Win 7
代理服務器:192.168.0.184 Ubuntu 11.04.1
通過使用Nginx做反向代理,安裝在192.168.0.184上。另外兩臺服務器均爲搜索服務器,並且都安裝了Tomcat Web服務器軟件,搜索服務器程序就部署在Tomcat中。服務器192.168.0.184接收搜索請求,並通過Nginx將請求轉發到兩臺搜索服務器上進行處理,然後返回結果,通過Nginx代理響應的搜索結果。
配置資源
這裏,說明一下我們各臺服務器的軟件配置,及其應用端口,如下所示:
服務器IP:端口 |
軟件配置 |
192.168.0.174:8080 | OpenJDK 1.6.0_22, apache-tomcat-7.0.22.tar |
192.168.0.181:8080 | Sun JDK 1.6.0_17, apache-tomcat-6.0.20.exe |
192.168.0.184:8888 | nginx-1.0.8.targz, pcre-8.13.tar.gz |
安裝配置過程
-
Nginx安裝
下載nginx-1.0.8.targz, pcre-8.13.tar.gz這兩個安裝包,並解壓縮到目錄/home/shirdrn/tools下面,然後安裝過程如下所示:
cd /home/shirdrn/tools
tar -xvf pcre-8.13.tar.bz2
tar -xzvf nginx-1.0.8.tar.gz
cd /home/shirdrn/tools/nginx-1.0.8
./configure --with-http_stub_status_module --prefix=/home/shirdrn/servers/nginx --with-pcre=/home/shirdrn/tools/pcre-8.13
make
make install
執行上述命令,需要使用超級用戶權限,將我們的Nginx安裝到/home/shirdrn/servers/nginx-1.0.8下面,由於指定了--with-pcre=/home/shirdrn/tools/pcre-8.13,即pcre的源碼路徑,在安裝的過程首先編譯pcre並安裝,然後纔開始配置安裝Nginx。
驗證是否安裝成功,只需要在瀏覽器輸入http://192.168.0.184:8888/即可,默認Nginx使用80端口,這裏我的80端口被佔用了,所以修改爲8888(有關Nginx的基本配置在下面說明)。
-
Ngin負載均衡配置
下面,我們看一下我們實現Nginx負載均衡的配置。配置文件爲conf/nginx.conf,由於我們進行的代理的配置,通過使用一個單獨的代理配置文件conf/proxy.conf,在conf/nginx.conf中引入該代理配置即可。
conf/proxy.conf的配置內容如下所示:
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
各配置項的含義,可以通過查閱相關文檔瞭解。下面看conf/nginx.conf的配置,我們根據實踐操作所做的修改,並對相關基本配來做適當的說明,如下所示:
user root root; # Nginx所在的用戶和用戶組
worker_processes 3; # 啓動的工作進程數量
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid logs/nginx.pid; # Nginx進程ID
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream localhost { # 發到localhost上的請求,通過Nginx轉發到實際處理請求的服務器
server 192.168.0.181:8080 weight=1;
server 192.168.0.184:8080 weight=1;
}
server {
listen 8888; # Nginx監聽的端口,默認爲80
server_name localhost; # Nginx所在主機的名稱
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html/solr; # 請求資源的路徑(代理:/home/shirdrn/servers/nginx/tml/solr/,該目錄下沒有任何數據)
index index.html index.htm;
proxy_pass http://localhost; # 代理:對發送到localhost上請求進行代理
include proxy.conf; # 引入proxy.conf配置
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443;
# server_name localhost;
# ssl on;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_timeout 5m;
# ssl_protocols SSLv2 SSLv3 TLSv1;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
-
啓動Nginx
啓動Nginx比較簡單,有兩種方式:一種是直接使用默認安裝路徑下的nginx.conf,啓動命令如下所示:
/home/shirdrn/servers/nginx-1.0.8/sbin/nginx
另一種是,nginx.conf配置可以放到其他目錄下面,啓動時通過-c選項指定配置文件路徑即可,啓動命令如下所示:
/home/shirdrn/servers/nginx-1.0.8/sbin/nginx -c /home/shirdrn/servers/nginx-1.0.8/conf/nginx.conf
可以查看啓動進程:
root@dev2:~$ ps -ef | grep nginx
root 15952 1 0 18:56 ? 00:00:00 nginx: master process sbin/nginx
root 15953 15952 0 18:56 ? 00:00:00 nginx: worker process
root 15954 15952 0 18:56 ? 00:00:00 nginx: worker process
root 15955 15952 0 18:56 ? 00:00:00 nginx: worker process
ubuntu 22988 22887 0 22:19 pts/0 00:00:00 grep --color=auto nginx
查看Nginx監聽的端口號:
root@dev2:/home/ubuntu# netstat -nap | grep '8888'
tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN 15952/nginx
-
Tomcat配置
無論在Windows下還是Linux下,Tomcat的配置無需做額外的配置,只要能夠發佈你的Web應用即可。但是,我們通過Nginx進行反向代理請求,必須保證多個Tomcat下的Web應用的請求路徑相一致,例如,我們配置的兩臺搜索服務器的單獨請求路徑,分別如下所示:
http://192.168.0.174:8080/solr/core0/search/?q=九寨溝&start=0&rows=10
http://192.168.0.181:8080/solr/core0/search/?q=馬爾代夫&start=0&rows=10
我們將我們的搜索服務器程序,分別發佈到這兩臺搜索服務器的Tomcat上,可以通過實際接口進行單獨接收請求並處理。
測試驗證
下面,來測試一下,驗證我們上述配置的內容,是否能夠按照開始設計的思路,實現負載均衡。由於在Nginx的配置中,我們設置了兩臺搜索服務器處理請求的權重爲1:1,所以在測試的過程中很容易就能看到。由於所有的請求都是先到達代理服務器,通過代理服務器進行轉發,所以對外部只有一個統一的接口:
http://192.168.0.184:8888/solr/core0/search/?q=普吉島&start=0&rows=10
根據代理配置,代理服務器只是轉發請求和相應,而不做請求的處理等工作,所以負荷會小一些。通過負載分攤,兩個搜索服務器的負荷也會比單臺的情況下有所好轉。上面代理的請求鏈接,實際會轉換爲如下兩者之一:
http://192.168.0.174:8080/solr/core0/search/?q=普吉島&start=0&rows=10
http://192.168.0.181:8080/solr/core0/search/?q=普吉島&start=0&rows=10
我們看一下,各臺服務器實際執行時的日誌記錄。如下4個請求:
http://192.168.0.184:8888/solr/core0/search/?q=九寨溝&start=0&rows=10
http://192.168.0.184:8888/solr/core0/search/?q=普吉島&start=0&rows=10
http://192.168.0.184:8888/solr/core0/search/?q=馬爾代夫&start=0&rows=10
http://192.168.0.184:8888/solr/core0/search/?q=西雙版納&start=0&rows=10
Nginx日誌,如下所示:
192.168.0.181 - - [05/Oct/2011:21:42:05 +0800] "GET /solr/core0/search/?q=九寨溝&start=0&rows=10 HTTP/1.1" 200 329495 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30"
192.168.0.181 - - [05/Oct/2011:21:42:12 +0800] "GET /solr/core0/search/?q=普吉島&start=0&rows=10 HTTP/1.1" 200 110349 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30"
192.168.0.181 - - [05/Oct/2011:21:42:25 +0800] "GET /solr/core0/search/?q=馬爾代夫&start=0&rows=10 HTTP/1.1" 200 85572 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30"
192.168.0.181 - - [05/Oct/2011:21:42:32 +0800] "GET /solr/core0/search/?q=西雙版納&start=0&rows=10 HTTP/1.1" 200 141030 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30"
我們看一下,各臺搜索服務器接收請求處理的日誌:
搜索服務器192.168.0.174請求處理日誌:
2011-10-5 21:42:12 org.apache.solr.core.SolrCore execute
信息: [core0] webapp=/solr path=/search/ params={bq=spiderName:baseSeSpider^1.5&start=0&q=普吉島&rows=10} hits=16 status=0 QTime=48
2011-10-5 21:42:32 org.apache.solr.core.SolrCore execute
信息: [core0] webapp=/solr path=/search/ params={bq=spiderName:baseSeSpider^1.5&start=0&q=西雙版納&rows=10} hits=29 status=0 QTime=54
搜索服務器192.168.0.181請求處理日誌:
2011-10-5 21:42:06 com.chenlb.mmseg4j.solr.MMSegTokenizerFactory newSeg
信息: create new Seg ...
2011-10-5 21:42:06 com.chenlb.mmseg4j.solr.MMSegTokenizerFactory newSeg
信息: use complex mode
2011-10-5 21:42:08 com.chenlb.mmseg4j.solr.MMSegTokenizerFactory newSeg
信息: create new Seg ...
2011-10-5 21:42:08 com.chenlb.mmseg4j.solr.MMSegTokenizerFactory newSeg
信息: use complex mode
2011-10-5 21:42:08 org.apache.solr.core.SolrCore execute
信息: [core0] webapp=/solr path=/search/ params={bq=spiderName:baseSeSpider^1.5&start=0&q=九寨溝0&rows=10} hits=54 status=0 QTime=2116
2011-10-5 21:42:27 com.chenlb.mmseg4j.solr.MMSegTokenizerFactory newSeg
信息: create new Seg ...
2011-10-5 21:42:27 com.chenlb.mmseg4j.solr.MMSegTokenizerFactory newSeg
信息: use complex mode
2011-10-5 21:42:28 com.chenlb.mmseg4j.solr.MMSegTokenizerFactory newSeg
信息: create new Seg ...
2011-10-5 21:42:28 com.chenlb.mmseg4j.solr.MMSegTokenizerFactory newSeg
信息: use complex mode
2011-10-5 21:42:29 org.apache.solr.core.SolrCore execute
信息: [core0] webapp=/solr path=/search/ params={bq=spiderName:baseSeSpider^1.5&start=0&q=馬爾代夫0&rows=10} hits=57 status=0 QTime=1721
測試發現,雖然只有4個請求,但是在負載權重相等情況下,很好地分攤到兩臺搜索服務器上去進行請求的實際處理。通過上面日誌可以看出,我們基本實現了一開始設計的思路。