高效能MySQL.讀書筆記(一)優化伺服器設定
阿新 • • 發佈:2019-01-22
MySQL有大量可以修改的引數——但不應該隨便去修改。通常只需要把基本的配置項配置正確(大部分情況下只有很少一些引數是真正重要的),應該將更多的時間花在schema的優化、索引,以及查詢設計上。
確保基本的配置是正確的,如果碰到了問題,並且問題是由於伺服器的某部分導致的,而這恰好可以通過某個配置項解決,那麼需要做的就是更改配置。
MySQL基本配置
InnoDB在大多數情況下如果要執行的很好,配置大小合適的緩衝池(Buffer Pool)和日誌檔案(Log File)是必須的。預設值都太小了。其他所有的InnoDB設定都是可選的。
我們建議,當配置記憶體緩衝區的時候,寧可謹慎,而不是把它們配置的過大。如果把緩衝池配置得比它可設的值少了20%,很可能只會對效能產生小的影響,也許就隻影響幾個百分點。如果設定得大了20%,則可能會造成更嚴重的問題:記憶體交換、磁碟抖動,甚至記憶體耗盡和硬體宕機。
配置記憶體使用
可以按下面的步驟來配置記憶體:
1、確定可以使用的記憶體上限。
2、確定每個連線MySQL需要使用多少記憶體,例如排序緩衝和臨時表。
3、確定作業系統需要多少記憶體。包括同一臺機器上其他程式使用的記憶體。
4、把剩下的記憶體全部給MySQL的快取,例如InnoDB緩衝池,這樣做很有意義。
為快取分配記憶體
下面是我們認為大部分情況來說最重要的緩衝:
InnoDB緩衝池(innodb_buffer_pool_size)
InnoDB日誌檔案(innodb_log_buffer_size)和MyISAM資料的作業系統快取(key_buffer_size)
MyISAM鍵快取(myisam_block_size)
執行緒快取(thread_cache_size)
查詢快取(query_cache_size)
無法手工配置的快取,例如二進位制日誌和表定義檔案的作業系統快取
InnoDB緩衝池
如果大部分都是InnoDB表,InnobDB緩衝池或許比其他任何東西更需要記憶體。
如果資料量不大,並且不會快速增長,就沒必要為緩衝池分配過多的記憶體。
很大的緩衝池也會帶來一些挑戰,例如,預熱和關閉都會花費很長的時間。如果有很多髒頁在緩衝池裡,InnoDB關閉時可能會花費較長的時間,因為關閉之前需要把髒頁寫回資料檔案。也可以強制快速關閉,但是重啟時就必須多做更多的恢復工作,也就是說無法同時加速關閉和重啟兩個動作。如果事先知道什麼時候需要關閉InnoDB,可以在執行時修改innodb_max_dirty_pages_pct變數,將值改小,等待重新整理執行緒清理緩衝池,然後在髒頁數量較少時關閉。可以監控innodb_buffer_pool_pages_dirty狀態變數或者SHOW INNODB STATUS來觀察髒頁的重新整理量。
更小的innodb_max_dirty_pages_pct變數值並不保證InnoDB將在緩衝池中保持更少的髒頁。他只是控制InnoDB是否可以“偷懶(Lazy)”的閾值。InnoDB預設通過一個後臺執行緒來重新整理髒頁,並且會合並寫入,更高效地順序寫出磁碟。當髒頁的百分比超過了這個閾值,InnoDB將快速地刷寫髒頁,嘗試讓髒頁的數量更低。當事務日誌沒有足夠的空間剩餘時,InnoDB也將進入“激烈刷寫(Furious Flushing)”模式,這就是大日誌可以提升效能的一個原因。
InnoDB事務日誌
InnoDB使用多個檔案作為一組迴圈日誌。通常不需要修改預設的日誌數量,只修改每個日誌檔案的大小即可。
要確定理想的日誌檔案大小,必須權衡正常資料變更的開銷和崩潰需要的時間。如果日誌太小,InnoDB將必須做更多的檢查點,導致更多的日誌寫。在極個別情況下,寫語句可能被拖累,在日誌沒有空間繼續寫入前,必須等待變更應用到資料檔案。另一方面,如果日誌太大了,在崩潰恢復時InnoDB可能不得不做大量的工作。這可能極大地增加恢復時間。
當InnoDB變更任何資料時,會寫一條變更記錄到記憶體日誌緩衝區。在緩衝滿的時候、事務提交的時候,或者每一秒鐘,InnoDB都會刷寫緩衝區的內容到磁碟日誌檔案。如果有大事務,增加日誌緩衝區(預設1MB)大小可以幫助減少I/O。變數innodb_log_buffer_size可以控制日誌緩衝區的大小。
可以通過檢查SHOW INNODB STATUS的輸出中LOG部分來監控InnoDB的日誌和日誌緩衝區的I/O效能,通過觀察Innodb_os_log_written狀態變數來檢視InnoDB對日誌檔案寫出了多少資料。一個好的經驗法則是,檢視10~100秒間隔的數字,然後記錄峰值。
日誌緩衝必須被重新整理到持久化儲存,以確保提交的事務完全被持久化了。如果和持久化相比更在乎效能,可以修改innodb_flush_log_at _trx_commit變數來控制日誌緩衝重新整理的頻繁程度。可能的設定如下:
0
把日誌緩衝寫到日誌檔案,並且每秒重新整理一次,但是事務提交時不做任何事。
1
將日誌緩衝寫到日誌檔案,並且每次事務提交都重新整理到持久化儲存。
2
每次提交時把日誌緩衝寫到日誌檔案,但是並不重新整理,InnoDB每秒做一次重新整理。
0與2最重重要的不同是,如果MySQL程序“掛了”,2不會丟失任何事務。如果整個伺服器“掛了”或者斷電了,則還是可能會丟失一些事務。
高效能事務處理需要的最佳配置是把innodb_flush_log_at_trx_commit設定為1且把日誌檔案放到一個有電池保護的寫快取的RAID券中。這兼顧了安全和速度。事實上,我們敢說任何希望能扛過高負載的產品資料庫伺服器,都需要這種型別的硬體。
(注:在測試環境可以將innodb_flush_log_at_trx_commit設為0,這個速度同上面=1時的RAID快取的情況差不多)
InnoDB怎樣開啟和重新整理日誌以及資料檔案
使用innodb_flush_method選項可以配置InnoDB如何跟檔案系統相互作用。它既影響日誌檔案,也影響資料檔案,而且有時候對不同型別的檔案的處理也不一樣。
下面是一些可能的值:
fdatasync
這是非Windows系統上的預設值:InnoDB用fsync()來重新整理資料檔案和日誌檔案。使用fsync()的缺點是作業系統至少會在自己的快取中緩衝一些資料。理論上,這種雙重緩衝是浪費的。因為InnoDB管理自己的緩衝比作業系統能做的更加智慧。
O_DIRECT
這個設定並不影響日誌檔案,它主要是影響資料檔案的寫操作,不象O_DSYNC標記同時影響讀和寫。
這個設定依然使用fsync()來重新整理檔案到磁碟,但是會通知作業系統不要快取資料,也不要預讀。這個選項完全關閉了作業系統快取,並且使所有的讀和寫都直接通過儲存裝置,避免了雙重緩衝。
如果使用O_DIRECT選項,通常需要帶有寫快取的RAID卡,並且設定為Write-Back策略,因為這是典型的唯一能保持好效能的方法。當InnoDB和實際儲存裝置之間沒有緩衝時使用O_DIRECT,例如當RAID卡沒有寫快取時,可能導致嚴重的效能下降。
O_DSYNC
它使得所有寫同步,就是隻有資料寫到磁碟後寫操作才返回,這個選項不影響資料檔案。
O_DSYNC和O_DIRECT的不同之處在於O_DSYNC沒有禁用作業系統層的快取。因此,它沒有避免雙重緩衝,並且它沒有使寫操作直接操作到磁碟。用了O_DSYNC標記,也還是要在緩衝中寫資料,然後傳送到磁碟。
InnoDB表空間
Innodb_file_per_table選項讓InnoDB為每張表使用一個檔案,它在資料字典儲存為“表名.idb”的資料。
即使開啟Innodb_file_per_table選項,依然需要為回滾日誌和其他系統資料建立共享表空間。
我們建議使用Innodb_file_per_table並且為共享表空間設定大小範圍,這樣可以過得舒服點。
如果有個很大的回滾日誌並且表空間因此增長很快,可以強制MySQL減速來使InnoDB的清理執行緒可以跟得上。可以設定innodb_max_purge_lag變數為一個大於0的值。這個值表示InnoDB開始延遲後面的語句更新資料之前,可以等待被清除的最大的事務數量。例如:事務平均影響1KB的行,並且可以容許表空間裡有100M的未清理,那麼可以設定這個值為100000。設定innodb_max_purge_lag也會降低效能,但是它的傷害較少。
雙寫緩衝(Doublewrite Buffer)
雙寫緩衝是表空間一個特殊的保留區域,在一些連續的塊中足夠儲存100個頁。本質上是一個最近寫回的頁面的備份拷貝。當InnoDB從緩衝池重新整理頁面到磁碟時,首先把它們寫(或者重新整理)到雙寫緩衝,然後再把它們寫到其所屬的資料區域中。這可以保證每個頁面的寫入都是原子並且持久的。
有些場景下,雙寫緩衝確實沒必要,例如,你也許想在備庫上禁止雙寫緩衝。此外一些檔案系統(例如ZES)做了同樣的事,所以沒必要再讓InnoDB做一遍。可以通過設定innodb_doublewrite為0來關閉雙寫緩衝。
二進位制日誌
sync_binlog選項控制MySQL怎麼重新整理二進位制日誌到磁碟。預設值是0,意味著MySQL並不重新整理,由作業系統自己決定什麼時候重新整理快取到持久化裝置。如果這個值比0大,它指定了兩次重新整理到磁碟的動作之間間隔多少次二進位制日誌寫操作(如果autocommit被設定了,每個獨立的語句都是一次寫,否則就是一個事務一次寫)。把它設定為0和1以外的值是很罕見的。
像InnoDB日誌檔案一樣,設定sync_binlog=1並把二進位制日誌放到一個帶有電池保護的寫快取的RAID券,可以極大地提升效能並保證日誌的持久化。事實上寫和重新整理二進位制日誌快取其實比InnoDB事務日誌要昂貴多了,因為不像InnoDB事務日誌(事務日誌檔案大小是預分配的,而且是group commit),每次寫二進位制日誌都會增加他們的大小,而且在sync_binlog=1的情況下是每個事務都要寫一次。這需要每次寫入檔案系統都更新元資訊。所以,設定sync_binlog=1可能比innodb_flush_log_at_trx_commit=1對效能的損害要大的多。
把帶有電池保護寫快取的高質量RAID控制器設定為使用寫回(Writeback)策略,可以支援每秒數千的寫入,並且依然會保證寫到持久化儲存。資料寫到了帶有電池的快取記憶體,所以即使系統斷電它也能存在。但電源恢復時,RAID控制器會在磁碟被設定為可用前,把資料從快取中寫到磁碟。因此,一個帶有電池保護寫快取的RAID控制器可以顯著地提升效能,這是非常值得投資的。
MyISAM的I/O配置
MyISAM通常每次寫操作之後把索引變更重新整理到磁碟。如你打算在一張表上做很多修改,那麼毫無疑問,批量操作會更塊一些。一種辦法是用LOCK_TABLES延遲寫入,直到解鎖這個表。這是個提升效能的很有價值的技巧。
InnoDB併發配置
在高併發場景下,InnoDB的某些方面的效能可能會降低,唯一的辦法是限制併發。如果是高版本的MySQL,在大部分場景都不再需要限制併發。
最基本的限制併發的方式是使用innodb_thread_concurrency變數,它會限制一次性可以有多少執行緒進入核心,0表示不限制,理論上,下面的公式可以給出一個這樣的值:併發值 = CPU數量 * 磁碟數量 * 2。
確保基本的配置是正確的,如果碰到了問題,並且問題是由於伺服器的某部分導致的,而這恰好可以通過某個配置項解決,那麼需要做的就是更改配置。
MySQL基本配置
InnoDB在大多數情況下如果要執行的很好,配置大小合適的緩衝池(Buffer Pool)和日誌檔案(Log File)是必須的。預設值都太小了。其他所有的InnoDB設定都是可選的。
我們建議,當配置記憶體緩衝區的時候,寧可謹慎,而不是把它們配置的過大。如果把緩衝池配置得比它可設的值少了20%,很可能只會對效能產生小的影響,也許就隻影響幾個百分點。如果設定得大了20%,則可能會造成更嚴重的問題:記憶體交換、磁碟抖動,甚至記憶體耗盡和硬體宕機。
配置記憶體使用
可以按下面的步驟來配置記憶體:
1、確定可以使用的記憶體上限。
2、確定每個連線MySQL需要使用多少記憶體,例如排序緩衝和臨時表。
3、確定作業系統需要多少記憶體。包括同一臺機器上其他程式使用的記憶體。
4、把剩下的記憶體全部給MySQL的快取,例如InnoDB緩衝池,這樣做很有意義。
為快取分配記憶體
下面是我們認為大部分情況來說最重要的緩衝:
InnoDB緩衝池(innodb_buffer_pool_size)
InnoDB日誌檔案(innodb_log_buffer_size)和MyISAM資料的作業系統快取(key_buffer_size)
MyISAM鍵快取(myisam_block_size)
執行緒快取(thread_cache_size)
查詢快取(query_cache_size)
無法手工配置的快取,例如二進位制日誌和表定義檔案的作業系統快取
InnoDB緩衝池
如果大部分都是InnoDB表,InnobDB緩衝池或許比其他任何東西更需要記憶體。
如果資料量不大,並且不會快速增長,就沒必要為緩衝池分配過多的記憶體。
很大的緩衝池也會帶來一些挑戰,例如,預熱和關閉都會花費很長的時間。如果有很多髒頁在緩衝池裡,InnoDB關閉時可能會花費較長的時間,因為關閉之前需要把髒頁寫回資料檔案。也可以強制快速關閉,但是重啟時就必須多做更多的恢復工作,也就是說無法同時加速關閉和重啟兩個動作。如果事先知道什麼時候需要關閉InnoDB,可以在執行時修改innodb_max_dirty_pages_pct變數,將值改小,等待重新整理執行緒清理緩衝池,然後在髒頁數量較少時關閉。可以監控innodb_buffer_pool_pages_dirty狀態變數或者SHOW INNODB STATUS來觀察髒頁的重新整理量。
更小的innodb_max_dirty_pages_pct變數值並不保證InnoDB將在緩衝池中保持更少的髒頁。他只是控制InnoDB是否可以“偷懶(Lazy)”的閾值。InnoDB預設通過一個後臺執行緒來重新整理髒頁,並且會合並寫入,更高效地順序寫出磁碟。當髒頁的百分比超過了這個閾值,InnoDB將快速地刷寫髒頁,嘗試讓髒頁的數量更低。當事務日誌沒有足夠的空間剩餘時,InnoDB也將進入“激烈刷寫(Furious Flushing)”模式,這就是大日誌可以提升效能的一個原因。
InnoDB事務日誌
InnoDB使用多個檔案作為一組迴圈日誌。通常不需要修改預設的日誌數量,只修改每個日誌檔案的大小即可。
要確定理想的日誌檔案大小,必須權衡正常資料變更的開銷和崩潰需要的時間。如果日誌太小,InnoDB將必須做更多的檢查點,導致更多的日誌寫。在極個別情況下,寫語句可能被拖累,在日誌沒有空間繼續寫入前,必須等待變更應用到資料檔案。另一方面,如果日誌太大了,在崩潰恢復時InnoDB可能不得不做大量的工作。這可能極大地增加恢復時間。
當InnoDB變更任何資料時,會寫一條變更記錄到記憶體日誌緩衝區。在緩衝滿的時候、事務提交的時候,或者每一秒鐘,InnoDB都會刷寫緩衝區的內容到磁碟日誌檔案。如果有大事務,增加日誌緩衝區(預設1MB)大小可以幫助減少I/O。變數innodb_log_buffer_size可以控制日誌緩衝區的大小。
可以通過檢查SHOW INNODB STATUS的輸出中LOG部分來監控InnoDB的日誌和日誌緩衝區的I/O效能,通過觀察Innodb_os_log_written狀態變數來檢視InnoDB對日誌檔案寫出了多少資料。一個好的經驗法則是,檢視10~100秒間隔的數字,然後記錄峰值。
日誌緩衝必須被重新整理到持久化儲存,以確保提交的事務完全被持久化了。如果和持久化相比更在乎效能,可以修改innodb_flush_log_at _trx_commit變數來控制日誌緩衝重新整理的頻繁程度。可能的設定如下:
0
把日誌緩衝寫到日誌檔案,並且每秒重新整理一次,但是事務提交時不做任何事。
1
將日誌緩衝寫到日誌檔案,並且每次事務提交都重新整理到持久化儲存。
2
每次提交時把日誌緩衝寫到日誌檔案,但是並不重新整理,InnoDB每秒做一次重新整理。
0與2最重重要的不同是,如果MySQL程序“掛了”,2不會丟失任何事務。如果整個伺服器“掛了”或者斷電了,則還是可能會丟失一些事務。
高效能事務處理需要的最佳配置是把innodb_flush_log_at_trx_commit設定為1且把日誌檔案放到一個有電池保護的寫快取的RAID券中。這兼顧了安全和速度。事實上,我們敢說任何希望能扛過高負載的產品資料庫伺服器,都需要這種型別的硬體。
(注:在測試環境可以將innodb_flush_log_at_trx_commit設為0,這個速度同上面=1時的RAID快取的情況差不多)
InnoDB怎樣開啟和重新整理日誌以及資料檔案
使用innodb_flush_method選項可以配置InnoDB如何跟檔案系統相互作用。它既影響日誌檔案,也影響資料檔案,而且有時候對不同型別的檔案的處理也不一樣。
下面是一些可能的值:
fdatasync
這是非Windows系統上的預設值:InnoDB用fsync()來重新整理資料檔案和日誌檔案。使用fsync()的缺點是作業系統至少會在自己的快取中緩衝一些資料。理論上,這種雙重緩衝是浪費的。因為InnoDB管理自己的緩衝比作業系統能做的更加智慧。
O_DIRECT
這個設定並不影響日誌檔案,它主要是影響資料檔案的寫操作,不象O_DSYNC標記同時影響讀和寫。
這個設定依然使用fsync()來重新整理檔案到磁碟,但是會通知作業系統不要快取資料,也不要預讀。這個選項完全關閉了作業系統快取,並且使所有的讀和寫都直接通過儲存裝置,避免了雙重緩衝。
如果使用O_DIRECT選項,通常需要帶有寫快取的RAID卡,並且設定為Write-Back策略,因為這是典型的唯一能保持好效能的方法。當InnoDB和實際儲存裝置之間沒有緩衝時使用O_DIRECT,例如當RAID卡沒有寫快取時,可能導致嚴重的效能下降。
O_DSYNC
它使得所有寫同步,就是隻有資料寫到磁碟後寫操作才返回,這個選項不影響資料檔案。
O_DSYNC和O_DIRECT的不同之處在於O_DSYNC沒有禁用作業系統層的快取。因此,它沒有避免雙重緩衝,並且它沒有使寫操作直接操作到磁碟。用了O_DSYNC標記,也還是要在緩衝中寫資料,然後傳送到磁碟。
InnoDB表空間
Innodb_file_per_table選項讓InnoDB為每張表使用一個檔案,它在資料字典儲存為“表名.idb”的資料。
即使開啟Innodb_file_per_table選項,依然需要為回滾日誌和其他系統資料建立共享表空間。
我們建議使用Innodb_file_per_table並且為共享表空間設定大小範圍,這樣可以過得舒服點。
如果有個很大的回滾日誌並且表空間因此增長很快,可以強制MySQL減速來使InnoDB的清理執行緒可以跟得上。可以設定innodb_max_purge_lag變數為一個大於0的值。這個值表示InnoDB開始延遲後面的語句更新資料之前,可以等待被清除的最大的事務數量。例如:事務平均影響1KB的行,並且可以容許表空間裡有100M的未清理,那麼可以設定這個值為100000。設定innodb_max_purge_lag也會降低效能,但是它的傷害較少。
雙寫緩衝(Doublewrite Buffer)
雙寫緩衝是表空間一個特殊的保留區域,在一些連續的塊中足夠儲存100個頁。本質上是一個最近寫回的頁面的備份拷貝。當InnoDB從緩衝池重新整理頁面到磁碟時,首先把它們寫(或者重新整理)到雙寫緩衝,然後再把它們寫到其所屬的資料區域中。這可以保證每個頁面的寫入都是原子並且持久的。
有些場景下,雙寫緩衝確實沒必要,例如,你也許想在備庫上禁止雙寫緩衝。此外一些檔案系統(例如ZES)做了同樣的事,所以沒必要再讓InnoDB做一遍。可以通過設定innodb_doublewrite為0來關閉雙寫緩衝。
二進位制日誌
sync_binlog選項控制MySQL怎麼重新整理二進位制日誌到磁碟。預設值是0,意味著MySQL並不重新整理,由作業系統自己決定什麼時候重新整理快取到持久化裝置。如果這個值比0大,它指定了兩次重新整理到磁碟的動作之間間隔多少次二進位制日誌寫操作(如果autocommit被設定了,每個獨立的語句都是一次寫,否則就是一個事務一次寫)。把它設定為0和1以外的值是很罕見的。
像InnoDB日誌檔案一樣,設定sync_binlog=1並把二進位制日誌放到一個帶有電池保護的寫快取的RAID券,可以極大地提升效能並保證日誌的持久化。事實上寫和重新整理二進位制日誌快取其實比InnoDB事務日誌要昂貴多了,因為不像InnoDB事務日誌(事務日誌檔案大小是預分配的,而且是group commit),每次寫二進位制日誌都會增加他們的大小,而且在sync_binlog=1的情況下是每個事務都要寫一次。這需要每次寫入檔案系統都更新元資訊。所以,設定sync_binlog=1可能比innodb_flush_log_at_trx_commit=1對效能的損害要大的多。
把帶有電池保護寫快取的高質量RAID控制器設定為使用寫回(Writeback)策略,可以支援每秒數千的寫入,並且依然會保證寫到持久化儲存。資料寫到了帶有電池的快取記憶體,所以即使系統斷電它也能存在。但電源恢復時,RAID控制器會在磁碟被設定為可用前,把資料從快取中寫到磁碟。因此,一個帶有電池保護寫快取的RAID控制器可以顯著地提升效能,這是非常值得投資的。
MyISAM的I/O配置
MyISAM通常每次寫操作之後把索引變更重新整理到磁碟。如你打算在一張表上做很多修改,那麼毫無疑問,批量操作會更塊一些。一種辦法是用LOCK_TABLES延遲寫入,直到解鎖這個表。這是個提升效能的很有價值的技巧。
InnoDB併發配置
在高併發場景下,InnoDB的某些方面的效能可能會降低,唯一的辦法是限制併發。如果是高版本的MySQL,在大部分場景都不再需要限制併發。
最基本的限制併發的方式是使用innodb_thread_concurrency變數,它會限制一次性可以有多少執行緒進入核心,0表示不限制,理論上,下面的公式可以給出一個這樣的值:併發值 = CPU數量 * 磁碟數量 * 2。