在生產環境中,常見MySQL架構使用最多的就是主從了,所以對於主從是否同步數據的監控尤其重要。若是使用了專業的監控軟件(如zabbix)監控MySQL,那麼選擇監控工具提供的模板或插件去監控就很方便,可是若是涉及到一些特殊要求就另當別論了。咱們能夠寫shell腳原本實現定製化的需求。python
本案例須要寫一個shell腳原本監控MySQL主從,需求以下:mysql
1)每分鐘檢測一次,本次執行腳本時需檢測上一次是否執行完成,若是還未完成則本次不執行linux
2)若是不一樣步須要發送告警郵件給admin@admin.comsql
3)須要作告警收斂,在沒有解決問題前每隔30分鐘發一次告警郵件shell
4)假設本機mysql root帳戶密碼爲tpH40Kznvvim
知識點一:特殊符號$?bash
在命令行或者在shell中,每執行完一條命令,都會有一個返回值,返回值爲0則表示這條命令執行成功,非0表示執行不成功,返回值能夠經過$?查看,以下:服務器
# ls 123 1.txt # echo $? 0
在shell腳本中,要想判斷一條命令是否執行成功,就可使用$?的值是否爲0來實現。架構
知識點二:查看MySQL主從狀態ide
判斷MySQL主從是否正常有兩種方法,第一種是對比兩臺MySQL上的數據是否一致,第二種是經過執行「show slave status」指令查看輸出的結果,判斷主從狀態。第一種是最精準的,可是比較麻煩,因此一般用第二種來判斷MySQL主從狀態。
操做以下(在從機上執行):
# mysql -uroot -ptpH40Kznv -e "show slave status \G" *************************** 1. row *************************** Slave_IO_State: Connecting to master Master_Host: 192.168.93.130 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: aminglinux1.000001 Read_Master_Log_Pos: 664307 Relay_Log_File: CLAY-relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: aminglinux1.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 664307 Relay_Log_Space: 120 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 2003 Last_IO_Error: error connecting to master 'repl@192.168.93.130:3306' - retry-time: 60 retries: 1 Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 0 Master_UUID: Master_Info_File: /data/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: 190718 18:49:05 Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0
須要關注的行有:Slave_IO_Running、Slave_SQL_Running,只有這兩行的值所有是Yes纔算是主從同步狀態正常。 任何一個爲No,則不正常,當不正常時須要查看下面的Error(如Last_Error、Last_IO_error、Last_SQL_Error)相關信息進一步判斷形成不一樣步的緣由。
在生產環境中,有很大一部分問題不是主從不一樣步,而是主從延遲太嚴重,對於以上輸出信息中,有一行顯示的是主從延遲信息,
Seconds_Behind_Master,這個顯示的是一個時間,單位是秒,表示從落後主多少秒。這個值其實並不徹底精準,但咱們卻能夠經過這個數值判斷主從是否有延遲(保證主從兩臺機器時間設置一致)。
知識點三:shell中的數學運算
shell中的加減乘除和取餘有點特殊,主要是格式上和C不太同樣。
# a=1;b=2 # c=$[$a+$b] # echo $c 3 # d=$[$b-$a] # echo $d 1 # e=$[$a*$b] # echo $e 2 # f=$[$b/$a] # echo $f 2 # g=$[$b%$a] //取餘 # echo $g 0
取餘隻能整數除以整數,若除數比被除數大,直接除數就是餘數;若除數比被除數小,被除數就除以除數直到剩下的數比除數小,則這個數就是餘數,並且注意餘數的符號要與被除數的符號一致。
c÷b,讀做c除以b(或b除c)。其中,c叫作被除數,b叫作除數。
在shell的數學運算中要想使用小數,或者限定小數位數,能夠藉助bc的scale實現:
# a=10;b=3 # echo $[$a/$b] 3 # echo "scale=2;$a/$b"|bc //scale等於2表示小數有2位 3.33
知識點四:查看MySQL隊列
在Linux系統中,能夠經過ps、top等指令來查看系統的進程狀況,在MySQL中,能夠經過「show porcesslist"指令查看MySQL進程隊列。當MySQL服務器負載變高或者訪問卡頓時,查看一下進程隊列很是有必要。操做以下:
# mysql -uroot -ptpH40Kznv -e "show processlist" +----+------+-----------+------+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+------+---------+------+-------+------------------+ | 2 | root | localhost | NULL | Query | 0 | init | show processlist | +----+------+-----------+------+---------+------+-------+------------------+
由於是實驗機器並無什麼訪問量,因此只列出了show processlist自己。
有時候列出來的隊列命令太長從而顯示不完整,則須要使用另一個指令:show full processlist。
知識點五:shell中的內置變量
在shell腳本中,你會不會奇怪,哪來的$1和$2,其實就是shell腳本中的預設變量,其中$1的值就是在執行的時候輸入的第一個參數,$2就是執行的時候輸入的第二個參數,shell腳本的預設變量是沒有限制的。另外還有一個$0,它表明的是腳本自己的名字,編寫一個測試腳本,以下:
# vim option.sh #!/bin/bash echo "$1 $2 $0"
執行結果以下:
# sh option.sh 1 2 1 2 option.sh
若是這樣執行腳本,那$0的值會有所不一樣,以下:
# chmod a+x option.sh # ./option.sh 1 2 1 2 ./option.sh
就是說,$0的值會跟着執行時的命令變化,用絕對路徑它就會顯示絕對路徑,用相對路徑它就會顯示相對路徑。
本案例參考腳本:
完成本腳本最核心的一個知識點就是查看slave的狀態,而後藉助grep、sed、awk把想要的字符串截取出來,而後進行判斷是否和預期一致。腳本中的mail.py參考案例二中的mail.py。
#!/bin/bash ##檢測MySQL主從是否同步 ##做者: ##日期: ##版本:v0.1 #把腳本名字存入變量s_name s_name=`echo $0 | awk -F '/' '{print $NF}'` Mysql_c="mysql -uroot -ptpH40Kznv" mail_user=aming_test@163.com #該函數實現郵件告警收斂,在案例五中出現過,通用 m_mail(){ log=$1 #此處的$1表示第一個函數chk_sp t_s=`date +%s` t_s2=`date -d "1 hours ago" +%s` if [ ! -f /tmp/$log ] then #建立$log文件 touch /tmp/$log #增長a權限,只容許追加內容,不容許更改或刪除 chattr +a /tmp/$log #第一次告警,能夠直接寫入1小時之前的時間戳 echo $t_s2 >> /tmp/$log fi #不管$log文件是不是剛剛建立,都須要查看最後一行的時間戳 t_s2=`tail -1 /tmp/$log|awk '{print $1}'` #取出最後一行即上次告警的時間戳後,當即寫入當前的時間戳 echo $t_s>>/tmp/$log #取兩次時間戳差值 v=$[$t_s-$t_s2] #若是差值超過1800,當即發郵件 if [ $v -gt 1800 ] then #發郵件,其中$2爲mail函數的第二個參數,這裏爲一個文件 python mail.py $mail_user "磁盤使用率超過90%" "`cat $2`" 2>/dev/null #定義計數器臨時文件,並寫入0 echo "0" > /tmp/$log.count else #若是計數器臨時文件不存在,須要建立並寫入0 if [ ! -f /tmp/$log.count ] then echo "0" > /tmp/$log.count fi nu=`cat /tmp/$log.count` #30分鐘內每發生一次告警,計數器加1 nu2=$[$nu+1] echo $nu2>/tmp/$log.count #當告警次數超過30次,須要再次發郵件 if [ $nu2 -gt 30 ] then python mail.py $mail_user "磁盤使用率超過90%持續30分鐘了" "`cat $2`" 2>/dev/null #第二次告警後,將計數器再次從0開始 echo "0" > /tmp/$log.count fi fi } #把進程狀況存入臨時文件,若是加管道求行數會有問題 ps aux |grep "$s_name" |grep -vE "$$|grep">/tmp/ps.tmp p_n=`wc -l /tmp/ps.tmp|awk '{print $1}'` #當進程數大於0,則說明上次的腳本還未執行完 if [ $p_n -gt 0 ] then exit fi #先執行一條show processlist,看是否執行成功 $Mysql_c -e "show processlist" >/tmp/mysql_pro.log 2>/tmp/mysql_log.err #若是上一條命令執行不成功,說明這個MySQL服務出現問題了。 if [ $? -gt 0 ] then m_mail mysql_service_error /tmp/mysql_log.err exit else $Mysql_c -e "show slave status\G" >/tmp/mysql_s.log n1=`wc -l /tmp/mysql_s.log | awk '{print $1}'` if [ $n1 -gt 0 ] then y1=`grep 'Slave_IO_Running:' /tmp/mysql_s.log | awk -F : '{print $2}' | sed 's/ //g'` y2=`grep 'Slave_SQL_Running:' /tmp/mysql_s.log | awk -F : '{print $2}' | sed 's/ //g'` if [ $y1 == "No" ] || [ $y2 == "No" ] then m_mail mysql_slavestatus_error /tmp/mysql_s.log fi fi fi