Mysql

如何限制mysql伺服器的記憶體消耗以防止OOM殺死?

  • January 21, 2022

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數據大小加上其他可變長度欄位(VARCHARVARBINARYTEXT類型欄位)的長度的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數據大小加上其他可變長度欄位(VARCHARVARBINARYTEXT類型欄位)的長度的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 和事務緩衝區在起作用。

引用自:https://dba.stackexchange.com/questions/296222