MySQL關閉過程詳解和安全關閉MySQL的方法


本文分析了mysqld進程關閉的過程,以及如何安全、緩和地關閉MySQL實例,對這個過程不甚清楚的同學可以參考下。

關閉過程:

1、發起shutdown,發出SIGTERM信號

2、有必要的話,新建一個關閉線程(shutdown thread)

   如果是客戶端發起的關閉,則會新建一個專用的關閉線程

   如果是直接收到 SIGTERM 信號進行關閉的話,專門負責信號處理的線程就會負責關閉工作,或者新建一個獨立的線程負責這個事

   當無法創建獨立的關閉線程時(例如內存不足),MySQL Server會發出類似下面的告警信息:

   Error: Can't create thread to kill server

3、MySQL Server不再響應新的連接請求

   關閉TCP/IP網絡監聽,關閉Unix Socket等渠道

4、逐漸關閉當前的連接、事務

   空閑連接,將立刻被終止;

   當前還有事務、SQL活動的連接,會將其標識為 killed,並定期檢查其狀態,以便下次檢查時將其關閉;(參考 KILL 語法)

   當前有活躍事務的,該事物會被回滾,如果該事務中還修改了非事務表,則已經修改的數據無法回滾,可能只會完成部分變更;

   如果是Master/Slave復制場景里的Master,則對復制線程的處理過程和普通線程也是一樣的;

   如果是Master/Slave復制場景里的Slave,則會依次關閉IO、SQL線程,如果這2個線程當前是活躍的,則也會加上 killed 標識,然后再關閉;

   Slave服務器上,SQL線程是允許直接停止當前的SQL操作的(為了避免復制問題),然后再關閉該線程;

   在MySQl 5.0.80及以前的版本里,如果SQL線程當時正好執行一個事務到中間,該事務會回滾;從5.0.81開始,則會等待所有的操作結束,除非用戶發起KILL操作。

   當Slave的SQL線程對非事務表執行操作時被強制 KILL了,可能會導致Master、Slave數據不一致;

5、MySQL Server進程關閉所有線程,關閉所有存儲引擎;

   刷新所有表cache,關閉所有打開的表;

   每個存儲引擎各自負責相關的關閉操作,例如MyISAM會刷新所有等待寫入的操作;InnoDB會將buffer pool刷新到磁盤中(從MySQL 5.0.5開始,如果innodb_fast_shutdown不設置為 2 的話),把當前的LSN記錄到表空間中,然后關閉所有的內部線程。

6、MySQL Server進程退出

關於KILL指令

   從5.0開始,KILL 支持指定  CONNECTION | QUERY兩種可選項:

@KILL CONNECTION和原來的一樣,停止回滾事務,關閉該線程連接,釋放相關資源;

@KILL QUERY則只停止線程當前提交執行的操作,其他的保持不變;

   提交KILL操作后,該線程上會設置一個特殊的 kill標記位。通常需要一段時間后才能真正關閉線程,因為kill標記位只在特定的情況下才檢查:

1、執行SELECT查詢時,在ORDER BY或GROUP BY循環中,每次讀完一些行記錄塊后會檢查 kill標記位,如果發現存在,該語句會終止;

2、執行ALTER TABLE時,在從原始表中每讀取一些行記錄塊后會檢查 kill 標記位,如果發現存在,該語句會終止,刪除臨時表;

3、執行UPDATE和DELETE時,每讀取一些行記錄塊並且更新或刪除后會檢查 kill 標記位,如果發現存在,該語句會終止,回滾事務,若是在非事務表上的操作,則已發生變更的數據不會回滾;

4、GET_LOCK() 函數返回NULL;

5、INSERT DELAY線程會迅速內存中的新增記錄,然后終止;

6、如果當前線程持有表級鎖,則會釋放,並終止;

7、如果線程的寫操作調用在等待釋放磁盤空間,則會直接拋出“磁盤空間滿”錯誤,然后終止;

8、當MyISAM表在執行REPAIR TABLE 或 OPTIMIZE TABLE 時被 KILL的話,會導致該表損壞不可用,指導再次修復完成。

安全關閉MySQL幾點建議

  想要安全關閉 mysqld 服務進程,建議按照下面的步驟來進行:

0、用具有SUPER、ALL等最高權限的賬號連接MySQL,最好是用 unix socket 方式連接;

1、在5.0及以上版本,設置innodb_fast_shutdown = 1,允許快速關閉InnoDB(不進行full purge、insert buffer merge),如果是為了升級或者降級MySQL版本,則不要設置;

2、設置innodb_max_dirty_pages_pct = 0,讓InnoDB把所有臟頁都刷新到磁盤中去;

3、設置max_connections和max_user_connections為1,也就最后除了自己當前的連接外,不允許再有新的連接創建;

4、關閉所有不活躍的線程,也就是狀態為Sleep  且 Time 大於 1 的線程ID;

5、執行 SHOW PROCESSLIST  確認是否還有活躍的線程,尤其是會產生表鎖的線程,例如有大數據集的SELECT,或者大范圍的UPDATE,或者執行DDL,都是要特別謹慎的;

6、執行 SHOW ENGINE INNODB STATUS 確認History list length的值較低(一般要低於500),也就是未PURGE的事務很少,並且確認Log sequence number、Log flushed up to、Last checkpoint at三個狀態的值一樣,也就是所有的LSN都已經做過檢查點了;

7、然后執行FLUSH LOCKAL TABLES 操作,刷新所有 table cache,關閉已打開的表(LOCAL的作用是該操作不記錄BINLOG);

8、如果是SLAVE服務器,最好是先關閉 IO_THREAD,等待所有RELAY LOG都應用完后,再關閉 SQL_THREAD,避免 SQL_THREAD 在執行大事務被終止,耐心待其全部應用完畢,如果非要強制關閉的話,最好也等待大事務結束后再關閉SQL_THREAD;

9、最后再執行 mysqladmin shutdown。

10、緊急情況下,可以設置innodb_fast_shutdown = 1,然后直接執行 mysqladmin shutdown 即可,甚至直接在操作系統層調用 kill 或者 kill -9 殺掉 mysqld 進程(在innodb_flush_log_at_trx_commit = 0 的時候可能會丟失部分事務),不過mysqld進程再次啟動時,會進行CRASH RECOVERY工作,需要有所權衡。

 

Innodb_fast_shutdown告訴innodb在它關閉的時候該做什么工作。有三個值可以選擇:
1.  0表示在innodb關閉的時候,需要purge all, merge insert buffer,flush dirty pages。這是最慢的一種關閉方式,但是restart的時候也是最快的。后面將介紹purge all,merge insert buffer,flush dirty pages這三者的含義。
2.  1表示在innodb關閉的時候,它不需要purge all,merge insert buffer,只需要flush dirty page。
3.  2表示在innodb關閉的時候,它不需要purge all,merge insert buffer,也不進行flush dirty page,只將log buffer里面的日志flush到log files。因此等下進行恢復的時候它是最耗時的。


那么在mysql restart的時候它的恢復流程(也稱作crash recovery)是怎么樣的呢?
1.   如果在上次關閉innodb的時候是在innodb_fast_shutdown=2或是mysql crash這種情況,那么它會利用redo log重做那些已經提交了的事務。
2.   接下來的操作就是這么幾個:
a>     Rollback uncompleted transitions 取消那些沒有提交的事務
b>     Purge all 清除無用的undo頁
c>      Merge insert buffer 合並插入緩沖

---------------------


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM