MySQL 服務器中的 6 種日誌類型

在這裏插入圖片描述

大家好!我是隻談技術不剪髮的 Tony 老師。今天我們來談談 MySQL 服務器中各種日誌文件的作用以及相關配置選項。

MySQL 提供了一套完整的服務器日誌體系,包含了多種日誌類型,可以幫助我們查找、解決系統問題和優化數據庫的性能。

日誌類型 記錄信息
錯誤日誌 啓動、運行、停止 mysqld 時出現的問題
通用查詢日誌 建立的客戶端連接和客戶端提交的語句
慢查詢日誌 執行時間超過 long_query_time(默認爲 10 秒)的查詢
二進制日誌 修改數據的語句,也用於複製
中繼日誌 從複製主節點接收到的數據變更
DDL日誌 元數據日誌,DDL 語句執行的元數據操作

默認情況下,服務器的日誌文件都位於數據目錄(datadir)中。

錯誤日誌

MySQL 錯誤日誌(error log)記錄了 mysqld 啓動和停止的相關信息,同時還記錄了服務器在啓動、停止以及運行期間發生的診斷消息,例如錯誤、警告和通知等。例如,當 mysqld 發現某個表需要執行自動檢查或修復時,它會向錯誤日誌中寫入一條消息。

默認安裝時,錯誤日誌通常在配置文件(my.cnf 或者 my.ini)中 mysqld 部分的 log-error 配置項進行設置;利用 MySQL 系統變量 log_error 可以查看錯誤日誌的文件名:

mysql> show variables like 'log_error';
+---------------+---------------------+
| Variable_name | Value               |
+---------------+---------------------+
| log_error     | /var/log/mysqld.log |
+---------------+---------------------+
1 row in set (0.01 sec)

如果查詢結果爲 stderr,表示標準錯誤輸出,也就是終端或控制檯窗口。

從 MySQL 8.0 開始,錯誤日誌採用了 MySQL 組件體系結構,由執行日誌過濾和寫入的多個組件構成,系統變量 log_error_services 配置了用於生成錯誤日誌的組件。當 log_error 系統變量指定了默認的錯誤日誌文件之後,日誌寫入器組件可能基於該值設置自己的輸出文件,或者使用單獨的輸出文件:

  • 如果 log_error 設置爲 stderr,默認的錯誤日誌將會輸出到控制檯;日誌寫入器組件 log_sink_internal、log_sink_json 以及 log_sink_test 都會輸出到控制檯,但是 log_sink_syseventlog 的輸出目標爲系統日誌文件,而不是 log_error。
  • 如果 log_error 設置爲系統文件,默認的錯誤日誌將會輸出到該文件;日誌寫入器組件 log_sink_internal 和 log_sink_test 都會輸出到該文件;log_error_services 中配置的多個 log_sink_json 將會使用文件名加上帶編號的 .NN.json 文件:file_name.00.json、file_name.01.json 等;log_sink_syseventlog 的輸出目標爲系統日誌文件,而不是 log_error。

📝MySQL 錯誤日誌是日常監控和服務器出現故障時首先應該查看的日誌文件。

通用查詢日誌

MySQL 通用查詢日誌(general query log)記錄了 mysqld 執行的各種操作,當客戶端連接或斷開連接、每次提交 SQL 語句時都會記錄相關的信息。當我們懷疑客戶端存在問題或者想要查看客戶端發送給服務器的確切請求時,通用查詢日誌將會非常有用。

默認情況下,通用查詢日誌沒有啓用;我們可以通過系統變量 general_log 查看和控制通用查詢日誌的設置:

mysql> show variables like 'general_log%';
+------------------+----------------------------+
| Variable_name    | Value                      |
+------------------+----------------------------+
| general_log      | OFF                        |
| general_log_file | /var/lib/mysql/sqlhost.log |
+------------------+----------------------------+
2 rows in set (0.01 sec)

查詢結果中的 general_log_file 是通用查詢日誌的文件名,默認爲數據目錄下的 host_name.log

通用查詢日誌和慢查詢日誌既可以寫入日誌文件,也可以寫入系統數據庫中的日誌表中;通過系統變量 log_output 可以查看和設置:

mysql> show variables like 'log_output';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output    | FILE  |
+---------------+-------+
1 row in set (0.01 sec)

FILE 表示輸出到日誌文件,TABLE 表示輸出到日誌表(分別爲 mysql.general_log 和 mysql.slow_log)中,也可以設置爲 TABLE, FILE;NONE 表示禁用查詢日誌和慢查詢日誌。

另外,我們還可以通過系統變量 sql_log_off 設置當前會話的通用查詢日誌狀態,當前前提是已經啓用了系統的通用查詢日誌功能:

mysql> show variables like 'sql_log_off';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_log_off   | OFF   |
+---------------+-------+
1 row in set (0.01 sec)

OFF 表示啓用日誌功能;如果想要關閉當前會話的通用查詢日誌,可以將其設置爲 ON。

📝MySQL 通用查詢日誌和慢查詢日誌支持運行時的動態設置,包括啓用、禁用、修改日誌文件名和輸出目標等,具體可以參考官方文檔

慢查詢日誌

MySQL 慢查詢日誌(slow query log)記錄了執行時間超過指定閾值的 SQL 語句,可以用於監控需要執行優化的查詢語句。如果啓用了慢查詢日誌,任何執行時間超過 long_query_time 並且執行次數達到 min_examined_row_limit 次的查詢語句都會被記錄到慢查詢日誌中:

mysql> show variables like 'long_query_time';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)

mysql> show variables like 'min_examined_row_limit';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| min_examined_row_limit | 0     |
+------------------------+-------+
1 row in set (0.01 sec)

默認情況下,執行時間超過 10 秒的任何查詢都會被看作慢查詢。

慢查詢日誌的啓用和禁用由系統變量 slow_query_log 進行控制,默認禁用該功能:

mysql> show variables like 'slow_query_log%';
+---------------------+---------------------------------+
| Variable_name       | Value                           |
+---------------------+---------------------------------+
| slow_query_log      | OFF                             |
| slow_query_log_file | /var/lib/mysql/sqlhost-slow.log |
+---------------------+---------------------------------+
2 rows in set (0.01 sec)

查詢結果中的 slow_query_log_file 是慢查詢日誌的文件名,默認爲數據目錄下的 host_name-slow.log

與通用查詢日誌類似,慢查詢日誌既可以寫入日誌文件,也可以寫入系統數據庫中的日誌表(mysql.slow_log)中;通過系統變量 log_output 進行設置,參考上文中的通用查詢日誌介紹。

默認情況下,管理語句不會被記錄到慢查詢日誌,包括 ALTER TABLE、ANALYZE TABLE、CHECK TABLE、CREATE INDEX、DROP INDEX、OPTIMIZE TABLE 以及 REPAIR TABLE。如果想要記錄這些操作,可以將 log_slow_admin_statements 設置爲 ON:

mysql> show variables like 'log_slow_admin_statements';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| log_slow_admin_statements | OFF   |
+---------------------------+-------+
1 row in set (0.00 sec)

另外,不使用索引進行查找的查詢也不會被記錄到慢查詢日誌。如果想要記錄這些查詢,可以將 log_queries_not_using_indexes 設置爲 ON:

mysql> show variables like 'log_queries_not_using_indexes';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | OFF   |
+-------------------------------+-------+
1 row in set (0.00 sec)

與此相關的另一個系統變量是 log_throttle_queries_not_using_indexes;如果啓用了 log_queries_not_using_indexes,每分鐘內執行次數超過 log_throttle_queries_not_using_indexes 的查詢纔會在慢查詢日誌中記錄一條彙總信息;該參數的默認值爲 0。

📝MySQL 通用查詢日誌和慢查詢日誌支持運行時的動態設置,包括啓用、禁用、修改日誌文件名和輸出目標等,具體可以參考官方文檔

對於慢查詢日誌的分析,推薦使用 mysqldumpslow 或者 pt-query-digest 工具。

二進制日誌

MySQL 二進制日誌(binary log)存儲了描述數據庫變更的事件信息,例如創建表或者修改數據;即使該語句實際上可能並沒有修改任何數據,例如沒有匹配到任何數據行的 DELETE 語句。不過它不會記錄查詢語句,例如 SELECT 或者 SHOW,因爲它們不會修改數據。如果想要記錄所有的語句(例如爲了找出存在問題的查詢)可以使用上文中的通用查詢日誌。

二進制日誌同時還包含了更新語句所消耗的時間。二進制日誌爲我們提供了兩個重要的功能:

  • 用於複製。主節點上的二進制日誌存儲了數據的變更記錄併發送給從節點,然後在從節點上回放日誌實現相同的操作。
  • 用於數據恢復。通過備份文件執行還原之後,利用二進制日誌可以將數據庫恢復到指定時間點或者最新狀態。

啓用二進制日誌會給性能稍微帶來一些影響,但是它對複製的支持和數據的還原功能帶來的優勢更加明顯。二進制日誌不會受到系統故障的影響,因爲它只記錄和回讀完整的事件和事務。

接下來我們介紹與二進制相關的幾個主要系統變量,完整的參數可以參考官方文檔

mysql> show variables like '%log_bin%';
+---------------------------------+-----------------------------+
| Variable_name                   | Value                       |
+---------------------------------+-----------------------------+
| log_bin                         | ON                          |
| log_bin_basename                | /var/lib/mysql/binlog       |
| log_bin_index                   | /var/lib/mysql/binlog.index |
| log_bin_trust_function_creators | OFF                         |
| log_bin_use_v1_row_events       | OFF                         |
| sql_log_bin                     | ON                          |
+---------------------------------+-----------------------------+
6 rows in set (0.01 sec)

在 MySQL 5.7 以及之前的版本中,默認沒有啓用二進制日誌;如果想要啓用,可以指定 --log-bin 選項。

從 MySQL 8.0 開始,無論是否指定 --log-bin 選項,默認開啓二進制日誌(系統變量 log_bin 設置爲 ON)。唯一的例外是手動執行帶 --initialize 或者 --initialize-insecure 選項的 mysqld 命令初始化數據目錄,此時默認不會啓用二進制日誌;當然也可以通過 --log-bin 選項啓用二進制日誌。

📝如果想要禁用二進制日誌,可以指定 --skip-log-bin 或者 --disable-log-bin 啓動選項。

系統變量 log_bin_basename 記錄了二進制日誌文件的路徑和文件名,可以使用 --log-bin 選項進行設置。對於 MySQL 8.0,如果沒有指定 --log-bin,默認的文件名爲 binlog。對於 MySQL 5.7,默認的文件名爲 host_name-bin。

[root@sqlhost ~]# ls /var/lib/mysql/binlog.* -1
/var/lib/mysql/binlog.000059
/var/lib/mysql/binlog.000060
/var/lib/mysql/binlog.000061
/var/lib/mysql/binlog.000062
/var/lib/mysql/binlog.000063
/var/lib/mysql/binlog.000064
/var/lib/mysql/binlog.000065
/var/lib/mysql/binlog.000066
/var/lib/mysql/binlog.000067
/var/lib/mysql/binlog.index

從文件系統可以看出,MySQL 在創建二進制日誌文件時增加了一個數字擴展名。每次創建一個新的日誌文件時,擴展名中的數字編號都會加 1。服務器會在以下情況創建一個新的日誌文件:

  • 服務器進程啓動或者重啓時;
  • 服務器刷新日誌;
  • 當前日誌文件的大小到達 max_binlog_size 參數的限制。

爲了追蹤已經使用的二進制日誌文件,MySQL 還創建了一個二進制日誌索引文件。默認的索引文件和二進制日誌文件名相同,後綴爲“.index”。索引文件名可以通過 --log-bin-index 選項進行設置,但是千萬不要在服務器運行時修改索引文件的內容。

如果客戶端擁有設置 RESTRICTED SESSION 系統變量的權限,可以通過 SET sql_log_bin=OFF 語句禁用當前會話的二進制日誌功能。系統變量 sql_log_bin 顯示了當前的設置,默認爲 ON。

日誌文件中的事件格式取決於二進制日誌的格式,可以通過 binlog_format 查看和設置 :

  • 基於語句的日誌格式(statement-based logging)。以 SQL 語句爲基礎記錄數據庫的變更,MySQL 中的複製功能最初就是基於語句從主節點到從節點的傳播。這種方式需要記錄的日誌量少,但是對於不確定性的函數(例如 now())無法保證主從節點的一致性。通過 --binlog-format=STATEMENT 啓動選項可以設置爲該模式。
  • 基於語句的日誌格式(row-based logging),默認設置。日誌中記錄了每一行數據庫的修改信息;如果一個 UPDATE 語句修改了 100 條記錄,需要記錄 100 條修改信息,所以可能產生大量的日誌。通過 --binlog-format=ROW 啓動選項可以設置爲該模式。
  • 混合日誌格式(mixed logging)。默認使用基於語句的日誌格式,對於不確定性的語句切換爲基於行的日誌格式。通過 --binlog-format=MIXED 啓動選項可以設置爲該模式。

關於二進制日誌格式的詳細介紹,可以參考 MySQL 官方文檔

MySQL 提供了一個實用工具 mysqlbinlog ,可以用於讀取二進制日誌文件中的內容。mysqlbinlog 可以通過重新執行日誌文件中的語句實現恢復操作:

shell> mysqlbinlog log_file | mysql -h server_name

默認情況下,每次提交事務都會將二進制日誌同步到磁盤;該行爲由系統參數 sync_binlog 控制,默認值爲 1;此時不會丟失已經提交的事務,但是會對性能產生一定的影響。如果禁用 sync_binlog(設置爲 0),操作系統或者服務器故障可能導致日誌中丟失一些已經提交的語句;將 sync_binlog 設置爲 N 意味着 N 次事務提交同步一次磁盤,這是一種性能和數據丟失風險的折衷。

對於 InnoDB 存儲引擎,爲了實現事務的持久性和故障恢復等功能,還使用了另外兩個事務日誌:重做日誌(redo log)和回滾日誌(undo log)。

📝MySQL 8.0.20 提供了二進制日誌事務壓縮功能,可以節省日誌的存儲空間,包括從節點中繼日誌以及日誌備份的存儲空間;而且可以節省主從節點之間發送日誌時的網絡帶寬。

中繼日誌

MySQL 中繼日誌(relay log)只存在於主從複製結構中的從節點上,用於保存主節點傳輸過來的數據變更事件,然後將這些事件應用於從節點。

中繼日誌與二進制日誌類似,也是由一組帶編號的文件組成;同時還包含了一個索引文件,記錄了所有已經使用過的中繼日誌文件。中繼日誌文件默認存放在數據目錄中。

mysql> show variables like 'relay_log%';
+---------------------------+----------------------------------------+
| Variable_name             | Value                                  |
+---------------------------+----------------------------------------+
| relay_log                 | sqlhost-relay-bin                      |
| relay_log_basename        | /var/lib/mysql/sqlhost-relay-bin       |
| relay_log_index           | /var/lib/mysql/sqlhost-relay-bin.index |
| relay_log_info_file       | relay-log.info                         |
| relay_log_info_repository | TABLE                                  |
| relay_log_purge           | ON                                     |
| relay_log_recovery        | OFF                                    |
| relay_log_space_limit     | 0                                      |
+---------------------------+----------------------------------------+
8 rows in set (0.01 sec)

其中,relay_logrelay_log_index 分別對應爲中繼日誌的文件名和索引文件名。

中繼日誌文件的格式和二進制日誌文件的格式相同,因此也可以使用 mysqlbinlog 工具進行讀取。

📝關於主從複製中的中繼日誌信息,可以參考官方文檔

DDL 日誌

MySQL DDL 日誌,也稱爲元數據日誌(metadata log)記錄了數據定義語言執行的元數據操作,例如 DROP TABLE 或者 ALTER TABLE。

如果元數據操作的過程中發生故障,MySQL 使用該日誌進行恢復。當我們執行 DROP TABLE t1, t2 命令時,需要確保 t1 和 t2 一起被刪除 ,而且每個表都被完整地刪除。另一個示例是 ALTER TABLE t3 DROP PARTITION p2 語句,必須確保分區被完整刪除並且分區的定義從t3 的分區列表中刪除。

對於 MySQL 5.7 以及之前的版本,元數據操作的記錄日誌位於數據目錄下的 ddl_log.log 文件。該文件是一個二進制文件,不支持手動修改,也沒有相關的配置選項和變量。

對於 MySQL 8.0,DDL 日誌存儲在 mysql.innodb_ddl_log 數據字典中。這是一個隱藏的數據字典表,不支持直接查詢;可以通過設置系統變量 innodb_print_ddl_logs (默認爲 OFF)將 DDL 日誌打印到標準錯誤輸出 strderr。

如果覺得文章對你有用,請不要白嫖!歡迎關注❤️、評論📝、點贊👍!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章