Premature optimization is the root of all evil.java
— Donald Knuth緩存
對於程序優化,我一直採起保守的態度,除非萬不得已。可是隨着業務的不斷髮展,程序愈來愈複雜,代碼越寫越多,優化彷佛是終有一天會到來的事情。安全
那麼對於一個典型的後臺服務接口,咱們能夠從那些方面入手進行優化呢?服務器
垂直拆分能夠簡單理解爲微服務化,把一個大而複雜的服務拆分紅多個相互獨立,職能單一的服務,單獨部署。 更細粒度拆分的好處是,能對某個具體的微服務進行特殊優化,以最大的投入產出比來解決整個服務的性能。 垂直拆分還有一個好處是,對於非必須的接口,能夠很方便的進行降級處理,把壞影響隔離到核心邏輯外部。 最容易想到的優化辦法是把某個對總體性能有決定性影響的微服務接口進行水平擴容。網絡
注意: 拆分後一定會增長外部接口調用,多少會有些額外開銷,可是對於有限幾個調用,拆分的仍是值得的。併發
這裏說的水平拆分必定不是把一個接口部署更多份,由於這樣只能解決接口的容量問題,可是不能減小接口的響應時間。 水平拆分能夠簡單理解成mapreduce模型,把整個計算邏輯或者數據平均分配到集羣中的N個服務器去,而後由一臺機器去併發調用並作結果合併。 理論上這種方式能把響應減小到1/N+合併+調用開銷
的時間。異步
注意: 一個問題須要考慮的是,若是併發調用的接口返回的數據量比較大,可能會對合並機器的網絡負載和數據序列化(CPU)有必定影響。分佈式
一個有着複雜邏輯或者大量計算數據的接口,能對整個結果進行緩存再好不過了。緩存針對不一樣的場景會有多種策略,對於有大量併發請求的場景, 推薦一個方案:一種基於「哨兵」的分佈式緩存設計,不會有損失第一個用戶,也不會有定時更新緩存的額外開銷。微服務
本地緩存有兩種場景,對於相似字典類型的數據,能夠靜態化後放入內存,定時去刷新或者採用通知機制去更新。性能
還有一種場景是用ThreadLocal緩存重複內部計算與重複的對象建立; 對於鏈路比較長或者循環比較深的接口,ThreadLocal減小重複計算和對象建立,從而下降RT和節約內存。
注意: 在有內部併發的地方使用ThreadLocal必定要注意不一樣線程間的數據同步。主線程的ThreadLocal數據和每一個併發子線程的ThreadLocal數據要同步好。
相似於發消息,寫日誌,更新緩存等不會影響接口準確性的非核心流程,能夠採用異步方式進行處理,不阻塞主計算邏輯處理。
若是進行水平拆分後,併發調用IO較大,能夠考慮換成內部併發解決IO問題。若是內部併發涉及到每一個線程更新同一個集合數據,不用忘了使用線程安全的集合。 這裏有一個併發更新HashMap的case:併發環境下HashMap引發full gc排查。
優化必定不是一蹴而就的,整個優化過程是一個統計-->方案-->驗證
的閉環,須要不斷試錯,不斷挖掘,最終達到預期。