深入淺出!阿里運維專家三種方法教你如何應對高併發“海嘯”場景
在資料庫的日常使用中,來自應用的高併發場景並不罕見,其標誌性的表現為高新連線建立速率(CPS,比如 PHP 短連線)、傳送大量請求到 DB 資料庫層。
如同海嘯,大量的新建連線和請求猛烈的衝擊考驗著 DB 層的處理能力,非常容易出現資料庫被衝擊 hang 住或響應極其緩慢的情況(想象下無預知無緩衝的短時間內突然工作量翻漲數倍,會不會立刻被忙哭了 ^_^)。
而資料庫通常作為架構最下端的資料存取匯聚單元,其效能表現和穩定性往往決定了應用的最終表現和使用體驗,可謂業務生死之大事,不可不察。
由此,我們一起看一下 “海嘯” 場景下可以用來 “保命” 的各種解決方案。
注:
• 本文目標是總結高併發場景下的應對處理方法,而應對熱點更新(秒殺)場景的“招數”會另文介紹。
• 本文的主旨在於方便資料庫的使用者理解業務高併發請求場景下的保障 DB 可用性和穩定性的機制和方法,非機制的全面深度技術細節介紹。
執行緒池
1.1 模型
我們舉一個生活中的例子方便大家理解執行緒池(Thread Pool)。
比如有個銀行,有 10 個視窗(例項規格 CPU 數量),官方說可以容納 10 人(Client Thread)。平時呢,人也不多,一直順暢。稍微忙一點呢,大家擠擠。這個 10 人的地方,擠個 50 人也可以(不是每個人時刻都在視窗辦業務)。效率也挺高。
年底發工資、公司結算、發行紀念幣來了一大幫人,大家一起擠,誰也不讓,就把銀行擠滿了;大家接踵摩肩,動也動不了,再發生些爭搶,那這銀行誰也辦不了業務了。
好了,來個保安(Timer Thread),搞了個隊伍機制(10 個佇列 loose_thread_pool_size = 10),按規定執行,一次放 10 個人。這個效率也不錯。
當然了,如果一下子來了 1000 個人,那麼門口等待的隊伍會很長,雖然不致於把銀行撐爆,但是後面的同學要等很長時間,有的會去抱怨了(應用側等待超過自身定義的超時時間後返回錯誤)。
問題來了,有的同學搞不清楚買哪種紀念幣,一直在看看停停,保安看他們也不像馬上能決定的樣子,而且視窗櫃員也不是非常忙,保安就又搞了個規則,叫 “stall_limit”。
看一些同學猶豫超過 stall_limit 定義的時間,那麼就算他們 stall 了,可以再放 1 個人進去(oversubscribing)。但去視窗辦業務的人數是有上限的,最多 50 個人(10 個視窗每個視窗 5 個人, loose_thread_pool_oversubscribe = 4)。
之後,只能出一個,進一個; 如果都不出來,那也 hang 了。這個時候,至少要讓保安能進去,把這些太慢的同學趕出來幾個,讓等待的佇列動起來。
還有,有的同學在裡面發現忘帶證件了,需要等送進來。他們找地方等(lock wait)。那麼他們是在等待了,這個是不算 oversubscribing 數量的,所以保安也可以放人,一直放到 thread_pool_max_threads 個人。
如果證件還沒送來,那麼銀行就被這些等證件的霸佔了(hang 了)。另外如果一下子證件都送來,那這個銀行一下子忙起來,也爆了(熱點更新)。
當然如果這個銀行沒有大量客戶同時辦業務的場景,是可以不需要搞個保安,不需要搞個隊伍的(loose_thread_pool_enabled = OFF)。這個銀行本身最多可以 50 個人,但是保安只讓 10 個人進去,那效率就會低了。
還有,門口等待隊伍長了,這個可以有 3 種可能:
• 顧客動作慢(慢 SQL),建議考慮最佳化 SQL 降低執行成本。
• 銀行小, 視窗數量少(例項規格小)建議擴店(升級例項規格)。
• 視窗動作慢(物理機問題、資料庫 bug;不在本文討論範圍內)。
從上面的例子中,我們可以看到 Thread Pool 是透過佇列機制限制資料庫的 Client Thread 的併發度(控制 Running Thread 數量),避免大量的爭搶和建立 Client Thread 的開銷來提升 CPU 使用 效率,保障吞吐的(在應用給與 DB 的訪問壓力不斷增加的情況下,保持 DB 吞吐處理能力)。
1.2 適用場景
如果我們仔細品位下上面的例子,可以發現 Thread Pool 的適用場景:
• 每個要辦的業務簡短(OLTP 場景)且效能瓶頸在 CPU 資源上
• 場景中不存在 大量 需要長時間執行且無停頓(可以暫時不使用 CPU)的 SQL
• 能夠接受一定損失(錯誤/開銷)的業務(啟用 Thread Pool 後需要一定開銷,存在簡單的查詢比不啟用 Thread Pool 的情況下執行時間增加的可能,比如被分配到了 stall 的 thread group 而要花時間等待執行)
1.3 小結
讓我們小結一下。(點選查看大圖)
官方文件:Thread Pool:
https://help.aliyun.com/document_detail/130306.html
核心文件: Thread Pool
那麼面對存在長時間執行的查詢,除了最佳化 SQL 降低執行成本外(有時不具有可操作性,當然如果該查詢對資料時效性不敏感可以考慮轉移到只讀例項上執行),是否還有其他招數可用?請看下一招“限流”。
限流
如果“海嘯”來的異常猛烈,並且在“海嘯”中能夠定義出一批帶有同樣特徵的查詢,比如 Redis 快取被擊穿,大量相似重複查詢打到 DB 層,或者如上例 Thread Pool 中的長時間執行的查詢,那麼在業務支援/允許降級的情況下我們可以透過對這批請求採取限流的方式來“保命”。
相對 thread pool 這種對“海嘯” 全方位覆蓋的應對機制,限流更像是集力量於一點的定向打擊。
2.1 Statement Concurrency Control
對於 RDS for MySQL 8.0 和 PolarDB for MySQL,我們可以透過“語句併發控制”(Statement Concurrency Control)特性來實現針對指定語句的限流。
比如發現下面的查詢在高併發的場景下拖累了整個例項的效能,和業務核實,業務可以接受該查詢被限流。
# 高成本慢查詢
select count(*)
from jacky.mytab
where cid = 90363
or uid = ???
(*請左右滑動閱覽)
# 增加限流規則,限制最多 1 個併發執行
call dbms_ccl.add_ccl_rule('select','jacky','mytab',1,'cid=;uid=');
# 顯示當前的限流規則
call dbms_ccl.show_ccl_rule();
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+-----------+
| ID | TYPE | SCHEMA | TABLE | STATE | ORDER | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITTING | KEYWORDS |
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+-----------+
| 2 | SELECT | jacky | mytab | Y | N | 1 | 116 | 1 | 26 | cid=;uid= |
+------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+-----------+
限流前後對比,可以看到限流後 CPU 使用率從 100% 降低到 50% 左右,有效恢復業務可用性。
2.2 DAS 限流
對於 RDS for MySQL 5.6 和 5.7 ,控制檯的 CloudDBA 功能直接整合了 SQL 限流功能。
我們來看一個真實生活中的例子,某客戶在業務高峰期出現大量的集中請求,導致高配例項 CPU 完全打滿,由於例項響應極其緩慢,能採集到的監控資料顯示當時 活動會話達到 14700+ 。
在業務層反覆調整無法恢復的情況下 在 2020.3.24 21:35 透過設定 SQL 限流恢復了業務可用性。
RDS 例項會話情況
RDS 例項 CPU 使用率情況
官方文件:SQL 限流:
https://help.aliyun.com/document_detail/131417.html
禦敵於外
上面介紹的都是資料庫層面的應對之策,那麼是否我們一定要被動的在資料庫層面“兵來將擋”呢?有沒有主動“禦敵於外”的辦法呢?
3.1 名詞解釋
3.2 短連線最佳化
首先我們來看看一個普通的 SQL 請求是如何被從應用透過網路傳送給 DB 層進而得到處理的。
仔細看一下上述時序圖,就會發現如果應用和資料庫之間在沒有可用的網路連線情況下,需要首先建立起一條基於 TCP/IP 協議棧的 MySQL 網路連線才能夠將 SQL 請求傳送給資料庫例項並獲取到處理的結果集。
在應用採用短連線機制(比如基於 PHP 語言開發的應用)的情況下,每個 SQL/Query 都需要和資料庫例項建立一個 TCP 網路連線,需要消耗資料庫例項(和其所在物理機)的 CPU 資源。
在“海嘯”的場景下,採用短連線機制的應用會保持很高的新連線建立速率(CPS,在出現 ListenOverFlow 和 ListenDrops 場景下大於等於 QPS),這樣在高負載(QPS) 的基礎上進一步消耗資料庫例項的 CPU 資源,拉高 CPU 使用率,降低 CPU 使用效率,進入惡性迴圈容易觸發資料庫雪崩式崩潰。
在 CPU 資源緊張的情況下會出現大量連線請求積壓無法處理而觸發 ListenOverFlow 和 ListenDrops 情況出現。
這裡我們看一個真實世界中的例子。
客戶在 13:30 將應用從長連線模式調整為短連線模式,由於短連線模式的高併發新建連線請求速率(CPS - 每秒新建連線數),修改後例項 CPU 使用率總體上升 25+% 左右,業務側出現大量連線失敗錯誤並感知 RDS 例項響應緩慢。
部分 CPU 被完全打滿,無法滿足處理高連線請求的需求而出現 ListenOverFlow / ListenDrops。
執行緒池 Thread Pool 是資料庫層對該場景較好的解決方案,而啟用了資料庫獨立代理(RDS for MySQL 讀寫分離地址 和 PolarDB for MySQL 的叢集地址)的例項還可以選擇啟用“短連線最佳化”的鏈路層解決方案。
當應用斷開連線後,資料庫獨享代理會判斷之前的連線是否為空閒(idle)連線,如果是空閒連線,代理會將代理與資料庫之間的連線保留在連線池內一段時間(僅釋放應用與代理之間的連線)。
在保留連線的這段時間內如果應用發起新連線,代理會直接從連線池裡使用保留的連線,從而減少與資料庫建立連線的開銷。
官方文件:短連線最佳化
(https://help.aliyun.com/document_detail/146352.html)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69940574/viewspace-2700084/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 深入淺出FaaS應用場景:資料編排
- EF Code 如何應對高併發
- 【高併發】面試官:講講高併發場景下如何優化加鎖方式?面試優化
- 伺服器高併發三種解決方法為:伺服器
- RocketMQ實戰--高併發秒殺場景MQ
- 高併發場景下如何優化伺服器的效能?優化伺服器
- 揭秘10億+高併發應用如何實現高效穩定的開發和運維運維
- 深入淺出 Java 併發程式設計 (1)Java程式設計
- 深入淺出 Java 併發程式設計 (2)Java程式設計
- Delegate 運算子深入淺出
- PHP 併發場景的幾種解決方案PHP
- 深入淺出 OceanBase 運維之彈性擴縮容運維
- 高併發場景下JVM調優實踐之路JVM
- 說說你對歸併排序的理解?如何實現?應用場景?排序
- 由面試題“併發程式設計的三個問題”深入淺出Synchronied面試題程式設計
- 應對高併發,伺服器如何笑而不“崩”伺服器
- 深入淺出MyBatis:MyBatis與Spring整合及實用場景MyBatisSpring
- 【高併發】億級流量場景下如何為HTTP介面限流?看完我懂了!!HTTP
- 深入淺出RxJava(三)--響應式的好處RxJava
- 請求合併與拆分在併發場景中應用
- 帶著三個問題深入淺出React高階元件React元件
- 【Mysql】mysqldump 匯出各種場景的應用MySql
- 面試官:每秒上千訂單的場景下,如何對分散式鎖進行高併發優化?面試分散式優化
- 從“悲劇”的幾個運維場景談談運維開發的痛點運維
- 618 Tech Talk|高併發場景下的資料訪問速度如何保障?
- 運維場景下的兩個自我運維
- 深入淺出理解 React高階元件React元件
- Tomcat深入淺出——Servlet(三)TomcatServlet
- PostgreSQL VACUUM 之深入淺出 (三)SQL
- 深入淺出UML類圖(三)
- 高併發業務場景下的秒殺解決方案 (初探)
- 針對不同場景的Python合併多個Excel方法PythonExcel
- 運維前線:一線運維專家的運維方法、技巧與實踐1.3 運維自動化的困境和價值運維
- 勒索病毒爆發,WFilter教你如何應對?Filter
- 面向173種應用場景阿里雲釋出ECS企業級19款例項阿里
- 真香!盤點雲主機三種典型應用場景
- 深入淺出:Linux裝置驅動中的併發控制Linux
- Memcached筆記——(四)應對高併發攻擊筆記