Запуск двух и более инстансов MySQL на одном Linux-сервере

Хочу поделиться еще одним способом решения такой проблемы, как запуск более одного mysql-server на одном linux-сервере. Я думаю, что некоторые из вас уже пробовали это делать, запуская руками, например, вот так:

 mysqld_safe --defaults-file=...my2.cnf... &

Я считаю этот подход не совсем правильным хотя бы потому, что корректно завершить такой запущенный mysql-сервер получится не всегда. Можно ещё, конечно, использовать mysqld_multi, но лично я предпочитаю полностью «изолировать» друг от друга инстансы. Именно поэтому я и предлагаю вам в своей публикации использовать в помощь систему инициализации.

Дано: OS Linux CentOS 6.5. Как ставить MySQL-сервер или его производные (например, Percona), я рассказывать не стану, перейду сразу к делу. Поставили, запустили.

[root@localhost /]# ps aux | grep sql

root      8455  0.0  0.2   5064  1344 pts/0    S    01:36   0:00 /bin/sh /usr/bin/mysqld_safe --datadir=/var/lib/mysql --socket=/var/lib/mysql/mysql.sock --pid-file=/var/run/mysqld/mysqld.pid --basedir=/usr --user=mysql
mysql     8566  0.0  3.0 135476 15328 pts/0    Sl   01:36   0:00 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock --port=3306

Сервер запустился, всё работает. Все параметры по-умолчанию, если не указано обратное в my.cnf.

Теперь займёмся запуском второго инстанса. Создаем место для второй базы:

mkdir /var/lib/mysql2 && chown -R mysql:mysql /var/lib/mysql2

Для хранения логов:

mkdir /var/log/mysql2 && chown -R mysql:mysql /var/log/mysql2

Копируем дефолтный конфигурационный файл для второго инстанса:

cp /etc/my.cnf /etc/my2.cnf

Займёмся отдельной директорией в /var/run:
mkdir /var/run/mysqld2 && chown -R mysql:mysql /var/run/mysqld2


Осталось поправить my2.cnf и добавить init-скрипт в /etc/init.d/ для корректного управления новым инстансом.

Правим /etc/my2.cnf:

[mysqld]
bind-address=127.0.0.1
port=3307
datadir=/var/lib/mysql2
socket=/var/lib/mysql2/mysql2.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

[mysqld_safe]
log-error=/var/log/mysql2/mysqld.log
pid-file=/var/run/mysqld2/mysqld.pid

Чем различаются конфигурационные файлы:

[root@localhost mysqld2]# diff /etc/my.cnf /etc/my2.cnf 
3,5c3,5
< port=3306
< datadir=/var/lib/mysql
< socket=/var/lib/mysql/mysql.sock
---
> port=3307
> datadir=/var/lib/mysql2
> socket=/var/lib/mysql2/mysql2.sock
11,12c11,12
< log-error=/var/log/mysqld.log
< pid-file=/var/run/mysqld/mysqld.pid
---
> log-error=/var/log/mysql2/mysqld.log
> pid-file=/var/run/mysqld2/mysqld.pid

Ну и, наконец, подготовим init-скрипт для запуска второго сервера. Здесь начинается самое интересное:

cp /etc/init.d/mysqld /etc/init.d/mysqld2

Открываем и правим отдельные строчки в файле /etc/init.d/mysqld2:
1) Во-первых, нам нужно закомментировать (или удалить) функцию get_mysql_option(), дабы она не подсовывала mysqld_safe значения по-умолчанию:

#get_mysql_option(){
#       result=`/usr/bin/my_print_defaults "$1" | sed -n "s/^--$2=//p" | tail -n 1`
#       if [ -z "$result" ]; then
#           # not found, use default
#           result="$3"
#       fi
#}


2) Также комментируем её использование в дальнейшем и записываем в нужные переменные уникальные пути и директории для нового инстанса:

#get_mysql_option mysqld datadir "/var/lib/mysql2"
datadir="/var/lib/mysql2"
#get_mysql_option mysqld socket "$datadir/mysql2.sock"
socketfile="$datadir/mysql2.sock"
#get_mysql_option mysqld_safe log-error "/var/log/mysql2/mysqld.log"
errlogfile="/var/log/mysql2/mysqld.log"
#get_mysql_option mysqld_safe pid-file "/var/run/mysqld2/mysqld.pid"
mypidfile="/var/run/mysqld2/mysqld.pid"


3) Последний штрих: в функции start() явно указываем mysqld_safe использовать наш отдельный конфигурационный файл и писать в отдельную папку логи. Для этого приводим следующую строку к приблизительно такому виду:

$exec   --defaults-file=/etc/my2.cnf --datadir="$datadir" --socket="$socketfile" \
                --pid-file="$mypidfile" --log-error=/var/log/mysql2/mysqld.log \
                --basedir=/usr --user=mysql >/dev/null 2>&1 &

Сохраняем. Запускаем, выполняя /etc/init.d/mysql2 start. Остановка: /etc/init.d/mysql2 stop. Проверка:

[root@localhost run]# ps aux | grep sql2
root      9375  0.0  0.2   5064  1348 pts/1    S    02:44   0:00 /bin/sh /usr/bin/mysqld_safe --defaults-file=/etc/my2.cnf --datadir=/var/lib/mysql2 --socket=/var/lib/mysql2/mysql2.sock --pid-file=/var/run/mysqld2/mysqld.pid --log-error=/var/log/mysql2/mysqld.log --basedir=/usr --user=mysql
mysql     9489  0.1  3.0 135476 15328 pts/1    Sl   02:44   0:00 /usr/libexec/mysqld --defaults-file=/etc/my2.cnf --basedir=/usr --datadir=/var/lib/mysql2 --user=mysql --log-error=/var/log/mysql2/mysqld.log --pid-file=/var/run/mysqld2/mysqld.pid --socket=/var/lib/mysql2/mysql2.sock --port=3307
root      9510  0.0  0.1   4356   732 pts/1    S+   02:44   0:00 grep sql2

Ну и, наконец-то, подключаемся с помощью клиента к нашему второму MySQL-серверу путем явного указывания сокет-файла:

mysql -S /var/lib/mysql2/mysql2.sock

… и видим, что у нас всё получилось.

Спасибо за внимание.

P.S. В директории второй базы можно сначала использовать либо дефолтную, скопировав её из /var/lib/mysql, либо заново созданную — с помощью mysql_install_db, либо уже имеющуюся (например, бэкап, созданный Percona XtraBackup). Самое главное — корректный пользователь-владелец (mysql) на файлы базы.
Поделиться публикацией
Комментарии 16
    +16
    Недавно поднимался такой же вопрос. Использовал Docker, проще в разы
      0
      Спорить не буду, скорее всего это действительно проще, но сам Docker уже как отдельный инструмент идет, а тут, считай, нативная реализация.
      • НЛО прилетело и опубликовало эту надпись здесь
        +3
        Эх. Не хочу натыкаться на хейтеров systemd, но вынужден сказать, что для запуска второго инстанса mysql при, правильно написанном unit-файле, достаточно выполнить что-то вроде:
        systemctl start mysql@second
        +3
        Коллега, это как-то слишком сложно.

        В тот же my.cnf добавляется секция [mysqld2], в которую прописывается всё новое.

        Потом создаются диры для второй бд, проводится туда mysql_install_db, а потом оба сервера рулятся методом mysqld_multi.
          –1
          Для того, чтобы начать «рулить» несколькими экземплярами DB с помощью mysqld_multi, нужно сначала останавливать экземпляр, что запущен. Иногда остановка mysql-сервера сама по себе критична, а нужно что-то быстро развернуть, отдать какие-то данные, а потом свернуть (например, достать нужную базу и поработать с ней из бэкапа).
            +1
            Для «по-быстрому» можно и прямым запуском mysqld_safe.

            Корректно завершить можно так — mysqladmin -S /path/to/second/server.sock shutdown
          +2
          может я что-то не понимаю, но в какой ситуации потребуется подобное действие?
          Не проще ли вынести второй сервер на отдельную машину?
            0
            Согласен. Имхо такое может быть только обосновано указом «сверху» экономить ресурсы (читай ценой производительности))
              0
              Не согласен. Разворачивание многих инстансов на одном сервере очень полезно если это будут слейвы для бекапа данных основных баз. У меня это все сделано правда в отдельных виртуалках KVM на одной машине, все никак руки не дойдут запустить на одной для экономии ресурсов (в первую очередь диска).
                0
                а смысл в бекапах на одной машине? уж лучше вынести слейв на другую физическую и уже там делать бекапы. иначе физически грохается винт на сервере — и все, придется разворачивать новый сервер и на него накатывать бекапы. в случае с слейвом на другой физической машине просто переназначаем его и все, простоя почти нет
                  0
                  Наверное неверно выразился.
                  На отдельной машинке развернуть ТОЛЬКО слейвы к основным базам. И они уже бекапятся через bacula в хранилище.
                  В итоге получается двойная защита: слейв с моментальным моментом состояния и периодичный бекап бакулы. Это сильно помогло нам когда рухнули серверы с основными базами.
                  Простое переключение не всегда помогает к сожалению. Бекапим с ДЦ в офис.
                    0
                    в таком виде да, все кошерно и надежно
            +2
            шел год 2015, человечество уже давно придумало для решения такого рода задач контейнеры (openvz, lxc, libcontainer, rocket, virtuozzo, pcs, freebsd jails, solaris zones и т.д. )
              +1
              шел год 2015… а человечество все никак не могло придумать резиновые жесткие диски для размещения контейнеров…
                +1
                overlayfs зато придумали.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое