非常慢的顯示過程/功能狀態,其中 Db = ‘a_database’
在夜間備份期間,我遇到了非常不尋常的行為。備份的僅模式備份部分需要很長時間才能執行,甚至會導致系統交換記憶體。具體來說,我正在執行:
mysqldump --user=my_back_user --password=my_back_user_password --host=localhost --all-databases --routines --no-data | bzip2 -c > schema_daily.sql.bz2
我們的 MySQL 5.5 伺服器有大約 230 個數據庫,由大約 2300 個表、8800 個儲存過程和 6700 個函式組成。/var/lib/mysql 大約 82GB,壓縮(bzip2)整個東西大約是 6.2GB。
伺服器的日常性能很好。在慢查詢日誌中甚至很少看到任何內容(long_query_time = 1 和 log_queries_not_using_indexes = 1)。我們有一個主從設置,但從屬僅作為故障轉移存在。我們最近確實將備份切換為從從站獲取,因為它們會干擾主站的性能。
如果從伺服器剛剛重新啟動,或者手動清理交換並重新啟動 MySQL,則整個備份需要 35 - 45 分鐘。執行幾次(4 或 5 次)後,備份所需的時間會攀升至大約 6 小時。這種瘋狂的時間峰值似乎是由於mysqldump在備份沒有數據的模式時呼叫的查詢SHOW PROCEDURE/FUNCTION STATUS WHERE Db = ‘’。數據備份部分,包括創建數據庫和表查詢,但不包括儲存過程和函式,始終是快速的。
我知道我可能可以從 mysqldump 切換並讓這個問題消失,但是是什麼導致了這個?在我看來,這似乎有問題和/或配置錯誤,我想在更改備份的完成方式之前解決這些問題。這是我可以在 my.cnf 中補償的嗎?我一直在網上搜尋類似的東西一段時間,結果都是空的。
更新 1
作為記錄,這個相同的備份已經在我們的開發環境中執行了大約一個月,在基本相同的架構上,但數據較少,並且從未出現過問題。
另外,在最初寫完這篇文章之後,我突然想到我沒有獨立地對備份的兩個部分進行廣泛的測試。我很幸運能夠針對這個問題對生產系統進行測試。我重新啟動了 MySQL,清除了交換,並連續八次只執行了備份的模式部分,它根本沒有問題。相反,它實際上在連續執行中變得更快。
這對我來說意味著它是架構備份和數據備份的組合造成了我所看到的問題。我們使用的所有表都是 InnoDB,因此我只針對 InnoDB 調整了性能。MySQL 內部幾乎所有東西都使用 MyISAM,這個問題只在執行幾次後才會出現。
我已經很久沒有研究過 MyISAM 的性能調整了,所以我將重新審視它以及 MySQL 如何為此管理記憶體。
更新 2
由於我的 InnoDB 配置可能是罪魁禍首,這似乎更加明顯,我將在這方面提供更多資訊。
在 my.cnf 中,這是我減去指向文件、目錄、埠時區或 ID 的任何內容。
max_connections = 500 character-set-server = utf8 collation-server = utf8_general_ci join_buffer_size = 262144 # InnoDB innodb_file_per_table = 1 innodb_buffer_pool_size = 12G innodb_buffer_pool_instances = 6 innodb_log_file_size = 256M innodb_stats_on_metadata = 0 innodb_read_io_threads = 24 innodb_write_io_threads = 24 innodb_io_capacity = 2000 innodb_concurrency_tickets = 5000 innodb_purge_threads = 1 innodb_purge_batch_size = 300 innodb_old_blocks_time = 1000 innodb_old_blocks_pct = 5 innodb_open_files = 900 table_definition_cache = 50000 table_open_cache = 100000 symbolic-links = 0 # Slow Queries slow_query_log = 1 slow_query_log_file = /var/lib/mysql/slow_query.log long_query_time = 1 log_queries_not_using_indexes = 1
該系統是一個裸機系統:
- 2x Intel(R) Xeon(R) CPU E5-2609 v3 @ 1.90GHz(每個 6 核)
- 16GB 記憶體
- RAID 5 上有大量 SSD 磁碟空間
- 執行 CentOS 7
我已經通過簡單的 dd 測試排除了磁碟 IO 作為瓶頸
# dd if=/dev/zero of=/root/testfile bs=1G count=1 1+0 records in 1+0 records out 1073741824 bytes (1.1 GB) copied, 4.32635 s, 248 MB/s
在設置這個系統時,我還確保核心中的交換最小化。
# sysctl vm.swappiness vm.swappiness = 0
任何見解將不勝感激。
因此,在這種情況下,罪魁禍首實際上是對執行備份的從屬伺服器進行了過多的性能調整。
我對開發伺服器和生產數據庫伺服器之間的配置差異進行了一些審查。沒有太大的區別,一些查詢和緩衝區大小定義,但都沒有對備份產生影響。
這恰好是 innodb_buffer_pool 的 80% 記憶體分配失敗的情況。事實上,我已經設置為問題中發布的 75%。我目前將其設置為 62.5% (10GB),這似乎可以解決問題。我可能還需要把它敲下來。多觀察幾天就知道了,但至少有解決辦法。
在閱讀MyISAM 儲存引擎部分下的MySQL 如何使用記憶體時,我突然想到了一些東西。
連接緩衝區和結果緩衝區均以等於 net_buffer_length 字節的大小開始,但根據需要動態擴大到 max_allowed_packet 字節。
在創建從站和導入數據時,我必須將 max_allowed_packet 設置為 1G 才能成功導入。這不是開發系統上的設置,它一直在愉快地執行相同的備份,但它仍然存在於生產中的主伺服器和兩個從伺服器上。因此,在 InnoDB 使用並填充緩衝池(設置為 12GB)後,充分利用系統記憶體(16GB),備份執行,允許 MySQL 使用比可用記憶體更多的記憶體。交換發生並且性能需要預期的下降。