今天,當我們選擇負載均衡時,大部分Web應用集群選擇基于軟件或硬件的服務器端方案,而《Digital Web Magazine》最近發表的一篇文章討論了一家公司如何在EC2支持的應用中實現客戶端負載均衡。
文章從負載均衡方案的需求談起:
需要在應用服務器集群中分擔負載; 溫和地應對單個服務器的宕機; 確保在最終用戶端可以把這組服務器視為一個單獨的服務器。
作者朱磊(音譯 Lei Zhu)分析了我們常用的服務端負載均衡手段——循環DNS(Round Robin DNS),文中提到:
很不幸,循環DNS的主要弱點是不能滿足上面提到的第二個需求,當兩臺服務器中的一臺宕機時,DNS服務器仍然會繼續把請求發給它,這導致一半用戶無法獲得響應。
他還指出集群前端軟、硬件專用方案的不足:負載均衡器(Load Balancer)自己總有一個響應數量上限,盡管可以通過循環DNS配合專用負載均衡器解決這一問題,但維護一個專用負載均衡器需要額外投入數萬美元, 而且通常后備負載均衡器只有在主設備出現故障后才會發揮作用。
在客戶端負載均衡概念的介紹中,作者請讀者考慮關于桌面應用如何負載均衡的問題:
桌面程序隨機選擇一臺服務器,然后嘗試獲取數據,如果服務器不可用或沒有在預設的時間內響應,那么就選擇另一臺服務器,直到可以 提取數據。桌面應用與Web應用不同的是,前者是獨立于服務器,可以在客戶端通過對服務器訪問的負載均衡實現應用的可擴展性,而后者把客戶端代碼 (JavaScript或Flash WSF)保存在提供數據和資源的服務器上。
為了把概念延伸到Web應用,作者剖析了典型AJAX應用的關鍵組成:
客戶端代碼:JavaScript/Flash客戶端的SWF; 資源:圖片、級聯樣式表、音頻和視頻文件、HTML文檔; 服務端代碼:用于反饋客戶端所需數據的后臺邏輯。
其中1、2兩類內容相對靜止,一般不像第3類那樣有負載均衡的需要。關注于第3類組成,作者建議采用可靠的服務器或者像亞馬遜S3那樣的服務,它描繪的策略如下:
就像桌面應用一樣,我們可以把一個應用服務器列表嵌到客戶端代碼里,Web客戶端包括一個稱為Servers.XML的文件,它保存了可用服務器的列表。客戶端通過AJAX或者Flash訪問列表中的每一個服務器,直到找到一臺可響應的。
盡管瀏覽器可以禁止客戶端代碼向它所來源的那些服務器之外的服務器發起服務端調用,但作者還是建議采用Flash或JavaScript的方案解決這個問題。采用客戶端負載均衡有兩個好處:
不需要額外的服務器設備,“不需要專用負載均衡設備,無需配置負載均衡硬件或確認備份功能和主負載均衡器是否正常工作”; 服務器可以被物理隔離,“由于是客戶端選擇服務器而不是由一個固定的負載均衡器重定向調用,所以服務器的位置不受限制”。
文章結尾,作者介紹了上述技術如何在亞馬遜的EC2和S3基礎上構造一個叫VoxLite的具有高可用性和可擴展性的視頻資訊應用,不過作者并沒有架構出一個沒有單點故障的負載均衡方案。
很多Web應用會面向特定區域,通過一個動態DNS支持的EC2實例實現調用的負載均衡。如果提供負載均衡的這個實例出現故障,在動態DNS映像到另一個EC2實例前,整個系統就不可用了。
為了克服這個問題,VoxLite通過向S3發起HTTP GET調用獲得可用的服務器列表,該列表由EC2實例的一系列任務維護:
根據你的需求,客戶端負載均衡在統一負載均衡的架構下,提供了一個有趣且具創新性的選擇。作者總結道:
通過在客戶端負載均衡中采用S3和EC2,可以簡化搭建一個具有彈性、擴展性、健壯性Web應用的工作。
查看英文原文:Client side load balancing of Ajax applications
上一個項目使用的是spring MVC; 客戶需要做Ajax應用;所以就找了一些資料研究了一下,比如DWR,dojo, prototype,JSON-RPC, trimpath 等等,發現很多不適合我們,比如DWR要生成客戶端js,服務器端還要部署,麻煩;dojo又太慢了;經過一輪淘汰剩下了prototype和trimpath;所以最終就選這2個了;
Prototype在書寫普通的js時候,有很多好處,比如簡單,實用的很多函數;比如$()系列;
Trimpath提供一個客戶端的js模板,如果從服務器回來的數據很復雜,要動態改變Html元素是比較費力的事情;用trimpath就方便許多;
在模板語言的世界里,總有2個東西:模板和模板中的數據;trimpath的模板接受的數據是javascript object,模板則定義在一個不顯示的textarea里面;
所以有個問題就是:怎么讓ajax調用返回一個javascript對象?
后來,我終于發現了(想起了劉若英)JSON;發現json是個好東東;比xml輕量級,又可以很容易的轉換為javascript對象,而且還有java api;唉,開源的世界多美妙;
所以解決方案就是,在springmvc框架中,用response返回json string,給ajax 客戶端,然后生成javascript對象,然后,調用trimpath模板,然后,動態修改頁面。
代碼片段:
public ModelAndView getClient(HttpServletRequest request, HttpServletResponse response) throws Exception {
JSONObject jsonObject = new JSONObject();
Client client=clientMgr.getClientByPk(Long.parseLong(request.getParameter("clientId")));
jsonObject.add("client", client);
return ajaxResponse(jsonObject, response);
}
protected ModelAndView ajaxResponse(JSONObject jsonObject, HttpServletResponse response) throws Exception {
response.setContentType("application/x-json;charset=UTF-8");
response.getWriter().print(jsonObject);
return null;
}
Selenium
是一個由ThoughtWorks做的專門為web應用所做的非常有效的功能測試工具。Selenium
的 tests
直接在瀏覽器里跑,就像用戶真的在操作一樣。Selenium
可運行 Windows, Linux, 和 Macintosh
的各種瀏覽器, 如
Internet Explorer, Mozilla 和 Firefox。
.......
訪問鏈接:
http://forum.springside.org.cn/viewthread.php?tid=195&extra=page%3D1
通常的處理流程:用prototype.js發出ajax請求,并注冊一個用于處理返回結果的回調函數,請求被spring的controller捕獲,
controller處理請求并將結果轉成JSON
Object(而非ModelAndView),并用response對象返回;
回調函數,將拿到返回的對象并把它轉成javascript對象,然后用Trimpath
JST模版技術將返回的對象和模版合并,得到合并后的
html代碼,然后將html代碼賦值給一個div來顯示;結束;
java reflection技術用于將java bean轉成JSON對象;