高性能高并發系統的穩定性保障
本文是2015年肖飛在內部分享的《高性能高并發系統的穩定性保障》PPT內容。
性能、并發、穩定性三者關系
-
高性能:高吞吐量、低延時
-
公式:吞吐量(并發)=單位時間/平均延時
-
N-th% Latency:TP99, TP999
-
穩定性:低延時的穩定性標準為TP99/TP999是隱含的必要條件;系統的穩定性標準:高+可用;用戶標準
吞吐量:QPS, TPS,OPS等等,并發。并不是越高越好,需要考慮TP99。用戶角度:系統是個黑盒,復雜系統中的任何一環到會導致穩定性問題。SLA:在某種吞吐量下能提供TP99為n毫秒的服務能力。降低延時,會提高吞吐量,但是延時的考核是TP99這樣的穩定的延時。
如何改善延時
你應該知道如下表格
JeffDean
Disk random read IOPS:
IOPS = 1000 / (4 + 60000/7200/2) = 122
IOPS = 1000 / (4 + 60000/10000/2) = 142
IOPS = 1000 / (4 + 60000/15000/2) = 166
SSD random read IOPS:
IOPS = 1000000/16=62500
數字的啟示
-
高速緩存的威力;
-
線程切換代價cache miss
-
順序寫優于隨機寫
-
局域網絡快于本地HDD
-
大塊讀優于小塊讀
-
SSD解決隨機讀寫
-
跨地域IDC網絡是最大的延時
策略
-
關鍵路徑: “28原則”(20%的代碼影響了80%的性能問題,抓重點)、“過早優化是萬惡之源”。不同解讀;
-
優化代碼:空間換時間: 各級緩存 ;時間換空間: 比如傳輸壓縮,解決網絡傳輸的瓶頸 ;多核并行: 減少鎖競爭 ; lesscode; 各類語言、框架、庫的trick; 算法+數據結構,保持代碼的清晰、可讀、可維護和擴展;
-
通過性能測試和監控找出瓶頸
metric
通過性能測試和監控:
-
單系統operf/jprofiler etc;
-
Java的一系列工具:jstat, jstack, jmap, jvisualvm,HeapAnalyzer, mat
-
分布式跟蹤系統:Dapper,鷹眼等
benchmark
微觀
-
內存分配
吞吐量和利用率的權衡
顯式分配器:jemalloc/tcmalloc代替默認的ptmalloc
隱式分配器:JVM GC的各種調優
是否使用hugepagen預分配和重用:Netty的Pooled ByteBuf
減少拷貝:new ArrayList(int), new StringBuilder(int)
內存分配器利用率:減少內部或外部碎片;Page Table(頁表), TLB(頁表寄存器緩沖),減少TLB miss,pin cache。增加COW的開銷, 與內存分配器的實現沖突。JVM的GC調優是很多Java應用的關注重點。
-
減少系統調用
批處理: buffer io,pipeline
使用用戶態的等價函數: gettimeofday ->clock_gettime
減少鎖競爭
RWMutex
CAS
Thread local
最小化鎖范圍
最小化狀態,不變類
批處理增加了內存拷貝的開銷,但是減少了系統調用開銷,減少了上下文切換的影響。bufferio的例子:日志、網絡讀寫。pipeline的例子:redis。
-
減少上下文切換
觸發:中斷、系統調用、時間片耗盡、IO阻塞等
危害:L1/L2 Cache Missing,上下文保存/恢復
單線程:基于狀態機redis和Master/Worker的nginx
CPU親和性綁定
ThreadPool的配置,不同任務類型不同的ThreadPool
幾個例子:1、docker中線程池大小的核數自動設定;2、CPU節能模式;3、CENTOS-7.1內核BUG。
-
網絡
內核TCP Tuning參數和SocketOption:net.ipv4.tcp_*
TCP Socket連接池
網絡I/O模型
傳輸壓縮
編解碼效率
超時、心跳和重試機制
網卡:多隊列中斷CPU綁定;增加帶寬:萬兆、Bonding;Offload特性:ethtool -k eth0;UIO Driver: DPDK
連接池:減少握手、減少服務端session創建消耗。網絡I/O模型:BIO、Non-Blocking IO、AIO;select/poll、epoll/kqueue、aio;netty使用nativetransport。Offload特性:ethtool-k eth0。 將數據包分組、重組、chksum等從內核層放到硬件層做。
如何提高吞吐量
改善和降低單機的延時,一般就能提高我們的吞吐量。從集群化上講,因素就比較多。
宏觀
-
提升系統擴展能力
-
應用的無狀態架構
-
緩存/存儲的集群架構:冗余復制(負載均衡、異構解除系統依賴 ); 分布式(數據sharding , 副本,路由,數據一致性 ) ;切換
-
微服務/SOA
-
擴容
-
異步化
-
緩存
復制
-
通過復制提高讀吞吐量、容災、異構
-
通過數據分片,提高寫吞吐量
-
程序雙寫:一致性難以控制,邏輯復雜,冪等性要求。完全把控復制和切換時機。異構系統唯一選擇。 同步雙寫(數據一致性高,影響性能,不適合多個復制集 ); 異步雙寫(數據一致性差,性能高,適合多個復制集 ); CDC[Change Data Capture](canal,databus等 )
-
底層存儲復制機制:一致性由底層控制,對應用端透明。程序和底層存儲配合切換
擴容
-
每年大促前的核心工作:該擴容了嗎?現狀分析;擴容規劃(關鍵系統峰值20倍吞吐量);擴容依據(架構梳理、線上壓測 ) ;
-
擴容checklist:前(部署、DB授權.... ); 后(配置更新、LB更新、接入日志、接入監控.... )
-
應用擴容、數據擴容、寫擴容、讀擴容
-
垂直擴容:加內存、升級SSD、更換硬件。數據復制、切換
-
水平擴容:數據遷移或初始化
現狀分析:去年雙十一到目前,峰值時的性能數據;軟硬件性能指標;數據存儲容量。
擴容規劃;流量規劃:核心系統20倍吞吐量 ; 數據增長量規劃;擴容依據;架構梳理;線上壓測。
讀擴容比寫擴容難;讀寫分離。
異步化
-
解耦利器
-
削峰填谷
-
頁面異步化
-
系統異步化
-
JMQ
-
狀態機(worker)+DB
-
本地隊列
-
集中式緩存隊列
本地內存隊列:實時價格回源服務響應之后,通過BlockingQueue異步更新前端緩存。本地日志隊列:庫存預占。集中式緩存隊列:商品變更任務下發系統。
異步化的一些例子:
1、操作系統內核的高速緩存隊列,磁盤延遲刷盤;
2、mysql數據庫復制、redis復制;
異步化需要注意的是:
1、任務要落地;
2、不可避免的重復執行,需要冪等;
3、是否需要保證順序、如何保證順序。
緩存
-
久經考驗的局部性原理
-
多級緩存:瀏覽器browser cache、cdn、nginx本地redis緩存、本地JVM緩存、集中式緩存...
-
緩存前置:2/8原則、單品頁、實時價格、庫存狀態
-
一致性、延遲權衡
-
緩存主節點負責寫,和最重要的校驗
-
通過CDC監聽數據庫binlog主動更新緩存
-
CPU不是瓶頸,網絡才是
-
優化編碼,減少尺寸
-
優化操作
-
優化拓撲
如何保障穩定性
宏觀
-
提高可用性
-
分組和隔離
-
限流
-
降級
-
監控和故障切換
可用性
-
可用性衡量指標:幾個9
-
可用性度量:A = MTBF / (MTBF + MTTR)
-
減少故障、加長可用時間
-
減少故障修復時間(發現、定位、解決)
-
冗余復制、災備切換,高可用的不二法門
-
如何快速切換?
-
切換的影響
-
監控、ThoubleShooting、軟件質量的影響
可行性指標:999,一周10分鐘;9999,一周1分鐘不可用。可用性:從客戶角度。可用性度量:A = MTBF / (MTBF + MTTR) ,其中MTBF表示mean time betweenfailures,而MTTR表示maximum time to repair or resolve。
高可用行性的成本和收益,好鋼用在刀刃上。
如何快速切換:有可以切換的?可以不重啟應用么? 操作快捷么?演練過么?
切換的影響:切換目標資源能否承受新增的壓力;切換是否影響狀態(數據的一致性、丟失問題)。
監控到位、即時,減少故障發現時間;監控全面,增加故障分析時可以參考的數據。
troubleshooting的能力,踩坑的精力, COE,問題本質、根源的追查。
軟件質量:編碼是否健壯、(異常處理、防御性、2/8原則)超時處理、日志是否全面合理、線程名稱等等。
測試:case是否全面、自動回歸。
上線:是否灰度:N+1, N+2;回滾方案、數據回滾。
分組和隔離
-
網絡流量隔離:大數據單獨部署,QOS;
-
業務系統隔離:秒殺系統獨立出主交易;
-
流量分組:對使用者按照重要程度、請求量、SLA要求等因素分級
-
存儲的分組:按照使用者重要程度、實時性要求等因素,將數據庫的復制集分組
傳統世界的例子:道路被劃分為高速道路、自行道、人行道等,各行其道。
流量分組
舉例:商品基礎信息讀服務。對使用者按照重要程度、請求量、SLA要求等因素分級,將服務實例和存儲分組:交易、生產、網站、移動、promise、ERP...
讀寫分離
舉例:商品主數據服務。按照使用者重要程度、實時性要求等因素,將數據庫分組:ERP、POP、網站、大數據平臺...
限流
-
限流原則:影響到用戶體驗,謹慎使用
-
區分正常流量和超預期流量:限流標準來自壓力測試、折算
-
讀少限,寫多限
-
客戶端配合限流
-
不同分組的限流閾值
-
各層限流手段
前置限流,快速失敗:比如通過提供給調用方的JSF客戶端,封裝限流邏輯。
Nginx層限流:自主研發的模塊;幾個規則:賬戶,IP,系統調用流程。
應用限流:減少并發數線程數;讀少限,寫多限;DB限流;連接數。
降級
-
保證用戶的核心需求
-
降級需要有預案和開關:確定系統和功能級別,是否可降,影響如何;降級需要有開關
-
非關鍵業務屏蔽:購物車的庫存狀態
-
業務功能模塊降級:實時價格更新不及時;peking庫,保訂單管道、生產,暫停統計相關
-
數據降級:動態降級到靜態;遠程服務降級到本地緩存:采銷崗服務
監控和切換
-
無所不在的監控:網絡流量;操作系統指標;服務接口調用量、TP99、錯誤率...;日志;業務量變化;太多監控了,如何提高監控的質量
-
切換:切換開關;成熟的流程可自動化;數據的重要性、一致性,要求強一致的,可以人工介入;系統的指標沒法判斷、監控點不全的,需人工判斷決定
review
Nginx層限流:自主研發的模塊;幾個規則:賬戶,IP,系統調用流程。
應用限流:減少并發數線程數;讀少限,寫多限;DB限流;連接數。
如何驗證性能和穩定性
-
線上壓測:兩類壓力測試場景(讀業務壓測、寫業務壓測 ) ;壓力測試方案(從集群中縮減服務器、復制流量、模擬流量、憋單)
-
全流程演練:降級、切換等
讀業務壓力測試:是將線上業務隔離后,壓測至系統臨界點,通過分析系統在臨界點時軟硬件指標定位系統短板并優化。
寫邏輯壓力測試,如果數據具有不可恢復性,一定要提前做好數據隔離保護,如訂單號壓測,為避免影響線上業務,壓測前后都要做好“跳號”以隔離線上數據。
從集群中縮減服務器。加大單臺服務器的壓力。大概估算出正常的集群規模能夠承載的流量。
復制流量。主要通過 Tcpcopy 復制端口流量,多層翻倍放大流。
模擬流量。模擬流量主要腳本攻擊工具和壓測工具結合,主要用ab,siege,webbench,loadruner通過多臺機器壓測。分機房,按分支進行壓測。
憋單。主要針對后續的訂單生產系統壓測。通過在管道積壓一批訂單,然后快速釋放,形成對后續生產系統持續快速的沖擊,達到壓測的目的。
來自:https://mp.weixin.qq.com/s/YMgIwaz8YC_zNPh_Jf98HA