Статьи

Получите лучшее понимание конфигурации ведущий / ведомый MongoDB

Сначала основы: что такое хозяин / раб?

Один сервер базы данных («мастер») отвечает и может делать все что угодно. Куча других серверов баз данных хранит копии всех данных, которые были записаны на мастер и могут опционально запрашиваться (это «ведомые»). Рабы не могут быть записаны напрямую, они просто копии основной базы данных. Настройка master и slave позволяет вам хорошо масштабировать чтения, потому что вы можете просто продолжать добавлять slave для увеличения емкости чтения. Рабы также делают отличные резервные машины. Если ваш мастер взорвется, вы получите копию данных в целости и сохранности.

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

 

 

Мастер рабыня
Количество серверов 1
разрешений читай пиши читать
используется для запросы, вставки, обновления, удаления запросы

 

 

Итак, как вы настраиваете Mongo в конфигурации master / slave? Предполагая, что вы загрузили MongoDB с mongodb.org , вы можете запустить мастер и слейв , вырезав и вставив в вашу оболочку следующие строки:

$ mkdir -p ~/dbs/master ~/dbs/slave
$ ./mongod --master --dbpath ~/dbs/master >> ~/dbs/master.log &
$ ./mongod --slave --port 27018 --dbpath ~/dbs/slave --source localhost:27017 >> ~/dbs/slave.log &

(Я предполагаю, что вы используете * NIX. Команды для Windows похожи, но я не хочу поощрять подобные вещи).

Что делают эти строки?

  1. Во-первых, мы создаем каталоги для хранения базы данных (~ / dbs / master и ~ / dbs / slave).
  2. Теперь мы запускаем мастер, указывая, что он должен поместить свои файлы в каталог ~ / dbs / master, а журнал — в файл ~ / dbs / master.log. Итак, теперь у нас есть мастер, работающий на localhost: 27017.
  3. Далее мы начинаем раб. Он должен прослушивать порт, отличный от главного, поскольку они находятся на одной машине, поэтому мы выберем 27018. Он будет хранить свои файлы в ~ / db / slave, а свои журналы — в ~ / dbs / slave.log. Самая важная часть — это сообщить ему, кто в доме хозяин: опция –source localhost: 27017 позволяет ему узнать, что мастер, с которого он должен читать, находится по адресу localhost: 27017.

Существует множество возможных конфигураций «ведущий / ведомый». Несколько примеров:

  • Вы можете иметь дюжину подчиненных ящиков, где вы хотите равномерно распределить показания по всем.
  • У вас может быть одна маленькая слабая подчиненная машина, на которую вы не хотите, чтобы выполнялись операции чтения, вы просто используете ее для резервного копирования.
  • Вы можете иметь самый мощный сервер в мире в качестве главной машины, и вы хотите, чтобы он обрабатывал как чтение, так и запись … если только вы не получаете более 1000 запросов в секунду, в этом случае вы хотите, чтобы некоторые из них перенаправились на ваш рабы.

Короче говоря, Mongo не может автоматически настроить ваше приложение, чтобы воспользоваться преимуществами вашей настройки «главный-подчиненный». Сожалею. Вам придется сделать это самостоятельно. (Изменить: драйвер Python действительно обрабатывает случай 1 для вас, см . Комментарий Майка .)

Тем не менее, это не слишком сложно, особенно для того, что MG хочет сделать. MG использует 3 сервера: главный и два подчиненных, поэтому нам нужно три подключения: одно к главному и одно к каждому ведомому. Предполагая, что у него есть мастер на master.example.com и подчиненные на slave1.example.com и slave2.example.com, он может создавать соединения с:

$master = new Mongo("master.example.com:27017");
$slave1 = new Mongo("slave1.example.com:27017");
$slave2 = new Mongo("slave2.example.com:27017");

Этот следующий фрагмент немного неприятен, и было бы здорово, если бы кто-то создал основу для этого (подсказка). Мы хотим абстрагировать логику master-slave в отдельный слой, поэтому приложение взаимодействует с логикой master-slave, которая взаимодействует с драйвером. Однако я ленив, поэтому я просто расширю класс MongoCollection и добавлю логику «ведущий-ведомый». Затем, если человек создает MongoMSCollection из своего соединения $ master, он может добавить своих подчиненных и использовать коллекцию, как если бы это был обычный MongoCollection. Между тем, MongoMSCollection будет равномерно распределять чтения среди рабов.

 

class MongoMSCollection extends MongoCollection {
    public $currentSlave = -1;
 
    // call this once to initialize the slaves
    public function addSlaves($slaves) {
        // extract the namespace for this collection: db name and collection name
        $db = $this->db->__toString();
        $c = $this->getName();
 
        // create an array of MongoCollections from the slave connections
        $this->slaves = array();
        foreach ($slaves as $slave) {
            $this->slaves[] = $slave->$db->$c;
        }
 
        $this->numSlaves = count($this->slaves);
    }
 
    public function find($query, $fields) {
        // get the next slave in the array
        $this->currentSlave = ($this->currentSlave+1) % $this->numSlaves;
 
        // use a slave connection to do the query
        return $this->slaves[$this->currentSlave]->find();
    }
}

Чтобы использовать этот класс, мы создаем его экземпляр в базе данных master, а затем добавляем в него массив ведомых:

$master = new Mongo("master.example.com:27017");
$slaves = array(new Mongo("slave1.example.com:27017"), new Mongo("slave2.example.com:27017"));
 
$c = new MongoMSCollection($master->foo, "bar");
$c->addSlaves($slaves);

Теперь мы можем использовать $ c как обычную коллекцию MongoCollection. MongoMSCollection :: find будет чередоваться между двумя ведомыми устройствами, и все другие операции (вставки, обновления и удаления) будут выполняться на ведущем устройстве. Если MG также хочет, чтобы основной дескриптор считывал, он может просто добавить его в массив $ slaves (который теперь может быть лучше назван массивом $ reader):

$slaves = array($master, new Mongo("slave1.example.com:27017"), new Mongo("slave2.example.com:27017"));

В качестве альтернативы он может изменить логику в методе MongoMSCollection :: find.

Редактировать: начиная с версии 1.4.0, slaveOkay не требуется для чтения из рабов. slaveOkay следует использовать, если вы используете наборы реплик, а не –master и –slave. Таким образом, следующий раздел больше не относится к обычному ведущему / ведомому устройству.

Единственная хитрость в реализации Mongo master / slave — то, что по умолчанию slave даже не читается, это просто способ резервного копирования базы данных master. Если вы действительно хотите считывать данные с ведомого, вы должны установить флаг в своем запросе, который называется «slaveOkay». Вместо того чтобы говорить:

$cursor = $slave->foo->bar->find();

у нас есть:

$cursor = $slave->foo->bar->find()->slaveOkay();

Или, так как это задница в задании задавать для каждого запроса (и почти невозможно сделать для findOnes, если вы не знаете внутренности), вы можете установить статическую переменную в MongoCursor, которая будет содержать все ваши запросы:

MongoCursor::$slaveOkay = true;

И теперь вам будет разрешено нормально запрашивать вашего ведомого, не вызывая slaveOkay () для каждого курсора.