CDN加速小水管動態應用技巧
不得不說現在大陸和HK的雲主機都是小水管模式,由於硬體的快速發展在這種小水管的情況下很難發揮出使用者硬體資源的能力,當然可以加水管但費用很高,更多時候會浪費頻寬;這個時候我們想到CDN加速,這種資源的好處就是可以把瞬間流量分擔出去,讓小水管可以應對更多的請求。但CDN在我們印象中都是加速靜態資源,更新慢對於動態不怎好用,但辦法總是用的接下來介紹一下如何用CDN加速動態應用。
需求
最近在做一個線上討論的服務,由於涉及到比較多的內容如傳送圖片,附件和歷史記錄等,對於這樣的動態資訊展示的確不適合小水管;對於3Mb的小水管來說一張圖片就可以把小水管給卡住了。。更不要說記錄中有大量的圖片和附件存在!接下來想到了CDN,經過一些時間的思考把傳送訊息和歷史資訊的資源都落地到CDN上,但這些訊息都是動態如果每次變更去刷CDN那基本就沒法用了!為了實現這些想到了一種新的思路並落地到group.beetlex.io
接下來就把這思路介紹給大家。
CDN配置
現有的雲服務商都提供CDN服務,費用也不高對於500G的年包也就一百塊不到。CDN配置很簡單,以下以百度為例(雖然百度搜索很爛,但這個CDN服務還是挺穩的)。在CDN中新增你的域名
裡面的CNAME就是你原域名的DNS指向值,新增完成後可以根據自己的需要制定訪問控制元件,最好配置一下主要防止其他網站直接利用網站的資源來進行流量輸出。
使用
當有了CDN後第一步就可以把你的靜態資源直接掛載的CDN中,主要是網站固定的HTML,CSS,JS和圖片等。可以直接在頁面中新增域引用的資源如:
<script src="http://group.tomap.me/js/comm.js"></script>
如果你的網站是HTTPS訪問,則資源連線也必須是HTTPS。
動態資料使用
對於動態資料的應用則因為應用的情況不同來進行不同的設計,不過方式差別不大;以下是針對group.beetlex.io應用做的一些處理。在這個應用中主要有兩類動態資訊主要是實時傳送訊息和歷史記錄;實時訊息並不需要走CDN但訊息內圖片和附件則無法由小水管來保障!還有每次進入房間獲取歷史聊天記錄都有著比較高的瞬間流量,這種流量小水管也應付不來。
訊息圖片和附件資源
由於group.beetlex.io以Markdown的方式進行訊息輸入,所以可以上傳圖片或附件進行一個訊息展示。雖然可以把這些資源先存到雲服務商中然後獲取相關訪問URL再輸出,但這種設計的方式有著一定的依賴性,以後相 關URL切換並不方便,最終還是選擇儲存到本地服務中;但這種儲存方式存在一個問題就是小水管輸出比較麻煩,既然有CDN只需要在Markdown輸出的時候更換一下URL地址即可;更換程式碼如下:
msg.Message = msg.Message.replace(/<img.*?src="(.*?)">/gi, (data) => { var regex = /<img.*?src="(.*?)"/; var src = regex.exec(data.toString())[1]; if (src[0] == '/') src = 'http://group.tomap.me' + src; var html = ''; if (insert == true) { if (src.indexOf('faces') >= 0) { html = '<img src="/images/imgloading.gif" _src="' + src + '">' } else { html = '<img src="/images/imgloading.gif" _src="' + src + '" onclick="page.imgViewSrc=\'' + src + '\'">' } } else { if (src.indexOf('faces') >= 0) { html = '<img src="' + src + '">' } else { html = '<img src="' + src + '" onclick="page.imgViewSrc=\'' + src + '\'">' } } return html });
只需要簡單地匹配一下相關圖片標籤替換即可,如果是站外圖片則不代替;對於下載的檔案的連線也可以使用這種處理方式。這樣這些圖片的展示和檔案下載都由CDN來輸出處理。
歷史記錄
在group.beetlex.io中每個使用者進討論組都要重新拉取歷史記錄資訊,如果訊息量太大的情況一個就把小水管的頻寬拉完了。為了解決這一問題也使用了CDN來載入歷史記錄,但房間的歷史記錄是經常變的如果變更後自動去重新整理CDN可能很難達到有效性。為了解決這一問題採用了URL重寫機制來解決這一問題,原理很簡單當討論組每次有訊息的時候都變更討論組的版本號,然後在進這個討論組時都訪問這樣一個版本的URL來處理,重寫程式碼如下:
"/rooms/{room}-{version}.html" => "/GetRoomHistory?room={room}"
這樣每次獲取討論歷史資訊的時候都訪問一個房間ID+版本的靜態頁面,而後臺則根據這個URL重寫到獲取資訊的控制器上,這樣只要資訊有變更每次載入新的都能從CDN中獲取。不過這種做法就是當第一個訪問的使用者大概延時1秒左右這延時完全可以接受,但後面訪問的速度就快多了;通過這樣做法即使小水管也能支撐很多歷史記錄載入而不影響服務效率。以下是呼叫的程式碼
this.enterRoom.asyncget({ room: id, password: password }) .then((result) => { var url = 'http://group.tomap.me/rooms/' + id + '-' + result + '.html'; this.getRoomHistory.loading = true; axios.get(url).then((r) => { r.data.forEach(v => { this.addMessage(v, true); }); this.imgs = null; setTimeout(this.loadImg, 1000); this.hasNewMessage = true; this.getRoomHistory.loading = false; }).catch((error) => { this.$errorMsg(error); this.getRoomHistory.loading = false; }); rooms_password[id] = password; }).catch((err) => { this.selectItem = {}; rooms_password[id] = null; });
技巧總結
其實動態資料使用CDN也是比較簡單事情,主要利用更改請求的URL或重寫來把靜態資源切換到動態資料介面上;為了讓CDN更快速地獲取到新資料,通過資料變更的版本號來定位到新的URL來讓CDN載入新的資料。通過這種方式就可以把很多動態介面做成CDN靜態