引入緩存nginx
在應用層和數據庫層增長緩存層,熱點數據放入緩存。如系統中經常使用的開關、白名單等數據,讀取頻率高寫入頻率低,針對這部分數據就能夠在JimDB(Redis)中存儲一份,JimDB (Redis)會把高頻數據存儲在內存中,讀寫性能很高。數據寫入緩存時設置一個有效期,更新數據庫成功後,異步更新緩存數據。若是實時性要求不高,也能夠等緩存失效後,主動更新緩存。引入緩存層,下降數據庫壓力,提高系統響應速度。數據庫
編寫併發處理程序後端
多任務併發處理,充分利用CPU資源。無依賴關係的多條任務能夠並行處理,提升系統處理能力。如結算任務,每筆訂單之間的結算操做沒有依賴關係,能夠同時執行多條結算任務緩存
系統結構優化網絡
核心生成流程異步處理,接收用戶訂單和給用戶充值兩個流程異步化處理,提升系統處理能力。對用戶來講,用戶付款成功,等待充值便可。系統可經過worker觸發充值動做,設置合理的重試次數,間隔必定的時間進行重試。在到達最終狀態前,給用戶顯示中間狀態。架構
拆解大應用,使其微服務化。如話費充值應用,核心功能有PC端接單、移動端接單、MQ消息處理端、後臺管理端、worker端等五大塊。拆解以前,話費應用只有三個系統,系統之間共用service\manager\dao模塊代碼,經過Maven構建管理。實現一個後臺的小需求,都須要考慮PC端、移動端、後臺管理端代碼是否會受到影響,是否須要所有迴歸測試。更恐怖的是上線,充值應用有將近100個實例,修改一行代碼都須要所有上線,即便沒有受到影響的系統也要發佈新版本由於要保證線上和代碼庫中的代碼一致。併發
從功能上進行微服務化之後,應用拆解爲PC端、Server端、MQ消息處理端、後臺管理端、worker端等五個應用,應用之間功能獨立,依賴公司的RPC框架(JSF)和消息框架(JMQ)進行通訊。單個應用的內聚性更高,應用之間的耦合度更低。再實現一個後臺的需求時,開發、測試、部署都只須要關注後臺管理端系統便可,無需再關注其餘四個系統。框架
系統微服務化設計,關鍵點是如何尋找限界。除了能夠從功能上進行切分還能夠根據關注點上進行拆解爲生產端和支撐端,業務場景不一樣,尋找限界的方法也不相同,關鍵是微服務後單個應用的內聚性更高,應用之間的耦合度更低。使大系統微服務化的方案有不少種,重點是制定好目標,逐步向目標靠攏。在服務粒度方面,如話費充值應用的MQ消息處理端,在功能上保持職責單一,只負責接收、解析MQ消息內容,具體業務邏輯處理交由相應的Server端處理。在技術選擇上,公司有成熟的技術框架,如RPC框架JSF,消息框架JMQ等,這些框架都有對應的服務治理和監控等相關服務和團隊。異步
不要爲了微服務化而實施對大系統微服務,要確保微服務化以後,系統運行更穩定,應對變化更快速,開發更敏捷。微服務
讀寫分離
實時性要求不高的數據讀取從庫,下降主庫壓力。如對帳功能,讀取的是前一天的訂單數據,這些數據就不必從主庫中讀取。關於技術實現上,Spring框架自己有提供,實現其抽象類AbstractRoutingDataSource便可。
變化頻率低的頁面靜態化
充值應用中有不少卡片頁,如QQ頁卡等,頁面上的數據變化的只有廣告位。這種類型的頁面就能夠靜態化,定時更新頁面,推送到存儲介質上,nginx配置location,直接讀取頁面,下降後端服務的壓力。
當業務量發展到必定程度後,數據庫就會成爲系統的瓶頸。話費充值應用包含企業訂單業務和普通用戶訂單業務,正是因爲其業務的特殊性,採用了垂直+水平分庫方案。根據業務類型進行垂直切分,不一樣業務類型訂單數據獨立存儲,同一種業務類型在水平上由多個庫保存。垂直+水平的分庫方案可以最大限度的下降不一樣業務類型訂單數據之間的相互影響,提升數據讀寫併發量。普通用戶訂單業務,根據帳戶PIN進行hash打散能夠均勻的分佈到每一個庫中,sharding規則就是hash(pin)值,同時這個hash(pin)值還作爲本地訂單號的前綴,這樣就能夠經過帳戶PIN和本地訂單號兩個維度中任一維度均可以路由到數據庫。建立ERP訂單成功後,把本地訂單號和ERP訂單的映射關係保存到JmiDB中,對於只有ERP訂單號的業務流程,能夠經過映射關係找到本地訂單號,有了本地訂單號也就能夠路由到數據庫了。而企業訂單業務,每一個企業帳戶的訂單量不均,差異能達到三個數量級,若是再根據帳戶PIN進行hash打散分佈到每一個書庫中的訂單就會不均勻,不能使用這種sharding規則。根據本地訂單號進行hash,而後再做爲本地訂單號的前綴。建立ERP訂單成功後,一樣須要保存本地訂單號和ERP訂單號的映射關係到JmiDB中,以保證在後續的業務流程中,可以根據ERP訂單號路由到數據庫。
拆分完成後,有的業務場景須要聚合查詢數據,如訂單管理。若是沒有聚合數據,就須要在應用中,開發人員自行考慮聚合。通用的聚合方案是從每一個庫中查詢一頁數據,在內存中根據條件排序,返回一頁數據,若是須要翻頁的話,邏輯更爲複雜。話費充值應用採用了第三方存儲,把每一個分庫中的訂單數據聚合到ElasticSearch中,查詢聚合數據的場景讀取ElasticSearch。模擬MySQL slave的交互協議,解析數據庫的增量BinLog,同步分庫的數據到ElasticSearch中。因爲數據庫主從同步存在延遲的風險,須要準備一個降級方案。在話費充值應用中,數據庫寫訂單成功後,插入一條任務記錄,經過任務模型當即同步數據到ElasticSearch中。保證數據同步的實時性。
計算機的CPU、線程、IO等資源都是寶貴且有上限的,當某一個資源耗盡時,那這臺計算機上全部的服務都將中止服務。例如某一個服務依賴的第三方服務性能低,響應緩慢,這時若是客戶端的繼續請求,會致使該服務持續建立線程等資源,最終致使服務宕機。此時,計算機資源的隔離顯得尤其重要。
在JVM內部隔離分爲信號量隔離和線程池隔離,Netflix Hystrix插件提供了完美的支持。JD-Peer(多機房公網出口路由系統)中使用了Hystrix對每個商家進行了隔離。話費充值應用對接了幾十個商家,經過JD-Peer系統跟商家進行交互。因爲某些網絡緣由致使其中一個商家A響應慢,持續的調用,全部資源都會被這一個商家佔用,致使其餘商家服務也不可用,最終宕掉。
獨立部署,物理隔離。每一個應用分配獨立容器,從硬件層面進行資源隔離。
多機房部署,從入口處分攤流量,提升系統總體的吞吐量。
版本發佈
灰度發佈,平滑過渡,異常狀況下的版本回滾,要確保回滾前的數據在老版本中可用。如京東話費充值系統在發佈數據庫架構升級版本時,設置了數據流向開關,並對訂單打標,同時緩存標識位。 開關打開時,數據進入新的數據庫,開關關閉,數據進入老的數據庫。線上驗證階段,一旦發現問題,可當即關閉開關。確保系統版本發佈,對用戶無感知。
在保證系統服務正常可用的狀況下,進行上述一系列的升級,猶如給空中的戰鬥機更換引擎,稍不留神就會墜機,因此除了充分的理論儲備,還須要綜合業務場景,從自身業務場景出發,合理設置引擎更換方案。
通過上面一系列的改造升級,話費充值應用的吞吐量、運行穩定性都達到了最優的狀態,歷經數次的618和雙11衝擊,各項運行指標保持穩定,面對流量洪峯,巋然不動。