Настройка master->slave репликации MongoDB на Debian 7 (Wheezy)

Для реализации приложения, которое очень активно пишет в базу, потребовалось развернуть кластер из баз MongoDB, ранее я в принципе не имел опыта работы с этой СУБД, поэтому сделал маленькую заметку. Маны которые попадались мне в сети не содержали всех мелочей с которыми мне пришлось провозиться, например:

  • В кластере mongo должно быть минимум 3 базы mongo (например 3 физических или виртуальных компьютера)
  • В случае возникновения ошибок работы со слейвами их нужно добавить в список разрешённых командой rs.slaveOk()

Данное решение разворачивалось на 3х серверах под управлением Debian 7 (Wheezy).

    Нужно выполнить на всех серверах

    Первым делом нужно установить самую свежую сборку базы, для этого добавим репозиторий:

    mcedit /etc/apt/sources.list.d/mongodb.list

    В нём такую строку запишем:

    deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen

    Обновим пакеты:

    apt-get update

    Далее выполним установку

    apt-get install mongodb-10gen

    Будет ошибка запуска базы, связано это с тем, что убунтовский скрипт /etc/init.d/mongodb ссылается на скрипт upstart, который есть в убунте, но отсутствует в дебиан. Вот заготовка, которую я использую:

    https://drive.google.com/file/d/0BwtFihi86jHaQ0N6OVVySXBENkU/edit?usp=sharing

    Нужно удалить ссылку на upstart из /etc/init.d:

    rm -v /etc/init.d/mongodb

    Затем скопировать тот файл, что Вы скачали из гугл-диска, в инициализацонные скрипты:

    cp -v mongodb /etc/init.d/

    И исправить права запуска:

    chmod 755 /etc/init.d/mongodb

    Повторим установку (должно пройти без ошибок):

    apt-get install mongodb-10gen

    Откроем в любом редакторе конфигурацию mongodb:

    mcedit /etc/mongodb.conf

    Тут добавим строку вида (она задаёт общее для всех хостов имя реплики):

    replSet = rs0

    Перезапустим на всех серверах:

    /etc/init.d/mongodb restart

    После этого можно приступать к настройкам мастера.

    Нужно выполнить только на PRIMARY сервере

    Подключимся к управляющей консоли (что-то вроде sqlplus или bash):

    mongo

    Проинициализируем реплику на мастере:

    rs0:PRIMARY> rs.initiate()

    Смотрим конфигурацию:

    rs0:PRIMARY> rs.conf()
    {
            "_id" : "rs0",
            "version" : 3,
            "members" : [
                    {
                            "_id" : 0,
                            "host" : "db-00:27017"
                    }
            ]

    Проверим статус:

    rs0:PRIMARY> rs.status()
    {
            "set" : "rs0",
            "date" : ISODate("2014-01-28T10:34:20Z"),
            "myState" : 1,
            "members" : [
                    {
                            "_id" : 0,
                            "name" : "db-00:27017",
                            "health" : 1,
                            "state" : 1,
                            "stateStr" : "PRIMARY",
                            "uptime" : 48,
                            "optime" : Timestamp(1390905202, 90),
                            "optimeDate" : ISODate("2014-01-28T10:33:22Z"),
                            "self" : true
                    }
            ],
            "ok" : 1
    }

    Добавим слейвы:

    rs0:PRIMARY> rs.add("db-01")
    { "ok" : 1 }
    rs0:PRIMARY> rs.add("db-02")
    { "ok" : 1 }

    Смотрим конфигурацию:

    rs0:PRIMARY> rs.conf()
    {
            "_id" : "rs0",
            "version" : 3,
            "members" : [
                    {
                            "_id" : 0,
                            "host" : "db-00:27017"
                    },
                    {
                            "_id" : 1,
                            "host" : "db-01:27017"
                    },
                    {
                            "_id" : 2,
                            "host" : "db-02:27017"
                    }
            ]

    Сразу после добавления будет отображаться что начат процесс синхронизации:

    rs0:PRIMARY> rs.status()
    {
            "set" : "rs0",
            "date" : ISODate("2014-01-28T10:34:56Z"),
            "myState" : 1,
            "members" : [
                    {
                            "_id" : 0,
                            "name" : "db-00:27017",
                            "health" : 1,
                            "state" : 1,
                            "stateStr" : "PRIMARY",
                            "uptime" : 84,
                            "optime" : Timestamp(1390905275, 1),
                            "optimeDate" : ISODate("2014-01-28T10:34:35Z"),
                            "self" : true
                    },
                    {
                            "_id" : 1,
                            "name" : "db-01:27017",
                            "health" : 1,
                            "state" : 5,
                            "stateStr" : "STARTUP2",
                            "uptime" : 23,
                            "optime" : Timestamp(0, 0),
                            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                            "lastHeartbeat" : ISODate("2014-01-28T10:34:55Z"),
                            "lastHeartbeatRecv" : ISODate("2014-01-28T10:34:55Z"),
                            "pingMs" : 2,
                            "lastHeartbeatMessage" : "initial sync cloning db: testdb"
                    },
                    {
                            "_id" : 2,
                            "name" : "db-02:27017",
                            "health" : 1,
                            "state" : 5,
                            "stateStr" : "STARTUP2",
                            "uptime" : 21,
                            "optime" : Timestamp(0, 0),
                            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                            "lastHeartbeat" : ISODate("2014-01-28T10:34:55Z"),
                            "lastHeartbeatRecv" : ISODate("2014-01-28T10:34:55Z"),
                            "pingMs" : 1,
                            "lastHeartbeatMessage" : "initial sync cloning db: testdb"
                    }
            ],
            "ok" : 1
    }

    Через некоторое время команда покажет:

    rs0:PRIMARY> rs.status()
    {
            "set" : "rs0",
            "date" : ISODate("2014-01-28T10:35:04Z"),
            "myState" : 1,
            "members" : [
                    {
                            "_id" : 0,
                            "name" : "db-00:27017",
                            "health" : 1,
                            "state" : 1,
                            "stateStr" : "PRIMARY",
                            "uptime" : 92,
                            "optime" : Timestamp(1390905275, 1),
                            "optimeDate" : ISODate("2014-01-28T10:34:35Z"),
                            "self" : true
                    },
                    {
                            "_id" : 1,
                            "name" : "db-01:27017",
                            "health" : 1,
                            "state" : 2,
                            "stateStr" : "SECONDARY",
                            "uptime" : 31,
                            "optime" : Timestamp(1390905275, 1),
                            "optimeDate" : ISODate("2014-01-28T10:34:35Z"),
                            "lastHeartbeat" : ISODate("2014-01-28T10:35:03Z"),
                            "lastHeartbeatRecv" : ISODate("2014-01-28T10:35:03Z"),
                            "pingMs" : 2,
                            "syncingTo" : "db-00:27017"
                    },
                    {
                            "_id" : 2,
                            "name" : "db-02:27017",
                            "health" : 1,
                            "state" : 2,
                            "stateStr" : "SECONDARY",
                            "uptime" : 29,
                            "optime" : Timestamp(1390905275, 1),
                            "optimeDate" : ISODate("2014-01-28T10:34:35Z"),
                            "lastHeartbeat" : ISODate("2014-01-28T10:35:03Z"),
                            "lastHeartbeatRecv" : ISODate("2014-01-28T10:35:03Z"),
                            "pingMs" : 2,
                            "syncingTo" : "db-00:27017"
                    }
            ],
            "ok" : 1
    }

    Ну вроде всё, сервера синхронизировались.

    В случае если SECONDARY сервера не хотят синхрониться

    Выполним команду:

    rs0:PRIMARY> rs.slaveOk()