在0和1的計算機世界裡,開發者和程式設計師們為了提升系統執行速度、最大化釋放伺服器效能,也要面對各種各樣的挑戰,不斷提出方案,展開實踐,以突破瓶頸、解決難題。
個推“大資料降本提效”專題,正是通過總結分享自身在大資料實戰過程中的踩坑經驗、調優技巧等,為從業人員開展大資料實踐提供參考。本文是“大資料降本提效”專題的第三篇,將為大家分享個推通過調優,實現TiDB千倍效能提升的實戰經驗。
個推與TiDB的結緣
作為一家資料智慧企業,個推為數十萬APP提供了訊息推送等開發者服務,同時為眾多行業客戶提供專業的數字化解決方案。在快速發展業務的同時,公司的資料體量也在高速增長。隨著時間的推移,資料量越來越大,MySQL已經無法滿足公司對資料進行快速查詢和分析的需求,一種支援水平彈性擴充套件,能夠有效應對高併發、海量資料場景,同時高度相容MySQL的新型資料庫成為個推的選型需求。
經過深入調研,我們發現“網紅”資料庫TiDB不僅具備以上特性,還是金融級高可用、具有資料強一致性、支援實時HTAP的雲原生分散式資料庫。因此,我們決定將MySQL切換到TiDB,期望實現在資料儲存量不斷增長的情況下,仍然確保資料的快速查詢,滿足內外部客戶高效分析資料的需求,比如為開發者使用者提供及時的推送下發量、到達率等相關資料包表,幫助他們科學決策。
完成選型後,我們就開始進行資料遷移。本次遷移MySQL資料庫例項的資料量有數T左右,我們採用TiDB自帶的生態工具Data Migration (DM)進行全量和增量資料的遷移。
全量資料遷移:從資料來源遷移對應表的表結構到TiDB,然後讀取存量資料,寫入到TiDB叢集。
增量資料複製:全量資料遷移完成後,從資料來源讀取對應的表變更,然後寫入到TiDB叢集。
個推將MySQL資料遷移到TiDB
當資料同步穩定之後,將應用逐步遷移到TiDB Cluster。把最後一個應用遷移完成之後,停止DM Cluster。這樣就完成了從MySQL到TiDB的資料遷移。
注:DM的具體配置使用詳見官方文件。
陷入TiDB使用的“反模式”
然而,當應用全部遷移到TiDB之後,卻出現了資料庫反應慢、卡頓,應用不可用等一系列的問題。
如下圖:
登陸資料庫時遇到卡頓
通過排查,我們發現有大量的慢SQL都是使用load匯入資料的指令碼。
慢SQL的匯入耗時幾十分鐘
和業務方溝通後,我們發現有些匯入語句就包含幾萬條記錄,匯入時間需要耗時幾十分鐘。
對比之前使用MySQL,一次匯入只需幾分鐘甚至幾十秒鐘就完成了,而遷到TiDB卻需要雙倍甚至幾倍的時間才完成,幾臺機器組成的TiDB叢集反而還不如一臺MySQL機器。
這肯定不是開啟TiDB的正確姿勢,我們需要找到原因,對其進行優化。
單個伺服器負載過高
通過檢視監控,發現伺服器負載壓力都是在其中一臺機器上(如上圖,紅色線框裡標註的這臺伺服器承擔主要壓力),這說明我們目前並沒有充分利用到所有的資源,未能發揮出TiDB作為分散式資料庫的效能優勢。
開啟TiDB的正確使用姿勢
首先優化配置引數
具體如何優化呢?我們首先從配置引數方面著手。眾所周知,很多配置引數都是使用系統的預設引數,這並不能幫助我們合理地利用伺服器的效能。通過深入查閱官方文件及多輪實測,我們對TiDB配置引數進行了適當調整,從而充分利用伺服器資源,使伺服器效能達到理想狀態。
下表是個推對TiDB配置引數進行調整的說明,供參考:
重點解決熱點問題
調整配置引數只是基礎的一步,我們還是要從根本上解決伺服器負載壓力都集中在一臺機器上的問題。可是如何解決呢?這就需要我們先深入瞭解TiDB的架構,以及TiDB中表儲存資料的內在原理。
在TiDB的整個架構中,分散式資料儲存引擎TiKV Server負責儲存資料。在儲存資料時,TiKV採用範圍切分(range)的方式對資料進行切分,切分的最小單位是region。每個region有大小限制(預設上限為96M),會有多個副本,每一組副本,成為一個raft group。每個raft group中由leader負責執行這個塊資料的讀&寫。leader會自動地被PD元件(Placement Driver,簡稱“PD”,是整個叢集的管理模組)均勻排程在不同的物理節點上,用以均分讀寫壓力,實現負載均衡。
TiDB架構圖(圖片來源於TiDB官網)
TiDB會為每個表分配一個TableID,為每一個索引分配一個IndexID,為每一行分配一個RowID(預設情況下,如果表使用整數型的Primary Key,那麼會用Primary Key的值當做RowID)。同一個表的資料會儲存在以表ID開頭為字首的一個range中,資料會按照RowID的值順序排列。在插入(insert)表的過程中,如果RowID的值是遞增的,則插入的行只能在末端追加。
當Region達到一定的大小之後會進行分裂,分裂之後還是隻能在當前range範圍的末端追加,並永遠僅能在同一個Region上進行insert操作,由此形成熱點(即單點的過高負載),陷入TiDB使用的“反模式”。
常見的increment型別自增主鍵就是按順序遞增的,預設情況下,在主鍵為整數型時,會將主鍵值作為RowID ,此時RowID也為順序遞增,在大量insert時就會形成表的寫入熱點。同時,TiDB中RowID預設也按照自增的方式順序遞增,主鍵不為整數型別時,同樣會遇到寫入熱點的問題。
在使用MySQL資料庫時,為了方便,我們都習慣使用自增ID來作為表的主鍵。因此,將資料從MySQL遷移到TiDB之後,原來的表結構都保持不變,仍然是以自增ID作為表的主鍵。這樣就造成了批量匯入資料時出現TiDB寫入熱點的問題,導致Region分裂不斷進行,消耗大量資源。
對此,在進行TiDB優化時,我們從表結構入手,對以自增ID作為主鍵的表進行重建,刪除自增ID,使用TiDB隱式的_tidb_rowid列作為主鍵,將
create table t (a int primary key auto_increment, b int);
改為:
create table t (a int, b int)SHARD_ROW_ID_BITS=4 PRE_SPLIT_REGIONS=2
通過設定SHARD_ROW_ID_BITS,將RowID打散寫入多個不同的Region,從而緩解寫入熱點問題。
此處需要注意,SHARD_ROW_ID_BITS值決定分片數量:
SHARD_ROW_ID_BITS = 0 表示 1 個分片
SHARD_ROW_ID_BITS = 4 表示 16 個分片
SHARD_ROW_ID_BITS = 6 表示 64 個分片
SHARD_ROW_ID_BITS值設定的過大會造成RPC請求數放大,增加CPU和網路開銷,這裡我們將SHARD_ROW_ID_BITS設定為4。
PRE_SPLIT_REGIONS指的是建表成功後的預均勻切分,我們通過設定PRE_SPLIT_REGIONS=2,實現建表成功後預均勻切分2^(PRE_SPLIT_REGIONS)個Region。
經驗總結
· 以後新建表禁止使用自增主鍵,考慮使用業務主鍵
· 加上引數SHARD_ROW_ID_BITS = 4 PRE_SPLIT_REGIONS=2
此外,由於TiDB的優化器和MySQL有一定差異,出現了相同的SQL語句在MySQL裡可以正常執行,而在TiDB裡執行慢的情況。我們針對特定的慢SQL進行了深入分析,並針對性地進行了索引優化,取得了不錯的成效。
優化成果
通過慢SQL查詢平臺可以看到,經過優化,大部分的匯入在秒級時間內就完成了,相比原來的數十分鐘,實現了數千倍的效能提升。
慢SQL優化結果
同時,效能監控圖表也顯示,在負載高的時刻,是幾臺機器同時高,而不再是單獨一臺升高,這說明我們的優化手段是有效的,TiDB作為分散式資料庫的優勢得以真正體現。
優化後,實現伺服器負載均衡
總結
作為一種新型分散式關係型資料庫,TiDB能夠為OLTP(Online Transactional Processing)和OLAP(Online Analytical Processing)場景提供一站式的解決方案。個推不僅使用TiDB進行海量資料高效查詢,同時也展開了基於TiDB進行實時資料分析、洞察的探索。
後續更多“大資料降本提效”的乾貨分享,請大家持續鎖定個推技術實踐公眾號~