聲明:以下僅為個(gè)人的一些總結(jié)和隨寫,如有不對(duì)之處,還請(qǐng)看到的網(wǎng)友指出,以免誤導(dǎo)。 (詳細(xì)的配置方案請(qǐng)google,這里只說解決方案。)
1、熟悉幾個(gè)組件
1.1、apache
—— 它是Apache軟件基金會(huì)的一個(gè)開放源代碼的跨平臺(tái)的網(wǎng)頁服務(wù)器,屬于老牌的web服務(wù)器了,支持基于Ip或者域名的虛擬主機(jī),支持代理服務(wù)器,支持安全Socket層(SSL)等等,目前互聯(lián)網(wǎng)主要使用它做靜態(tài)資源服務(wù)器,也可以做代理服務(wù)器轉(zhuǎn)發(fā)請(qǐng)求(如:圖片鏈等),結(jié)合tomcat等servlet容器處理jsp。
1.2、ngnix
—— 俄羅斯人開發(fā)的一個(gè)高性能的 HTTP和反向代理服務(wù)器。由于Nginx 超越 Apache 的高性能和穩(wěn)定性,使得國(guó)內(nèi)使用 Nginx 作為 Web 服務(wù)器的網(wǎng)站也越來越多,其中包括新浪博客、新浪播客、網(wǎng)易新聞、騰訊網(wǎng)、搜狐博客等門戶網(wǎng)站頻道等,在3w以上的高并發(fā)環(huán)境下,ngnix處理能力相當(dāng)于apache的10倍。
參考:apache和tomcat的性能分析和對(duì)比(http://blog.s135.com/nginx_php_v6/)
1.3、lvs
——
Linux Virtual Server的簡(jiǎn)寫,意即
linux虛擬服務(wù)器,是一個(gè)虛擬的服務(wù)器集群系統(tǒng)。由畢業(yè)于國(guó)防科技大學(xué)的章文嵩博士于1998年5月創(chuàng)立,可以實(shí)現(xiàn)LINUX平臺(tái)下的簡(jiǎn)單負(fù)載均衡。了解更多,訪問官網(wǎng):http://zh.linuxvirtualserver.org/。
1.4、HAProxy
—— HAProxy提供高可用性、負(fù)載均衡以及基于TCP和HTTP應(yīng)用的代理,支持虛擬主機(jī),它是免費(fèi)、快速并且可靠的一種解決方案。HAProxy特別適用于那些負(fù)載特大的web站點(diǎn), 這些站點(diǎn)通常又需要會(huì)話保持或七層處理。HAProxy運(yùn)行在當(dāng)前的硬件上,完全可以支持?jǐn)?shù)以萬計(jì)的并發(fā)連接。并且它的運(yùn)行模式使得它可以很簡(jiǎn)單安全的整合進(jìn)您當(dāng)前的
架構(gòu)中, 同時(shí)可以保護(hù)你的web服務(wù)器不被暴露到網(wǎng)絡(luò)上.
1.5、keepalived
—— 這里說的keepalived不是apache或者tomcat等某個(gè)組件上的屬性字段,它也是一個(gè)組件,可以實(shí)現(xiàn)web服務(wù)器的高可用(HA high availably)。它可以檢測(cè)web服務(wù)器的工作狀態(tài),如果該服務(wù)器出現(xiàn)故障被檢測(cè)到,將其剔除服務(wù)器群中,直至正常工作后,keepalive會(huì)自動(dòng)檢測(cè)到并加入到服務(wù)器群里面。實(shí)現(xiàn)主備服務(wù)器發(fā)生故障時(shí)ip瞬時(shí)無縫交接。它是LVS集群節(jié)點(diǎn)健康檢測(cè)的一個(gè)用戶空間守護(hù)進(jìn)程,也是LVS的引導(dǎo)故障轉(zhuǎn)移模塊(director failover)。Keepalived守護(hù)進(jìn)程可以檢查L(zhǎng)VS池的狀態(tài)。如果LVS服務(wù)器池當(dāng)中的某一個(gè)服務(wù)器宕機(jī)了。keepalived會(huì)通過一 個(gè)setsockopt呼叫通知內(nèi)核將這個(gè)節(jié)點(diǎn)從LVS拓?fù)鋱D中移除。
1.6、memcached
—— 它是一個(gè)高性能分布式內(nèi)存對(duì)象緩存系統(tǒng)。當(dāng)初是Danga Interactive為了LiveJournal快速發(fā)展開發(fā)的系統(tǒng),用于對(duì)業(yè)務(wù)查詢數(shù)據(jù)緩存,減輕
數(shù)據(jù)庫的負(fù)載。其守護(hù)進(jìn)程(daemon)是用C寫的,但是客戶端支持幾乎所有語言(客戶端基本上有3種版本[memcache client for
Java;spymemcached;xMecache]),服務(wù)端和客戶端通過簡(jiǎn)單的協(xié)議通信;在memcached里面緩存的數(shù)據(jù)必須序列化。
1.7、terracotta
—— 是一款由美國(guó)Terracotta公司開發(fā)的著名開源Java集群平臺(tái)。它在JVM與Java應(yīng)用之間實(shí)現(xiàn)了一個(gè)專門處理集群功能的抽象層,允許用戶在不改變系統(tǒng)代碼的情況下實(shí)現(xiàn)java應(yīng)用的集群。支持?jǐn)?shù)據(jù)的持久化、session的復(fù)制以及高可用(HA)。詳細(xì)參考:http://topmanopensource.iteye.com/blog/1911679
2、關(guān)鍵術(shù)語
2.1、負(fù)載均衡(load balance)
在互聯(lián)網(wǎng)高速發(fā)展的時(shí)代,
大數(shù)據(jù)量、高并發(fā)等是互聯(lián)網(wǎng)網(wǎng)站提及最多的。如何處理高并發(fā)帶來的系統(tǒng)性能問題,最終大家都會(huì)使用負(fù)載均衡機(jī)制。它是根據(jù)某種負(fù)載策略把請(qǐng)求分發(fā)到集群中的每一臺(tái)服務(wù)器上,讓整個(gè)服務(wù)器群來處理網(wǎng)站的請(qǐng)求。
公司比較有錢的,可以購買專門負(fù)責(zé)負(fù)載均衡的硬件(如:F5),效果肯定會(huì)很好。對(duì)于大部分公司,會(huì)選擇廉價(jià)有效的方法擴(kuò)展整個(gè)系統(tǒng)的架構(gòu),來增加服務(wù)器的吞吐量和處理能力,以及承載能力。
2.2、集群(Cluster)
用N臺(tái)服務(wù)器構(gòu)成一個(gè)松耦合的多處理器系統(tǒng)(對(duì)外來說,他們就是一個(gè)服務(wù)器),它們之間通過網(wǎng)絡(luò)實(shí)現(xiàn)通信。讓N臺(tái)服務(wù)器之間相互協(xié)作,共同承載一個(gè)網(wǎng)站的請(qǐng)求壓力。
2.3、高可用(HA)
在集群服務(wù)器架構(gòu)中,當(dāng)主服務(wù)器故障時(shí),備份服務(wù)器能夠自動(dòng)接管主服務(wù)器的工作,并及時(shí)切換過去,以實(shí)現(xiàn)對(duì)用戶的不間斷服務(wù)。ps:這里我感覺它跟故障轉(zhuǎn)移(failover)是一個(gè)意思,看到的網(wǎng)友給個(gè)解釋,謝謝?
2.4、session復(fù)制/共享
在訪問系統(tǒng)的會(huì)話過程中,用戶登錄系統(tǒng)后,不管訪問系統(tǒng)的任何資源地址都不需要重復(fù)登錄,這里面servlet容易保存了該用戶的會(huì)話(session)。如果兩個(gè)tomcat(A、B)提供集群服務(wù)時(shí)候,用戶在A-tomcat上登錄,接下來的請(qǐng)求web服務(wù)器根據(jù)策略分發(fā)到B-tomcat,因?yàn)锽-tomcat沒有保存用戶的會(huì)話(session)信息,不知道其登錄,會(huì)跳轉(zhuǎn)到登錄界面。
這時(shí)候我們需要讓B-tomcat也保存有A-tomcat的會(huì)話,我們可以使用tomcat的session復(fù)制實(shí)現(xiàn)或者通過其他手段讓session共享。
3、常用web集群
3.1、tomcat集群方案
apache+tomcat;ngnix+tomcat;lvs+ngnix+tomcat;大家比較熟悉的是前兩種。(lvs負(fù)責(zé)集群調(diào)度,nginx負(fù)責(zé)靜態(tài)文件處理,tomcat負(fù)責(zé)動(dòng)態(tài)文件處理[最優(yōu)選擇])。 以apache+tomcat集群為例,簡(jiǎn)單說一下:
1、他們之間的通信有三種方式:ajp_proxy、mod_jk鏈接器、http_proxy。具體參考:http://www.ibm.com/developerworks/cn/opensource/os-lo-apache-tomcat/
2、apache的分發(fā)策略有4種。權(quán)重(默認(rèn))、流量(bytraffic)、請(qǐng)求次數(shù)(byRequests)、繁忙程度(byBusyness根據(jù)活躍請(qǐng)求數(shù)的多少)
3、apache支持stickysession(粘性session),即為:訪問用戶訪問了A-tomcat,那么他的所有請(qǐng)求都會(huì)轉(zhuǎn)發(fā)到A-tomcat,而不會(huì)到B-tomcat。[這樣的負(fù)載均衡效果不好,適用于小型網(wǎng)站,下面說非粘性session]
4、它們之間的架構(gòu)如圖1:
問題1:只有一個(gè)web服務(wù)器,明顯的單點(diǎn)故障。如果該apache出現(xiàn)問題,整個(gè)網(wǎng)站就會(huì)癱瘓。
3.2、session復(fù)制
如果不采用stickysession(粘性session),那么我們可以采用tomcat的session復(fù)制使所有節(jié)點(diǎn)tomcat的會(huì)話相同,tomcat使用組播技術(shù),只要集群中一個(gè)tomcat節(jié)點(diǎn)的session發(fā)生改變,會(huì)廣播通知所有tomcat節(jié)點(diǎn)發(fā)生改變。
問題2:據(jù)網(wǎng)友
測(cè)試,當(dāng)tomcat節(jié)點(diǎn)數(shù)達(dá)到4個(gè)以上時(shí)候,集群性能呈線性下滑;另外當(dāng)用戶訪問量大到一定程度,會(huì)話內(nèi)容隨之增多,tomcat節(jié)點(diǎn)相互之間通信產(chǎn)生大量的網(wǎng)絡(luò)消耗,產(chǎn)生網(wǎng)絡(luò)阻塞,整個(gè)集群的吞吐量不能再上升。
4、高可用(HA)和session共享(解決上面提到的兩個(gè)問題)
4.1、使用lvs+keepalive實(shí)現(xiàn)集群高可用,達(dá)到更健壯的LB
我們可以做前端使用lvs來做負(fù)載均衡,根據(jù)lvs的8種調(diào)度
算法(可設(shè)置),分發(fā)請(qǐng)求到對(duì)應(yīng)的web服務(wù)器集群上。lvs做雙機(jī)熱備,通過keepalived模塊能夠達(dá)到故障自動(dòng)轉(zhuǎn)移到備份服務(wù)器,不間斷提供服務(wù),結(jié)構(gòu)如圖2:
說明:據(jù)查詢了解,一般在WEB端使用的負(fù)載均衡比較多的是HAProxy+keepalived+nginx;數(shù)據(jù)庫
MySQL集群使用Lvs+keepalived+
mysql實(shí)現(xiàn)。因?yàn)镠AProxy和nginx一樣是工作在網(wǎng)絡(luò)7層之上,并且前者彌補(bǔ)了nginx的一些缺點(diǎn)如session的保持,cookie的引導(dǎo)等,且它本身是個(gè)負(fù)責(zé)均衡軟件,處理負(fù)載均衡上面必然優(yōu)于nginx;lvs比較笨重,對(duì)于比較龐大的網(wǎng)絡(luò)應(yīng)用實(shí)施比較復(fù)雜,雖然它運(yùn)行在網(wǎng)絡(luò)4層之上,僅做分發(fā)沒有流量產(chǎn)生,但是它不能做正則處理也不能也不能做動(dòng)靜分離,所以一般用lvs+keepalived或heatbeat做數(shù)據(jù)庫層的負(fù)載均衡。
LVS、HAProxy、Nginx做負(fù)載均衡的比較4.2、使用terracotta或者memcached使session共享
4.2.1、terracotta是jvm級(jí)別的session共享
它基本原理是對(duì)于集群間共享的數(shù)據(jù),當(dāng)在一個(gè)節(jié)點(diǎn)發(fā)生變化的時(shí)候,Terracotta只把變化的部分發(fā)送給Terracotta服務(wù)器,然后由服務(wù)器把它轉(zhuǎn)發(fā)給真正需要這個(gè)數(shù)據(jù)的節(jié)點(diǎn),并且共享的數(shù)據(jù)對(duì)象不需要序列化。
4.2.2、通過memcached實(shí)現(xiàn)內(nèi)存級(jí)session共享
通過memcached-session-manager(msm)插件,通過tomcat上一定的配置,即可實(shí)現(xiàn)把session存儲(chǔ)到memcached服務(wù)器上。注意:tomcat支持tomcat6+,并且memcached可以支持分布式內(nèi)存,msm同時(shí)支持黏性session(sticky sessions)或者非黏性session(non-sticky sessions)兩種模式,在memcached內(nèi)存中共享的對(duì)象需要序列化。結(jié)構(gòu)如圖3:
通過一定的配置,可以實(shí)現(xiàn)故障轉(zhuǎn)移(只支持對(duì)非粘性session)。如:
Xml代碼
<Context>
...
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:host1.yourdomain.com:11211,n2:host2.yourdomain.com:11211"
failoverNodes="n1"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
</Context>
說明:failoverNodes:故障轉(zhuǎn)移節(jié)點(diǎn),對(duì)非粘性session不可用。屬性failoverNodes="n1"的作用是告訴msm最好是把session保存在memcached "n2"節(jié)點(diǎn)上,只有在n2節(jié)點(diǎn)不可用的情況下才把session保存在n1節(jié)點(diǎn)。這樣即使host2上的tomcat宕機(jī),仍然可以通過host1上的tomcat訪問存放在memcached "n1" 節(jié)點(diǎn)中的session。
4.2.3、其他方案
通過cookie保存用戶信息(一般是登錄信息),每一個(gè)請(qǐng)求到達(dá)web應(yīng)用的時(shí)候,web應(yīng)用從cookie中取出數(shù)據(jù)進(jìn)行處理(這里盡量對(duì)cookie做加密處理);
另外一種是把用戶信息的關(guān)鍵屬性保存到數(shù)據(jù)庫,這樣就不需要session了。請(qǐng)求過來從數(shù)據(jù)庫查詢關(guān)鍵屬性數(shù)據(jù),做相應(yīng)處理。缺點(diǎn):加大了數(shù)據(jù)庫的負(fù)載,使數(shù)據(jù)庫成為集群的瓶頸。
原理
在第三,四篇文章中講到了會(huì)話保持的問題,而且還遺留了一個(gè)問題,就是會(huì)話保持存在單點(diǎn)故障,
當(dāng)時(shí)的方案是cookie插入后綴,即haproxy指負(fù)責(zé)分發(fā)請(qǐng)求,應(yīng)用服務(wù)自行保持用戶會(huì)話,如果應(yīng)
用服務(wù)器宕機(jī),則session會(huì)丟失。
現(xiàn)在來溫習(xí)下解決方案
方案1:session復(fù)制
原理
就是將1臺(tái)服務(wù)器的session復(fù)制到其它所有的服務(wù)器上,這樣無論訪問哪臺(tái)服務(wù)器,都會(huì)得到用戶 的session
優(yōu)點(diǎn)
不存在單點(diǎn)故障問題
缺點(diǎn)
當(dāng)服務(wù)器的數(shù)量比較大時(shí),session同步將會(huì)變得相當(dāng)耗時(shí)
方案2:session粘滯
原理
就是用戶請(qǐng)求一個(gè)服務(wù)器之后,同一個(gè)會(huì)話的其它請(qǐng)求,都會(huì)被分配到這臺(tái)服務(wù)器,session粘滯的 功能由負(fù)載均衡中間件完成
優(yōu)點(diǎn)
解決了session復(fù)制的性能問題
缺點(diǎn)
由于用戶的會(huì)話被保存到單一的服務(wù)器,就容易出現(xiàn)單點(diǎn)故障
方案3:session服務(wù)器
原理
部署一個(gè)專門的服務(wù),保存用戶session,同時(shí)在web服務(wù)器本地也保存一份,當(dāng)本地沒有或者失效時(shí), 去訪問session服務(wù)器,當(dāng)然session服務(wù)器就成了單點(diǎn),當(dāng)用戶量大的時(shí)候也容易宕機(jī),這時(shí)可以做一 個(gè)session服務(wù)器集群,做主備同步備份,這樣就達(dá)到了較好的效果,具體實(shí)現(xiàn)可以用redies,memcached 等緩存中間件。
優(yōu)點(diǎn)
解決了單點(diǎn)故障和性能問題
缺點(diǎn)
實(shí)現(xiàn)復(fù)雜
Redis保存session方案
上篇文章講到的就是session粘滯的方案,既然前2種方案都有各自的缺點(diǎn),那么就采用第三中方案
可以用
redis做session緩存,保存用戶session,做成主備模式,采用同步備份或者異步備份。
同步備份:在主機(jī)宕機(jī)時(shí),備機(jī)接管之后session數(shù)據(jù)不丟失。
異步備份:在主機(jī)宕機(jī)時(shí),備機(jī)接管主機(jī),但是如果有一部分session還沒來得及同步到備機(jī),session將丟失。
可以根據(jù)實(shí)際情況來決定采用同步備份還是異步備份。
系統(tǒng)架構(gòu)圖如下:
如果用戶量比較大,單服務(wù)器訪問和存儲(chǔ)session將會(huì)成為瓶頸,可以考慮用session服務(wù)器集群,架構(gòu)圖如下:
redis集群特點(diǎn)
1)將數(shù)據(jù)分散到集群中的多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)量就會(huì)變少,這樣存儲(chǔ)和訪問
的效率會(huì)得到提升。
2)每個(gè)節(jié)點(diǎn)都有主備,如果節(jié)點(diǎn)的主存儲(chǔ)掛了,備份存儲(chǔ)會(huì)接管主存儲(chǔ),提高可用性。
Redis+Tomcat實(shí)現(xiàn)
session流程
1.客戶端首次請(qǐng)求服務(wù)端
2.服務(wù)端產(chǎn)生session并set cookie響應(yīng)給客戶端
3.客戶端再次請(qǐng)求服務(wù)端,會(huì)帶上cookie
4.服務(wù)端根據(jù)cookie找到對(duì)應(yīng)的session
實(shí)現(xiàn)思路
如果我們要編寫程序?qū)崿F(xiàn)這個(gè)方案,需要解決以下問題:
1.session的安全性,即不容易被仿造。
2.session的唯一性,如果用tomcat產(chǎn)生session的策略,多臺(tái)tomcat會(huì)產(chǎn)生的session會(huì)存在重復(fù)的可能。
3.session的有效期維護(hù),session會(huì)有個(gè)有效期,用戶在這個(gè)時(shí)間內(nèi)不訪問系統(tǒng),session將會(huì)失效,如果
用戶一直訪問,則要自動(dòng)延長(zhǎng)session有效期。
4.在集群session服務(wù)器中,要考慮負(fù)載均衡,這也是需要編寫客戶端代碼的,在分布式session緩存中,
需要根據(jù)sessionId哈希分布,那么就和服務(wù)器個(gè)數(shù)進(jìn)行了耦合,在添加和移除服務(wù)器的時(shí)候,將出現(xiàn)數(shù)
據(jù)不一致的問題 。
5.如何實(shí)現(xiàn)才能讓應(yīng)用程序改動(dòng)最小,或者是不改動(dòng)。
我們可以選擇自己寫程序來實(shí)現(xiàn)以上功能,不過在這里我使用一個(gè)現(xiàn)成的框架,即tomcat-redis-session-manager
有時(shí)間并感興趣的朋友,可以在這個(gè)基礎(chǔ)上自行實(shí)現(xiàn)一個(gè),這樣更適合自己的項(xiàng)目。
服務(wù)器部署分布:
ha主機(jī) 192.168.1.227:80
ha備機(jī) 192.168.1.246:80
keepalived 主機(jī) 192.168.1.227
keepalived備機(jī) 192.168.1.246
web1
http://192.168.1.226:8888/loginweb2
http://192.168.1.246:8888/loginredis主 192.168.1.245 6380
redis備
安裝redis
主機(jī)和備機(jī)都安裝redis
wget
http://download.redis.io/releases/redis-2.8.5.tar.gz解壓:
tar xzf redis-2.8.5.tar.gz
cd redis-2.8.5
make
啟動(dòng)
src/redis-server redis.conf --port 6380 &
客戶端登錄
src/redis-cli -p 6380
備機(jī)配置復(fù)制:
redis.conf文件中
添加
slaveof 192.168.1.245 6380
Tomcat配置
tomcat版本:7.0.61
相關(guān)jar包:
注意這里的jar包最好是按下面的版本,否則會(huì)出現(xiàn)jar包沖突的問題。
tomcat-redis-session-manager-1.1.jar
commons-pool-1.6.jar
jedis-2.1.0.jar
下載tomcat redis session manager
https://github.com/jcoleman/tomcat-redis-session-manager/downloads下載 apache common pool
http://commons.apache.org/proper/commons-pool/download_pool.cgi下載版本:tomcat-redis-session-manager-1.1
redis的jar包可以從maven中央倉庫下載
將以上3個(gè)jar包放入tomcat/lib目錄中
在tomcat context.xml中加入如下內(nèi)容
<!-- host: optional: defaults to "localhost" --><!-- port: defaults to "6379" --><!-- database: optional: defaults to "0" --><!-- maxInactiveInterval: optional: defaults to "60" (in seconds) --><Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" /><Manager className="com.radiadesign.catalina.session.RedisSessionManager" host="192.168.1.245" port="6380" database="0" maxInactiveInterval="60" />
啟動(dòng)tomcat,瀏覽器請(qǐng)求tomcat
http://192.168.1.226:8888/login/登錄redis客戶端,查看session
session已經(jīng)被保存到redis
下面,我們進(jìn)行一項(xiàng)測(cè)試
測(cè)試流程:
1.先訪問虛擬ip1.99的應(yīng)用,得到sessionId
web服務(wù)器是226
2.然后將對(duì)應(yīng)的tomcat停掉
3.刷新該應(yīng)用,若sessionId未變,則表示redis保存session成功。
我們發(fā)現(xiàn)web服務(wù)器變成了246,但是sessionId未發(fā)生變化
該方案將session集中保存在了redis服務(wù)器,并做了主備容災(zāi),從一定程度上提高了系統(tǒng)的高可用,由于
redis是內(nèi)存存儲(chǔ),訪問效率較高,在性能上也是比較好的,但是本例中session不是分布式存儲(chǔ),因此當(dāng)用戶量
非常大,并發(fā)訪問量非常高的時(shí)候,session服務(wù)器會(huì)成為性能瓶頸。