天天看點

MySQL高并發場景實戰 ——淩洛

内容簡要:

一、問題和挑戰

二、系統調優

三、流程管理和生态工具

MySQL高并發場景實戰 ——淩洛

阿裡巴巴CEO逍遙子曾說過:“雙11是商業界的奧林匹克。”

如上圖所示,雙十一購物始于2009年,曆年的訂單建立、支付筆數與交易總額都是成倍增長,這不僅帶來許多商業機遇,也給後端技術、架構以各個子產品帶來技術沉澱。

雙11為MySQL帶來了高并發場景的問題與挑戰,主要表現在:

1) 洪峰般地并發

根據市場部部門的推廣和引流、曆年雙11的經驗,大促的起始時刻呈現接近90度上升趨勢。在這麼大通路流量下,所有的核心鍊路的增删改查都是在資料庫上操作,對資料庫有比較大的沖擊,在大量線程并發工作時線程排程工作過多、大量緩存失效、資源競争加劇、鎖沖突嚴重,如果有複雜SQL或大事務的話還可能導緻系統資源耗盡,整個資料庫服務不可用,進而導緻大促收到影響,甚至失敗,比如:下單失敗、網頁無法打開、無法支付等。此外此類場景也會發生在線上教育、直播電商、線上協同辦公等。

2) 熱點行更新

庫存扣減場景是一個典型的熱點問題,當多個使用者去争搶扣減同一個商品的庫存(對資料庫來說,一個商品的庫存就是資料庫内的一行記錄),資料庫内對同一行的更新由行鎖來控制并發。當單線程(排隊)去更新一行記錄時,性能非常高,但是當非常多的線程去并發更新一行記錄時,整個資料庫的性能會跌到趨近于零。

3) 突發SQL通路

當緩存穿透或異常調用、有資料傾斜SQL、未建立索引SQL等情況發生時,在高并發場景下很容易導緻資料庫壓力過大,響應過慢,導緻應用連結釋放慢,導緻整個系統不可用。

4) 智能化運維

雙十一期間這些執行個體的水位管控,機器水位管控,高風險執行個體識别,高風險執行個體優化,在流量高峰期從收到報警、識别問題、解決問題至少需要十多分鐘,如果處理不及時峰值已經過去,導緻大促失敗。

此外,結合業務還有商品超賣、資源的挑戰等問題存在。

為解決以上挑戰與問題,我們做了系統調優,主要從六個方面進行:容量評估、性能評測、架構調優、執行個體調優、核心調優和監控報警。

(一)容量評估

容量評估主要分為三個部分:經驗評估、單元壓測與全鍊路壓測。

MySQL高并發場景實戰 ——淩洛

l  經驗評估

容量評估剛開始階段是經驗評估,根據以往經驗值給出一個預估的壓力,再除以單台機器的性能,大緻可得出所需伺服器的數量。根據伺服器數量、應用機器數量與DB機器數量,可以得出整個資料庫(如連結池)的設定,以及要擴充多少執行個體和應用機器等,判斷能否支撐得住雙11的容量。需要針對上述的預估做一個判斷驗證,通過壓測來完成。

l  單元壓測

經過經驗預估後,需要針對上述的預估做判斷驗證,可以通過單元壓測來完成。由于是分布式的系統,需要針對單個執行個體、單個單元以及單個應用子產品來進行壓測。單元壓測的主要功能是完成單元内的驗證,系統整個的架構很多是異地多國,是以不但需要驗證整個雙11的流量,還要驗證在單元内的容量是否充足,以及單個系統的容量,例如壓測某一個子產品、交易子產品、優惠子產品等容量是否充足。

l  全鍊路壓測

等每一個應用子產品驗證完成之後,需要對整個鍊路進行壓測,也就是全鍊路壓測。全鍊路壓測是基于場景化的仿真測試,其資料最接近業務的系統值,針對全鍊路壓測,可以借助壓測來驗證整個分布式系統的容量是否充足。

(二)性能評測

1.性能評測的意義

1)目的

發現基礎設施瓶頸、中間件瓶頸、系統容量瓶頸;

發現分布式系統短闆。

2)用途

保障大促容量充足,保障業務正常運轉;

保障核心功能、保證使用者體驗;

評估大促成本,包含人工成本、機器成本、運維成本等。

3)難點

真實業務場景壓測;

真實SQL模拟。

2.基準測試

MySQL高并發場景實戰 ——淩洛

壓測可以分為基準測試和仿真測試。對于MySQL而言,基準測試可以用sysbench或mysqlslap等。基于通用場景的測試,每個執行個體在不同的業務場景下達到的容量也不同,通常情況下,同一個執行個體的應用真實的業務場景的值不會超過其基準測試的值。

3. 全鍊路壓測是大促備戰核武器

真實業務場景的壓測往往比基準測試更加複雜,阿裡巴巴在雙11的場景下整個壓測過程大概可以分為4個步驟,如下圖所示:

MySQL高并發場景實戰 ——淩洛

首先針對涉及到的業務進行子產品梳理與技術架構梳理,以及容量預估是否充足。梳理完成之後需要進行環境準備,包含伺服器準備、資料構造與業務請求準備等。第三步正式壓測,可以通過壓測來發現短闆,驗證容量是否充足。預案驗證可以驗證在某個壓力場景下,降級某個預案會給系統減少多少壓力。驗證壓測執行完之後,需要針對過程中發現的短闆、架構以及容量等問題進行優化,這個過程并非一蹴而就,而是要經過多輪壓測。

阿裡巴巴集團及各BU每年壓測4000+次,13年全鍊路發現700+問題,14年發現500+問題,15年發現400+問題。真實業務場景的全鍊路壓測,已成為每年雙11前籌備工作的核心之一。

4.工具

對于上述的全鍊路壓測操作,我們有一些現成的工具以供使用。

1)PTS(Performance Testing Service)

是面向所有技術背景人員的雲化測試工具,可了解為全鍊路壓測工具。有别于傳統工具的繁複,PTS以網際網路化的互動,提供性能測試、API調試和監測等多種能力。自研和适配開源的功能可以輕松模拟任意體量的使用者通路業務的場景,任務随時發起,免去繁瑣的搭建和維護成本。緊密結合監控、流控等兄弟産品提供一站式高可用能力,高效檢驗和管理業務性能。

2)DAS(Database Autonomy Service)

智能壓測主要應用在以下兩種場景:

l  為應對即将到來的短期業務高峰,驗證目前的RDS MySQL規格是否需要擴容;

l  資料庫遷移上雲前,驗證目标RDS MySQL的規格是否滿足業務需求。

5.注意事項

根據以往的情況,性能評測時主要有4個方面需要特别注意:

MySQL高并發場景實戰 ——淩洛

1)參數

如果想對比一兩個參數在不同情況下,例如打開和關閉、設定不同的值時對性能的影響,可以單獨做測試。一旦測試出來最優值,需在壓測之前将參數調到最優值。

2)網絡

曾有使用者拿線下的機器連結本地資料庫,然後拿本地的應用機器連結RDS做性能對比,這種對比不準确,主要原因是壓測機到RDS的網絡延遲和到本地資料庫的延遲存在很大差異。

3)規格

RDS的規格的性能差别較大,如果想測試CPU的性能,實體IO要少,資料大小在記憶體容量範圍内即可。但大多數業務場景都是涉及到實體IO,是以在到測試資料時,資料量要大于記憶體的大小

4)ECS的網絡帶寬

阿裡雲的ECS是限制網絡帶寬的,以往有使用者在做測試時,RDS的資源沒有用滿,壓力也上不去,經過定位發現是ECS的網絡帶寬打滿了,是以在準備整個壓測環境時,要将這些内容調好。

(三)架構調優

1.資料庫架構調優

MySQL高并發場景實戰 ——淩洛

如果業務的通路都用資料庫支撐的話成本高昂,緩存可以代替一部分關系型資料庫在讀方面的請求。基于原理的設計以及成本方面考慮,緩存的讀性能比關系型資料庫好,成本效益較高。

到資料庫層面,如果是讀多寫少,針對于單個執行個體很難支撐的情況下,可以借助于隻讀執行個體。隻讀執行個體可以實作線上彈性的擴充讀能力,讀的業務請求可以實作隔離,例如可以把輕分析型以及拖資料類型在隻讀執行個體内完成。

此外,每個隻讀執行個體都有一個單獨的連結位址,如果把某一類的業務和其他的業務區分開,例如某一類的隻讀的這個場景,隻到某一個執行個體通路,可以單獨連結隻讀執行個體的連結串。

如果要是想從整個層面來控制主執行個體和隻讀執行個體的通路,可以借助負載均衡獨享代理完成。獨享代理可以緩解大量短連結的場景,使用代理後不用反複變更應用類的連結位址,減少維護成本。使用獨享代理之後,可以對線上的資源實作可擴充,承受更高的流量。如果是RDS的執行個體規格以及隻讀執行個體都已經升到最大,但仍然不能支撐業務發展的話,可以考慮把RDS的更新到Polar Mysql或者是分布分表Polar X2.0,完成讀寫容量的擴充。

2. 降低隻讀執行個體和主執行個體的延遲

針對主執行個體和隻讀執行個體的資料一緻性的問題,例如有延遲以及中斷場景。針對線上延遲的問題我們做了分析,得出原因主要包括5個方面:

1)主執行個體的DDL

占40%,如Alter、Drop等。需要Kill DDL語句或用DMS的無鎖變更等。

2)主執行個體的大事務

占20%,如大批量導入、删除、更新資料。需要将大事務拆分成為小事務進行批量送出,這樣隻讀節點就可以迅速的完成事務的執行,不會造成資料的延遲。

3)主執行個體寫入壓力過大

占20%,如主執行個體規格較小、壓力過大。這種情況需要更新主執行個體和隻讀執行個體的規格。

4)隻讀節點規格過小

占10%,這種情況更新隻讀執行個體規格。

5)其他(無主鍵)

占10%, RDS目前已經支援對表添加隐式主鍵,但是對于以前曆史建立的表需要進行重建才能支援隐式主鍵。

3. 提升緩存命中率

在高并發場景下,寫入壓力過大,如何提升緩存的命中率?

根據以往的經驗,有4種更新方式:Cache aside,Read through,Write through,Write behind caching。

緩存的更新時,應用可以從Cache裡面讀取資料,取到後傳回,沒有得到從資料庫裡面取,成功後再傳回緩存當中;

Read through是已讀沒有讀到,就更新緩存;

Right through是在資料更新時,發現緩存中沒有就更新緩存;

Write behind caching類似于底層的 Linux作業系統機制,如果要是用Write behind caching合并同一個資料的多次操作,以上幾種方式都不能保證緩存命中率。

我們做核心系統時有一個小巧思,下面以産品的形式進行解釋。

MySQL高并發場景實戰 ——淩洛

如上圖所示,應用程式把寫請求到RDS,讀請求到 Redis。RDS實時擷取變更資料,通過訂閱資料變更的方式拿到增量資料後,更新Redis,這個巧思有以下好處:

l  更新路徑短,延遲低

緩存失效為異步流程,業務更新DB完成後直接傳回,不需要關心緩存失效流程, 整個更新路徑短 ,更新延遲低。

l  應用簡單可靠

應用無需實作複雜雙寫邏輯,隻需啟動異步線程監聽增量資料,更新緩存資料即可。

l  應用更新無額外性能消耗

因為資料訂閱是通過解析DB的增量日志來擷取增量資料,擷取資料的過程對業務、DB性能無損。

(四)執行個體調優

執行個體調優主要包含兩部分:彈性擴容和參數調優。

1.彈性擴容

MySQL高并發場景實戰 ——淩洛

2.參數調優

參數調優主要從三個方面進行,分别問連接配接、記憶體和IO,如下圖所示,這裡重點闡述幾個參數。

MySQL高并發場景實戰 ——淩洛

連接配接相關的參數,back_log是标記MySQL的并發連接配接數。如果在短時間内有大量的連接配接請求時,主線程會在一段時間内或者是瞬間檢查連接配接數并啟動新連接配接。

table_open_cache是所有線程打開表的數量,性能較小時會導緻性能下降,但也不能設定過大,否則可能會造成 OMM。

IO相關的參數,sync_binlog大家不會陌生,我們在每年的雙11會将這些數值調到最優。io_capacity和刷髒是IO兩個比較重要的參數。

記憶體相關的主要參數是innodb_buffer_pool_instances。在5.6之前,相對來說innodb_buffer_pool_instances隻有一個時,如果記憶體越大,它的性能越不穩定,因為刷髒的時候要鎖。當有buffer_pool_instances了之後,會把Buffer拆到好幾個記憶體的List中。這種情況下,每一個記憶體都會維護自己的List和鎖結構,相當把鎖拆分,性能會提升很多。此外還有和幾個連接配接相關的參數,例如join_buffer以及臨時表。

針對影響性能幾個主要的參數,使用者可以單獨設定。這裡我們已經将對性能影響較大的參數調到高性能模闆中,應用時可以找到對應的參數,應用到對應的執行個體上即可。

MySQL高并發場景實戰 ——淩洛

上圖是普通模闆與高性能模闆的一個對比,可以看到,相比高性能模闆,普通模闆的性能要低25%左右。

(五)核心調優

1.版本更新

MySQL高并發場景實戰 ——淩洛

如上圖所示,從版本上來看,目前官方維護的是5.6、5.7和8.0版本,每一個大版本的更新會帶來一些新的特性,同時它的性能也會有上升,從表中可以看到8.0性能是最強的。但更新時也會遇到一些問題,例如執行計劃有一些和原來版本不太相容的地方。

2. AliSQL特性

1)内容調優的4個更新檔

MySQL高并發場景實戰 ——淩洛

針對高并發與熱點庫存的場景,AliSQL提供了4個更新檔解決,其中記憶體注釋、語句隊列以及語句傳回這3個更新檔是針對熱點庫存更新。

l  庫存注釋

MySQL高并發場景實戰 ——淩洛

在秒殺業務中,從邏輯上來說減庫存包含兩個場景:拍下減庫存和付款減庫存。

拍下減庫存表示客戶拍下時把庫存減掉,業務邏輯較為簡單。付款減庫存表示客戶付完款後減掉庫存,業務邏輯較為複雜,不是一條語句能夠完成的,而是在事務中完成。在事務中,行鎖沖突本來就較為嚴重,是以需要提升事務的性能。

通常的情況下,釋放事務、開啟事務和結束事務都是由應用來完成,如果是應用處理得過慢,或是網絡互動的時間過慢,或者是網絡擁堵,就會增加行鎖持有的時間。

庫存注釋是把持有行鎖的時間行鎖釋放,交給資料庫自己來做。使用排隊和事務性Hint來控制并發控制、快速送出或者復原事務,成功就送出,失敗就復原,将控制權交給MySQL核心可以減少行鎖持有的時間,快速地結束事務,提升減庫存的吞吐能力。

l  語句隊列

MySQL高并發場景實戰 ——淩洛

MySQL分為引擎層和Server層,在高并發的場景下同一行的行鎖會在Server層和引擎層會來回切換。

InnoDB的事務鎖是最細粒度的行級鎖,如果語句針對相同行進行并發操作,會導緻沖突比較嚴重,AliSQL将沖突放在Server層進行排隊。對于相同行的沖突,如果讓它在一個桶内,會減少沖突檢測的開銷,進而減少引擎層和Server層上下文切換帶來的消耗。

l  語句傳回

MySQL高并發場景實戰 ——淩洛

語句傳回即更新完之後直接把結果傳回,這個特性在PG和Oracle中都有,叫Returning,在MySQL沒有,AliSQL吸納了這個特性。

如果在一個事務中更新完一行記錄之後,應用再發請求Select這一條結果再傳回給應用,會多一次網絡互動。如果直接把Update的結果傳回,就可以減少這一次網絡互動。性能的提升可以節省多次網絡互動和應用判斷的時間,帶來事務性能與應用性能的提升。

l  線程池

MySQL高并發場景實戰 ——淩洛

對于高并發場景,AliSQL使用線程池來解決。

在有大量線程進行并發通路時,線程池會自動調節并發的線程數量在合理範圍内,避免線程池因為線程數量過多造成大量緩存失效。

線程池會将語句和事務分為不同的優先級,分别控制語句和事務的并發數量,減少資源競争,根據不同語句的複雜性來控制它的優先級。

是以使用線程池可以将不同的SQL控制在一個合理的連接配接數範圍,使資料庫在高并發的場景下保持較高性能。

MySQL高并發場景實戰 ——淩洛

上圖是用庫存注釋與語句隊列後的性能對比,可以看到和原生性能相比翻了40倍不止。

(六)監控報警

MySQL高并發場景實戰 ——淩洛

監控報警是系統調優裡必不可少的一部分。

監控有RDS自帶的監控,資源層監控,引擎層監控,慢日志的監控,收費的有審計日志,以及自治服務會基于上面RDS自帶的以及審計日志做一些分析,在這個基礎上做一些報警。此外,分布式監控可以監控不同元件的瓶頸。

基于生态工具的保障,可以從變更流程、穩定性和資料恢複這三方面來介紹。

(一)變更流程

在大促期間,通過增加審批節點與流程,很好地提升我們的穩定性。

MySQL高并發場景實戰 ——淩洛

增加審批節點

可以通過設定DMS來執行的這些SQL,不讓它超過一定的時間。也可以針對某一類的DDL或者是DML不允許執行,設定安全規則。

(二)穩定性相關

1.設定逾時時間(通用)

MySQL高并發場景實戰 ——淩洛

穩定性相關,不要因為人為的因素給系統造成壓力,可以通過設定DMS來執行的這些SQL,不讓它超過一定的時間,超過一定時間則Kill掉。

2. 禁用部分文法(企業版)

MySQL高并發場景實戰 ——淩洛

可針對DDL、DML設定部分文法不允許在大促期間執行。

3. 異步清理大表

Ø  核心特性

MySQL高并發場景實戰 ——淩洛

AliSQL支援通過異步删除大檔案的方式保證系統穩定性。使用InnoDB引擎時,直接删除大檔案會導緻POSIX檔案系統出現嚴重的穩定性問題,是以InnoDB會啟動一個背景線程來異步清理資料檔案。當删除單個表空間時,會将對應的資料檔案先重命名為臨時檔案,然後清除線程将異步、緩慢地清理檔案。

路徑:RDS管理控制台->執行個體清單->參數設定

4. 突發SQL通路控制

Ø  核心特性--并發控制

當業務流量突然暴漲,或出現Bad SQL時,DBA要考慮做限流,止損恢複業務。AliSQL設計了基于語句規則的并發控制,Statement Concurrency Control,簡稱 CCL。

Ø  DAS限流

為防止資料庫壓力過大,一般都會在應用端做優化和控制。但在以下場景,也需要在資料庫端做優化控制,如:

1)某類SQL并發急劇上升;

2)有資料傾斜SQL;

3)未建立索引SQL。

MySQL高并發場景實戰 ——淩洛

(三)資料恢複

1.DMS資料追蹤

在大促高峰期間,經常會人工做一些資料變更,如果資料變更出錯的話,可以通過資料追蹤恢複,最快五分鐘内可完全恢複。

MySQL高并發場景實戰 ——淩洛
MySQL高并發場景實戰 ——淩洛

Ø  使用場景

1)MySQL 5.5/5.6/5.7/8.0版本;

2)DELETE/UPDATE/INSERT;

3)少量資料。

Ø  功能

1)線上搜尋日志内容,無需手工下載下傳 Binlog;

2)支援資料的插入/更新/删除日志搜尋,無需手工解析Binlog;

3)支援逐條資料恢複,無需手工生成復原語句。

Ø  支援的Binlog

OSS Binlog(RDS會定時将Binlog備份到OSS上);

本地熱Binlog(資料庫伺服器上Binlog)。

(二)控制台克隆執行個體/庫表級别恢複

資料恢複還可通過備份來實作,可分為克隆整個執行個體恢複與庫表級别恢複,還可以通過DBS資料庫備份來恢複。

路徑:RDS管理控制台->執行個體清單->單擊執行個體ID->備份恢複

MySQL高并發場景實戰 ——淩洛
MySQL高并發場景實戰 ——淩洛

總結以上内容,系統調優主要從内容評估、性能評測、架構調優、執行個體調優以及核心調優等方面實作,可以借助監控報警來發現問題、解決問題,最終實作系統優化。