Mysql
MySQL“無法為緩衝池分配記憶體”記憶體使用率為 73%?
我在 DigitalOcean 液滴(1GB RAM)上託管一個 WordPress 網站。該網站的MySQL數據庫偶爾會崩潰,導致網站顯示“建立數據庫連接時出錯”。記憶體使用量在凌晨 2:40 左右下降,表明這是數據庫崩潰的時候。我查看了當天的 MySQL 日誌文件,最早的條目是上午 10 點 47 分。這是日誌文件的開頭:
2021-12-06T10:47:14.800977Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timest$ 2021-12-06T10:47:14.806192Z 0 [Note] /usr/sbin/mysqld (mysqld 5.7.36-0ubuntu0.18.04.1) starting as process 2810 ... 2021-12-06T10:47:14.819674Z 0 [Note] InnoDB: PUNCH HOLE support available 2021-12-06T10:47:14.819711Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins 2021-12-06T10:47:14.819716Z 0 [Note] InnoDB: Uses event mutexes 2021-12-06T10:47:14.819720Z 0 [Note] InnoDB: GCC builtin __atomic_thread_fence() is used for memory barrier 2021-12-06T10:47:14.819723Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.11 2021-12-06T10:47:14.819727Z 0 [Note] InnoDB: Using Linux native AIO 2021-12-06T10:47:14.820551Z 0 [Note] InnoDB: Number of pools: 1 2021-12-06T10:47:14.823342Z 0 [Note] InnoDB: Using CPU crc32 instructions 2021-12-06T10:47:14.825847Z 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M 2021-12-06T10:47:14.826246Z 0 [ERROR] InnoDB: mmap(137428992 bytes) failed; errno 12 2021-12-06T10:47:14.826258Z 0 [ERROR] InnoDB: Cannot allocate memory for the buffer pool 2021-12-06T10:47:14.826262Z 0 [ERROR] InnoDB: Plugin initialization aborted with error Generic error 2021-12-06T10:47:14.826270Z 0 [ERROR] Plugin 'InnoDB' init function returned error. 2021-12-06T10:47:14.826274Z 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed. 2021-12-06T10:47:14.826278Z 0 [ERROR] Failed to initialize builtin plugins. 2021-12-06T10:47:14.826282Z 0 [ERROR] Aborting 2021-12-06T10:47:14.832237Z 0 [Note] Binlog end 2021-12-06T10:47:14.832297Z 0 [Note] Shutting down plugin 'CSV' 2021-12-06T10:47:14.832572Z 0 [Note] /usr/sbin/mysqld: Shutdown complete
根據日誌文件,MySQL 似乎記憶體不足。但是,Droplet 的記憶體使用率穩定在 73% 左右,直到凌晨 2:40 左右數據庫崩潰,才下降到 32%。它似乎有足夠的可用記憶體,那麼為什麼會崩潰?
編輯根據要求,這是我的 MySQL 配置文件的內容:
/etc/mysql/conf.d/mysql.cnf
[mysql]
/etc/mysql/conf.d/mysqldump.cnf
[mysqldump] quick quote-names max_allowed_packet = 16M
/etc/mysql/mysql.conf.d/mysqld.cnf
# # The MySQL database server configuration file. # # You can copy this to one of: # - "/etc/mysql/my.cnf" to set global options, # - "~/.my.cnf" to set user-specific options. # # One can use all long options that the program supports. # Run program with --help to get a list of available options and with # --print-defaults to see which it would actually understand and use. # # For explanations see # http://dev.mysql.com/doc/mysql/en/server-system-variables.html # This will be passed to all mysql clients # It has been reported that passwords should be enclosed with ticks/quotes # escpecially if they contain "#" chars... # Remember to edit /etc/mysql/debian.cnf when changing the socket location. # Here is entries for some specific programs # The following values assume you have at least 32M ram [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] # # * Basic Settings # user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking # # Instead of skip-networking the default is now to listen only on # localhost which is more compatible and is not less secure. bind-address = 127.0.0.1 # # * Fine Tuning # key_buffer_size = 16M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8 # This replaces the startup script and checks MyISAM tables if needed # the first time they are touched myisam-recover-options = BACKUP #max_connections = 100 #table_open_cache = 64 #thread_concurrency = 10 # # * Query Cache Configuration # query_cache_limit = 1M query_cache_size = 16M # # * Logging and Replication # # Both location gets rotated by the cronjob. # Be aware that this log type is a performance killer. # As of 5.1 you can enable the log at runtime! #general_log_file = /var/log/mysql/mysql.log #general_log = 1 # # Error log - should be very few entries. # log_error = /var/log/mysql/error.log # # Here you can see queries with especially long duration #slow_query_log = 1 #slow_query_log_file = /var/log/mysql/mysql-slow.log #long_query_time = 2 #log-queries-not-using-indexes # # The following can be used as easy to replay backup logs or for replication. # note: if you are setting up a replication slave, see README.Debian about # other settings you may need to change. #server-id = 1 #log_bin = /var/log/mysql/mysql-bin.log expire_logs_days = 10 max_binlog_size = 100M #binlog_do_db = include_database_name #binlog_ignore_db = include_database_name # # * InnoDB # # InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/. # Read the manual for more InnoDB related options. There are many! # # * Security Features # # Read the manual, too, if you want chroot! # chroot = /var/lib/mysql/ # # For generating SSL certificates I recommend the OpenSSL GUI "tinyca". # # ssl-ca=/etc/mysql/cacert.pem # ssl-cert=/etc/mysql/server-cert.pem # ssl-key=/etc/mysql/server-key.pem
/etc/mysql/mysql.conf.d/mysqld_safe_syslog.cnf
[mysqld_safe] syslog
在聊天中查看核心日誌後,MySQL崩潰的原因是記憶體不足。
Dec 6 02:47:13 kernel: [341799.228400] Out of memory: Kill process 23566 (mysqld) score 197 or sacrifice child Dec 6 02:47:13 kernel: [341799.229866] Killed process 23566 (mysqld) total-vm:1168576kB, anon-rss:198536kB, file-rss:0kB, shmem-rss:0kB
在那段時間裡,有很多 Apache2 程序處於活動狀態。這意味著增加流量會導致記憶體消耗增加。結果,核心決定殺死 MySQL 以釋放記憶體。
可以執行
mysqltuner
分析 MySQL 配置。它提供了一些建議,有助於減少 MySQL 記憶體消耗。然而,增加流量仍然會導致同樣的問題。因此,更可持續的解決方案是增加可用於液滴的記憶體。