1. 程式人生 > >【MySQL技術內幕】64-效能優化

【MySQL技術內幕】64-效能優化

效能優化不是一項簡單的工作,但也不是複雜的難事,關鍵在於對 InnoDB儲存引擎特性的瞭解。如果之前各章的內容讀者已經完全理解並掌握了,那就應該基本掌握瞭如何使 InnoDB儲存引擎更好地工作。本章將從以下幾個方面集中講解 InnodB儲存引擎的效能問題:

  • 選擇合適的CPU
  • 記憶體的重要性
  • 硬碟對資料庫效能的影響
  • 合理地設定RAID
  • 作業系統的選擇也很重要
  • 不同檔案系統對資料庫的影響
  • 選擇合適的基準測試工具

1、選擇合適的CPU

使用者首先需要清楚當前資料庫的應用型別。一般而言,可分為兩大類:OLTP(Online Transaction Processing,線上事務處理)和OLAP(Online analytical Processing,線上分析處理)。這是兩種截然不同的資料庫應用。OLAP多用在資料倉庫或資料集市中,一般需要執行復雜的SQL語句來進行查詢;OLTP多用在日常的事物處理應用中,如銀行交易、線上商品交易、Blog、網路遊戲等應用。相對於OLAP,資料庫的容量較小。 InnoDB儲存引擎一般都應用於OLTP的資料庫應用,這種應用的特點如下:

  • 使用者操作的併發量大
  • 事務處理的時間一般比較短
  • 查詢的語句較為簡單,一般都走索引
  • 複雜的查詢較少

可以看出,OLTP的資料庫應用本身對CPU的要求並不是很高,因為複雜的查詢可能需要執行比較、排序、連線等非常耗CPU的操作,這些操作在OLTP的資料庫應用中較少發生。因此,可以說OLAP是CPU密集型的操作,而OLTP是IO密集型的操作建議在採購裝置時,將更多的注意力放在提高IO的配置上此外,為了獲得更多記憶體的支援,使用者採購的CPU必須支援64位,否則無法支援64位作業系統的安裝。因此,為新的應用選擇64位的CPU是必要的前提。現在4核的CPU已經非常普遍,如今 Intel和AMD又相繼推出了8核的CPU,將來 隨著作業系統的升級我們還可能看到128核的CPU,這都需要資料庫更好地對其提供支援。 從 InnoDB儲存引擎的設計架構上來看,其主要的後臺操作都是在一個單獨的master thread中完成的,因此並不能很好地支援多核的應用。當然,開源社群已經通過多種方法來改變這種局面,而InnoDB1.0版本在各種測試下已經顯示出對多核CPU的處理效能的支援有了極大的提高,而 InnoDB1.2版本又支援多個purge執行緒,以及將重新整理操作從 master thread中分離出來。因此,若使用者的CPU支援多核, InnoDB的版本應該選擇1.1或更高版本。另外,如果CPU是多核的,可以通過修改引數 innodb_read_io_threads和innodb_write_io_threads來增大IO的執行緒,這樣也能更充分有效地利用CPU的多核效能。 在當前的 MySQL資料庫版本中,一條SQL查詢語句只能在一個CPU中工作,並不支援多CPU的處理。OLTP的資料庫應用操作一般都很簡單,因此對OLTP應用的影響並不是很大。但是,多個CPU或多核CPU對處理大併發量的請求還是會有幫助。

2、記憶體的重要性

記憶體的大小是最能直接反映資料庫的效能。通過之前各個章節的介紹,已經瞭解到InnoDB儲存引擎既快取資料,又快取索引,並且將它們緩存於一個很大的緩衝池中,即InnoDB Buffer Pool因此,記憶體的大小直接影響了資料庫的效能。 Percona公司的CTO Vadin對此做了一次測試,以此反映記憶體的重要性,結果如圖9-1所示。

在上述測試中,資料和索引總大小為18GB,然後將緩衝池的大小分別設為2GB、4GB、6GB、8GB、10GB、12GB、14GB、16GB、18GB、20GB、22GB,再進行 sysbench的測試。可以發現,隨著緩衝池的增大,測試結果TPS(Transaction Per Second)會線性增長。當緩衝池增大到20GB和2GB時,資料庫的效能有了極大的提高,因為這時緩衝池的大小已經大於資料檔案本身的大小,所有對資料檔案的操作都可以在記憶體中進行。因此這時的效能應該是最優的,再調大緩衝池並不能再提高資料庫的效能所以,應該在開發應用前預估“活躍”資料庫的大小是多少,並以此確定資料庫伺服器記憶體的大小。當然,要使用更多的記憶體還必須使用64位的作業系統。 如何判斷當前資料庫的記憶體是否已經達到瓶頸了呢?可以通過檢視當前伺服器的狀態,比較物理磁碟的讀取和記憶體讀取的比例來判斷緩衝池的命中率,通常 InnoDB儲存引擎的緩衝池的命中率不應該小於99%,如: 

mysql> show global status like 'innodb%read%';
+---------------------------------------+---------------+
| Variable_name                         | Value         |
+---------------------------------------+---------------+
| Innodb_buffer_pool_read_ahead_rnd     | 0             |
| Innodb_buffer_pool_read_ahead         | 4180          |
| Innodb_buffer_pool_read_ahead_evicted | 0             |
| Innodb_buffer_pool_read_requests      | 472889481455  |
| Innodb_buffer_pool_reads              | 33048         |
| Innodb_data_pending_reads             | 0             |
| Innodb_data_read                      | 1330352128    |
| Innodb_data_reads                     | 76350         |
| Innodb_master_thread_active_loops     | 922124        |
| Innodb_master_thread_idle_loops       | 8245265       |
| Innodb_pages_read                     | 81193         |
| Innodb_rows_read                      | 1329913665393 |
| Innodb_read_views_memory              | 3832          |
+---------------------------------------+---------------+
13 rows in set (0.01 sec)
當前伺服器的狀態引數
引數 說明
Innodb_buffer_pool_read_ahead_rnd 隨機預讀的次數
Innodb_buffer_pool_read_ahead 預讀的次數
Innodb_buffer_pool_read_ahead_evicted 預讀的頁數,但是沒有被讀取就從緩衝池中被替換的頁的數量,一般用來判斷預讀的效率
Innodb_buffer_pool_read_requests 從緩衝池中讀取頁的次數
Innodb_buffer_pool_reads 表示從物理磁碟讀取的頁數
Innodb_data_pending_reads innodb當前等待的讀的次數
Innodb_data_read 總共讀入的位元組數
Innodb_data_reads innodb完成的讀的次數
Innodb_pages_read 物理讀資料頁數
Innodb_rows_read 物理讀資料行數
Innodb_read_views_memory This status variable shows the total amount of memory allocated for the InnoDB read view (in bytes).

可以通過以下公式計算InnoDB快取池的命中率:

(1-innodb_buffer_pool_reads/inodb_buffer_pool_read_request)*100

如果命中率太低,則應考慮擴充記憶體,增加innodb_buffer_pool_size的值。

即使緩衝池的大小已經大於資料庫檔案的大小,這也並不意味著沒有磁碟操作。資料庫的緩衝池只是一個用來存放熱點的區域,後臺的執行緒還負責將髒頁非同步地寫入到磁碟。此外,每次事務提交時還需要將日誌寫入重做日誌檔案。

3、硬碟對資料庫效能的影響

3.1、傳統機械硬碟

當前大多數資料庫使用的都是傳統的機械硬碟。機械硬碟的技術目前已非常成熟,在伺服器領域一般使用SAS或SATA介面的硬碟。伺服器機械硬碟開始向小型化轉型,目前大部分使用25寸的SAS機械硬碟。 機械硬碟有兩個重要的指標:一個是尋道時間,另一個是轉速。當前伺服器機械硬碟的尋道時間已經能夠達到3ms,轉速為15000RM(rotate per minute)。傳統機械硬碟最大的問題在於讀寫磁頭,讀寫磁頭的設計使硬碟可以不再像磁帶一樣,只能進行順序 訪問,而是可以隨機訪問。但是,機械硬碟的訪問需要耗費長時間的磁頭旋轉和定位來查詢,因此順序訪問的速度要遠高於隨機訪問。傳統關係資料庫的很多設計也都是在儘量充分地利用順序訪問的特性。 通常來說,可以將多塊機械硬碟組成RAID來提高資料庫的效能,也可以將資料檔案分佈在不同硬碟上來達到訪問負載的均衡。

3.2、固態硬碟

固態硬碟,更準確地說是基於快閃記憶體的固態硬碟,是近幾年出現的一種新的儲存裝置,其內部由快閃記憶體( Flash Memory)組成。因為快閃記憶體的低延遲性、低功耗,以及防震性,快閃記憶體裝置已在移動裝置上得到了廣泛的應用。企業級應用一般使用固態硬碟,通過並聯多塊快閃記憶體來進一步提高資料傳輸的吞吐量。傳統的儲存服務提供商EMC公司已經開始提供基於快閃記憶體的固態硬碟的TB級別儲存解決方案。資料庫廠商 Oracle公司最近也開始提供繫結固態硬碟的 Exadata伺服器。 不同於傳統的機械硬碟,快閃記憶體是一個完全的電子裝置,沒有傳統機械硬碟的讀寫磁頭。因此,固態硬碟不需要像傳統機械硬碟一樣,需要耗費大量時間的磁頭旋轉和定位來查詢資料,所以固態硬碟可以提供一致的隨機訪問時間。固態硬碟這種對資料的快速讀寫和定位特性是值得研究的。 另一方面,快閃記憶體中的資料是不可以更新的,只能通過扇區(sector)的覆蓋重寫,而在覆蓋重寫之前,需要執行非常耗時的擦除(erase)操作。擦除操作不能在所含資料的扇區上完成,而需要在刪除整個被稱為擦除塊的基礎上完成,這個擦除塊的尺寸大於扇區的大小,通常為128KB或者256KB。此外,每個擦除塊有擦寫次數的限制。已經有一些演算法來解決這個問題。但是對於資料庫應用,需要認真考慮固態硬碟在寫入方面存在的問題。 因為存在上述寫人方面的問題,快閃記憶體提供的讀寫速度是非對稱的。讀取速度要遠快於寫人的速度,因此對於固態硬碟在資料庫中的應用,應該好好利用其讀取的效能,避免過多的寫入操作 圖9-2顯示了一個雙通道的固態硬碟架構,通過支援4路的快閃記憶體交叉儲存來降低固態硬碟的訪問延時,同時增大併發的讀寫操作。通過進一步增加通道的數量,固態硬碟的效能可以線性地提高,例如我們常見的 Intel X25M固態硬碟就是10通道的固態硬碟。

由於快閃記憶體是一個完全的電子裝置,沒有讀寫磁頭等移動部件,因此固態硬碟有著較低的訪問延時。當主機發佈一個讀寫請求時,固態硬碟的控制器會把IO命令從邏輯地址對映成實際的實體地址,寫操作還需要修改相應的對映表資訊。算上這些額外的開銷,固態硬碟的訪問延時一般小於0.1ms左右。圖9-3顯示了傳統機械硬碟、 記憶體、固態硬碟的隨機訪問延時之間的比較。

對於固態硬碟在 InnoDB儲存引擎中的優化,可以增加innodb_io_capacity變數的值達到充分利用固態硬碟帶來的高IOPS特性。不過這需要使用者根據自己的應用進行有針對性的調整。在 InnoSQL及 InnoDB1.2版本中,可以選擇關閉鄰接頁的重新整理,同樣可以為資料庫的效能帶來一定效果的提升。 此外,還可以使用 InnoSQL開發的L2 Cache解決方案,該解決方案可以充分利用固態硬碟的超高速隨機讀取效能,在記憶體緩衝池和傳統儲存層之間建立一層基於快閃記憶體固態硬碟的二級緩衝池,以此來擴充緩衝池的容量,提高資料庫的效能。與基於磁碟的固態硬碟 Cache類似的解決方案還有 Facebook Flash Cache和 bcache,只不過它們是基於通用檔案系統的,對 InnoDB儲存引擎本身的優化較少。

4、合理地設定RAID

4.1RAID型別

RAID(Redundant Array of Independent Disks,獨立磁碟冗餘陣列)的基本思想就是把多個相對便宜的硬碟組合起來,成為一個磁碟陣列,使效能達到甚至超過一個價格昂貴、容量巨大的硬碟。由於將多個硬碟組合成為一個邏輯扇區,RAID看起來就像一個單獨的硬碟或邏輯儲存單元,因此作業系統只會把它當作一個硬碟。 RAID的作用是

  • 增強資料整合度
  • 增強容錯功能
  • 增加處理量或容量

根據不同磁碟的組合方式,常見的RAID組合方式可分為RAID0、RAID1、RAID5、RAID10和RAID50等。 RAD0:將多個磁碟合併成一個大的磁碟,不會有冗餘,並行IO,速度最快。RAID0亦稱為帶區集,它將多個磁碟並列起來,使之成為一個大磁碟,如圖9-4所示在存放資料時,其將資料按磁碟的個數進行分段,同時將這些資料寫進這些盤中。所以,在所有的級別中,RAID0的速度是最快的。但是RAID0沒有冗餘功能,如果一個磁碟(物理)損壞,則所有的資料都會丟失。理論上,多磁碟的效能就等於(單一磁碟效能)×(磁碟數),但實際上受限於匯流排IO瓶頸及其他因素的影響,RAID效能會隨邊際遞減。也就是說,假設一個磁碟的效能是50MB/s,兩個磁碟的RAID0效能約96MB/s,三個磁碟的RAID0也許是130MB/s而不是150MB/s。

RAD1:兩組以上的N個磁碟相互作為映象(如圖9-5所示),圖9-4RAID0結構在一些多執行緒作業系統中能有很好的讀取速度,但寫入速度略有降低。除非擁有相同資料的主磁碟與映象同時損壞,否則只要一個磁碟正常即可維持運作,可靠性最高。RAID1就是映象,其原理為在主硬碟上存放資料的同時也在映象硬碟上寫相同的資料。當主硬碟(物理〕損壞時,映象硬碟則代替主硬碟的工作。因為有映象硬碟做資料備份,所以RAID1的資料安全性在所有的RAID級別上來說是最好的。但是,無論用多少磁碟作為RAID1,僅算一個磁碟的容量,是所有RAID中磁碟利用率最低的一個級別。 RAID5:是一種儲存效能、資料安全和儲存成本兼顧的儲存解決方案。它使用的是 Disk Striping(硬碟分割槽)技術。RAID5至少需要三個硬碟,RAID5不對儲存的資料進行備份,而是把資料和相對應的奇偶校驗資訊儲存到組成RAID5的各個磁碟上,並且奇偶校驗資訊和相對應的資料分別儲存於不同的磁碟上。當RAID5的一個磁碟資料發生損壞後,利用剩下的資料和相應的奇偶校驗資訊去恢復被損壞的資料。RAID5可以理解為是RAID0和RAID1的折中方案。RAID5可以為系統提供資料安全保障,但保障程度要比映象低而磁碟空間利用率要比映象高。RADS5具有和RAD0相近似的資料讀取速度,只是多了一個奇偶校驗資訊,寫入資料的速度相當慢,若使用Write Back可以讓效能改善不少。同時,由於多個數據對應一個奇偶校驗資訊,RAID5的磁碟空間利用率要比RAID1高,儲存成本相對較低。 RAID10和RAD01:RAID10是先映象再分割槽資料,將所有硬碟分為兩組,視為RAID0的最低組合,然後將這兩組各自視為RAID1運作。 RAID10有著不錯的讀取速度,而且擁有比RAID0更高的資料保護性。RAID01則與RAID10的程式相反,先分割槽再將資料鏡射到兩組硬碟。RAID01將所有的硬碟分為兩組,變成RAID1的最低組合,而將兩組硬碟各自視為RAID0運作。RAID01比RAID10有著更快的讀寫速度,不過也多了一些會讓整個硬碟組停止運轉的機率,因為只要同一組的硬碟全部損毀,RAID01就會停止運作,而RAID10可以在犧牲RAID0的優勢下正常運作。RAID10巧妙地利用了RAID0的速度及RAID1的安全(保護)兩種特性,它的缺點是需要較多的硬碟,因為至少必須擁有四個以上的偶數硬碟才能使用。RAID10和RAID01的結構如圖97所示。

RAD50:RAID50也被稱為映象陣列條帶,由至少六塊硬碟組成,像RAID0樣,資料被分割槽成條帶,在同一時間內向多塊磁碟寫人;像RAID5一樣,也是以資料的校驗位來保證資料的安全,且校驗條帶均勻分佈在各個磁碟上,其目的在於提高RAID5的讀寫效能。

對於資料庫應用來說,RAID10是最好的選擇,它同時兼顧了RAID1和RAID0的特性。但是,當一個磁碟失效時,效能可能會受到很大的影響,因為條帶(strip)會成為瓶頸。我曾在生產環境下遇到過的情況是,兩臺負載基本相同的資料庫,一臺正常的伺服器磁碟IO負載為20%左右,而另一臺伺服器IO負載卻高達90%。

4.2、RAID Write Back功能

RAID Write Back功能是指RAID控制器能夠將寫入的資料放入自身的快取中,並把它們安排到後面再執行。這樣做的好處是,不用等待物理磁碟實際寫入的完成,因此寫入變得更快了。對於資料庫來說,這顯得十分重要。例如,對重做日誌的寫人,在將sync_binlog設為1的情況下二進位制日誌的寫入、髒頁的重新整理等都可以使效能得到明顯的提升但是,當作業系統或資料庫關機時, Write Back功能可能會破壞資料庫的資料。這是由於已經寫人的資料庫可能還在RAID卡的快取中,資料可能並沒有完全寫入磁碟,而這時故障發生了。為了解決這個問題,目前大部分的硬體RAID卡都提供了電池備份單元(BBU, Battery Backup Unit),因此可以放心地開啟 Write Back的功能。不過我發現每臺伺服器的出廠設定都不相同,應該將RAID設定要求告知伺服器提供商,開啟一些認為需要的引數。 如果沒有啟用 Write Back功能,那麼在RAID卡設定中顯示的就是 Write Through。 Write Through沒有緩衝寫入,因此寫入效能可能不是很好,但它卻是最安全的寫入即使使用者開啟了 Write Back功能,RAID卡也可能只是在 Write Through模式下工作。 這是因為安全使用 Write back的前提是RAID卡有電池備份單元。為了確保電池的有效性,RAID卡會定期檢查電池狀態,並在電池電量不足時對其進行充電,在充電的這段時間內會將 Write Back功能切換為最為安全的 Write Through。 使用者可以在沒有電池備份單元的情況下強制啟用 Write Back功能,也可以在電池充電時強制使用 Write Back功能,只是寫入是不安全的。使用者應該非常確信這點,否則不應該在沒有電池備份單元的情況下啟用 Write back可以通過插入20W的記錄來比較 Write back和 Write Through的效能差異:

首先建立一個向表t插入20W記錄的儲存過程,並在 Write Back和 Write Through的設定下分別進行測試,最終測試結果如表9-2所示。

由於批量插入不是在一個事務中完成的,而是直接用命令CALP來執行的,因此資料庫實際執行了20W次的事務。很明顯可以看到,在 Write Back模式下執行時間只需要43秒,而在 Write Through模式下執行時間需要31分鐘,大約有40多倍的差距。 當然,在 Write Through模式下,通過將引數 innodb_flush_log_at_trx_commit設定為0也可以提高執行儲存過程P的效能,這時只需要68秒了。因為,在此設定下,重做日誌的寫入不是發生在每次事務提交時,而是發生在後臺 master執行緒每秒鐘自動重新整理的時候,因此減少了物理磁碟的寫入請求,所以執行速度也可以有明顯的提高。

4.3、RAID配置工具

對RAID卡進行配置可以在伺服器啟動時進入一個類似於BIOS的配置介面,然後再對其進行各種設定。此外,很多廠商都開發了各種作業系統下的軟體對RAID進行配置,如果使用者使用的是LSI公司生產提供的RAID卡,則可以使用 MegaCLI工具來進行配置。 MegaCLI為多個作業系統提供了支援,對 Windows作業系統還提供了GU介面的配置環境,因此相對來說比較簡單。這裡主要介紹命令列下 MegaCLI的使用,在Windows下同樣可以使用命令 MegaCLI.exe。 使用 MegaCL檢視RAID卡的資訊:

MegaLI還可以用來檢視當前物理磁碟的資訊,如:

通過上面的結果可以發現當前開啟了RAID卡的 Write Back功能,並且當BBU有問題時或在充電時禁用 Write Back功能。此外,這裡還顯示了不需要啟用RAID卡的預讀功能,寫入方式為直接寫入通過下面的命令可以對當前的寫入策略進行調整: 特別需要注意地是,當RAID卡的寫人策略從 Write Back切換為 Write Through時,該更改立即生效。然而從 Write Through切換為 Write Back時,必須重啟伺服器才能使其生效。

5、作業系統的選擇

Linux是 MySQL資料庫伺服器中最常使用的作業系統。與其他作業系統不同的是Linux有著眾多的發行版本,每個使用者的偏好可能不盡相同。然而在將 Linux作業系統作為資料庫伺服器時需要考慮更多的是作業系統的穩定性,而不是新特性除了 Linux作業系統外, FreeBSD也是另一個常見的優秀作業系統。之前版本的FreeBSD對 MySQL資料庫支援得不是很好,需要選擇單獨的執行緒庫進行手動編譯但是新版本的 FreeBSD對 MySQL資料庫的支援已經好了很多,直接下載二進位制安裝包即可。

Solaris也是非常不錯的作業系統,之前是基於 SPARC硬體的作業系統,現在已經移植到了X86平臺上。 Solaris是高效能、高可靠性的作業系統,同時其提供的ZFS檔案系統非常適合 MySQL的資料庫應用。如果需要,使用者可以嘗試它的開源版本open Solaris。 Windows作業系統在 MySQL資料庫應用中也非常普及。也有公司喜歡在開發環境下使用 Windows版本的 MySQL資料庫,而在正式生產環境下選擇使用 Linux作業系統。這本身沒有什麼問題,但問題通常存在於檔案系統大小寫敏感對應用程式的影響。 在 Windows作業系統下表名不區分大小寫,而 Linux作業系統卻是大小寫敏感的,這點在開發階段需要特別注意。 4G記憶體在當前已經非常普遍了,即使是桌面使用者也開始使用8G的記憶體。為了可以更好地使用大於4G的記憶體容量,使用者必須使用64位的作業系統,上述介紹的這些作業系統都提供了64位的版本。此外,使用64位的作業系統還必須使用64位的軟體。這聽上去像是句廢話,但是我曾多次看到32位的 MySQL資料庫安裝在64位的系統上,導致不能充分發揮64位作業系統的記憶體定址能力。

6、不同的檔案系統對資料庫效能的影響

每個作業系統都預設支援一種檔案系統並推薦使用者使用,如 Windows預設支援NTFS, Solaris預設支援ZFS。而對於 Linux這樣的作業系統,不同發行版本預設支援的檔案系統各不相同,有的預設支援EXT3,有的是 ReiserFS,有的是EXT4,有的是XFS。 雖然不同特性的檔案系統有很多,但是在實際使用過程中從未感覺到檔案系統的效能差異有多大。網上有多個關於XFS檔案系統的“神話”,認為其是多麼地適合資料庫應用,效能較之EXT3有極大的提升。但是在實際測試和使用後發現,它的效能和EXT3在整體上沒有大的差距。因此,DBA首先應該把更多的注意力放到資料庫上,而不是糾結於檔案系統。 檔案系統可提供的功能也許是DBA需要關注的,例如ZFS檔案系統本身就可以支援快照,因此就不需要IM這樣的邏輯卷管理工具。此外,可能還需要知道 mount的引數,這些引數在每個檔案系統中可能有所不同。