1. 程式人生 > 其它 >微博MySQL優化之路 - 肖鵬

微博MySQL優化之路 - 肖鵬

肖鵬老師對於開源資料庫尤其是MySQL的研究特別深入,今天我們來一起聽他分享自己對MySQL資料庫的優化經驗!

作者簡介

肖鵬

微博研發中心資料庫技術負責人,主要負責微博資料庫(MySQL/Reids/HBase/Memcached)相關的業務保障,效能優化,架構設計以及周邊的自動化系統建設。10年網際網路資料庫架構和管理經驗,專注於資料庫的高效能和高可用技術保障方向。

正文

資料庫是所有架構中不可缺少的一環,一旦資料庫出現效能問題,那對整個系統都回來帶災難性的後果。並且資料庫一旦出現問題,由於資料庫天生有狀態(分主從)帶資料(一般還不小),所以出問題之後的恢復時間一般不太可控,所以,對資料庫的優化是需要我們花費很多精力去做的。接下來就給大家介紹一下微博資料庫這些年的一點經驗,希望可以對大家有幫助。

1硬體層優化

這一層最簡單,最近幾年相信大家對SSD這個名詞並不陌生,其超高的IOPS在剛出現在大家視野中的時候就讓人驚豔了一把,而隨著最近價格的不斷下調,已經非常具有價效比,目前微博已經把SSD伺服器作為資料庫類服務的標配。

我們來看下我們早些年自己對SSD的OLTP的效能測試:

可以看到OLTP的qps可以達到2.7w左右,配合1m2s的架構可以支援5w的qps,在一些簡單場景下,甚至可以不必配置cache層來做快取。

ps:硬體測試最好自己進行實測,官方資料僅能作為一個參考值,因為很多時候效能要嚴重依賴於場景,細化到不同的SQL會得到相差很大的結論,故最好自行測試。

微博在12年的時候使用PCIE-FLASH支撐了feed系統在春晚3.5w的qps,在初期很好的支撐了業務的發展,為架構優化和改造爭取了非常多的時間。並且大家可以看到,目前很多的雲廠商的物理機基本全都是SSD裝置,AWS更是虛機都提供SSD盤來提供IO效能,可以預見未來IO將不會在是資料庫遇到的最大瓶頸點。

經驗:如果公司不差錢,最好直接投入SSD or PCIE-FLASH裝置,而且投入的時間越早越好

2系統層優化

配合SSD硬體之後,系統層原有的一些設計就出現了問題,比如IO scheduler,系統預設的為CFQ,主要針對的是機械硬碟進行的優化,由於機械硬碟需要通過懸臂尋道,所以CFQ是非常適合的。

Complete Fair Queuing

該演算法為每一個程序分配一個時間視窗,在該時間視窗內,允許程序發出IO請求。通過時間視窗在不同程序間的移動,保證了對於所有程序而言都有公平的發出IO請求的機會。同時CFQ也實現了程序的優先順序控制,可保證高優先順序程序可以獲得更長的時間視窗。

但是由於SSD盤已經沒有了尋道而是基於電子的擦除,所以CFQ演算法已經明顯的不合適了,一般情況下網上都推薦使用NOOP演算法,但是我個人更推薦DEADLINE演算法。我們看下這2種演算法的特點。

NOOP演算法只擁有一個等待佇列,每當來一個新的請求,僅僅是按FIFO的思路將請求插入到等待佇列的尾部,預設認為 I/O不會存在效能問題,比較節省CPU資源。

DEADLINE排程演算法通過降低效能而獲得更短的等待時間,它使用輪詢的排程器,簡潔小巧,提供了最小的讀取延遲和尚佳的吞吐量,特別適合於讀取較多的環境。

從演算法的特點看,NOOP確實更適合SSD介質,非常的簡單,但是由於資料庫型服務有很多複雜查詢,簡單的FIFO可能會造成一些事務很難拿到資源從而一直處於等待狀態,所以個人更推薦使用DEADLINE。

ps:更主要的是因為對這2個演算法的壓測顯示效能並沒有太明顯的區別。

以下是我們自己在線上業務調整之後的效果:

除了以上這點之外,還有一些小地方也許要調整,雖然收益不會看上去這麼明顯,但是聚沙成塔,積少成多,還是非常值得優化的。

  • 使用EXT4 or XFS
  • 在mount的時候加上 noatime屬性
  • raid卡的讀寫策略改為write back
  • 使用jemalloc替換現有的Glibc

經驗:重點放在針對IO的優化上,資料庫尤其是MySQL是IO密集型服務,解決IO的問題會減少不必要的問題。

3MySQL自身的優化

我們先說說有那些引數可以帶來效能的改變

  • innodb_max_dirty_pages_pct

爭議比較大,一般來說都是在75-90之間,主要控制BP中的髒資料刷盤的時機,如果太小會頻繁刷盤造成IO上升,如果太大會導致MySQL正常關閉的時候需要很長的時間才能normal shutdown,具體需要看實際場景,個人推薦90

  • innodb_io_capacity

磁碟IO吞吐,具體為緩衝區落地的時候,可以刷髒頁的數量,預設200,由於使用了SSD硬碟,所以推薦設定到3000-5000

  • innodb_read_io_threads
  • innodb_write_io_threads

增加後臺處理執行緒的數目,預設為4,推薦改成8

  • sync_binlog
  • innodb_flush_log_at_trx_commit

著名的雙1引數,對效能影響非常的大

sync_binlog控制刷binlog的策略,MySQL在每寫N次 二進位制日誌binary log時,會使用fdatasync()函式將它的寫二進位制日誌binary log同步到磁碟中去。 innodb_flush_log_at_trx_commit控制log buffer刷log file的策略,設定為0的時候每秒重新整理一次,設定為1的時候每次commit都會重新整理。

從上述描述就可以看出如果追求資料的安全性,那麼設定雙一是最安全的,如果追求效能最大化,那麼雙0最合適,這中間可以相差至少2倍的效能。

  • innodb_log_file_size

innodb redo log的size大小,5.5最大4G,5.6最大256G,這個越大可以提升寫的效能,大部分時候不需要等待checkpoint覆蓋就可以一直write。

  • query_cache_type

看上去很美的東西,但是在實際生產環境中,多次給我們帶來了故障,由於每次表的更新都會清空buffer,並且對於sql的匹配是逐個字元效驗實際效果很長,大部分時間並沒有得到cache的效果,反而得到了很多wait for query cache lock。建議關閉。

以上,僅針對MySQL 5.5,目前我們還在摸索5.6和5.7由於還沒有大規模線上使用,所以還談不上有什麼經驗。

經驗:如果有人力可以投入,可以學習BAT針對資料庫進行二次開發,通過path的方式獲得更高的效能和穩定性。如果沒有人力,只要深入瞭解MySQL自身引數的影響也可以滿足業務的需求,不用一味的追原始碼級別的開發改造。

4業務優化

所謂的業務優化其實說白了很多時候就是index的優化,我們DBA常說一條慢SQL就能將上面所有的優化都付之一炬,CPU直接打滿,RT全都都飆升到500ms甚至1s以上。

優化慢查有三寶:

  • pt-query-digest
  • explain
  • show profiling

首先,使用pt-query-digest可以定位到定位影響最中的慢查是哪條。

然後通過explain具體分析慢查曉的問題所在

重點檢視type,rows和extra這三個欄位。

其中type的順序如下:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

最後,如果問題還是比較嚴重,可以通過show profiling來定位一下到底是那個環節出現的問題。

可以看到sending data最消耗時間,這時候就需要找到底為什麼在sending上消耗了這麼多的時間,是結果集太大,還是io效能不夠了,諸如此類

以下就是一個複雜語句的優化結果,可以從rows那裡明顯的看出減少了很多查詢的開銷。

經驗:最好建立慢查詢監控系統,每天都花時間在慢查的優化上,避免一條SQL引發的血案之類的事情發生。

4架構優化

最後,也就是終極手段了,那就是架構優化,其實很多時候,當我們將上面幾個方向都做了之後發現還沒有很好的效果,那就必須找開發同學一起聊一下了。ps:當然找PM同學聊一下人生會更有效果。

記得有一次,我們找開發聊了一下,最後開發決定將這個功能改掉,這個時候你會突然發現無論什麼優化手段都比不上「不做」這個優化手段,簡直無敵了。

根據我個人的經驗來說架構層的優化有如下幾個普適原則:

  • cache為王

熱點資料必須使用Redis或者mc之類的cache抗量,讓MySQL抗流量是不明智的。

  • 使用佇列消峰

眾所周知MySQL的非同步同步機制是單執行緒的,所有主庫上的併發到從庫上都是通過io-thread來慢慢做的,即使主庫寫入速度再快,從庫延遲了,整個叢集還是不可用,所以最好採用佇列來進行一定的寫入消峰,使寫入維持在一個較為均衡的水平。

  • 適度的過度設計

很多產品最開始的時候比較小,但是有可能上線之後廣受好評一下用活躍度就上來了,這個時候如果資料庫出現瓶頸需要拆分需要開發、DBA、架構師等等一起配合來做,而且很有可能沒有時間。所以在產品初期進行一定的過度設計會為未來這種情況打好鋪墊。最明顯的就是拆庫拆表,最好在一開始就對業務進行適度的垂直拆分和比較過度的水平拆分,以便應對業務的高速增長。

舉一個例子:

1、通過mcq降低對MySQL的寫入效能的要求。

2、通過mc和Redis來承擔使用者的實際訪問,90%的量依靠cache層承載和遮蔽。

3、MySQL作為最終的資料落地,儲存全量的資料,但是僅支撐部分業務查詢,小於10%。

經驗:讓合適的軟體做適合的事情,不要光從技術層面思考優化方案,也要從需求方面去分解。

5總結中的總結

轉一篇很經典的資料庫優化漏斗法則,很多年前就看到過,現在再看依然覺得適用,大家共勉。

唯一不適用的就是最下的增加資源,SSD真是個好東西,誰用誰知道。

本期趣味競答答案公佈:

答案ABCEA: 這往表中增加了開始和結束日期列。然後它用這些列建立了期間。這使得Oracle能夠把 "as of period for"轉換為標準的where子句。B: 如果你想要更加精確,也可以使用時間戳作為期間的列。C: (推薦)這建立了一個期間,起始和終止列帶有資料庫時區,沒有小數的秒數。D: 你可以在number型的列建立期間。但是insert會報錯:"ORA-00932: inconsistent datatypes: expected NUMBER got DATE" number型是用於數值的,不是日期! E:(不推薦)你可以在temporal validity“混用”資料型別。但這不是個好主意!