Get MySQL這5個優化技巧,你將如虎添翼

一個成熟的數據庫架構並非一開始設計就具有高可用、高伸縮等特性的,它是隨着用戶量的增長,基礎架構才逐漸完善。這篇文章主要談談MySQL數據庫在發展週期中所面臨的問題及優化方案,暫且拋開前端應用不說,大體分爲如下五個階段:前端

 

階段一:數據庫表設計mysql

項目立項後,開發部門根據產品部門需求開發項目。linux

開發工程師在開發項目初期會對錶結構設計。對於數據庫來講,表結構設計很重要,若是設計不當,會直接影響到用戶訪問網站速度,用戶體驗很差!這種狀況具體影響因素有不少,例如慢查詢(低效的查詢語句)、沒有適當創建索引、數據庫堵塞(鎖)等。固然,有測試部門的團隊,會作產品測試,找Bug。web

因爲開發工程師重視點不一樣,初期不會考慮太多數據庫設計是否合理,而是儘快完成功能實現和交付。等項目上線有必定訪問量後,隱藏的問題就會暴露,這時再去修改就不是這麼容易的事了!redis

階段二:數據庫部署算法

是時候運維工程師出場了,項目上線。sql

項目初期訪問量通常是寥寥無幾,此階段Web+數據庫單臺部署足以應對在1000左右的QPS(每秒查詢率)。考慮到單點故障,應作到高可用性,可採用MySQL主從複製+Keepalived實現雙機熱備。主流HA軟件有:Keepalived(推薦)、Heartbeat。數據庫

階段三:數據庫性能優化緩存

若是將MySQL部署到普通的X86服務器上,在不通過任何優化狀況下,MySQL理論值正常能夠處理1500左右QPS,通過優化後,有可能會提高到2000左右QPS。不然,訪問量當達到1500左右併發鏈接時,數據庫處理性能可能響應就會慢,並且硬件資源還比較富裕,這時就該考慮性能優化問題了。那麼怎樣能讓數據庫發揮最大性能呢?主要從硬件配置、數據庫配置、架構方面着手,具體分爲如下:安全

3.1 硬件配置

若是有條件必定要SSD固態硬盤代替SAS機械硬盤,將RAID級別調整爲RAID1+0,相對於RAID1和RAID5有更好的讀寫性能,畢竟數據庫的壓力主要來自磁盤I/O方面。

Linux內核有一個特性,會從物理內存中劃分出緩存區(系統緩存和數據緩存)來存放熱數據,經過文件系統延遲寫入機制,等知足條件時(如緩存區大小到達必定百分比或者執行sync命令)纔會同步到磁盤。也就是說物理內存越大,分配緩存區越大,緩存數據越多。固然,服務器故障會丟失必定的緩存數據。建議物理內存至少富裕50%以上。

3.2 數據庫配置優化

MySQL應用最普遍的有兩種存儲引擎:一個是MyISAM,不支持事務處理,讀性能處理快,表級別鎖。另外一個是InnoDB,支持事務處理(ACID屬性),設計目標是爲大數據處理,行級別鎖。

表鎖:開銷小,鎖定粒度大,發生死鎖機率高,相對併發也低。

行鎖:開銷大,鎖定粒度小,發生死鎖機率低,相對併發也高。

爲何會出現表鎖和行鎖呢?主要爲保證數據完整性。舉個例子,一個用戶在操做一張表,其餘用戶也想操做這張表,那麼就要等第一個用戶操做完,其餘用戶才能操做,表鎖和行鎖就是這個做用。不然多個用戶同時操做一張表,確定會數據產生衝突或者異常。

根據這些方面看,使用InnoDB存儲引擎是最好的選擇,也是MySQL5.5+版本默認存儲引擎。每一個存儲引擎相關運行參數比較多,如下列出可能影響數據庫性能的參數。

公共參數默認值:

  1. max_connections = 151  
  2. # 同時處理最大鏈接數,建議設置最大鏈接數是上限鏈接數的80%左右  
  3. sort_buffer_size = 2M  
  4. # 查詢排序時緩衝區大小,只對order by和group by起做用,建議增大爲16M  
  5. open_files_limit = 1024   
  6. # 打開文件數限制,若是show global status like 'open_files'查看的值等於或者大於open_files_limit值時,程序會沒法鏈接數據庫或卡死  

MyISAM參數默認值:

  1. key_buffer_size = 16M  
  2. # 索引緩存區大小,通常設置物理內存的30-40%  
  3. read_buffer_size = 128K    
  4. # 讀操做緩衝區大小,建議設置16M或32M  
  5. query_cache_type = ON  
  6. # 打開查詢緩存功能  
  7. query_cache_limit = 1M   
  8. # 查詢緩存限制,只有1M如下查詢結果纔會被緩存,以避免結果數據較大把緩存池覆蓋  
  9. query_cache_size = 16M    
  10. # 查看緩衝區大小,用於緩存SELECT查詢結果,下一次有一樣SELECT查詢將直接從緩存池返回結果,可適當成倍增長此值  

InnoDB參數默認值:

  1. innodb_buffer_pool_size = 128M  
  2. # 索引和數據緩衝區大小,建議設置物理內存的70%左右  
  3. innodb_buffer_pool_instances = 1      
  4. # 緩衝池實例個數,推薦設置4個或8個  
  5. innodb_flush_log_at_trx_commit = 1    
  6. # 關鍵參數,0表明大約每秒寫入到日誌並同步到磁盤,數據庫故障會丟失1秒左右事務數據。1爲每執行一條SQL後寫入到日誌並同步到磁盤,I/O開銷大,執行完SQL要等待日誌讀寫,效率低。2表明只把日誌寫入到系統緩存區,再每秒同步到磁盤,效率很高,若是服務器故障,纔會丟失事務數據。對數據安全性要求不是很高的推薦設置2,性能高,修改後效果明顯。 
  7.  
  8. innodb_file_per_table = OFF    
  9. # 是否共享表空間,5.7+版本默認ON,共享表空間idbdata文件不斷增大,影響必定的I/O性能。建議開啓獨立表空間模式,每一個表的索引和數據都存在本身獨立的表空間中,能夠實現單表在不一樣數據庫中移動。 
  10. innodb_log_buffer_size = 8M   
  11. # 日誌緩衝區大小,因爲日誌最長每秒鐘刷新一次,因此通常不用超過16M  

3.3 系統內核參數優化

大多數MySQL都部署在linux系統上,因此操做系統的一些參數也會影響到MySQL性能,如下對Linux內核參數進行適當優化

  1. net.ipv4.tcp_fin_timeout = 30  
  2. # TIME_WAIT超時時間,默認是60s  
  3. net.ipv4.tcp_tw_reuse = 1    
  4. # 1表示開啓複用,容許TIME_WAIT socket從新用於新的TCP鏈接,0表示關閉  
  5. net.ipv4.tcp_tw_recycle = 1     
  6. # 1表示開啓TIME_WAIT socket快速回收,0表示關閉  
  7. net.ipv4.tcp_max_tw_buckets = 4096     
  8. # 系統保持TIME_WAIT socket最大數量,若是超出這個數,系統將隨機清除一些TIME_WAIT並打印警告信息  
  9. net.ipv4.tcp_max_syn_backlog = 4096  
  10. # 進入SYN隊列最大長度,加大隊列長度可容納更多的等待鏈接 

在Linux系統中,若是進程打開的文件句柄數量超過系統默認值1024,就會提示「too many files open」信息,因此要調整打開文件句柄限制。

重啓永久生效:

  1. # vi /etc/security/limits.conf    
  2. * soft nofile 65535  
  3. * hard nofile 65535  

當前用戶當即生效:

  1. # ulimit -SHn 65535  

階段四:數據庫架構擴展

隨着業務量愈來愈大,單臺數據庫服務器性能已沒法知足業務需求,該考慮增長服務器擴展架構了。主要思想是分解單臺數據庫負載,突破磁盤I/O性能,熱數據存放緩存中,下降磁盤I/O訪問頻率。

4.1 增長緩存

給數據庫增長緩存系統,把熱數據緩存到內存中,若是緩存中有請求的數據就再也不去請求MySQL,減小數據庫負載。緩存實現有本地緩存和分佈式緩存,本地緩存是將數據緩存到本地服務器內存中或者文件中。分佈式緩存能夠緩存海量數據,擴展性好,主流的分佈式緩存系統:memcached、redis,memcached性能穩定,數據緩存在內存中,速度很快,QPS理論可達8w左右。若是想數據持久化就選擇用redis,性能不低於memcached。

工做過程:

4.2 主從複製與讀寫分離

在生產環境中,業務系統一般讀多寫少,可部署一主多從架構,主數據庫負責寫操做,並作雙機熱備,多臺從數據庫作負載均衡,負責讀操做。主流的負載均衡器:LVS、HAProxy、Nginx。

怎麼來實現讀寫分離呢?大多數企業是在代碼層面實現讀寫分離,效率高。另外一個種方式經過代理程序實現讀寫分離,企業中應用較少,會增長中間件消耗。主流中間件代理系統有MyCat、Atlas等。

在這種MySQL主從複製拓撲架構中,分散單臺負載,大大提升數據庫併發能力。若是一臺從服務器能處理1500 QPS,那麼3臺就能處理4500 QPS,並且容易橫向擴展。

有時,面對大量寫操做的應用時,單臺寫性能達不到業務需求。就能夠作雙向複製(雙主),但有個問題得注意:兩臺主服務器若是都對外提供讀寫操做,就可能遇到數據不一致現象,產生這個緣由是程序有同時操做兩臺數據庫概率,同時的更新操做會形成兩臺數據庫數據發生衝突或者不一致。

可設置每一個表ID字段自增惟一:auto_increment_increment和auto_increment_offset,也能夠寫算法生成隨機惟一。

官方近兩年推出的MGR(多主複製)集羣也能夠考慮下。

4.3 分庫

分庫是根據業務將數據庫中相關的表分離到不一樣的數據庫中,例如web、bbs、blog等庫。若是業務量很大,還可將分離後的數據庫作主從複製架構,進一步避免單庫壓力過大。

4.4 分表

數據量的日劇增長,數據庫中某個表有幾百萬條數據,致使查詢和插入耗時太長,怎麼能解決單表壓力呢?你應該考慮把這個表拆分紅多個小表,來減輕單個表的壓力,提升處理效率,此方式稱爲分表。

分表技術比較麻煩,要修改程序代碼裏的SQL語句,還要手動去建立其餘表,也能夠用merge存儲引擎實現分表,相對簡單許多。分表後,程序是對一個總表進行操做,這個總表不存放數據,只有一些分表的關係,以及更新數據的方式,總表會根據不一樣的查詢,將壓力分到不一樣的小表上,所以提升併發能力和磁盤I/O性能。

分表分爲垂直拆分和水平拆分:

  • 垂直拆分:把原來的一個不少字段的表拆分多個表,解決表的寬度問題。你能夠把不經常使用的字段單獨放到一個表中,也能夠把大字段獨立放一個表中,或者把關聯密切的字段放一個表中。
  • 水平拆分:把原來一個表拆分紅多個表,每一個表的結構都同樣,解決單表數據量大的問題。

4.5 分區

分區就是把一張表的數據根據表結構中的字段(如range、list、hash等)分紅多個區塊,這些區塊能夠在一個磁盤上,也能夠在不一樣的磁盤上,分區後,表面上仍是一張表,但數據散列在多個位置,這樣一來,多塊硬盤同時處理不一樣的請求,從而提升磁盤I/O讀寫性能。

注:增長緩存、分庫、分表和分區主要由程序猿或DBA來實現。

階段五:數據庫維護

數據庫維護是數據庫工程師或運維工程師的工做,包括系統監控、性能分析、性能調優、數據庫備份和恢復等主要工做。

5.1 性能狀態關鍵指標

專業術語:QPS(Queries Per Second,每秒查詢書)和TPS(Transactions Per Second)

經過show status查看運行狀態,會有300多條狀態信息記錄,其中有幾個值幫能夠咱們計算出QPS和TPS,以下:

Uptime:服務器已經運行的實際,單位秒

Questions:已經發送給數據庫查詢數

Com_select:查詢次數,實際操做數據庫的

Com_insert:插入次數

Com_delete:刪除次數

Com_update:更新次數

Com_commit:事務次數

Com_rollback:回滾次數

那麼,計算方法來了,基於Questions計算出QPS

  1. mysql> show global status like 'Questions';  
  2. mysql> show global status like 'Uptime';  
  3. QPS = Questions / Uptime  

基於Com_commit和Com_rollback計算出TPS:

  1. mysql> show global status like 'Com_commit';  
  2. mysql> show global status like 'Com_rollback';  
  3. mysql> show global status like 'Uptime';  
  4. TPS = (Com_commit + Com_rollback) / Uptime  

另外一計算方式:

基於Com_select、Com_insert、Com_delete、Com_update計算出QPS:   

  1. mysql> show global status where Variable_name in('com_select','com_insert','com_delete','com_update'); 

等待1秒再執行,獲取間隔差值,第二次每一個變量值減去第一次對應的變量值,就是QPS。

TPS計算方法:

  1. mysql> show global status where Variable_name in('com_insert','com_delete','com_update'); 

計算TPS,就不算查詢操做了,計算出插入、刪除、更新四個值便可。

經網友對這兩個計算方式的測試得出,當數據庫中myisam表比較多時,使用Questions計算比較準確。當數據庫中innodb表比較多時,則以Com_*計算比較準確。

5.2 開啓慢查詢日誌

MySQL開啓慢查詢日誌,分析出哪條SQL語句比較慢,支持動態開啓:

  1. mysql> set global slow-query-log=on    
  2. # 開啓慢查詢日誌   
  3. mysql> set global slow_query_log_file='/var/log/mysql/mysql-slow.log';   
  4. # 指定慢查詢日誌文件位置   
  5. mysql> set global log_queries_not_using_indexes=on;    
  6. # 記錄沒有使用索引的查詢   
  7. mysql> set global long_query_time=1;  
  8. # 只記錄處理時間1s以上的慢查詢  

分析慢查詢日誌,可使用MySQL自帶的mysqldumpslow工具,分析的日誌較爲簡單。  

  1. mysqldumpslow -t 3 /var/log/mysql/mysql-slow.log     
  2. # 查看最慢的前三個查詢   

也可使用percona公司的pt-query-digest工具,日誌分析功能全面,可分析slow log、binlog、general log。

分析慢查詢日誌:pt-query-digest /var/log/mysql/mysql-slow.log

分析binlog日誌:mysqlbinlog mysql-bin.000001 >mysql-bin.000001.sql

pt-query-digest --type=binlog mysql-bin.000001.sql

分析普通日誌:pt-query-digest --type=genlog localhost.log

5.3 數據庫備份

備份數據庫是最基本的工做,也是最重要的,不然後果很嚴重,你懂得!高頻率的備份策略,選用一個穩定快速的工具相當重要。數據庫大小在2G之內,建議使用官方的邏輯備份工具mysqldump。超過2G以上,建議使用percona公司的物理備份工具xtrabackup,不然慢的跟蝸牛似得。這兩個工具都支持InnoDB存儲引擎下熱備,不影響業務讀寫操做。

5.4 數據庫修復

有時候MySQL服務器忽然斷電、異常關閉,會致使表損壞,沒法讀取表數據。這時就能夠用到MySQL自帶的兩個工具進行修復,myisamchk和mysqlcheck。前者只能修復MyISAM表,而且中止數據庫,後者MyISAM和InnoDB均可以,在線修復。

注意:修復前最好先備份數據庫。

myisamchk經常使用參數:

-f --force    強制修復,覆蓋老的臨時文件,通常不使用

-r --recover  恢復模式

-q --quik     快速恢復

-a --analyze  分析表

-o --safe-recover 老的恢復模式,若是-r沒法修復,可使用此參數試試

-F --fast     只檢查沒有正常關閉的表

例如:myisamchk -r -q *.MYI

mysqlcheck經常使用參數:

-a  --all-databases  檢查全部的庫

-r  --repair   修復表

-c  --check    檢查表,默認選項

-a  --analyze  分析表

-o  --optimize 優化表

-q  --quik   最快檢查或修復表

-F  --fast   只檢查沒有正常關閉的表

例如:mysqlcheck -r -q -uroot -p123456 weibo

5.5 MySQL服務器性能分析

重點關注:

  • id:CPU利用率百分比,平均小於60%正常,但已經比較繁忙了。
  • wa:CPU等待磁盤IO響應時間,通常大於5說明磁盤讀寫量大。

KB_read/s、KB_wrtn/s 每秒讀寫數據量,主要根據磁盤每秒最高讀寫速度評估。

r/s、w/s:每秒讀寫請求次數,能夠理解爲IOPS(每秒輸入輸出量),是衡量磁盤性能的主要指標之一。

await:IO平均每秒響應時間,通常大於5說明磁盤響應慢,超過自身性能。

util:磁盤利用率百分比,平均小於60%正常,但已經比較繁忙了。

小結

因爲關係型數據庫初衷設計限制,在大數據處理時會顯得力不從心。所以NoSQL(非關係型數據庫)火起來了,天生勵志,具有分佈式、高性能、高可靠等特性,彌補了關係型數據庫某方面先天性不足,很是適合存儲非結構化數據。主流NoSQL數據庫有:MongoDB、HBase、Cassandra等。

單純數據庫層面優化效果提高並很少明顯,主要仍是要根據業務場景選擇合適的數據庫!

相關文章
相關標籤/搜索