背景
近幾年的互聯網創業風潮持續在高漲中,所涉及的行業從涵蓋了社交、資訊、電商、生活服務等方方面面。其中也涌現不少優秀的APP,而這些產品或平台的特點都包含了"快速",即更新快,迭代快的特性。
然而作為一名軟件工程師的角度,按以前軟件工程的理論來說,系統在設計初期應考慮更多的復雜度、良好的擴展性,盡可能達到以不變應萬變的結果,而這些快速變更的新秀產品,在系統架構上如何做到靈活擴展、快速演進的呢? 這便是以下要開始探討的內容。
一、初定系統架構
在最開始的時候,產品經理(或項目經理)找到你,在嘮嘮叨叨敘述完整個系統的功能需求后,要求你一個月內就開發出來。
經理:
"領導那邊催得要命,一個月內必須上線!"
"這些功能都很常規呢,需要開發這么久嗎!"
你:
...
當然,以上的場景稍顯誇張,但在互聯網思維方式的APP開發場景下,這樣的節奏其實很常見。
研發經理都是任勞任怨的角兒,於是乎,大腦開始高速運轉:
"這么短的的時間" .. "好吧,先不考慮性能問題了!"
"單元測試也可以省了,做好自測就可以,能省下不少時間呢"
經過一輪掙扎和思考,研發經理推斷出了產品的第一代系統架構:


單點,以滿足功能為主,簡單、輕量級架構。
數據流
來自多種場景的的http請求直接由單個server接入、完成業務邏輯處理、輸出計算結果。
組件介紹
1 App Server,應用系統的服務端節點,可以有很多種選擇,以Java系列為例:
tomcat
最流行不過的j2ee容器,官網 http://tomcat.apache.org/
jetty
一款更為輕量級的servlet容器,輕量小巧,提供可編程server的實現(容易嵌入),在continuation機制也有比較良好的表現。
詳細參見 http://www.eclipse.org/jetty/
playframework
此前最為喜愛的一款非主流應用服務器,應該是首個java版本的"ruby on rails"的實現。其摒棄了j2ee繁重的各種理念枷鎖,讓編程變得更加簡單、可依賴。
playframework框架目前已經主推2.x (同時支持java和scala)版本,然而學習曲線相較1.2.x版本更加陡峭,建議可從1.2.5版本開始入門使用。
值得一提的是該框架內置了netty以支持http請求的接入及處理。
netty是一款基於NIO實現的輕量級http服務器,
關於netty的實現原理可參考: http://stonexmx.blog.163.com/blog/static/122158587201061331614536/
play框架的官網:https://www.playframework.com/
2 mysql,流行的開源數據庫,應用基於JPA/JDBC進行訪問,以實現數據持久化
3 memcached,
高速的內存服務器系統,支持KV數據流的快速讀寫,用作數據緩存及加速訪問
二、演變的開始
好的,經過一個月的努力,系統上線了。
運營也開始干活,緊接着是對線上各種問題的緊急修復。
系統漸漸有了一些活躍度,在幾個月內,產品經理和研發經理開始聽到了一些抱怨:
"系統怎么老掛啊,動不動就訪問不了,這什么破玩意啊" "我這都已經換成wifi了,圖片怎么還是一直加載不了呢?"
.....
所謂積少成怨,團隊終於頂不住壓力,下決心開始優化系統。針對上述的問題,分析如下:
1 可用性;

單點發生崩潰,整個系統直接不可用,所有用戶將受到影響;
JVM的內存溢出,系統進程意外終止都可能導致這樣的問題。
2 帶寬;
應用系統在初期設計時更多的考慮了網絡調用、html動態頁面的輸出,而針對圖片的訪問並未做過多考慮,因此文件資源訪問很快出現了瓶頸。
研發經理決定將架構優化如下:


負載均衡
使用nginx提供應用服務器的負載均衡,提供兩個應用服務器節點,保證單點崩潰時而系統仍然可用。
文件訪問分離
使用單獨的web服務器(nginx)用作文件訪問服務器,所有的靜態圖片地址將指向獨立域名。
三、加速進化
繼上一次優化之后,用戶的抱怨已經明顯減少,產品經理和領導都對此次工作表示滿意。
研發經理開始感受到了前所未有的成就感。
然而好景不長,在幾個月后公司重點引入了營銷團隊。這是相當給力的團隊,在短短的時間內,在各大網絡平台布置了多個入口。
各種推廣活動、事件營銷接踵而來。最可觀的如在微信朋友圈的一次事件營銷直接引入了好幾倍的用戶量。
這樣的情況在互聯網產品的發展軌跡上至少也可以稱得上一次小小的爆發式增長了。
當然,領導、產品經理都開心和興奮起來了。但這次,研發經理內心開始發愁了:
1 訪問壓力;
一個server的並發處理能力很容易達到上限,一旦超過負載閾值,將直接導致訪問時長加大,甚至系統崩潰、無法訪問等情形;
2 數據存取;
數據量的擴充,單個數據庫表不斷增大,查詢速度將產生下降;
此外數據庫的單點也成為隱患
3 緩存空間;
與數據庫同理,為加速更多數據的訪問,需要提供更大容量緩存空間;
這次,研發經理將系統架構做了一次較為徹底的改進:

負載均衡
增加負載均衡的服務器節點,提高整體處理能力;
數據庫擴展
采取水平切分的方式,實現基於Shard的分布式數據庫集群;
memcached集群
開啟多個memcached節點,組成高可用的緩存集群,同時可支持更大的緩存空間
其中對於服務端程序改造最大的在於分布式Shard數據的實現,一般可從數據量較大的局部表開始切分,在數據存取上加入水平分庫的機制;
當然此時的數據遷移工作也是一個重點。
四、未來的展望
至此,系統優化已經告一段落。當前的后台架構已經處在一個表現穩定,容易擴展的一個狀態。
性能指標方面大致已經可以達到百萬級用戶量,日PV過百萬,甚至還可能更好。
然而這還僅僅是一個雛形,應用系統的場景是多種多樣的,在未來需要解決的問題往往不僅僅這些,比如:
1 系統存在全文搜索、或是標簽式搜索的場景,為了提高搜索性能,你可能會引入sphinx中間件;
sphinx的中文版本為coreseek(可支持中文全文搜索),。
2 為了提高事務處理的效率,你需要隊列服務器來解決,這個可以是ttserver + worker的模式;
3 頻繁的處理緩存數據的解析在開發上會比較麻煩,你還可以更換redis來直接支持數據結構式的緩存...
redis為一款支持數據結構緩存及數據持久化的優秀的nosql中間件,
官網地址:http://redis.io/
備注
架構設計需秉承的"適用"原則,不同業務場景所采取的架構都會有些差異,
此處僅僅討論最常見的擴展思路,關於讀寫分離、數據主備等做法在此不做討論。
本文所提及的故事情節均屬杜撰,如有雷同,實屬巧合。