如何限制mysql伺服器的記憶體消耗以防止OOM殺死?
oom_killer
由於 mysql 在插入longblob
列時消耗了大量記憶體,我的 MySQL 實例被 Linux 殺死。還原包含非常大的longblob
列的 mysqldump 時會發生這種情況。我已經瀏覽過類似這個部落格的東西,它建議將各種讀/寫緩衝區設置為不同的大小,以限制記憶體消耗。但是,儘管上述腳本在調整後輸出了 350MB 的“TOTAL (MAX)”記憶體,但 mysql 在最終被殺死之前仍然會愉快地吞噬 GB 的記憶體。
這是通過 Docker 複製的:
docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=foobar -d --name mysql-longblob mysql:5.7 mysql -h 127.0.0.1 -P 3306 -u root --password -e "CREATE DATABASE blobs; USE blobs; CREATE TABLE longblob_test (bigcol LONGBLOB NOT NULL) ENGINE = InnoDB;" mysql -h 127.0.0.1 -P 3306 -u root --password -e \ "SET GLOBAL max_allowed_packet=536870912;" # 512MB mysql -h 127.0.0.1 -P 3306 -u root --password -D blobs -e "source ./500MB.sql"
在這種情況下,docker stats 報告在 OOM 因超過其限製而被殺死之前消耗了約 1.8GB 記憶體。在空閒時,mysql 報告 ~200MB 記憶體。
其中 500MB.sql 是在形狀中插入 500MB 文本塊的文件:
INSERT INTO longblob_test VALUES ('500MB_WORTH_OF_TEXT_HERE')
所以有幾個問題:
1)為什麼mysql需要吃掉1.6GB的記憶體才能攝取一個500MB的列?
2)我如何設置mysql的硬上限以防止它超過“x”的記憶體量?
PS:您可能很想告訴我這很愚蠢,您不應該在數據庫中儲存 500MB 以上的 blob。我絕對100%同意!但這是一種不幸的情況,在這種情況下重新架構數據儲存是不可能的。
客戶端和伺服器是否在同一個 docker 空間中?
我希望客戶端載入 500MB,將其擴展為十六進制(1.0GB),然後將其發送到伺服器。然後伺服器可能需要類似的空間進行解析。
所以,我想需要6倍。請注意,“日誌文件”需要是最大 blob 的 10 倍。所以也許 10x 是你需要的數字。那隻是在伺服器上。
重新 10 倍:
—– 2014-12-01 5.6.22 通用可用性 – 已修復的錯誤 – InnoDB —–
針對 Bug #16963396 / MySQL BLOB的 MySQL 5.6.20 更新檔寫入重做日誌文件大小的 10%。這個限制已經放寬了。重做日誌BLOB寫入現在限制為總重做日誌大小的 10% ( innodb_log_file_size * innodb_log_files_in_group )。因此,innodb_log_file_size * innodb_log_files_in_group應該是表行中發現的最大BLOB數據大小加上其他可變長度欄位(VARCHAR、VARBINARY和TEXT類型欄位)的長度的10 倍。如果innodb_log_file_size *則不需要任何操作innodb_log_files_in_group已經足夠大,或者如果您的表不包含BLOB數據。(錯誤 #73707、錯誤 #19498877)
參考:另見:Bug #16963396。
—– 2014-12-01 5.6.22 通用可用性 – 已修復的錯誤 – InnoDB —–
針對 Bug #16963396 / MySQL BLOB的 MySQL 5.6.20 更新檔寫入重做日誌文件大小的 10%。這個限制已經放寬了。重做日誌BLOB寫入現在限制為總重做日誌大小的 10% ( innodb_log_file_size * innodb_log_files_in_group )。
因此,innodb_log_file_size * innodb_log_files_in_group應該是表行中發現的最大BLOB數據大小加上其他可變長度欄位(VARCHAR、VARBINARY和TEXT類型欄位)的長度的10 倍。如果innodb_log_file_size * innodb_log_files_in_group已經足夠大或者您的表不包含BLOB數據,則無需執行任何操作。(錯誤 #73707、錯誤 #19498877)
您可能必須讓執行插入操作的客戶端將巨大的 blob 分解為碎片。根據您獲取該 SQL 文件的方式,這可能可行,也可能不可行。
mysql
此外,這將需要使用程序化 MySQL 客戶端(例如來自 Java、Python 或 C 程序)而不是使用cli。一個起點可能是如何在另一個答案中:https ://stackoverflow.com/a/4846674/1680777 ,其中使用者能夠
max_allowed_packet
通過讓 MySQL 客戶端驅動程序在插入過程中自動將 blob 分段為小單元來規避手術。我不肯定這會完全解決記憶體問題,因為有各種 InnoDB 和事務緩衝區在起作用。