MySQL並不孤單的存在—硬件環境的限制與優化

    之因此寫這篇文章也是由於前幾天出的一個問題,當時業務感受到卡頓,而且伴隨着鎖超時的報錯。最後經過分析發現是因爲磁盤I/Q繁忙致使SQL耗時增長,部分鎖競爭激烈的熱數據出現了鎖等待和鎖超時。因而可知,系統的硬件環境對數據庫總體性能的影響也是很是大的,MySQL在運行環境中並非孤立存在的,它的總體性能每每受限於系統最薄弱的環節,今天想和你們分享下,都有哪些系統指標會對數據庫的總體性能產生影響,咱們又如何進行分析。
CPU

    在2000年先後,博客盛行的時代,OLTPOnline Transaction Processing)型的數據庫對CPU的要求並不高,當時的業務併發量較低,也不多有排序、分組、鏈接等很是耗CPU的操做,隨着互聯網業務的高速發展,雙11618以及關鍵節日會有一些搶購、秒殺活動,這時候業務訪問密集,併發ni需求大,併發執行的SQL不少,這時候對CPU的要求相應也提升了,就須要核數更多的CPUMySQL能夠經過innodb_thread_concurrency來限制併發線程的數量,保護系統不被hang住,通常是cpu核數的4倍。
    根據多年的DBA經驗,若是你的CPU忽然之間升高,多半是由於數據量增大到必定層度,數據在內存中的排序、分組、join等動做消耗CPU增高致使,這時爛SQL就會浮出水面了,能夠經過如下方法精肯定位是哪一個SQL引發。
1.首先是經常使用的top命令 (簡單粗暴最有效),它能夠對進程和線程進行實時監控。
   
     
   
   
    
    
             
    
    
top - 14:13:24 up 214 days, 16:30, 28 users,  load average: 0.61, 0.44, 0.27Tasks: 2941 total,   1 running, 2927 sleeping,  12 stopped,   1 zombieCpu(s):  4.6%us,  4.2%sy,  0.0%ni, 90.3%id,  0.7%wa,  0.0%hi,  0.1%si,  0.0%stMem:  16335708k total, 16109152k used,   226556k free,   486544k buffersSwap: 16777212k total,  1325068k used, 15452144k free,  4629420k cached  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND 17468 efs       20   0 20.1g 7.4g  17m S 45.8 47.6   0:16.73 java 18281 mysql 20 0 5029m 442m 7148 S 3.9 2.8 0:48.18 mysqld
第一行顯示了當前時間,系統運行的時間,已登陸的用戶數量,以及系統的平均負載。平均負載分別包含1分鐘、5分鐘、15分鐘的平均負載。
第二行顯示了進程信息,有多長進程正在運行、睡眠、已中止和僵死。
第三行就是CPU信息了,
4.6%us-表示用戶空間佔用CPU的比例。
4.2%sy-內核空間佔用CPU的比例。
90.3%id-空閒CPU的比例。
0.7%wa-IO等待佔用CPU的比例。
0.0%hi-硬中斷佔用CPU的比例。
0.1%si-軟中斷佔用CPU的比例
第四行和第五行是內存和swap的總量及使用狀況。
最後,下一部分顯示當前正在運行的進程的詳細列表。
PID:進程IP
USER:進程全部者的用戶名
PR:進程的優先級
VIRT:進程所使用的虛擬內存總量
RES:進程當前使用的物理內存量
SHR:進程與其餘進程共享的內存量
S:進程狀態(D=可中斷睡眠,R=進行中,S=睡眠,T=已跟蹤或已中止,Z=僵死)
%CPU:進程正在使用的CPU時間份額
%MEM:進程正在使用的可用物理內存份額
TIME+:進程啓動後已使用的總CPU時間
COMMAND:進程的命令行名稱
2.輸入H, 能夠按照顯示線程狀態。
3.輸入P, 能夠按照cpu的使用時間份額進行排序,這時候咱們就能夠看下是否有超過70%-90%以上的線程了。
 
4.登陸mysql,執行如下命令
select * from performance_schema.threads where THREAD_OS_ID=4461 \G
 


內存

    正確的分配和使用內存對MySQL來講相當重要,數據的修改、緩存、排序、分組以及內部管理等動做大部分都是在內存中完成的,內存的大小最能直接反應數據庫的性能。下面咱們一塊兒來看下MySQL數據庫服務器上都有哪些須要內存的地方。
InnoDB緩衝池(Buffer Pool)
    數據庫再啓動的時候,會劃出很大一塊內存區,做爲數據緩衝區,用來緩存InnoDB表的數據、索引、插入緩存、數據字典等信息,這就是innodb_buffer_poolInnoDB嚴重依賴於緩衝池,可是也不是說bufferpool越大越好,由於預熱和關閉都會花費很長時間,仍是要根據數據大小來設定,通常設置爲物理內存的50%-80%
鏈接須要的內存
    MySQL會爲每一個鏈接都分配一些內存,主要有sort_buffer(排序)、join_buffer(錶鏈接)、read_buffer(表順序掃描的緩存)、read_rnd_buffer(隨機讀緩衝區,用於mrr)等緩存區。
線程緩存
    爲了避免頻繁的建立、銷燬線程,MySQL通常會先緩存一些線程。當有新的鏈接上來時,直接從線程池中分配一個線程給新的鏈接,當鏈接關閉時,若是線程池中還有空間的話會把線程放回緩存,若是沒有空間的話,就會銷燬該線程。緩存的線程數量由thread_cache_size參數控制。
操做系統保留內存
    操做系統也須要保留足夠的內存,能夠經過free –m命令查看swap的使用狀況來判斷內存是否夠用。
    關於內存的使用狀況能夠經過vmstat命令分析,能夠分析cpu使用率、內存使用狀況、虛擬內存交換狀況、IO讀寫狀況。
   
     
   
   
    
    
             
    
    
[root@node1 ~]# vmstat 2 3     #每隔2秒採集一次,一共採集三次procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st 0  0     0  99764  83536 375416   0    0    21    3   30   71  0  0 99  1  0 0  0     0  99732  83536 375416   0    0    0     0   31   65  0  0 100  0  00 0 0 99732 83536 375416 0 0 0 0 29 66 0 0 100 0 0
procs(進程)
r:表示運行隊列中進程的數量,就是有多少個進程真的分配到cpu,當這個值超過了cpu數目,就會出現cpu瓶頸了。
b:等待IO的進程數量,即阻塞的進程數。
memory(內存)
swpd: 表示虛擬內存的已使用的大小,若是大於0,表示物理內存不足了,若是不是程序內存泄漏的緣由,該升級內存了。
free:空閒的物理內存大小。
buff:用做緩衝的內存大小。
cache:用做緩存的內存大小。
swap(交換區)
Si:每秒從磁盤讀入虛擬內存的大小,若是這個值大於 0,表示物理內存不夠用或者內存泄露了,要查找消耗內存進程解決掉。
So:每秒虛擬內存寫入磁盤的大小
IO
bi:每秒讀取的的塊數。
bo:每秒寫入的塊數。
若是bi和bo常常不等於0,表示內存不足。
system(系統)
in:每秒 cpu 的中斷次數,包括時間中斷。
cs:每秒上下文切換次數
CPU(百分比表示)
us:用戶進程佔用cpu時間百分比
sy:系統進程佔用cpu時間百分比,若是過高,表示系統調用時間長,例如IO操做頻繁。
id:空閒cpu時間百分比,若是r常常大於4,而且id常常少於40,表示cpu的負載很重。
wa:IO等待時間百分比,太高時,說明io等待比較嚴重,多是因爲磁盤大量隨機訪問形成的,也有多是磁盤的帶寬出現瓶頸。
磁盤I/O

    咱們以前一直在強調MySQL的順序讀寫在性能上要比隨機讀寫高出不少,這是由於如今大多數數據庫使用的是機械硬盤,在機械硬盤進行隨機讀寫時須要來回移動磁頭,這樣就須要耗費長時間的磁頭旋轉和移動來查找。近幾年出現的固態硬盤,因其低延遲、低功耗等特性獲得了普遍的應用,若是你使用了固態硬盤,能夠經過增長innodb_io_capacity參數來充分利用固態硬盤帶來的高IOPS特性。
    關於針對磁盤IO異常的排查,能夠經過iostat命令進行分析。
   
     
   
   
    
    
             
    
    
[root@node1 ~]# iostat -x 5Linux 2.6.32-696.el6.x86_64 (node1) 07/13/2020 _x86_64_(1 CPU)avg-cpu:  %user   %nice %system %iowait  %steal   %idle           3.25    0.00    7.27   26.45    0.00   63.03Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %utilsda              77.54    40.37   48.03    7.82  3332.45   385.45    66.57     4.04   72.38    9.07  461.07   5.61  31.32scd0              0.38     0.00    0.38    0.00     3.05     0.00     8.00     0.00    0.56    0.56    0.00   0.56   0.02scd1 0.00 0.00 0.36 0.00 2.86 0.00 8.00 0.00 1.11 1.11 0.00 1.11 0.04
關於avg-cpu一欄,主要是CPU的平均使用狀況:
%user:用戶層面使用CPU的狀況。
%system:系統層面使用CPU的狀況,若是該值較高,多半是IO出了問題。由於MySQLIO請求發出後,最終是由系統的IO進程完成,假如讀寫很高的話,sys就很繁忙。
%iowait:IO等待狀況,iowait 很高的話表示浪費cpu資源。
%idle:cpu 空閒時間。
system和iowait通常結合着看,表示系統IO的狀況,若是iowait很高的話,說明cpu花太多的時間在IO等待上,說明系統的IO成爲瓶頸了,iowait通常但願小於5%,若是大於25%就說明有問題了。Idle通常但願大於25%,但願有25%的時間是空閒的。
關於Device一欄,描述了IO的具體使用狀況。
rrqm/s:合併讀,合併讀通常爲0,若是值很高的話,說明系統有大量的全表掃描。由於
數據庫的特色是隨機讀(oltp交易系統),因此兩個讀被合併的機率很低,因此若是出現大量的合併讀,說明系統在全盤掃描。
wrqm/s:合併寫,若是系統在作批量的insert,而且是按照主鍵順序遞增插入的時候,該值會比較高。
r/s:每秒讀。
w/s:每秒寫。每秒讀+每秒寫=IOPS,能夠看出系統是讀仍是寫爲主。
rsec/s:每秒讀扇區的數量。每一個扇區是 512 字節。
wsec/s:每秒寫扇區的數量。rsec/s+ wsec/s就是IO的吞吐量。
avgrq-sz:平均每次IO操做的扇區數。
avgqu-sz:平均等待處理的IO請求隊列長度
await:平均每次IO請求的等待時間。
svctm:每個請求的服務時間(單位毫秒),反應了io性能,56ms表示io性能還能夠,能夠降到1ms如下。
%util:繁忙度,週期內用於IO操做的時間比例,即IO隊列非空的時間比率。若是io不高,但繁忙度高,說明磁盤有問題。
網絡帶寬

    網絡在整個系統中充當了橋樑和道路的做用,因此的數據都是經過網絡進行傳輸的。有時候業務反饋系統慢了,這時候咱們就要分析究竟是慢在哪了,這時候除了分析應用和數據庫的日誌以外,咱們還能夠經過tcpdump命令進行抓包分析。具體tcpdump的使用能夠參考文章《tcpdumpMySQL中的應用》。
其餘系統限制


1.關閉selinux
vi /etc/selinux/config
把SELINUX=enforcing改爲SELINUX=disabled,
修改完成以後要重啓操做系統。
2.關閉防火牆
redhat6
   
     
   
   
    
    
             
    
    
查看防火牆狀態:service iptables status臨時關閉防火牆:service iptables stop永久關閉防火牆:chkconfig iptables off
redhat7及以上
   
     
   
   
    
    
             
    
    
查看防火牆狀態:systemctl status firewalld臨時關閉防火牆:systemctl stop firewalld永久關閉防火牆:systemctl disable firewalld
3.關閉numa
    numa(Non-Uniform Memory Access)譯爲非一致性內存訪問,在這種架構下一個CPU和一組內存構成一個node,每一個CPU訪問本身node下的內存。對於MySQL來講,它是單進程多線程,會形成MySQL用一顆cpu的內存不夠用了,可是還不能用其餘node的內存,只能去用swap空間的,因此MySQL不適合運行在NUMA結構的服務器上。
關閉NUMA的方式
redhat6
   
     
   
   
    
    
             
    
    
vi /etc/grub.conf
在Kernel ... rhgb quiet後加上numa=off,保存後重啓.
 
查看是否生效,numactl --hardware只有一個節點
redhat7及以上
   
     
   
   
    
    
             
    
    
vi /etc/default/grub
添加numa=off
 
從新生成/etc/grub2.cfg :  
   
     
   
   
    
    
             
    
    
grub2-mkconfig -o /etc/grub2.cfg
 
重啓系統:reboot
確認是否已經關閉numa:
   
     
   
   
    
    
             
    
    
dmesg |grep -i numa
 
4.調整swap
    swap分區即交換區,是在系統的物理內存不夠用的時候,把硬盤內存中的一部分空間釋放出來,以供當前運行的程序使用。swap的調整對Linux服務器的性能相當重要。
    咱們通常經過修改swapiness的值來調整系統如何分配swap, 這個值在 0-100 之間,0 表示最大限度的使用物理內存,當物理內存耗盡才使用 swap 空間,有可能致使系統內存溢出,出現OOM的錯誤,從而致使MySQL被強制kill掉。100 表示積極的使用 swap 空間,linux 系統默認是 60,能夠修改成10
修改方式:
   
     
   
   
    
    
             
    
    
vi /etc/sysctl.conf加入vm.swappiness = 10。#執行下面命令生效sysctl -p /etc/sysctl.conf
5.文件句柄和進程的最大數量限制
經過ulimt –a能夠查看文件的最大句柄數和進程的最大數量限制。
 
Linux默認的最大文件句柄數是1024,表示單個進程最多能夠訪問1024個文件句柄,超出文件句柄限制會報錯:「too many open files」。
max user processes主要用來限制每一個用戶的最大processes數量,超出數量就會報錯:「resource temporarily unavailable」。
主要經過修改如下兩個配置文件修改。
vi /etc/security/limits.conf
#新增如下內容(注意必須有空格)
   
     
   
   
    
    
             
    
    
* soft nofile 65535* hard nofile 65535* soft nproc 65535* hard nproc 65535
vi /etc/security/limits.d/20-nproc.conf
#新增如下內容(注意必須有空格)
   
     
   
   
    
    
             
    
    
* soft nproc 65535* hard nproc 65535


爲了方便你們交流,我建了一個微信羣,你們能夠在羣裏聊技術、聊理想、聊生活,歡迎加入!javascript


本文分享自微信公衆號 - MySQL數據庫技術棧(Mysqltechnology)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。css

相關文章
相關標籤/搜索