2012年2月17日

淺談私有 CDN(內容傳遞網路)佈署



當 Web Application(以下簡稱 WebApp)大量取代傳統桌面應用程式,資訊服務類型的軟體公司,需要解決的「重複與浪費」問題,就不只有軟體架構本身;相信大家都清楚軟體架構本身,需要模組化、元件化,讓寫好的功能(程式碼)可以盡可能再利用,最好有很多 Plugins 或 Modules,當有需要的時候就可以拿來使用或擴充。

資訊服務公司通常不會只有一或少數幾項軟體專案,而是會建立非常多系統。因此,重複造成的浪費問題就更加嚴重。

一般來說,經過編譯的程式或者原始碼本身,都不太會有體積的問題。例如封裝成 .dll 或 .jar 之後,就可以再不同專案中引用。搭配好的自動化建置機制,通常我們不需要將外部共用的模組(或元件),放到專案的版本控制系統,只有進行測試或最後發佈時,才需要把這些檔案暫時加進來。

但是 WebApp 包含的內容並不只有程式,還有許多比較像是「資源」的東西。例如:

  • jQuery core + jQuery UI + .... 一大票 jQuery Plugins
  • Ext JS + 一大票 Widgets ...
  • ICON library + ... 一大票圖庫
  • 自行開發維護的 JavaScript、CSS、ICON 共用 libraries 等
如果沒有好的解決辦法,這些資源除了被重複發佈到很多網站伺服器,造成儲存空間及頻寬的浪費,甚至也會被加到專案版本控制系統的 repository。

舉例來說,Ext JS 4 的原始碼 ext-4.0.7-gpl 解壓縮後體積高達 166MB,為了某些情況除錯方便,我們可能不會只保留必要及壓縮最佳化的檔案,而是需要完整的檔案。除非使用的 Framework 有良好的 Plugins 機制,可以引用 Ext JS 但不會實際被加到專案資料夾(只有在建置 test 或 production 階段才會加入暫存的區域);否則,一般來說都是直接在 WebApp 的資料夾中,也保存一份完整的副本。

相信有很大一部份比例的專案,都是直接就把這些資源加到專案的 repository,一起發佈到版本控制系統;這是最簡便的方式,可是也是最浪費資源。這麼做會帶來一些問題:
  1. 不屬於專案的東西,卻要納入專案的版本控管。佔空間(雖然現在硬碟很便宜,這問題顯得不大)、維護麻煩。
  2. 專案的 repository 變得十分肥大,真正屬於專案的部份也許不到 30MB,但整體卻超過 100MB。對於版本較舊的 SVN 來說,執行速度可能隨檔案愈多愈複雜而變得愈慢。
  3. 不管是新加入的成員,或經歷一次災難後需要重新取出(checkout)完整的檔案,浪費伺服器資源及網路頻寬,最重要的寶貴時間也會因此白白浪費。
  4. 假設一家資訊服務公司有 20 個系統,就造成資源 20 倍浪費。
  5. 對於導入持續整合機制的專案來說,又造成更多的浪費。
  6. 像是 GitHub 等專案托管服務,有檔案容量的限制,佔空間就是個需要考慮的問題。
即使在開發階段,解決資源重複造成的浪費問題,例如可以不必將外部資源納入版本控管;但是最終打包發佈時,放到正式的伺服器運作,還是需要加入這些檔案(可以透過最佳化讓檔案少一些、體積小一些),最終,浪費的問題還是存在。

對於資訊服務公司來說,建置私有 CDN 不僅可以得到很多好處,而且在雲端服務價格低廉的時代,更是很難找到理由不這麼做。

CDN(內容傳遞網路,content delivery network)的概念,是指一種透過網際網路互相連接的電腦網路系統,提供高效能、可擴展性、及低成本的網路將內容傳遞給使用者。

簡單地說,我們可以建置遠端的檔案服務伺服器,將 WebApp 專案常需要用到的靜態資源,都放到這些伺服器,讓這些伺服器維持高可用性、擴展性,提供足夠的負載量;如此一來,所有的專案共用的 WebApp 資源,就可以佈署到這些伺服器。

建立 CDN 的優點很多,包括開發人員可以快速利用(不必每次都要重新下載、建立 library),減少遠端佈署需要的時間,讓不同專案之間可以共用資源,降低正式伺服器的存取及頻寬消耗,幫助需要高負載的 WebApp 減輕負擔,...

事實上,Google 就建立了自己的 CDN,提供包含 jQuery、jQuery UI、Prototype 等網站常用到的資源,並且也把這個 CDN 免費開放給所有開發者使用。

不過,免費的 CDN 通常不會剛好有你需要的所有東西;以 Ext JS 來說,Google 僅提供核心部份 Ext Core,而 Sencha 雖然也有為 Ext JS GPL 架設 CDN,但實測後發現經常有找不到檔案的情況。

對資訊服務公司來說,用其他人提供的 CDN 並不是個好辦法,因為哪天該 CDN 結束運作,或者已經不提供某個版本的資源,就會造成一些系統因此受連累而掛點。所以,建置私有 CDN 是比較好的方案。

一般來說,自己租用專線架設伺服器來做 CDN 並不划算,光是要達到資料及網路的備援,以及高可用性(要預防斷電斷網路天災人禍等問題),要付出的成本實在太高。

使用虛擬主機(Virtual Host 或 VPN)是個相對便宜的方法,但是一般的虛擬主機都有容量、頻寬流量限制,以及不管有沒有用到它,都需要付基本的月租費。

所以,本文介紹的方案,是採用 Amazon S3(Simple Storage Service)及 CloudFront。

Amazon S3 的主要優點,包括它是採「使用量付費」,計費內容包括儲存空間、存取次數、傳輸量三項。因此若剛開始只需要放 500MB 的檔案,就只需要為這有用到的儲存空間及傳輸量付費,註冊 S3 服務並不需要設定容量,即使未來可能成長到幾 TB 的容量,也不需要一開始就租賃旗艦級的方案,同時也不會有每月傳輸量限制的問題。

使用 S3 建立 CDN 的步驟很簡單:
  1. 建立 S3 Bucket(儲存空間),並將名稱設為 CDN 網址(如:cdn.yourname.com)
  2. 修改 DNS 設定,將網址透過 CNAME 指向 Bucket 的 End Point 網址
  3. 設定 Bucket 的 Web Site 為 Enabled
  4. 將要放到 CDN 的檔案如 Ext JS 等,上傳至 Bucket,並設為 Public
對於 Mac 及 Linux 的使用者來說,可以用 s3cmd 工具來管理檔案,這個軟體可以在 command line 下輕鬆將本地檔案,上傳或同步到指定的 S3 位址。

除了在建立 CDN 時可以用 s3cmd,如果遇到客戶因預算或速度考量,需要把專案整個搬遷到企業內部網路可以直接存取的伺服器,也可以利用 s3cmd 做一份 mirror,維持專案使用到的資源有一致的存取配置。

如果開發的 WebApp 是需要提供給大眾使用,甚至有來自世界各地的使用者,使用 S3 可以方便地搭配 CloudFront 建置全球化的 CDN。

CloudFront 不能儲存檔案,它是用來「傳遞」S3 或其他來源的檔案,透過分散在世界各地的資料中心(S3 的 Bucket),減少網路傳遞路徑的延遲。簡單地說,CloudFront 可以讓 S3 的檔案下載速度更快,而且傳輸費用也比 S3 便宜(包括傳輸費用+存取次數)。

因此,S3+CloudFront 用於架設私有 CDN 是相對划算的方案,只要依照實際使用量付費,若未來需求不斷提高,也不會有需要升級頻寬和儲存空間的問題。

4 則留言:

  1. 當專案中用了太多資料,
    應該怎麼分出那些是要建在CDN?
    又那些在先建好在本機中?

    公司如果以版本控制的想法建立CDN,
    目的只是統一開放環境是否可行?

    回覆刪除
  2. 一般來說,
    3rd party libraries, common/shared libraries, icons, ... => CDN
    project cores, ... => Project Repository

    CDN本身和版本控制並無關係

    回覆刪除
  3. 很棒的文章,清楚解釋s3+cf thx

    回覆刪除

lyhcode by lyhcode
歡迎轉載,請務必註明出處!