1. 程式人生 > >可伸縮架構簡短系列

可伸縮架構簡短系列

activemq 數據庫 自動 流程 範例 中心 了解 mon 計劃

采取什麽辦法可以讓一個Web服務可大規模可擴展?相信你會對這個問題感興趣。

克隆

通常來說,公共服務器上的一個可伸縮的web服務總是隱藏在一個Load Balancer(負載均衡器)之後。這個負載均衡器會將負載(來自用戶的請求)均勻的分配到一組服務器或者服務器集群。那意味著什麽?舉個例子:某個用戶訪問你的服務,他第一次的請求可能會由第二臺服務器提供,第二次請求由第9臺服務器提供,第3次請求又再次由第二臺服務器提供。

對於該用戶而言,他每次得到的結果應該是一樣的,不依賴服務到底是哪臺服務器提供的。這個正是可伸縮性的第一個黃金法則:每個服務器都包含完全相同的代碼庫,不在本地磁盤或內存存儲任何與用戶相關的數據,如session或用戶信息。Session需要集中存儲,使得每一臺服務器都可以訪問到它。它可以是一個外部數據庫或外部持久緩存,比如Redis。相比外部數據庫,在持久化的緩存中存放session將會有更好的性能。這裏提到的“外部”指的是數據存儲不放置在這些應用服務器上,而是在接近您的應用程序服務器的數據中心。

但是這要怎麽部署呢?你如何確定當應用代碼發生了改變能夠發送到所有的服務器而沒有一臺服務器依舊使用之前的代碼?幸運的是,這個棘手的問題已經被一個很好的工具capistrano解決了,你需要稍微學習了解下。

在解決了session和多臺服務器上新版本的同步更新問題之後,你需要做的就是克隆你的機器鏡像了,然後將你最新的代碼部署上去。可以參考Amazon提供的AMI服務(Amazon Machine Image)

現在你的服務器可以水平擴展,並且處理成千上萬的並發請求了。

數據庫

但是你發現應用程序變得越來越來最終崩潰。問題的原因:是MySql,不是嗎?
現在不是增加更多的機器可以解決的問題了,你有兩種辦法:

  • 1,堅持使用MySql,並且讓它運行良好。做主從復制(從服務器負責讀取,主服務器負責寫入),並且升級主服務器,不斷加入更多的內存。隨著不斷優化,你會使用數據庫分片、反規模化、SQL調優等常用手段。這時,對於數據庫的任何一個操作成本都會變得相當昂貴。
  • 2,切換到一個更加容易擴展的NoSQL數據庫,比如 MongoDB或CouchDB,連接查詢現在需要在應用代碼層裏去進行了。

現在,你的數據庫有了一個可擴展的解決方案了,你再也不用擔心存儲TB級的數據,世界看起來那麽的美好。

緩存

當大量的數據請求發往到數據庫,你發現又變慢了,解決辦法是增加緩存。
這裏說的緩存指的是內存緩存,比如常見的內存數據庫Memcached或者Redis ,千萬不要使用文件緩存,它會讓你服務器的克隆和自動伸縮很痛苦。

但是回到內存緩存,緩存是一個簡單的鍵值存儲並且應該介於應用程序和數據存儲。任何時候當你的應用程序需要去讀取數據時,它首先應該嘗試從緩存裏面獲取數據,只有無法從緩存中讀取數據時,才會嘗試從數據庫中讀到。為什麽要這麽做呢?因為緩存快如閃電,它將數據集存放在內存中,並且可以快速的被處理。舉個例子:Redis沒秒鐘可以處理成千上萬的讀操作。

訪問流程:第一次訪問綠色,第二次和之後的藍色:
技術分享

有兩種緩存數據的模式,一種是老的方式,一種是新的方式:

  • 1,緩存數據庫查詢,這個仍然是最普遍的緩存方式,當你做一次查詢時,將數據集進行緩存,通過哈希後查詢串作為鍵。下一次查詢時,檢查緩存中是否有結果。這種方式存在一些問題,最主要的問題就是過期。當數據表中的一塊數據發生變化時,你需要刪除所有包含這個數據塊的查詢串的緩存。
  • 2,緩存對象,我強烈推薦使用這種方式,這也是我經常使用的。

一些適合緩存的對象:

  • 用戶Session(永遠不存放在數據庫中)
  • 完全呈現的博客文章
  • 活動流
  • 用戶<- -> 朋友 之類的關系

異步

請想象一下,你想在你最喜歡的面包店買面包,所以你走進面包店,向一個店員詢問購買面包,但是面包都賣光了。你被告知2個小時之後你訂的面包可以好,這個很惱人,不是嗎?
為了避免這種“請等片刻”的場景,需要采取異步。比如什麽時候有面包了,店員會將面包派送給你的家裏。通常來說,有兩種異步的範例:

  • 1,讓我們回到普通的買面包的場景,第一種異步處理流程是:“晚上把面包都烹制好,第二天早上賣”,這個對於顧客來說不需要等待。對於一個web應用程序,這意味著提前做耗時的工作,這樣就可以在短時間處理完工作。通常這種模式用來將動態的內容轉換為靜態內容。比如提前渲染好CMS裏面的一些網頁,並且本地存儲這些HTML文件。采用定時任務,可能是通過腳本叫做每小時的計劃。這種對通用數據預先計算可以極大的提升網站和web app的可伸縮性和性能。可以通過腳本將這些預先渲染好的HTML頁面發布至CDN。你的網站將能做到響應超快並且每小時可以處理成千上萬的遊客!
  • 2,回到面包店,有的時候顧客可能會有一些特殊的需求,不然在面包上加上“生日快樂”等裝飾。面包店並不能提前知道這種顧客類型的需求,所以當顧客來到店裏後,必須馬上開啟一個任務並且告訴他:”你明天再來吧!“ 對於web而言,這意味著異步任務。這裏有一個典型的工作流:一個用戶來到你的網站,開始一項計算密集型任務,這個任務需要花費幾分鐘來完成,所以網站前端會往任務隊列裏面發送一個任務,並且告訴用戶你的任務已經在處理中了,你可以繼續瀏覽網頁了。一個任務隊列會不斷的被處理任務的workers 檢查處理。如果有一個新任務,work會處理這個任務,過了幾分鐘之後會發送一個處理完畢的消息信號。前端會不斷的檢查(比如輪詢)這個任務是否已經處理完,一旦處理完則通知用戶。如果你想更深入了解,推薦你去看看RabbmitMQ),Rabbit MQ是一個實現了異步消息隊列的優秀中間件。你也可以使用ActiveMQ或者一個簡單的Redis list,異步消息隊列看起來很復雜,但是它值得你花時間去學習和實現。

如果你做一些耗時的操作,試著采用異步。

可伸縮架構簡短系列