Как увеличить максимальное число открытых файлов для MySQL

Зачастую при увеличении параметров max_connections или table_open_cache в более высокие значения они не могут быть установлены из-за ограничение ОС. При старте MySQL в логе error.log мы видим предупреждения:

2018-04-27T01:01:18.027751Z 0 [Warning] Changed limits: max_open_files: 1024 (requested 32310)
2018-04-27T01:01:18.027846Z 0 [Warning] Changed limits: max_connections: 214 (requested 300)
2018-04-27T01:01:18.027853Z 0 [Warning] Changed limits: table_open_cache: 400 (requested 16000)

Которые говорят, что наши параметры не могут быть установлены.
Но как это исправить?
Читаем ниже.

Исходные данные:
ОС: Ubuntu 16.04.4 LTS
БД: Oracle MySQL 5.7.22
Задача: Решить проблему с невозможностью установки параметров max_connections=300 и table_open_cache=16000

При старте MySQL в логе error.log мы можем увидеть предупреждения вида:

2018-04-27T01:01:18.027751Z 0 [Warning] Changed limits: max_open_files: 1024 (requested 32310)
2018-04-27T01:01:18.027846Z 0 [Warning] Changed limits: max_connections: 214 (requested 300)
2018-04-27T01:01:18.027853Z 0 [Warning] Changed limits: table_open_cache: 400 (requested 16000)

При этом в файле конфигурации /etc/mysql/mysql.conf.d/mysqld.cnf у нас установлено:

max_connections        = 300
table_open_cache       = 16000

Но MySQL не может установить эти значение и они понижаются до разрешенных, а именно max_connections всего до 214 разрешенных соединений, а table_open_cache до 400.

Если посмотреть настройки MySQL, то можем увидеть такую картину:

# mysql -u root -p

mysql> show global variables like '%max_connections%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 300   |
+-----------------+-------+
1 row in set (0,00 sec)

mysql> show global variables like '%open_files_limit%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| open_files_limit | 1024  |
+------------------+-------+
1 row in set (0,00 sec)

mysql> show global variables like '%table_open_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| table_open_cache | 400   |
+------------------+-------+
1 row in set (0,00 sec)

Вроде как max_connections и установлен 300, но остальные настройки явно не те, что нам нужны.

Корень проблемы кроется в ограничении ОС на количество открываемых файловых дескрипторов для процесса mysqld, посмотреть ограничение мы можем так:

# cat /proc/$(pgrep mysqld)/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             1031546              1031546              processes
Max open files            1024                 4096                 files
Max locked memory         65536                65536                bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       1031546              1031546              signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

Нас интересует строка:

Max open files            1024                 4096                 files

В ней мы видим, что максимально разрешено открывать не более 1024 файловых дескрипторов.

Именно из-за этого при старте mysqld не может установить запрошенные нами опции max_connections, table_open_cache.

Давайте увеличим лимит файловых дескрипторов для mysqld на 10000.

Для начала нужно выяснить систему инициализации в нашем Linux дистрибутиве, выполняем:

strings /sbin/init | awk 'match($0, /(upstart|systemd|sysvinit)/) { print toupper(substr($0, RSTART, RLENGTH));exit; }'

Команда выдала SYSTEMD.

Для systemd лимиты устанавливаются немного по другому, чем принято думать, а именно:

1. Выясним где находится unit файл для запуска MySQL:

# systemctl status mysql
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: active (running) since Пт 2018-04-27 06:01:36 +05; 6h ago
 Main PID: 6370 (mysqld)
    Tasks: 82
   Memory: 88.2G
      CPU: 1d 19h 2min 53.203s
   CGroup: /system.slice/mysql.service
           └─6370 /usr/sbin/mysqld

2. Создадим файл с описанием новых лимитов:

Мы выяснили, что unit файл это /lib/systemd/system/mysql.service, теперь нам нужно создать каталог /lib/systemd/system/mysql.service.d и в нем разместить файл limit.conf со следующим содержимым:

[Service]
LimitNOFILE=10000

Выполним несколько команд для этого:

mysql_systemd_dir="/lib/systemd/system/mysql.service.d"
mkdir -p ${mysql_systemd_dir}
echo "[Service]" >${mysql_systemd_dir}/limit.conf
echo "LimitNOFILE=10000" >>${mysql_systemd_dir}/limit.conf
systemctl daemon-reload

Теперь проверим будет ли наша конфигурация подхвачена:

# systemctl status mysql

● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
  Drop-In: /lib/systemd/system/mysql.service.d
           └─limit.conf
   Active: active (running) since Пт 2018-04-27 06:01:36 +05; 6h ago
 Main PID: 6370 (mysqld)
    Tasks: 82
   Memory: 88.2G
      CPU: 1d 19h 2min 53.203s
   CGroup: /system.slice/mysql.service
           └─6370 /usr/sbin/mysqld

Отлично, теперь нам нужно перезапустить MySQL:

systemctl restart mysql

3. Проверим лимиты:

# cat /proc/$(pgrep mysqld)/limits
Limit                     Soft Limit           Hard Limit           Units
..
Max open files            10000                 10000               files
...

Проверим настройки MySQL:

# mysql -u root -p

mysql> show global variables like '%max_connections%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 300   |
+-----------------+-------+
1 row in set (0,00 sec)

mysql> show global variables like '%open_files_limit%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| open_files_limit | 10000 |
+------------------+-------+
1 row in set (0,00 sec)

mysql> show global variables like '%table_open_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| table_open_cache | 16000 |
+------------------+-------+
1 row in set (0,00 sec)

Отлично, это то, что нам нужно.

На этом все, до скорых встреч. Если у Вас возникли вопросы или Вы хотите чтобы я помог Вам, то Вы всегда можете связаться со мной разными доступными способами.