使用Nginx、Keepalived構(gòu)建文藝負載均衡
原創(chuàng)【51CTO獨家特稿】面對網(wǎng)站服務(wù)器端負載增大的問題,是“拿15萬¥買一臺服務(wù)器”來解決,還是靠“加三倍服務(wù)器”來解決?還是用其它一些辦法?
對于一個訪問量日益增加的網(wǎng)站架構(gòu)而言,從單機到集群、從集群到分布式,架構(gòu)演化是必然的。
接手環(huán)境,分析瓶頸,擴展架構(gòu)
筆者現(xiàn)在的環(huán)境在剛接手時算是單機LAMP環(huán)境。在單機LAMP環(huán)境時,由于訪問量逐漸變大,網(wǎng)站會經(jīng)常出現(xiàn)打不開的情況,為了解決這個問題在LAMP前端臨時加了一臺vanish來緩存一些靜態(tài)文件,從而減輕了web服務(wù)器的負載。再到后來為了滿足業(yè)務(wù)訪問需求,將架構(gòu)改為CDN+Nginx負載均衡(反向代理)+LNMP+代碼層緩存+MySQL主從,從而將網(wǎng)站整體負載性能提升15倍,且訪問速度也得到很大提升。
負載均衡為什么要選擇使用Nginx呢?
普通負載均衡用LVS,文藝負載均衡用Nginx/F5/HAproxy,XX負載均衡用NLB
LVS:四層負載均衡的典型代表,目前已經(jīng)被添加到linux發(fā)行版的內(nèi)核。LVS用于較為成熟,因此不再做類述,在此推薦一篇不錯的LVS文章:《互聯(lián)網(wǎng)運營智慧》第六章負載均衡及服務(wù)器集群(LVS)。
Nginx/F5/HAproxy:均為七層負載均衡,F(xiàn)5為商業(yè)設(shè)備,功能強大,但價格不菲,所以在此不做討論;HAproxy為重量級的七層負載均衡/反向代理程序,一般應(yīng)用于大中型站點;而Nginx雖然屬于輕量級產(chǎn)品,但是功能毫不遜色與HAproxy,如可以對靜態(tài)文件可以實現(xiàn)緩存、可以通過URL、目錄結(jié)構(gòu)、靜動分離對網(wǎng)站實現(xiàn)分流,還可以實現(xiàn)對后端服務(wù)器狀態(tài)碼健康檢測、對網(wǎng)絡(luò)依賴較小、對虛擬主機支持友好等等,這也是筆者選擇Nginx來做負載均衡的原因。
NLB:windows下的東東,性能、可操作性可想而知。在此也提醒一下各位同仁,針對HTTP類的應(yīng)用千萬不要選擇使用windows,如同樣的業(yè)務(wù)放linux上只需兩臺服務(wù)器,而放windows上可能會需要三臺甚至更多,運維/硬件采購成本也會增加,同時license也是一筆不小的費用。國內(nèi)較大的一些web站點后端架構(gòu)為windows的分別有京東商城、當當網(wǎng)、凡客誠品、麥包包。
使用Nginx構(gòu)建負載均衡時需要注意的幾個問題
Session同步:由于筆者所維護的架構(gòu)硬件預(yù)算受限,所以在整個架構(gòu)中沒有共享存儲,針對于session處理,筆者使用ip_hash來解決后端服務(wù)器session問題。另外,關(guān)于存儲session,推薦使用redis或memcached(感謝小衛(wèi)、小灰狼 兩位兄弟的建議)。
網(wǎng)站代碼存儲:還是由于沒有共享存儲,所以筆者每臺web服務(wù)器本地均存放一份代碼,為了保證多臺web服務(wù)器的代碼數(shù)據(jù)一致性,使用rsync+inotify實現(xiàn)動態(tài)同步(具體實現(xiàn)方法會在后面的文章中介紹)。倘若硬件條件允許的情況下,推薦使用NFS來存儲;若考慮到NFS無法滿足性能需求,可以將NFS的硬盤換成SSD或者使用分布式文件系統(tǒng)來解決。
負載均衡模式選擇:在不受session困擾的情況下,負載均衡模式可以使用weight,因為ip_hash會有導(dǎo)致后端服務(wù)器負載不均的情況出現(xiàn)。
開始部署Nginx和Keepalived
為了避免負載均衡出現(xiàn)單點故障,所以使用keepalived對Nginx負載均衡做了HA,也就是說當主負載均衡發(fā)生軟硬件故障時,負載均衡服務(wù)將有備用負載均衡服務(wù)器自動接管服務(wù),環(huán)境拓撲如下:
Vip:192.168.1.100
Nginx-proxy-master:192.168.1.101
Nginx-proxy-backup:192.168.1.102
安裝Nginx與Keepalived
在Nginx-proxy-master和Nginx-proxy-backup上分別安裝Nginx、Keepalived,兩臺主機安裝步驟相同
安裝Nginx
#yum -y install pcre pcre-devel #useradd www -s /sbin/nologin #tar zxvf nginx-0.7.62.tar.gz #cd nginx-0.7.62 #./configure \ --prefix=/usr/local/nginx \ --user=www \ --group=www \ --with-http_stub_status_module \ --with-http_ssl_module #make && make install
安裝Keepalived
#tar zxvf keepalived-1.1.17.tar.gz #cd cd keepalived-1.1.17 #./configure --prefix=/usr/local/keepalived #make && make install #rm -rf /usr/local/keepalived/etc/keepalived/keepalived.conf #mkdir /etc/keepalived
配置Nginx
注:Nginx-proxy-master和Nginx-proxy-backup的Nginx配置相同
#more /usr/local/nginx/conf/nginx.conf user www www; worker_processes 4; error_log logs/error.log crit; pid logs/nginx.pid; worker_rlimit_nofile 51200; events { use epoll; worker_connections 51200; } http { include mime.types; default_type application/octet-stream; server_names_hash_bucket_size 256; client_header_buffer_size 256k; large_client_header_buffers 4 256k; keepalive_timeout 120; client_max_body_size 50m; client_body_buffer_size 256k; server_tokens off; gzip on; gzip_min_length 1k; gzip_buffers 4 1024k; gzip_http_version 1.1; gzip_comp_level 6; gzip_types text/plain application/x-javascript text/css application/xml; #gzip_vary on; proxy_hide_header Vary; proxy_connect_timeout 600; proxy_read_timeout 600; proxy_send_timeout 600; proxy_buffer_size 16k; proxy_buffers 4 64k; proxy_busy_buffers_size 128k; proxy_temp_file_write_size 128k; sendfile on; tcp_nodelay on; # add_header Cache-Control no-cache; upstream blog.luwenju.com { ip_hash; server 192.168.1.201:80; server 192.168.1.202:80; server 192.168.1.203:80; } server { listen 80; server_name blog.luwenju.com; location / { index index.php; proxy_pass http://blog.luwenju.com; proxy_set_header Host $host; proxy_next_upstream error timeout invalid_header http_500 http_502 http_504; proxy_set_header X-Forwarded-For $remote_addr; } location /NginxStatus { stub_status on; allow 192.168.1.0/24; } log_format blog.luwenju.com '$remote_addr - $remote_user [$time_local] $upstream_addr $upstream_status $request' '"$status" $body_bytes_sent "$http_referer"' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /usr/local/nginx/logs/blog.luwenju.com_access.log blog.luwenju.com; } }
說明:upstream為服務(wù)器池。以本配置文件為例,upstream中共包含三臺web服務(wù)器,負載均衡方式為ip_hash。server為主機,用于為upstream內(nèi)的三臺web服務(wù)器實現(xiàn)反向代理,從而到達負載均衡的目的。在本配置文件中只設(shè)置了一個主機(server),如果要實現(xiàn)虛擬主機,將一個server分別對應(yīng)一個upstream即可。
另外,還有兩個關(guān)于日志設(shè)置的問題:
負載均衡上是否需要開啟access_log:系統(tǒng)/程序剛上線時需要開啟,用于Nginx調(diào)試,后期運行穩(wěn)定后建議將日志打印關(guān)閉,因為對于訪問量較大的網(wǎng)站來說大量日志寫入磁盤也會導(dǎo)致磁盤性能下降。
如何設(shè)置日志格式:可能使用Nginx部署過負載均衡的朋友都知道,當把Nginx反向代理服務(wù)器部署在web前端時,web服務(wù)器的access_log就無法獲取用戶的真實ip地址了,針對這個問題的解決辦法會放到后面的文章中<Nginx日志設(shè)置及日志分析>
在Nginx-proxy-master服務(wù)器上配置Keepalived
#more /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { router_id nginx-proxy-ha } vrrp_script check_nginx { script "/etc/keepalived/check_nginx.sh" interval 2 weight 2 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 200 advert_int 1 authentication { auth_type PASS auth_pass 1234 } track_interface { eth0 } track_script { check_nginx } virtual_ipaddress { 192.168.1.100 } }
有關(guān)check_nginx.sh的說明:如果Nginx-proxy-master上的nginx進程由于某種原因停止了,但是keepalived進程還正常運行著,這時候Nginx-proxy-backup上的keepalived會認為Nginx-proxy-master是正常的(因為master檢測到backup的keepalived進程還存在),所以在這種情況下當Nginx進程死亡的時候Keepalived也不會發(fā)生故障轉(zhuǎn)移。那么這個腳本的作用就是讓keepalived實時監(jiān)控Nginx進程,當發(fā)現(xiàn)Nginx進程不存在的時候自動將本機的keepalived進程殺死,從而實現(xiàn)故障轉(zhuǎn)移,腳本內(nèi)容如下(注:Nginx-proxy-master和Nginx-proxy-backup上此腳本內(nèi)容均一樣)
#more /etc/keepalived/check_nginx.sh #!/bin/bash if [ "$(ps -ef | grep "nginx: master process"| grep -v grep )" == "" ] then killall -9 keepalived fi
在Nginx-proxy-backup服務(wù)器上配置Keepalived
注:Nginx-proxy-backup上keepalived的配置與Nnginx-proxy-master只有兩處不同,state為BACKUP、優(yōu)先級低于master
#more /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { router_id nginx-proxy-ha } vrrp_script check_nginx { script "/etc/keepalived/check_nginx.sh" interval 2 weight 2 } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 180 advert_int 1 authentication { auth_type PASS auth_pass 1234 } track_interface { eth0 } track_script { check_nginx } virtual_ipaddress { 192.168.1.100 } }
啟動Nginx和Keepalived
#/usr/local/nginx/sbin/nginx #/usr/local/keepalived/sbin/keepalived –D #echo “/usr/local/nginx/sbin/nginx”>>/etc/rc.local #echo “/usr/local/keepalived/sbin/keepalived –D” >>/etc/rc.local
測試負載均衡是否正常工作
1、打開瀏覽器,分別訪問Nginx-proxy-master、Nginx-proxy-backup、vip,如都能訪問到后端web內(nèi)容,則說明如上所有配置正確
2、殺死Nginx-proxy-master服務(wù)器上的Nginx進程,觀察keepalived進程是否自動消失、觀察vip是否已經(jīng)轉(zhuǎn)移到了Nginx-proxy-backup服務(wù)器上,如殺死Nginx進程后,keepalived進程也隨之消失,且vip已經(jīng)轉(zhuǎn)移到Nginx-proxy-backup服務(wù)器,則說明Nginx-proxy-master可正常實現(xiàn)故障轉(zhuǎn)移
3、依次啟動 Nginx-proxy-master的Nginx、Keepalived(必須先啟動Nginx后啟動Keepalived。如果先啟動Keepalived,Keepalived檢測到Nginx沒有啟動還是會執(zhí)行殺死自己進程的腳本),然后將Nginx-proxy-backup的Nginx進程殺死,看vip是否會自動轉(zhuǎn)移到Nginx-proxy-master服務(wù)器上,如殺死Nginx進程后,keepalived進程也隨之消失,且vip已經(jīng)轉(zhuǎn)移到Nginx-proxy-master服務(wù)器,則說明Nginx-proxy-backup可正常實現(xiàn)故障轉(zhuǎn)移
至此,Nginx負載均衡配置完畢。另外,Nginx非常穩(wěn)定,筆者的Nginx負載均衡運行在HP DL380服務(wù)器上(一顆至強E5620CPU,16G內(nèi)存,萬轉(zhuǎn)SAS硬盤),運行四個月以來,從未出現(xiàn)過任何問題。在負載性能上,2000并發(fā)情況下load average:僅為0.02, 0.01, 0.00,CPU使用率僅為3%,內(nèi)存使用為1G(算上linux系統(tǒng)本身使用,系統(tǒng)為64bit)。
作者簡介:陸文舉(微博),85后,一個整天跟機器打交道的山東人。