天天看點

高性能、高流量Java Web站點打造的22條建議

從2005年-2013年,Ashwanth Fernando曾供職于Best Buy、Pearson VUE、Walgreens、Walmart eCommerce等多家知名公司,現在Apple從事進階工程師、平台工程師一職,擁有豐富的高流量Web應用程式打造及架構經驗,近日Ashwanth撰文分享了他的高流量Web軟體打造經驗。

下為譯文

受Joshua Bloch寫的《Effective Java》啟發,我想分享自己關于建立高流量Web軟體的整體建議。這些術語中的一些可能不僅僅關于軟體設計也關于工程組織、文化等相關領域。

免責聲明

  • 隻代表個人觀點
  • 如發現與現實情況相違背的原則,請謹慎對待,或使用一般認識

1. 考慮使用不止一個資料中心

在商務領域,一直存在許多恐怖的道聽途說,而這些恐慌都因為他們隻使用了單一的資料中心。如果你想在自然災害或者電力供應故障中幸免,那麼請使用多于1個的資料中心,使用active-active模式來配置你所有的資料中心。雖然在開銷上可能會有所增加,但是比隻使用單active的配置要值得多——因為在passive和active副本上,總會發現有些資料片不一緻。

2. 考慮使用稀疏資料中心部署

不管是通過PaaS,還是營運團隊進行,當軟體叢集被部署到同一個資料中心的機架上時,確定這些機架使用不同的電力供應。你不可能保證機架供電的萬無一失,一旦失敗将會導緻整個機架上伺服器的丢失,這個時候你絕對不會希望整個資料中心都隻連在一個電路上。

3. 考慮使用私有雲來組織資源

IaaS開源解決方案Openstack等其他的軟體至今尚未成熟,需要龐大的團隊來營運,在運作期間會産生各種各樣的問題,除非你有足夠的預算,否則别考慮建立一個私有的雲服務。然而,私有雲可以提供衆多優勢。首先在部署方面就可以進行衆多的定制化,這遠比AWS或者是Rackspace貨架上的選擇要多。其次它允許你做許多的硬體定制化,就好比在硬體層次的Oracle就比準虛拟化環境快得多。

4. 考慮使用PaaS做解決方案

為軟體釋放投入巨量人力進行部署的日子已接近盡頭,各個機構在靈活及快速市場投放上絞盡腦汁,而PaaS無疑會加速這個部署過程。它允許特性盡可能快的釋出,同時也能讓開發者得到極大的滿足。這是個非常好的開始,給予開發者部署集維護自己軟體的工具,這将給工作積極性帶來很大的提高。同時,越來越多的開發者甚至不願意加入沒有自動化軟體部署系統的公司。更少的上司,更簡化的環節,将給你帶來無與倫比的效率。

5. 如果使用Oracle或者MySQL,隻做基于主鍵的查詢

隻有在RAC中存在很少的Artifacts時,Oracle才能在流量高峰時獲得最佳性能。盡可能避免使用Referential Integrity、Triggers、Materialized Views、Views、Stored Procedures和其他的Oracle Artifacts。Triggers可以在從資料通路層實作。Stored Procedures可以完全轉移到應用層。資料庫隻用來存儲資料,基于字段進行存儲而不是主鍵,使用類似Lucene的索引器做表的索引,使用一個允許在結果集上做基于其他字段的查詢,這将會傳回這個記錄的主鍵,而這個主關鍵字可以進一步被用來拿取記錄。<artifacts時,oracle才能在流量高峰時獲得最佳性能。盡可能避免使用referential integrity、triggers、materialized="" views、views、stored="" procedures和其他的oracle="" artifacts。<triggers可以在從資料通路層實作。stored="" procedures可以完全轉移到應用層。資料庫隻用來存儲資料,基于字段進行存儲而不是主鍵,使用類似lucene的索引器做表的索引,使用一個允許在結果集上做基于其他字段的查詢,這将會傳回這個記錄的主鍵,而這個主關鍵字可以進一步被用來拿取記錄。="" <="" p="">

6. 考慮使用Oracle或者MySQL分片

當schema達到臨界點,Oracle的可伸縮性将被限制,這裡建議你對schema做基于功能(比如訂單,産品目錄,促銷活動,客戶等)上的分片,同時也為高密度表做key shards。為key shards使用一緻性哈希,這樣當一個新的RAC被添加RAC集時,你不再需要周遊所有RAC中的鍵,以獲悉哪些鍵需要被移動到鍵的分片中。

7. 如果你使用Oracle做RDBMS,考慮使用Data Guard及Golden Gate

使用這兩種技術将大大簡化甲骨文的營運周期,Data Guard允許一個近實時passive讀副本(沒有用戶端會與之連接配接),而Golden Gate則允許一個近實時的active讀寫副本。

推薦的部署拓撲之一就是為同個資料中心的每個分片配置1個Data Guard;使用Golden Gate來備份其他資料中心的每一個分片。

注意:Golden Gate隻是近實時

8. 為Oracle或者MySQL添加資料通路層

假設你有一個可以接受500個連接配接的Oracle RAC,而你有25個jBoss執行個體和這個甲骨文RAC對話,每個Jboss執行個體配置範圍10到50的資料庫連接配接池。

當jBoss叢集開啟時,連接配接到Oracle的數目為250(25乘10),一切運作良好。随着流量快到jBoss叢集的峰值,想象一下将會發生什麼。在某個點後,Oracle将開始拒絕連接配接。

是以建議通過一個Multiplexer層建立一個Multiplexe應用程式伺服器連接配接。可以是一個簡單的 netty應用,這個應用運作在一個每個netty節點僅能夠與Oracle建立25個連接配接的叢集上,但是對入站連接配接來者不拒。它會将所有的連接配接循環傳遞給Oracle,但是絕對不會超過25個,同時還使用Oracle JDBC驅動與Oracle通信。

9. 避免跨資料中心事務

當下,這已經是非常簡單的事情,但是在任何地方都非常适用,包括Oracle。在兩個資料不同資料中心,不要适用1個XA擴充卡去做跨資料中心事務,這将導緻相當長時間的應用線程阻塞,直到兩個階段的送出完成,是以将帶來你的應用程式服務、服務和所有同步上傳流崩潰,最終會因為線程數量增加而導緻整個應用程式崩潰,比如在類似Black Friday流量情況下。

10. 考慮分布式緩存架構

Memcached、Counbase是最常用的選擇。但實際上,解除安裝非易失性資料到一個中心緩存叢集上,确實沒必要在每個JVM上做相同的拷貝。但是确實需要設定小數量的JVM堆作為分布式緩存的一個MRU緩存,這樣的話,緩存叢集本身将會受到非常少的網絡調用。

  • 在JVM上大多數分布式緩存支援本地緩存的概念,它将儲存最常用的對象。
  • JVM上,GC的pause time同樣被最小化了,因為對象圖中需要周遊的對象比以前更少了。
  • Warmup過程是必不可少的,這可以幫助将資料導入分布式緩存,這個過程應該在晚上或者是使用者通路量低的時候。
  • 11. 考慮把web應用程式分解為服務

    上帝保佑,如果你負責的web應用程式超過50萬行代碼,而且仍然隻作單一的項目部署,那麼是時候根據服務功能把它分解成專業的服務了,并配置設定到不同的子組織或團隊去操作。将Web應用程式分解為服務有以下諸多優勢:

    • Debug将變得簡單
    • 擴充及讓子系統運作的更好将變得簡單
    • 很容易了解運作環境裡發生了什麼
    • 更快的添加新功能

    12. 不要使用session stickiness

    這絕是與魔鬼共舞,session stickiness會讓極值負荷下無法擴充。你的用戶端應該能夠調用ANY應用程式伺服器,并得到其查詢值。其中一個方法是讓服務無狀态,也稱為RestFUL服務。每個請求,用戶端會收發辨別狀态的id,代表客戶session的資料存儲在資料庫或跨多個請求的分布式緩存。

    如果因為某個原因,取代RestFUL服務,你網站大部分是建立在HttpServlets和HttpSession屬性上,使用以下方法可以實作獨立session stickiness的網站:

    一個servlet過濾器面對每項服務,取走每個請求的id,然後調用分布式緩存來填充會話屬性,這将有助于處理請求。是以資料中心任何伺服器都可以響應來自用戶端的請求,因為session狀态被保持在memcached。

    不使用session stickiness還允許使用“rolling restart”方式重新開機你的應用程式伺服器叢集,進而實作100%的正常運作時間。

    13. 終止反向代理商的SSL

    在SSL信号交換及潛在TCP通信有效保持上,反向代理非常擅長。在反向代理有上設定一個顯式的TCP維持計時器,nGinx及許多其他http伺服器都允許這麼做,這允許TCP連接配接多次重複使用。與TCP信号交換的成本是3個network call,這樣許多請求就可以避免這個開銷。

    是以從反向代理到應用程式伺服器,通常是RAW http;是以,同樣也要維持TCP的上行連接配接。

    14. 為GSLB類型的負載平衡器使用粘性負載平衡

    跨資料中心的負載平衡,建議使用session stickiness。這是因為在跨資料中心複制上,資料庫Oracle或Cassandra隻能依賴最終一緻性技術。是以,非粘性跨資料中心負載均衡器将使你的用戶端再也無法通路網站。是以經常使用GSLB,多數情況下,你的CDN将獲得基于位置的GSLB資料中心解決方案。

    15. 減少首頁上的CNAME查找

    盡量減少首頁上的CNAME查找。單單首頁的CNAME查找,一些網站就有10個或更多。即使用戶端DNS查找的答案可能來自他們的ISP遞歸緩存,我們仍然可以做的更好。www.amazon.com CNAME查找為零。

    dig  www.amazon.com  

    ;; QUESTION SECTION: 

    ;www.amazon.com. IN A 

    ;; ANSWER SECTION: 

    www.amazon.com.28 IN A 205.251.242.54

    16. 擁抱一切“reactor”

    在高流量軟體系統中,reactor模式一次又一次的得以證明。一系列架構被建立用以實作reactor模式,reactor大緻使用場景如下:

    • 作為一個反向代理:nGinx
    • 應用程式伺服器: node.js
    • 并行處理的: Scala的actor model

    除非你的業務邏輯是高度CPU綁定,否則就得考慮使用reactor模式或基于事件循環的軟體。如果無法實作,可以考慮像RxJava架構那樣的響應式程式設計模型。

    17. 實作調用取消

    從Siddharth Anand的一個會議上得到靈感,服務調用時的調用圖。首先,通過數字的遞減實作逾時。接下來,服務調用圖的每次調用,都會建立一個UUID,并在分布式緩存中為UUID設定一個标志:

    UUID:true

    • 如果服務調用圖中的任何服務逾時,UUID的标志設定為false。
    • 現在為所有服務實作一個servlet過濾器,一直檢查這個标志,隻在這個标志是真時才繼續處理。
    • 如果标志是是假,程式傳回一個空的response。
    • 這在大業務量時,可以禁止不必要的調用。

    18. 執行GC搜尋協定

    再次,靈感來自于同一個人——通過Netty讓所有的服務也顯示一個TCP端口。在調用一個服務之前,調用TCP端口然後暫停2 - 5 ms等待通路。如果調用逾時,這意味着這個Java程序正字做一個“stop the world”的垃圾收集。客戶立即切換到另一個服務執行個體,然後嘗試同樣的步驟。如果調用成功,然後調用執行個體上的實際服務。

    注意:實作GC搜尋協定需要的用戶端ip位址配置(即用戶端負載均衡)。

    19. 盡可能讓業務邏輯和I / O存取異步進行

    在流量爆炸時,異步業務邏輯能讓您的應用程式避免建立過多的線程。将事件隊列推送給負載均衡叢集,讓它去做程序訂閱的業務邏輯,而不是在http request/response周期線程做這些事。

    20. 偏愛最終一緻性資料庫

    尤其是當你在運作跨資料中心的應用程式。除非你的用例是事務處理的(比如訂單)等等,否則偏愛使用最終一緻性資料庫比如Cassandra,并盡可能少的使用ACID類型資料庫。

    21. 使用CDN服務靜态内容

    使用CDN服務靜态内容——javascript、圖像、css 等。CDN能有效地将靜态内容複制到近客戶地方,是以許多針對這些靜态内容的http請求最終穿越不會超過幾百英裡。 

    22. 打包壓縮javascript到一個檔案中

    減少javascript内聯。

    注意:不要在pre-prod環境中這麼做,這裡需要使用調試程式做javascript的debug。

    原文連結: 22 Recommendations For Building Effective High Traffic Web Software(編譯/陳翔宇、魏偉 審校/仲浩)

繼續閱讀