«MangoDB Документация для v 1.2» и «DNS сервер BIND с локальными зонами»: разница между страницами

Материал из support.qbpro.ru
(Различия между страницами)
imported>Vix
(Новая страница: «Документация для официального драйвера MongoDB Nodejs Official Driver v 1.2 (supported by 10gen) [https://github.com/mongodb/n…»)
 
imported>Vix
Нет описания правки
 
Строка 1: Строка 1:
Документация для официального драйвера MongoDB Nodejs Official Driver v 1.2  (supported by 10gen)
Исходные данные
[https://github.com/mongodb/node-mongodb-native/tree/1.2-dev/docs оригинал полной документации]


Примечания для понимания взяты [http://jsman.ru/mongo-book/ здесь].
Для корректной работы DNS нем необходимо иметь настроенную сеть. DNS в текущей статье будет настроен на дистрибутиве Debian, особенности других дистрибутивов тоже будут отмечены. Конфиг сети стенда следующий:
= MongoClient - новый улучшенный или как по новому подключится лучше =
*[https://github.com/mongodb/node-mongodb-native/blob/1.2-dev/docs/articles/MongoClient.md оригинал]
Начиная с драйвера версии '''1.2'''  включен новый класс подключения, который имеет одинаковое название во всех официальных драйверах. Это не означает, что существующие приложения перестанут работать, просто рекомендуется использовать новые API упрощенного подключения и разработки.


В дальнейшем будет разработан новый класс '''MongoClient''' принимающий все написанное (???неточный перевод) для MongoDB в отличие от существующего класса подключения '''Db''' в котором acknowledgements выключен.
dns:~# cat /etc/network/interfaces
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
  address 10.0.0.152
  netmask 255.255.255.0
  gateway 10.0.0.254
auto eth1
iface eth1 inet static
  address 192.168.1.1
  netmask 255.255.255.0
где 10.0.0.152/24 - внешний интерфейс (подсеть, выделенная провайдером), 192.168.1.1/24 - внутренний (Локальная сеть). Настраиваемая зона будет иметь имя example.com. В примере со slave сервером, вторичный сервер будет расположен на IP 10.0.0.191.


<nowiki>MongoClient = function(server, options);
Установка BIND9
MongoClient.prototype.open


MongoClient.prototype.close
Для работы DNS сервера необходимо установить пакет bind9 (в некоторых дистрибутивах - bind). Как отмечено на схеме - основным конфигурационным файлом BIND является файл named.conf (данный файл может быть размещен в каталоге /etc, иногда в /etc/bind ).


MongoClient.prototype.db
Параметры (синтаксис) named.conf


MongoClient.connect</nowiki>
Синтаксис файла named.conf придерживается следующих правил:


IP-адреса - список IP должен быть разделен символом ";" , возможно указывать подсеть в формате 192.168.1.1/24 или 192.168.1.1/255.255.255.0, (для исключения IP перед ним нужно поставить знак !), возможно указывать имена "any", "none", "localhost" в двойных кавычках.


Выше описан полный интерфейс MongoClient. Методы '''open''', '''close''' and '''db''' работают аналогично существующим методам в классе (прим. переводчика: Объекте) '''Db'''. Основное отличие в том, что конструктор пропускает '''database name''' из '''Db'''. Рассмотрим простое подключение используя '''open''', код заменит тысячи слов.
Комментарии - строки начинающиеся на #, // и заключенные в /* и */ считаются комментариями.


В файлах описания зон - символ @ является "переменной" хранящей имя зоны, указанной в конфигурационном файле named.conf или в директиве @ $ORIGIN текущего описания зоны.


<nowiki>var MongoClient = require('mongodb').MongoClient,
Каждая завершенная строка параметров должна завершаться символом ; .
    Server = require('mongodb').Server;


var mongoClient = new MongoClient(new Server('localhost', 27017));
Раздел Acl
           
Acl (access control list) - позволяет задать именованный список сетей. Формат раздела: acl "имя_сети" {ip; ip; ip; };
    mongoClient.open(function(err, mongoClient) {


var db1 = mongoClient.db("mydb");
Раздел Options
Раздел Options задает глобальные параметры конфигурационного файла, управляющие всеми зонами. Данный раздел имеет формат: options {операторы_раздела_Options};. Options может быть "вложен" в раздел Zone, при этом он переопределяет глобальные параметры. Часто используемые операторы options:


    mongoClient.close();
allow-query {список_ip} - Разрешает ответы на запросы только из список_ip. При отсутствии - сервер отвечает на все запросы.
  });</nowiki>
allow-recursion {список_ip} - На запросы из список_ip будут выполняться рекурсивные запросы. Для остальных - итеративные. Если  не задан параметр, то сервер выполняет рекурсивные запросы для всех сетей.
allow-transfer {список_ip} - Указывает список серверов, которым разрешено брать зону с сервера (в основном тут указывают slave сервера)
  directory /path/to/work/dir - указывает абсолютный путь к рабочему каталогу сервера. Этот оператор допустим только в разделе  options.
forwarders {ip порт, ip порт...} - указывает адреса хостов и если нужно порты, куда переадресовывать запросы (обычно тут указываются DNS провайдеров ISP).
forward ONLY или forward FIRST - параметр first указывает, DNS-серверу пытаться разрешать имена с помощью DNS-серверов, указанных в параметре forwarders, и лишь в случае, если разрешить имя с помощью данных серверов не удалось, то будет осуществлять попытки разрешения имени самостоятельно.
notify YES|NO - YES - уведомлять slave сервера об изменениях в зоне, NO - не уведомлять.
recursion YES|NO - YES - выполнять рекурсивные запросы, если просит клиент, NO - не выполнять (только итеративные запросы). Если ответ найден в кэше, то возвращается из кэша. (может использоваться только в разделе Options)
Раздел Zone
Определяет описание зон(ы). Формат раздела: zone {операторы_раздела_zone}; Операторы, которые наиболее часто используются:


Следует обратить внимание, что настройки MongoClient такие же, как для объекта '''Db'''. Основным отличием является то, что доступ к данным происходит через метод '''db''' объекта MongoClient вместо непосредственного использования экземпляра объекта '''db''', как было раньше. Также MongoClient поддерживает те же параметры, что и предыдущий экземпляр Db.
allow-update {список_ip} - указывает системы, которым разрешено динамически обновлять данную зону.
file "имя_файла" - указывает путь файла параметров зоны (должен быть расположен в каталоге, определенном в разделе options оператором directory)
masters {список_ip} -указывает список мастер-серверов. (допустим только в подчиненных зонах)
type "тип_зоны" - указывает тип зоны, описываемой в текущем разделе,тип_зоны может принимать следующие значения:
forward - указывает зону переадресации, которая переадресовывает запросы, пришедшие в эту зону.
hint - указывает вспомогательную зону (данный тип содержит информацию о корневых серверах, к которым сервер будет обращаться в случае невозможности найти ответ в кэше)
  master - указывает работать в качестве мастер сервера для текущей зоны.
  slave - указывает работать в качестве подчиненного сервера для текущей зоны.
Дополнительные параметры конфигурации
Значения времени в файлах зон по умолчанию указывается в секундах, если за ними не стоит одна из следующих букв: S - секунды, M - минуты, H- часы, D - дни, W - недели. Соответственно, запись 2h20m5s будет иметь значение 2 часа 20 минут 5 секунд и соответствовать 8405 секунд.


Таким образом, с минимальными изменениями в приложении можно применить новый объект MongoClient для подключения.  
Любое имя хоста/записи, не оканчивающиеся точкой считается неFQDN именем и будет дополнено именем текущей зоны. Например, запись domen в файле зоны examle.com будет развернуто в FQDN-имя domen.examle.com. .


== URL формат подключения ==
В конфигурационных файлах BIND могут применяться следующие директивы:
<nowiki>mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]</nowiki>


URL формата унифицированы во всех официальных драйверах от 10gen, некоторые опции не поддерживается сторонними драйверами в силу естественных причин.
$TTL - определяет TTL по-умолчанию для всех записей в текущей зоне.
$ORIGIN - изменяет имя зоны с указанного в файле named.conf. При этом, область действия данной директивы не распространяется  "выше" (то есть если файл включен директивой $INCLUDE, то область действия$ORIGN не распространяется на родительский)
$INCLUDE - включает указанный файл как часть файла зоны.
Для того чтобы локальный резолвер сервера тоже использовал локальный DNS, необходимо привести файл resolv.conf к следующему виду:


=== Составные части url ===
dns:~# cat /etc/resolv.conf
* <span style="color:darkgreen">'''mongodb://'''</span> - префикс запроса идентифицирующий строку как стандартный формат подключения
nameserver 127.0.0.1
* <span style="color:darkgreen">'''username:password@'''</span> - необязательные параметры. Если заданы, драйвер использует авторизацию для подключения к database после соединения с серером.
Если в имени ресурсной записи встречается символ "*", то это он означает что вместо него можно подразумевать любую разрешенную последовательность символов. Такую запись называют "wildcard запись". Однако, символ "*" не может быть использован где угодно. Это может быть только первый символ в поле Name текущего домена, отделенный от остальных символом "."
* <span style="color:darkgreen">'''host1'''</span> - единственная обязательная часть URI. Идентифицируется каждый hostname, IP адрес или  or unix сокет
* <span style="color:darkgreen">''':portX'''</span> - порт подключения, необязательный параметр, по умолчанию :27017.
* <span style="color:darkgreen">'''/database'''</span> это имя базы данных для входа и, следовательно, имеет смысл только, если имя пользователя: пароль @ синтаксис. Если не указано "Admin" база данных будет использоваться по умолчанию.(???не понятно)
* <span style="color:darkgreen">'''?options'''</span> - параметры подключения. Если значение database будет отсутствовать, то символ / должен все равно присутствовать между последним host и знаком ?, предваряющим параметры. Параметры имеют формат name=value и разделены знаком "&". Для неправильных или не поддерживаемых параметров драйвер запишет предупреждение в лог и продолжит выполнение. Драйвер не поддерживает других опций, кроме описанных в спецификации. Это делается для того, чтобы уменьшить вероятность того, что различные драйверы будут поддерживать немного измененные, но в последствие несовместимые параметры (например, другие имена, разные значения, или другое значение по умолчанию).


===Параметры Replica set: ===
Настройка кэширующего DNS сервера
* '''replicaSet=name'''
** Драйвер проверяет имя replica set для подключения к машине с этим именем. Подразумевается, что hostы указаны в списке, а драйвер будет пытаться найти все элементы набора.
** НЕТ ЗНАЧЕНИЯ ПО УМОЛЧАНИЮ.
:::::Прим. Репликация в MongoDB работает сходным образом с репликацией в реляционных базах данных. Записи посылаются на один сервер — ведущий (master), который потом синхронизирует своё состояние с другими серверами — ведомыми (slave). Вы можете разрешить или запретить чтение с ведомых серверов, в зависимости от того, допускается ли в вашей системе чтение несогласованных данных. Если ведущий сервер падает, один из ведомых может взять на себя роль ведущего.


:::::Хотя репликация увеличивает производительность чтения, делая его распределённым, основная её цель — увеличение надёжности. Типичным подходом является сочетание репликации и шардинга. Например, каждый шард может состоять из ведущего и ведомого серверов. (Технически, вам также понадобится арбитр, чтобы разрешить конфликт, когда два ведомых сервера пытаются объявить себя ведущими. Но арбитр потребляет очень мало ресурсов и может быть использован для нескольких шардов сразу.)
После установки bind, он полностью готов работать как кэширующий DNS сервер без дополнительной настройки. Единственный недостаток - он обрабатывает запросы на всех интерфейсах, что нам абсолютно не нужно, поэтому мы немного подредактируем настройки сервера.


=== Конфигурация подключения: ===
Для того, чтобы BIND работал в качестве кэширующего сервера, необходимо иметь конфигурационные файлы заполненные необходимой информацией:
* '''ssl=true|false|prefer'''
** true: драйвер инициирует каждое подключение и использованием SSL
** false: драйвер инициирует каждое подключение без использования SSL
** prefer: драйвер будет пытаться инициировать каждое подключение и использованием SSL, в случае неудачи, будет инициировано подключение без использования SSL
** Значение по умолчанию: false.
* '''connectTimeoutMS=ms'''
** How long a connection can take to be opened before timing out.
** Current driver behavior already differs on this, so default must be left to each driver. For new implementations, the default should be to never timeout.
* '''socketTimeoutMS=ms'''
** How long a send or receive on a socket can take before timing out.
** Current driver behavior already differs on this, so default must be left to each driver. For new implementations, the default should be to never timeout.


=== Конфигурация пула подключений: ===
named.conf;
* '''maxPoolSize=n:''' Максимальное число подключений в пуле
описание серверов корневой зоны (зона типа hint);
** Значение по умолчанию: 100
описание зоны 127.in-addr.arpa.
dns:~# cat /etc/bind/named.conf
acl "lan" {
            192.168.1.1/24;
            127.0.0.1;
};
options {
            directory "/var/cache/bind";
          // If there is a firewall between you and nameservers you want
          // to talk to, you may need to fix the firewall to allow multiple
          // ports to talk.  See http://www.kb.cert.org/vuls/id/800113
          /*
          * Тут сказано, что если используется фаерволл, то необходимо
          * нашему серверу создать соответствующие правила
          *  то есть открыть доступ по 53 TCP и UDP порту
          */
          forward first;              // задаем пересылку только первого запроса
          forwarders {                // указываем DNS сервера для пересылки
                      83.239.0.202;    // предоставленные провайдером
                      213.132.67.110;  // ибо до них ближе чем до корневых
          };
          listen-on { lan; };        // пусть слушает только нужные интерфейсы
          allow-query { lan; };      // разрешить запросы только из локальной сети
          allow-recursion { lan; };  // рекурсивные запросы тоже только из локальной
          allow-transfer { none; };  // трансфер зон нам не нужен
          version "unknown";        // не отображать версию DNS сервера при ответах
          auth-nxdomain no;    # для совместимости RFC1035
          listen-on-v6 { none; };    //IPv6 нам не нужен
          };
// описание настроек корневых серверов
zone "." {
          type hint;
          file "db.root";
};
// нижеописанные зоны определяют сервер авторитетным для петлевых
// интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)
zone "localhost" {
          type master;
          file "localhost";
};
zone "127.in-addr.arpa" {
          type master;
          file "127.in-addr.arpa";
};
zone "0.in-addr.arpa" {
          type master;
          file "0.in-addr.arpa";
};
zone "255.in-addr.arpa" {
          type master;
          file "255.in-addr.arpa";
};


=== Write concern configuration: ===
В данном примере приведен кэширующий DNS сервер, обрабатывающий запросы из списка сетей lan, в которую входит только одна локальная сеть 192.168.1.1/24 и петлевой интерфейс. При необходимости можно включить туда и другие сети. После определения списка сетей в директиве acl, в любом месте конфига можно будет ссылаться на этот список по имени (в нашем примере имя - lan), что, собственно и сделано в разделе options. Большинство параметров я прокомментировал, но отдельного внимания требует раздел, описывающий зону корневых серверов. В параметре file задан относительный путь к файлу описания корневых серверов (путь, относительно рабочего каталога сервера). За обновлениями данного файла необходимо следить, хотя он обновляется довольно редко (откуда брать обновленный файл я писал в теории DNS). Как вы заметили, имеется так же две записи для зоны localhost и две записи обратных зон для бродкаст доменов. Назначение этих зон состоит в том, чтобы избежать трансляции случайных запросов имен соответствующих IP-адресов на серверы, обслуживающие корневую зону.
'''w=wValue'''


*For numeric values above 1, the driver adds { w : wValue } to the getLastError command.
Чтобы не вносить неразбериху в куче конфигурационных файлов, в статье я привожу примеры на основе единого конфигурационного файла. На  самом деле, в последних версиях Debian (и других дистрибутивах Linux), файл named.conf выглядит следующим образом:


*wValue is typically a number, but can be any string in order to allow for specifications like "majority"
root@master:~# cat /etc/bind/named.conf
// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local


*Default value is 1.
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
То есть основной файл не содержит конфигураций, а включает в себя более узко специализированные файлы, которые отвечают за свои задачи, например named.conf.options - содержит глобальные параметры конфигурации, named.conf.default-zones - содержит описание localhost и broadcast зон, а named.conf.local содержит описания зон, за которые отвечает данный сервер.


*If wValue == -1 ignore network errors


*If wValue == 0 Don't send getLastError
Далее, хочу обратить внимание на наличие файлов зон в каталоге, указанном в разделе options в параметре directory с именами, соответствующими параметрам file в разделах, описывающих зоны:


*If wValue == 1 send {getlasterror: 1} (no w)
dns:~# ls -l /var/cache/bind/
итого 24
-rw-r--r-- 1 root root  237 Май 28 01:28 0.in-addr.arpa
-rw-r--r-- 1 root root  271 Май 28 01:28 127.in-addr.arpa
-rw-r--r-- 1 root root  237 Май 28 01:28 255.in-addr.arpa
-rw-r--r-- 1 root root 2994 Май 28 01:28 db.root
-rw-r--r-- 1 root root  270 Май 28 01:28 localhost
dns:~# cat /var/cache/bind/127.in-addr.arpa
;
; BIND reverse data file for local loopback interface
;
$TTL    604800
@      IN      SOA    localhost. root.localhost. (
                              1        ; Serial
                              604800    ; Refresh
                              86400    ; Retry
                              2419200  ; Expire
                              604800 ) ; Negative Cache TTL
;
@      IN      NS      localhost.
1.0.0  IN      PTR    localhost.
Рассматривать файлы "петлевых" и бродкастовых зон не вижу смысла, т.к. после установки пакета bind настройки заданные по умолчанию в данных файлах вполне приемлемы. Далее, при организации мастер сервера мы рассмотрим пример описания файла зоны. Хочу обратить внимание, что мы настраиваем кэширующий сервер, а определяем мы его и как master для некоторых из зон. В нашем случае "кэширующий" говорит о том, что наш сервер не поддерживает ни одну из реально существующих зон, т.е. ему не делегировано прав на такое обслуживание.


'''wtimeoutMS=ms'''
Да, чуть не забыл, демон named должен быть разрешен для запуска на необходимых уровнях выполнения ОС (команда в RedHat - /sbin/chkconfig bind9 on, в Debian - /usr/sbin/update-rc.d bind9 defaults). После изменения конфигурационных файлов можно добавить сервис в автозагрузку и запустить демон:


*The driver adds { wtimeout : ms } to the getlasterror command.
dns:~# update-rc.d bind9 defaults
Adding system startup for /etc/init.d/bind9 ...
/etc/rc0.d/K20bind9 -> ../init.d/bind9
/etc/rc1.d/K20bind9 -> ../init.d/bind9
/etc/rc6.d/K20bind9 -> ../init.d/bind9
/etc/rc2.d/S20bind9 -> ../init.d/bind9
/etc/rc3.d/S20bind9 -> ../init.d/bind9
/etc/rc4.d/S20bind9 -> ../init.d/bind9
/etc/rc5.d/S20bind9 -> ../init.d/bind9
dns:~# /etc/init.d/bind9 start
Starting domain name service...: bind9.
На этом настройка кэширующего DNS завершена. Все запросы, которые попадают в кэш DNS сервера он хранит в оперативной памяти компьютера и при перезапуске демона эти данные обнуляются. Для проверки работы кэша можно выполнить команду nslookup mail.ru example.com., если в ответе содержится строка Non-authoritative answer, то адрес пришел из кэша, а так же если выполнить dig www.ru. (или другой домен, которого еще нет в кэше) и через некоторое время повторить команду, то время ответа должно быть гораздо меньше.


*Used in combination with w
Давайте рассмотрим другие варианты сервера.


*No default value
Главный (master) сервер зоны


'''journal=true|false'''
Основной конфиг содержит следующие настройки:


*true: Sync to journal.
dns:~# cat /etc/bind/named.conf
acl "lan" {
          192.168.1.1/24;
          127.0.0.1;
};


*false: the driver does not add j to the getlasterror command
options {
          directory "/var/cache/bind";
          allow-query { any; };      // отвечать на зпросы со всех интерфейсов
          recursion no;              // запретить рекурсивные запросы
          auth-nxdomain no;          // для совместимости RFC1035
          listen-on-v6 { none; };    // IPv6 нам не нужен
          version "unknown";          // не отображать версию DNS сервера при ответах


*Default value is false
          /*
          *  Раскомментируйте строки ниже, если
          *  хотите разрешить рекрусивные запросы
          *  из локальной сети.
          *  (так же, необходимо закомментировать
          *  recursion no; )
          */
          # forwarders {                // указываем DNS сервера для пересылки
          #        83.239.0.202;        // предоставленные провайдером
          #        213.132.67.110;      // ибо до них ближе чем до корневых
          # };


'''fsync=true|false'''
          # allow-recursion { lan; };    // рекурсивные запросы тоже только из локальной


*true: Sync to disk.
};


*false: the driver does not add fsync to the getlasterror command
// описание настроек корневых серверов
zone "." {
          type hint;
          file "db.root";
};


*Default value is false
// нижеописанные зоны определяют сервер авторитетным для петлевых
// интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)


If conflicting values for fireAndForget, and any write concern are passed the driver should raise an exception about the conflict.
zone "localhost" {
          type master;
          file "localhost";
};


=== Read Preference ===
zone "127.in-addr.arpa" {
'''slaveOk=true|false:''' Whether a driver connected to a replica set will send reads to slaves/secondaries.
          type master;
          file "127.in-addr.arpa";
};


*Default value is false
zone "0.in-addr.arpa" {
          type master;
          file "0.in-addr.arpa";
};


'''readPreference=enum:''' The read preference for this connection. If set, it overrides any slaveOk value.
zone "255.in-addr.arpa" {
          type master;
          file "255.in-addr.arpa";
};


*Enumerated values:
// описание основной зоны
zone "example.com" {
          type master;
          file "example.com";
          allow-transfer { 10.0.0.191; };
};


:*primary
//описание обратных зон
zone "0.0.10.in-addr.arpa" {
          type master;
          file "0.0.10.in-addr.arpa";
          allow-transfer { 10.0.0.191; };
};


:*primaryPreferred
zone "1.168.192.in-addr.arpa" {
          type master;
          file "1.168.192.in-addr.arpa";
#        allow-transfer { 10.0.0.191; };  // зона описывает локальную сеть поэтому ее не передаем
};


:*secondary
// настройки логирования
logging {
          channel "misc" {
                    file "/var/log/bind/misc.log" versions 4 size 4m;
                    print-time yes;
                    print-severity yes;
                    print-category yes;
          };


:*secondaryPreferred
          channel "query" {
                    file "/var/log/bind/query.log" versions 4 size 4m;
                    print-time yes;
                    print-severity no;
                    print-category no;
          };


:*nearest
          category default {
                    "misc";
          };


*Default value is primary
          category queries {
                    "query";
          };
};
Давайте кратко разберем конфигурационный файл и настройки master сервера: мы настраиваем мастер сервер для зоны example.com. . Согласно конфига, наш BIND имеет рабочий каталог /var/cache/bind, сервер отвечает на запросы со всех интерфейсов (allow-query {any ;};), рекурсивные запросы обрабатывает как итеративные (recursion no), является мастер-сервером для зоны example.com и локальных служебных зон (type master). При этом, если необходимо разрешить кэширование (то есть рекурсивные запросы) для локальной сети, то необходимо раскомментировать параметры forwarders и allow-recursion и закомментировать recursion no;.


'''readPreferenceTags=string.''' A representation of a tag set as a comma-separated list of colon-separated key-value pairs, e.g.'''dc:ny,rack:1'''. Spaces should be stripped from beginning and end of all keys and values. To specify a list of tag sets, using multiple readPreferenceTags, e.g. '''readPreferenceTags=dc:ny,rack:1&readPreferenceTags=dc:ny&readPreferenceTags='''
Так же, для примера, я привел возможности BIND логировать все происходящее при работе сервера (можно для этой цели использовать syslog). В разделе logging задаются 2 параметра channel (можно и больше двух - на ваше усмотрение), эти параметры дословно можно назвать "канал" записи. Каждый канал определяет имя канала и настройки параметров записи (что записывать, а что - нет и куда писать). Директива category задает какую категорию сообщений в какой канал отправлять. Исходя из этого, мы имеем: запись стандартной информации в канал misc, а приходящие запросы посылаются в канал query. При этом, если файлы журнала достигают 4Мб (size 4m), он переименовывается добавлением к имени .1 и начинается запись в новый журнал, числа в конце других журналов увеличиваются. Журналы с номером, более указанного в version (в нашем случае 4) удаляются (Управлять ротацией логов можно так же с помощью logrotate). Параметры print* определяют заносить ли в журнал время появления, важность и категорию информации. Более подробно про настройки раздела logging можно почитать в man (5) named.conf.


*Note the empty value, it provides for fallback to any other secondary server if none is available
Отдельно хочется описать параметр  allow-transfer { 10.0.0.191; };. Данный параметр описывает серверы, которым разрешено скачивать копию зоны - т.н. slave серверА. В следующем примере мы разберем настройку slave DNS.


*Order matters when using multiple readPreferenceTags
Для корректной работы логирования необходимо создать соответствующий каталог и присвоить необходимые права:


*There is no default value
dns:~# mkdir /var/log/bind/
dns:~# chmod 744 /var/log/bind/
dns:~# ps aux | grep named
bind      4298  0.0  3.4  46792 13272 ?        Ssl  Jul05  0:00 /usr/sbin/named -u bind
root      4815  0.0  0.1  3304  772 pts/4    S+  18:19  0:00 grep named
dns:~# chown bind /var/log/bind/
dns:~# ls -ld /var/log/bind/
drwxr--r-- 2 bind root 4096 Июл  6 18:18 /var/log/bind/
Давайте далее рассмотрим наш файл описания зоны example.com.:


== MongoClient.connect ==
dns:~# cat /var/cache/bind/example.com
При использовании MongoClient.connect можно (наверное нужно) использовать URL формат подключения. Где возможно, MongoClient максимально наилучшие параметры по умолчанию, но их всегда можно изменить. Это относится к параметрам '''auto_reconnect:true'''и '''native_parser:true''' если возможно. Ниже примеры подключения к single server a replicaset and a sharded system using '''MongoClient.connect'''
$TTL 3D
@      IN      SOA    ns.example.com. root.example.com. (
                                        2011070601      ; serial
                                        8H              ; refresh
                                        2H              ; retry
                                        2W              ; expire
                                        1D)            ; minimum


=== Подключение к single server ===
@      IN      NS      ns.example.com.
<nowiki>var MongoClient = require('mongodb').MongoClient;
@      IN      NS      ns2.example.com.
@      IN      A      10.0.0.152
@      IN      MX      5 mx.example.com.
ns      IN      A      10.0.0.152
ns2    IN      A      10.0.0.191
mx      IN      A      10.0.0.152
www    IN      CNAME  @
а так же в домене in-addr.arpa.


MongoClient.connect("mongodb://localhost:27017/integration_test", function(err, db) {
dns:~# cat /var/cache/bind/0.0.10.in-addr.arpa
  test.equal(null, err);
$TTL 3600
   test.ok(db != null);
@      IN      SOA    ns.examle.com.  root.example.com. (
            2007042001 ; Serial
            3600      ; Refresh
            900        ; Retry
            3600000   ; Expire
            3600 )     ; Minimum
        IN      NS      ns.examle.com.
        IN      NS      ns2.example.com.
152    IN      PTR    examle.com.
191    IN      PTR    ns.example.com.
*      IN      PTR    examle.com.


  db.collection("replicaset_mongo_client_collection").update({a:1}, {b:1}, {upsert:true}, function(err, result) {
dns:~# cat /var/cache/bind/1.168.192.in-addr.arpa
    test.equal(null, err);
$TTL 3600
    test.equal(1, result);
@      IN      SOA    ns.examle.com.  root.example.com. (
            2007042001 ; Serial
            3600      ; Refresh
            900        ; Retry
            3600000    ; Expire
            3600 )     ; Minimum
        IN      NS      ns.examle.com.
        IN      NS      ns2.example.com.
*      IN      PTR    examle.com.
Наша сеть небольшая, предполагается, что в сети совсем мало машин. Все сервисы сети размещены на одном хосте example.com., поэтому и master DNS (ns.example.com.) и почтовый сервер (mx.example.com.) указывает на одну машину (10.0.0.152).


    db.close();
Вторичный (secondary, slave) авторитетный сервер зоны
    test.done();
  });
});</nowiki>


=== A replicaset connect using no ackowledgment by default and readPreference for secondary ===
Основная функция slave сервера - автоматическая синхронизация описания зоны с master сервером. Данная задача регламентируется документом RFC 1034 в разделе 4.3.5. Согласно данному документу обмен данными между серверами рекомендовано производить по протоколу TCP, посредством запроса AXFR. По этому запросу за одно TCP соединение должна передаваться вся зона целиком (RFC 1035).
<nowiki>var MongoClient = require('mongodb').MongoClient;


MongoClient.connect("mongodb://localhost:30000,localhost:30001/integration_test_?w=0&readPreference=secondary", function(err, db) {
Так же, slave DNS-сервер делит нагрузку с master сервером или принимает на себя всю нагрузку в случае аварии па первом сервере.
  test.equal(null, err);
  test.ok(db != null);


  db.collection("replicaset_mongo_client_collection").update({a:1}, {b:1}, {upsert:true}, function(err, result) {
Прежде чем приступить к настройке slave DNS сервера, необходимо проверить возможность получения зоны вручную со вторичного сервера с помощью следующей команды:
    test.equal(null, err);
    test.equal(1, result);


    db.close();
root@debian:~# dig @10.0.0.152 example.com. axfr
    test.done();
  });
});</nowiki>


=== A sharded connect using no ackowledgment by default and readPreference for secondary ===
; <<>> DiG 9.7.3 <<>> @10.0.0.152 example.com. axfr
  <nowiki>var MongoClient = require('mongodb').MongoClient;
; (1 server found)
;; global options: +cmd
example.com.            259200  IN      SOA    ns.example.com. root.example.com. 2011070801 28800 7200 1209600 86400
example.com.            259200  IN      NS      ns.example.com.
example.com.            259200  IN      NS      ns2.example.com.
example.com.            259200  IN      A      10.0.0.152
example.com.            259200  IN      MX      5 mx.example.com.
mx.example.com.        259200  IN      A      10.0.0.152
ns.example.com.        259200  IN      A      10.0.0.152
ns2.example.com.        259200  IN      A       10.0.0.191
www.example.com.        259200  IN      CNAME  example.com.
example.com.            259200  IN      SOA    ns.example.com. root.example.com. 2011070801 28800 7200 1209600 86400
;; Query time: 14 msec
;; SERVER: 10.0.0.152#53(10.0.0.152)
;; WHEN: Fri Jul 8 15:33:54 2011
;; XFR size: 11 records (messages 1, bytes 258)
Получение зоны прошло успешно. Далее, для настройки подчиненного сервера, алгоритм следующий:


  MongoClient.connect("mongodb://localhost:50000,localhost:50001/integration_test_?w=0&readPreference=secondary", function(err, db) {
Скопировать конфигурационный файл named.conf с master сервера;
  test.equal(null, err);
Заменить параметр type master на type slave в тех зонах, для которых он будет вторичным;
  test.ok(db != null);
Параметр allow-transfer { 10.0.0.191; }; заменить на masters { 10.0.0.152;}; в тех зонах, для которых он будет вторичным;
Удалить зоны, которые не будет обслуживать текущий сервер, в том числе и корневую, если slave не будет отвечать на рекурсивные запросы;
Создать каталоги для логов, как в предыдущем примере.
Итого, мы получаем конфиг slave сервера:


  db.collection("replicaset_mongo_client_collection").update({a:1}, {b:1}, {upsert:true}, function(err, result) {
root@debian:~# cat /etc/bind/named.conf
    test.equal(null, err);
options {
    test.equal(1, result);
          directory "/var/cache/bind";
          allow-query { any; };      // отвечать на запросы со всех интерфейсов
          recursion no;              // запретить рекурсивные запросы
          auth-nxdomain no;          // для совместимости RFC1035
          listen-on-v6 { none; };    // IPv6 нам не нужен
          version "unknown";         // не отображать версию DNS сервера при ответах
};


    db.close();
// нижеописанные зоны определяют сервер авторитетным для петлевых
    test.done();
// интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)
  });
});</nowiki>


Notice that when connecting to the shareded system it's pretty much the same url as for connecting to the replicaset. This is because the driver itself figures out if it's a replicaset or a set of Mongos proxies it's connecting to. No special care is needed to specify if it's one or the other. This is in contrast to having to use the '''ReplSet''' or '''Mongos''' instances when using the '''open''' command.
zone "localhost" {
          type master;
          file "localhost";
};


== MongoClient.connect опции ==
zone "127.in-addr.arpa" {
The connect function also takes a hash of options divided into db/server/replset/mongos alowing you to tweak options not directly supported by the unified url string format. To use these options you do pass in a has like this.
          type master;
          file "127.in-addr.arpa";
};


<nowiki>var MongoClient = require('mongodb').MongoClient;
zone "0.in-addr.arpa" {
          type master;
          file "0.in-addr.arpa";
};


MongoClient.connect("mongodb://localhost:27017/integration_test_?", {
zone "255.in-addr.arpa" {
    db: {
          type master;
      native_parser: false
          file "255.in-addr.arpa";
    },
};
    server: {
      socketOptions: {
        connectTimeoutMS: 500
      }
    },
    replSet: {},
    mongos: {}
  }, function(err, db) {
  test.equal(null, err);
  test.ok(db != null);


  db.collection("replicaset_mongo_client_collection").update({a:1}, {b:1}, {upsert:true}, function(err, result) {
// описание основной зоны
    test.equal(null, err);
zone "example.com" {
    test.equal(1, result);
          type slave;
          file "example.com";
          masters { 10.0.0.152; };
};


    db.close();
//описание обратной зоны
    test.done();
zone "0.0.10.in-addr.arpa" {
  });
          type slave;
});</nowiki>
          file "0.0.10.in-addr.arpa";
          masters { 10.0.0.152; };
};


Below are all the options supported for db/server/replset/mongos.
// настройки логирования
logging {
          channel "misc" {
                    file "/var/log/bind/misc.log" versions 4 size 4m;
                    print-time YES;
                    print-severity YES;
                    print-category YES;
          };


*'''db''' A hash of options at the db level overriding or adjusting functionaliy not suppported by the url
          channel "query" {
                    file "/var/log/bind/query.log" versions 4 size 4m;
                    print-time YES;
                    print-severity NO;
                    print-category NO;
          };


:*'''w'''<nowiki>, {Number/String, > -1 || 'majority'} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1 or w = 'majority' acknowledges the write</nowiki>
          category default {
                    "misc";
          };


:*'''wtimeout''', {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
          category queries {
                    "query";
          };
};
после перезапуска наш slave сервер благополучно скопирует необходимую ему информацию с главного сервера, о чем будет говорить наличие файлов в  каталоге:


:*'''fsync''', (Boolean, default:false) write waits for fsync before returning
root@debian:~# ls -la /var/cache/bind/
итого 28
drwxrwxr-x  2 root bind 4096 Июл  8 18:47 .
drwxr-xr-x 10 root root 4096 Июл  8 15:17 ..
-rw-r--r--  1 bind bind  416 Июл  8 18:32 0.0.10.in-addr.arpa
......
-rw-r--r--  1 bind bind  455 Июл  8 18:32 example.com
........
В принципе,/stroallow-transfer {pngp slave сервер может не хранить копию зоны у себя в файловой системе. Эта копия нужна только в момент старта DNS. Наличие копии зоны в файловой системе может избавить от сбоя при недоступности master сервера во время запуска slave DNS. Если не указать опцию file в разделе zone, то копия не создается.


:*'''journal''', (Boolean, default:false) write waits for journal sync before returning
Настройка netfilter (iptables) для DNS BIND


:*'''readPreference''' {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
Собственно, настроив работу сервера, неплохо было бы его защитить. Мы знаем, что сервер работает на 53/udp порту. Почитав статью о том, что такое netfilter и правила iptables и ознакомившись с практическими примерами iptables, можно создать правила фильтрации сетевого трафика:


:*'''native_parser''' {Boolean, default:false}, use c++ bson parser.
dns ~ # iptables-save
# типовые правила iptables для DNS
*filter
:INPUT DROP [7511:662704]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
# разрешить доступ локальной сети к DNS серверу:
-A INPUT -s 192.168.1.1/24 -d 192.168.1.1/32 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT
-A OUTPUT -p udp -m udp --sport 32768:61000 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 32768:61000 -j ACCEPT
-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# разрешить доступ DNS серверу совершать исходящие запросы
-A OUTPUT -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
COMMIT
Это типовой пример! Для задания правил iptables под Ваши задачи и конфигурацию сети, необходимо понимать принцип работы netfilter в Linux, почитав вышеуказанные статьи.


:*'''forceServerObjectId''' {Boolean, default:false}, force server to create _id fields instead of client.
Устранение неполадок


:*'''pkFactory''' {Object}, object overriding the basic ObjectID primary key generation.
Основным источником для выявления проблем с DNS является системный лог. Вот пример ошибок при запуске, когда я ошибся с путем к файлу зоны коревых серверов:


:*'''serializeFunctions''' {Boolean, default:false}, serialize functions.
Jul  5 18:12:43 dns-server named[4224]: starting BIND 9.7.3 -u bind
Jul  5 18:12:43 dns-server named[4224]: built with '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' '--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' '--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' '--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE -O2' 'LDFLAGS=' 'CPPFLAGS='
Jul  5 18:12:43 dns-server named[4224]: adjusted limit on open files from 1024 to 1048576
Jul  5 18:12:43 dns-server named[4224]: found 1 CPU, using 1 worker thread
Jul  5 18:12:43 dns-server named[4224]: using up to 4096 sockets
Jul  5 18:12:43 dns-server named[4224]: loading configuration from '/etc/bind/named.conf'
Jul  5 18:12:43 dns-server named[4224]: reading built-in trusted keys from file '/etc/bind/bind.keys'
Jul  5 18:12:43 dns-server named[4224]: using default UDP/IPv4 port range: [1024, 65535]
Jul  5 18:12:43 dns-server named[4224]: using default UDP/IPv6 port range: [1024, 65535]
Jul  5 18:12:43 dns-server named[4224]: listening on IPv4 interface lo, 127.0.0.1#53
Jul  5 18:12:43 dns-server named[4224]: listening on IPv4 interface eth1, 192.168.1.1#53
Jul  5 18:12:43 dns-server named[4224]: generating session key for dynamic DNS
Jul  5 18:12:43 dns-server named[4224]: could not configure root hints from '/etc/bind/db.root': file not found
Jul  5 18:12:43 dns-server named[4224]: loading configuration: file not found            # файл не найден
Jul  5 18:12:43 dns-server named[4224]: exiting (due to fatal error)
Jul  5 18:15:05 dns-server named[4298]: starting BIND 9.7.3 -u bind
Jul  5 18:15:05 dns-server named[4298]: built with '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' '--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' '--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' '--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE -O2' 'LDFLAGS=' 'CPPFLAGS='
Jul  5 18:15:05 dns-server named[4298]: adjusted limit on open files from 1024 to 1048576
Jul  5 18:15:05 dns-server named[4298]: found 1 CPU, using 1 worker thread
Jul  5 18:15:05 dns-server named[4298]: using up to 4096 sockets
Jul  5 18:15:05 dns-server named[4298]: loading configuration from '/etc/bind/named.conf'
Jul  5 18:15:05 dns-server named[4298]: using default UDP/IPv4 port range: [1024, 65535]
Jul  5 18:15:05 dns-server named[4298]: using default UDP/IPv6 port range: [1024, 65535]
Jul  5 18:15:05 dns-server named[4298]: listening on IPv4 interface lo, 127.0.0.1#53
Jul  5 18:15:05 dns-server named[4298]: listening on IPv4 interface eth1, 192.168.1.1#53
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 254.169.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 2.0.192.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 100.51.198.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 113.0.203.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 255.255.255.255.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: D.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 8.E.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 9.E.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: A.E.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: B.E.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 8.B.D.0.1.0.0.2.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: zone 0.in-addr.arpa/IN: loaded serial 1
Jul  5 18:15:05 dns-server named[4298]: zone 127.in-addr.arpa/IN: loaded serial 1
Jul  5 18:15:05 dns-server named[4298]: zone 255.in-addr.arpa/IN: loaded serial 1
Jul  5 18:15:05 dns-server named[4298]: zone localhost/IN: loaded serial 2
Jul  5 18:15:05 dns-server named[4298]: running                                  # запуск прошел удачно
Отличным инструментом для диагностики являются команды диагностики DNS.


:*'''raw''' {Boolean, default:false}, peform operations using raw bson buffers.
* [http://www.k-max.name/linux/howto-dns-server-bind/ HOWTO DNS сервер BIND (практика)]
 
:*'''recordQueryStats''' {Boolean, default:false}, record query statistics during execution.
 
:*'''retryMiliSeconds''' {Number, default:5000}, number of miliseconds between retries.
 
:*'''numberOfRetries''' {Number, default:5}, number of retries off connection.
 
*'''server''' A hash of options at the server level not supported by the url.
 
:*'''readPreference''' {String, default:null}, set's the read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
 
:*'''ssl''' {Boolean, default:false}, use ssl connection (needs to have a mongod server with ssl support)
 
:*'''slaveOk''' {Boolean, default:false}, legacy option allowing reads from secondary, use '''readPrefrence''' instead.
 
:*'''poolSize''' {Number, default:1}, number of connections in the connection pool, set to 1 as default for legacy reasons.
 
:*'''socketOptions''' {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number))
 
:*'''logger''' {Object, default:null}, an object representing a logger that you want to use, needs to support functions debug, log, error '''({error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}})'''.
 
:*'''auto_reconnect''' {Boolean, default:false}, reconnect on error.
 
:*'''disableDriverBSONSizeCheck''' {Boolean, default:false}, force the server to error if the BSON message is to big
 
*'''replSet''' A hash of options at the replSet level not supported by the url.
 
:*'''ha''' {Boolean, default:true}, turn on high availability.
 
:*'''haInterval''' {Number, default:2000}, time between each replicaset status check.
 
:*'''reconnectWait''' {Number, default:1000}, time to wait in miliseconds before attempting reconnect.
 
:*'''retries''' {Number, default:30}, number of times to attempt a replicaset reconnect.
 
:*'''rs_name''' {String}, the name of the replicaset to connect to.
 
:*'''socketOptions''' {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number))
 
:*'''readPreference''' {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
 
:*'''strategy''' {String, default:null}, selection strategy for reads choose between (ping and statistical, default is round-robin)
 
:*'''secondaryAcceptableLatencyMS''' {Number, default:15}, sets the range of servers to pick when using NEAREST (lowest ping ms + the latency fence, ex: range of 1 to (1 + 15) ms)
 
:*'''connectArbiter''' {Boolean, default:false}, sets if the driver should connect to arbiters or not.
 
*'''mongos''' A hash of options at the mongos level not supported by the url.
 
:*'''socketOptions''' {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number))
 
:*'''ha''' {Boolean, default:true}, turn on high availability, attempts to reconnect to down proxies
 
:*'''haInterval''' {Number, default:2000}, time between each replicaset status check.
 
= Database =
The first thing to do in order to make queries to the database is to open one. This can be done with the Db constructor.
 
<nowiki>var mongodb = require("mongodb"),
    mongoserver = new mongodb.Server(host, port, server_options),
    db_connector = new mongodb.Db(name, mongoserver, db_options);
 
db_connector.open(callback);</nowiki>
 
* host is a server hostname or IP
* port is a MongoDB port, use mongodb.Connection.DEFAULT_PORT for default (27017)
* server_options see ''Server options''
* name is the databse name that needs to be opened, database will be created automatically if it doesn't yet exist
* db_options see ''DB options''
 
== Параметры Server ==
Several options can be passed to the Server constructor with options parameter.
 
* auto_reconnect - to reconnect automatically, default:false
* poolSize - specify the number of connections in the pool default:5
* socketOptions - a collection of pr socket settings
 
== Параметры Socket  ==
Several options can be set for the socketOptions.
 
* timeout = set seconds before connection times out '''default:0'''
* noDelay = Отключает алгоритм Nagle '''default:true'''
::::''Алгоритм Nagle TCP/IP был разработан, чтобы избежать проблем при передаче небольших пакетов, называемых tinygrams, в медленных сетях. Задача алгоритма балансировать нагрузку TCP соединения, т.е. он пытается равномерно "размазывать" трафик. Поэтому когда идёт активная передача небольших (менее 1500 байт) пакетов данных, алгоритм старается сгладить этот пик нагрузки, задерживая пакеты и пытаясь распределить их более равномерно по времени. Последствием работы данного алгоритма могут быть задержки в передаче пакетов до 200мс. [http://heroes.fragoria.ru/forum/index.php?topic=6161.0 источник 1], [http://support.microsoft.com/kb/138831/ru источник 2]''
* keepAlive = Set if keepAlive is used default:0, which means no keepAlive, set higher than 0 for keepAlive
* encoding = 'ascii'|'utf8'|'base64' default:null
 
== DB опции ==
Several options can be passed to the Db constructor with options parameter.
 
* native_parser - if true, use native BSON parser
* strict - sets ''strict mode'', if true then existing collections can't be "recreated" etc.
* pk - custom primary key factory to generate _id values (see Custom primary keys).
* forceServerObjectId - generation of objectid is delegated to the mongodb server instead of the driver. default is false
* retryMiliSeconds - specify the number of milliseconds between connection attempts default:5000
* numberOfRetries - specify the number of retries for connection attempts default:3
* reaper - enable/disable reaper (true/false) default:false
* reaperInterval - specify the number of milliseconds between each reaper attempt default:10000
* reaperTimeout - specify the number of milliseconds for timing out callbacks that don't return default:30000
* raw - driver expects Buffer raw bson document, default:false
* logger - object specifying error(), debug() and log() functions
 
== Подключение к database ==
Database может быть открыта с помощью метода '''open'''.
 
<nowiki>db_connector.open(callback);</nowiki>
 
callback is a callback function which gets 2 parameters - an error object (or null, if no errors occured) and a database object.
 
Resulting database object can be used for creating and selecting  [[Документация_для_v_1.2#Collections|collections]].
 
<nowiki>db_connector.open(function(err, db){
    db.collection(...);
});</nowiki>
 
=== Свойства Database ===
* databaseName is the name of the database
* serverConfig includes information about the server (serverConfig.host, serverConfig.port etc.)
* state indicates if the database is connected or not
* strict indicates if ''strict mode'' is on (true) or off (false, default)
* version indicates the version of the MongoDB database
 
===События Database ===
* close to indicate that the connection to the database was closed
 
Например:
 
<nowiki>db.on("close", function(error){
    console.log("Connection to the database was closed!");
});</nowiki>
 
NB! If auto_reconnect was set to true when creating the server, then the connection will be automatically reopened on next database operation. Nevertheless the close event will be fired.
 
== Совместное использование соединений с несколькими базами ==
Для совместного использования пула соединений между несколькими базами данных экземпляр базы данных имеет метод '''db'''
 
<nowiki>db_connector.db(name)</nowiki>
 
this returns a new db instance that shares the connections off the previous instance but will send all commands to the databasename. This allows for better control of resource usage in a multiple database scenario.
 
== Удаление database ==
Для удаления database, вначале необходимо установить на неё курсор. Удаление может быть выполнено методом '''dropDatabase'''
<nowiki>db_connector.open(function(err, db){
    if (err) { throw err; }
    db.dropDatabase(function(err) {
        if (err) { throw err; }
        console.log("database has been dropped!");
    });
});</nowiki>
 
== Пользовательские первичные ключи ==
Каждая запись в database имеет уникальный '''первичный ключ''' называющийся '''_id'''. По умолчанию первичный ключ представляет собой хэш длиной 12 байт, но пользовательский генератор ключей может это переопределить. Если установить '''_id''' вручную,  то для добавляемых записей можно использовать что угодно, генератор первичных ключей (primary key factory generates) подставит автосгенерированное значение '''_id''' только для тех записей, где ключ '''_id''' не определен.
 
Example 1: No need to generate primary key, as its already defined:
 
<nowiki>collection.insert({name:"Daniel", _id:"12345"});</nowiki>
 
Example 2: No primary key, so it needs to be generated before save:
 
<nowiki>collectionn.insert({name:"Daniel"});</nowiki>
 
Custom primary key factory is actually an object with method createPK which returns a primary key. The context (value for this) forcreatePK is left untouched.
 
<nowiki>var CustomPKFactory = {
    counter:0,
    createPk: function() {
        return ++this.counter;
    }
}
 
db_connector = new mongodb.Db(name, mongoserver, {pk: CustomPKFactory});</nowiki>
 
== Отладка ==
In order to debug the commands sent to the database you can add a logger object to the DB options. Make sure also the propertydoDebug is set.
 
Пример:
 
<nowiki>options = {}
options.logger = {};
options.logger.doDebug = true;
options.logger.debug = function (message, object) {
    // print the mongo command:
    // "writing command to mongodb"
    console.log(message);
 
    // print the collection name
    console.log(object.json.collectionName)
 
    // print the json query sent to MongoDB
    console.log(object.json.query)
 
    // print the binary object
    console.log(object.binary)
}
 
var db = new Db('some_database', new Server(...), options);</nowiki>
 
= Collections =
Так же смотри:
* [[Документация_для_v_1.2#Database|Database]]
* [[Документация_для_v_1.2#Queries|Queries]]
 
== Объекты-коллекции ==
Collection object is a pointer to a specific collection in the [[Документация_для_v_1.2#Database|database]]. If you want to [[Документация_для_v_1.2#Insert|insert]] new records or [[Документация_для_v_1.2#Queries|query]] existing ones then you need to have a valid collection object.
 
'''Примечание''' Название коллекций не может начинаться или содержать знакa $ (.tes$t - is not allowed)
 
== Создание коллекции ==
Collections can be created with createCollection
 
<nowiki>db.createCollection([[name[, options]], callback)</nowiki>
 
where name is the name of the collection, options a set of configuration parameters and callback is a callback function. db is the database object.
 
The first parameter for the callback is the error object (null if no error) and the second one is the pointer to the newly created collection. If strict mode is on and the table exists, the operation yields in error. With strict mode off (default) the function simple returns the pointer to the existing collection and does not truncate it.
 
db.createCollection("test", function(err, collection){
    collection.insert({"test":"value"});
});
 
== Создание параметров коллекции ==
Several options can be passed to the createCollection function with options parameter.
 
<nowiki>* `raw` - driver returns documents as bson binary Buffer objects, `default:false`</nowiki>
 
=== Collection properties ===
* collectionName is the name of the collection (not including the database name as a prefix)
* db is the pointer to the corresponding databse object
 
Example of usage:
 
console.log("Collection name: "+collection.collectionName)
 
== Список стандартных коллекций ==
=== Список names ===
Collections can be listed with collectionNames
 
<nowiki>db.collectionNames(callback);</nowiki>
 
callback gets two parameters - an error object (if error occured) and an array of collection names as strings.
 
Collection names also include database name, so a collection named posts in a database blog will be listed as blog.posts.
 
Additionally there's system collections which should not be altered without knowing exactly what you are doing, these sollections can be identified with system prefix. For example posts.system.indexes.
 
Пример:
 
<nowiki>var mongodb = require("mongodb"),
    mongoserver = new mongodb.Server("localhost"),
    db_connector = new mongodb.Db("blog", mongoserver);
 
db_connector.open(function(err, db){
    db.collectionNames(function(err, collections){
        <nowiki>console.log(collections); // ["blog.posts", "blog.system.indexes"]</nowiki>
    });
});</nowiki>
 
== Список collections ==
Collection objects can be listed with database method collections
 
db.collections(callback)
 
Where callback gets two parameters - an error object (if an error occured) and an array of collection objects.
 
== Выбор collections ==
Созданная коллекция может быть открыта при помощи метода '''collection'''
 
<nowiki>db.collection([[name[, options]], callback);</nowiki>
 
Если strict mode выключен, тогда в случае отсутствия коллекции, новая коллекция создастся автоматически.
 
== Selecting collections options ==
Several options can be passed to the collection function with options parameter.
 
* `raw` - driver returns documents as bson binary Buffer objects, `default:false`
 
== Renaming collections ==
A collection can be renamed with collection method rename
 
collection.rename(new_name, callback);
 
== Removing records from collections ==
Records can be erased from a collection with remove
 
<nowiki>collection.remove([[query[, options]], callback]);</nowiki>
 
Where
 
* query is the query that records to be removed need to match. If not set all records will be removed
* options indicate advanced options. For example use {safe: true} when using callbacks
* callback callback function that gets two parameters - an error object (if an error occured) and the count of removed records
 
== Removing collections ==
A collection can be dropped with drop
 
collection.drop(callback);
 
or with dropCollection
 
db.dropCollection(collection_name, callback)
 
= Inserting and updating =
See also:
 
* [[Документация_для_v_1.2#Database|Database]]
* [[Документация_для_v_1.2#Collections|Collections]]
 
== Insert ==
Records can be inserted to a collection with insert
 
<nowiki>collection.insert(docs[, options, callback])</nowiki>
 
Where
 
* docs is a single document object or an array of documents
* options is an object of parameters, if you use a callback, set safe to true - this way the callback is executed ''after'' the record is saved to the database, if safe is false (default) callback is fired immediately and thus doesn't make much sense.
* callback - callback function to run after the record is inserted. Set safe to true in options when using callback. First parameter for callback is the error object (if an error occured) and the second is an array of records inserted.
 
For example
 
var document = {name:"David", title:"About MongoDB"};
collection.insert(document, {safe: true}, function(err, records){
    <nowiki>console.log("Record added as "+records[0]._id);</nowiki>
});
 
If trying to insert a record with an existing _id value, then the operation yields in error.
 
collection.insert({_id:1}, {safe:true}, function(err, doc){
    // no error, inserted new document, with _id=1
    collection.insert({_id:1}, {safe:true}, function(err, doc){
        // error occured since _id=1 already existed
    });
});
 
== Save ==
Shorthand for insert/update is save - if _id value set, the record is updated if it exists or inserted if it does not; if the _id value is not set, then the record is inserted as a new one.
 
collection.save({_id:"abc", user:"David"},{safe:true}, callback)
 
callback gets two parameters - an error object (if an error occured) and the record if it was inserted or 1 if the record was updated.
 
== Update ==
Updates can be done with update
 
<nowiki>collection.update(criteria, update[, options[, callback]]);</nowiki>
 
Where
 
* criteria is a query object to find records that need to be updated (see [[Документация_для_v_1.2#Queries|Queries]])
* update is the replacement object
* options is an options object (see below)
* callback is the callback to be run after the records are updated. Has two parameters, the first is an error object (if error occured), the second is the count of records that were modified.
 
=== Update options ===
There are several option values that can be used with an update
 
* safe - run callback only after the update is done, defaults to false
* multi - update all records that match the query object, default is false (only the first one found is updated)
* upsert - if true and no records match the query, insert update as a new record
* raw - driver returns updated document as bson binary Buffer, default:false
 
=== Replacement object ===
If the replacement object is a document, the matching documents will be replaced (except the _id values if no _id is set).
 
collection.update({_id:"123"}, {author:"Jessica", title:"Mongo facts"});
 
The example above will replace the document contents of id=123 with the replacement object.
 
To update only selected fields, $set operator needs to be used. Following replacement object replaces author value but leaves everything else intact.
 
collection.update({_id:"123"}, {$set: {author:"Jessica"}});
 
See [http://www.mongodb.org/display/DOCS/Updating MongoDB documentation] for all possible operators.
 
== Find and Modify ==
To update and retrieve the contents for one single record you can use findAndModify.
 
<nowiki>collection.findAndModify(criteria, sort, update[, options, callback])</nowiki>
 
Where
 
* criteria is the query object to find the record
* sort indicates the order of the matches if there's more than one matching record. The first record on the result set will be used. See [https://github.com/mongodb/node-mongodb-native/blob/1.2-dev/docs/queries.md Queries->find->options->sort] for the format.
* update is the replacement object
* options define the behavior of the function
* callback is the function to run after the update is done. Has two parameters - error object (if error occured) and the record that was updated.
 
=== Options ===
Options object can be used for the following options:
 
* remove - if set to true (default is false), removes the record from the collection. Callback function still gets the object but it doesn't exist in the collection any more.
* new - if set to true, callback function returns the modified record. Default is false (original record is returned)
* upsert - if set to true and no record matched to the query, replacement object is inserted as a new record
 
=== Example ===
<nowiki>var mongodb = require('mongodb'),
    server = new mongodb.Server("127.0.0.1", 27017, {});
 
new mongodb.Db('test', server, {}).open(function (error, client) {
    if (error) throw error;
    var collection = new mongodb.Collection(client, 'test_collection');
    collection.findAndModify(
        {hello: 'world'}, // query
        <nowiki>[['_id','asc']], </nowiki> // sort order
        {$set: {hi: 'there'}}, // replacement, replaces only the field "hi"
        {}, // options
        function(err, object) {
            if (err){
                console.warn(err.message);  // returns error if no matching object found
            }else{
                console.dir(object);
            }
        });
    });
</nowiki>
 
= Queries =
See also:
 
* [[Документация_для_v_1.2#Database|Database]]
* [[Документация_для_v_1.2#Collections|Collections]]
 
== Выполнение запросов при помощи find() ==
[[Документация_для_v_1.2#Collections|Collections]] can be queried with find.
 
<nowiki>collection.find(query[[[, fields], options], callback]);</nowiki>
 
Where
 
* query - is a query object, defining the conditions the documents need to apply
* fields - indicates which fields should be included in the response (default is all)
* options - defines extra logic (sorting options, paging etc.)
* raw - driver returns documents as bson binary Buffer objects, default:false
 
The result for the query is actually a cursor object. This can be used directly or converted to an array.
 
var cursor = collection.find({});
cursor.each(...);
 
To indicate which fields must or must no be returned fields value can be used. For example the following fields value
 
{
    "name": true,
    "title": true
}
 
retrieves fields name and title (and as a default also _id) but not any others.
 
== Find first occurence with findOne() ==
findOne is a convinence method finding and returning the first match of a query while regular find returns a cursor object instead. Use it when you expect only one record, for example when querying with _id or another unique property.
 
<nowiki>collection.findOne([query], callback)</nowiki>
 
Where
 
* query is a query object or an _id value
* callback has two parameters - an error object (if an error occured) and the document object.
 
Example:
 
collection.findOne({_id: doc_id}, function(err, document) {
    console.log(document.name);
});
 
== Значения _id ==
Default _id values are 12 byte binary hashes. You can alter the format with custom Primary Key factories (see ''[[Документация_для_v_1.2#Custom_primary_keys|Custom Primarky Keys]]'' in [[Документация_для_v_1.2#Database|Database]]).
 
In order to treat these binary _id values as strings it would be wise to convert binary values to hex strings. This can be done withtoHexString property.
 
var idHex = document._id.toHexString();
 
Hex strings can be reverted back to binary (for example to perform queries) with ObjectID.createFromHexString
 
{_id: ObjectID.createFromHexString(idHex)}
 
When inserting new records it is possible to use custom _id values as well which do not need to be binary hashes, for example strings.
 
collection.insert({_id: "abc", ...});
collection.findOne({_id: "abc"},...);
 
This way it is not necessary to convert _id values to hex strings and back.
 
== Объект Query ==
The simplest query object is an empty one {} which matches every record in the database.
 
To make a simple query where one field must match to a defined value, one can do it as simply as
 
{fieldname: "fieldvalue"} 
 
This query matches all the records that a) have fields called ''fieldname'' and b) its value is ''"fieldvalue"''.
 
For example if we have a collection of blog posts where the structure of the records is {title, author, contents} and we want to retrieve all the posts for a specific author then we can do it like this:
 
posts = pointer_to_collection;
posts.find({author:"Daniel"}).toArray(function(err, results){
    console.log(results); // output all records
});
 
If the queried field is inside an object then that can be queried also. For example if we have a record with the following structure:
 
{
    user: {
        name: "Daniel"
    }
}
 
Then we can query the "name" field like this: {"user.name":"Daniel"}
 
=== AND ===
If more than one fieldname is specified, then it's an AND query
 
{
    key1: "value1",
    name2: "value2"
}
 
Whis query matches all records where ''key1'' is ''"value1"'' and ''key2'' is ''"value2"''
 
=== OR ===
OR queries are a bit trickier but doable with the $or operator. Query operator takes an array which includes a set of query objects and at least one of these must match a document before it is retrieved
 
{
    <nowiki>$or:[</nowiki>
        {author:"Daniel"},
        {author:"Jessica"}
    ]
}
 
This query match all the documents where author is Daniel or Jessica.
 
To mix AND and OR queries, you just need to use $or as one of regular query fields.
 
{
    title:"MongoDB",
    <nowiki>$or:[</nowiki>
        {author:"Daniel"},
        {author:"Jessica"}
    ]
}
 
=== Conditionals ===
Conditional operators <nowiki><</nowiki>, <nowiki><=</nowiki>, >, >= and != can't be used directly, as the query object format doesn't support it but the same can be achieved with their aliases $lt, $lte, $gt, $gte and $ne. When a field value needs to match a conditional, the value must be wrapped into a separate object.
 
{"fieldname":{$gte:100}}
 
This query defines that ''fieldname'' must be greater than or equal to 100.
 
Conditionals can also be mixed to create ranges.
 
{"fieldname": {$lte:10, $gte:100}}
 
=== Regular expressions in queries ===
Queried field values can also be matched with regular expressions
 
{author:/^Daniel/}
 
=== Специальные операторы в запросах ===
In addition to OR and conditional there's some more operators:
 
* $in - specifies an array of possible matches, <nowiki>{"name":{$in:[1,2,3]}}</nowiki>
* $nin - specifies an array of unwanted matches
* $all - array value must match to the condition <nowiki>{"name":{$all:[1,2,3]}}</nowiki>
* $exists - checks for existence of a field {"name":{$exists:true}}
* $mod - check for a modulo {"name":{$mod:{3,2}} is the same as "name" % 3 == 2
* $size - checks the size of an array value {"name": {$size:2}} matches arrays ''name'' with 2 elements
 
== Queries inside objects and arrays ==
If you have a document with nested objects/arrays then the keys inside these nested objects can still be used for queries.
 
For example with the following document
 
{
    "_id": idvalue,
    "author":{
        "firstname":"Daniel",
        "lastname": "Defoe"
    },
    <nowiki>"books":[</nowiki>
        {
            "title":"Robinson Crusoe"
            "year": 1714
        }
    ]
}
 
not only the _id field can be used as a query field - also the firstname and even title can be used. This can be done when using nested field names as strings, concated with periods.
 
collection.find({"author.firstname":"Daniel})
 
Works even inside arrays
 
collection.find({"books.year":1714})
 
== Query options ==
Query options define the behavior of the query.
 
var options = {
    "limit": 20,
    "skip": 10,
    "sort": title
}
 
collection.find({}, options).toArray(...);
 
=== Paging ===
Paging can be achieved with option parameters limit and skip
 
{
    "limit": 20,
    "skip" 10
}
 
retrieves 10 elements starting from 20
 
=== Sorting ===
Sorting can be acieved with option parameter sort which takes an array of sort preferences
 
{
    <nowiki>"sort": [['field1','asc'], ['field2','desc']]</nowiki>
}
 
With single ascending field the array can be replaced with the name of the field.
 
{
    "sort": "name"
}
 
=== Explain ===
Option parameter explain turns the query into an explain query.
 
== Cursors ==
Cursor objects are the results for queries and can be used to fetch individual fields from the database.
 
=== nextObject ===
cursor.nextObject(function(err, doc){}) retrieves the next record from database. If doc is null, then there weren't any more records.
 
=== each ===
cursor.each(function(err, doc){}) retrieves all matching records one by one.
 
=== toArray ===
cursor.toArray(function(err, docs){}) converts the cursor object into an array of all the matching records. Probably the most convenient way to retrieve results but be careful with large datasets as every record is loaded into memory.
 
collection.find().toArray(function(err, docs){
    console.log("retrieved records:");
    console.log(docs);
});
 
=== rewind ===
cursor.rewind() resets the internal pointer in the cursor to the beginning.
 
== Counting matches ==
Counting total number of found matches can be done against cursors with method count.
 
cursor.count(callback)
 
Where
 
* callback is the callback function with two parameters - an error object (if an error occured) and the number on matches as an integer.
 
Example
 
cursor.count(function(err, count){
    console.log("Total matches: "+count);
});
 
= Replicasets =
== Introduction ==
Replica sets is the asynchronous master/slave replication added to Mongodb that takes care off all the failover and recovery for the member nodes. According to the mongodb documentation a replicaset is
 
* Two or more nodes that are copies of each other
* Automatic assignment of a primary(master) node if none is available
* Drivers that automatically detect the new master and send writes to it
 
More information at [http://www.mongodb.org/display/DOCS/Replica+Sets Replicasets]
 
== Driver usage ==
To create a new replicaset follow the instructions on the mongodb site to setup the config and the replicaset instances. Then using the driver.
 
<nowiki>var replSet = new ReplSetServers( [ </nowiki>
    new Server( 127.0.0.1, 30000, { auto_reconnect: true } ),
    new Server( 127.0.0.1, 30001, { auto_reconnect: true } ),
    new Server( 127.0.0.1, 30002, { auto_reconnect: true } )
  ],
  {rs_name:RS.name}
);
 
var db = new Db('integration_test_', replSet);
db.open(function(err, p_db) {
  // Do you app stuff :)
})
 
The ReplSetSrvers object has the following parameters
 
var replSet = new ReplSetSrvers(servers, options)
 
Where
 
* servers is an array of Server objects
* options can contain the following options
 
== Replicaset options ==
Several options can be passed to the Replicaset constructor with options parameter.
 
* rs_name is the name of the replicaset you configured when you started the server, you can have multiple replicasets running on your servers.
* read_secondary set's the driver to read from secondary servers (slaves) instead of only from the primary(master) server.
* socketOptions - a collection of pr socket settings
 
== Socket options ==
Several options can be set for the socketOptions.
 
* timeout = set seconds before connection times out default:0
* noDelay = Disables the Nagle algorithm default:true
* keepAlive = Set if keepAlive is used default:0, which means no keepAlive, set higher than 0 for keepAlive
* encoding = 'ascii'|'utf8'|'base64' default:null
 
= Indexes =
Indexes are needed to make queries faster. For example if you need to find records by a field named ''username'' and the field has a related index set, then the query will be a lot faster compared to if the index was not present.
 
See [http://www.mongodb.org/display/DOCS/Indexes MongoDB documentation] for details.
 
== Create indexes with createIndex() ==
createIndex adds a new index to a collection. For checking if the index was already set, use ensureIndex instead.
 
<nowiki>collection.createIndex(index[, options], callback)</nowiki>
 
or
 
<nowiki>db.createIndex(collectionname, index[, options], callback)</nowiki>
 
where
 
* index is the field or fields to be indexed. See ''index field''
* options are options, for example {sparse: true} to include only records that have indexed field set or {unique: true} for unique indexes. If the options is a boolean value, then it indicates if it's an unique index or not.
* callback gets two parameters - an error object (if an error occured) and the name for the newly created index
 
== Ensure indexes with ensureIndex() ==
Same as createIndex with the difference that the index is checked for existence before adding to avoid duplicate indexes.
 
== Index field ==
Index field can be a simple string like "username" to index certain field (in this case, a field named as ''username'').
 
collection.ensureIndex("username",callback)
 
It is possible to index fields inside nested objects, for example "user.firstname" to index field named ''firstname'' inside a document named ''user''.
 
collection.ensureIndex("user.firstname",callback)
 
It is also possible to create mixed indexes to include several fields at once.
 
collection.ensureIndex({firstname:1, lastname:1}, callback)
 
or with tuples
 
<nowiki>collection.ensureIndex([["firstname", 1], ["lastname", 1]], callback)</nowiki>
 
The number value indicates direction - if it's 1, then it is an ascending value, if it's -1 then it's descending. For example if you have documents with a field ''date'' and you want to sort these records in descending order then you might want to add corresponding index
 
collection.ensureIndex({date:-1}, callback)
 
== Remove indexes with dropIndex() ==
All indexes can be dropped at once with dropIndexes
 
collection.dropIndexes(callback)
 
callback gets two parameters - an error object (if an error occured) and a boolean value true if operation succeeded.
 
== Get index information with indexInformation() ==
indexInformation can be used to fetch some useful information about collection indexes.
 
collection.indexInformation(callback)
 
Where callback gets two parameters - an error object (if an error occured) and an index information object.
 
The keys in the index object are the index names and the values are tuples of included fields.
 
For example if a collection has two indexes - as a default an ascending index for the _id field and an additonal descending index for"username" field, then the index information object would look like the following
 
{
    <nowiki>"_id":[["_id", 1]],</nowiki>
    <nowiki>"username_-1":[["username", -1]]</nowiki>
}
 
 
= GridStore =
GridFS is a scalable MongoDB ''filesystem'' for storing and retrieving large files. The default limit for a MongoDB record is 16MB, so to store data that is larger than this limit, GridFS can be used. GridFS shards the data into smaller chunks automatically. See [http://www.mongodb.org/display/DOCS/GridFS+Specification MongoDB documentation] for details.
 
GridStore is a single file inside GridFS that can be managed by the script.
 
== Open GridStore ==
Opening a GridStore (a single file in GridFS) is a bit similar to opening a database. At first you need to create a GridStore object and then open it.
 
<nowiki>var gs = new mongodb.GridStore(db, filename, mode[, options])</nowiki>
 
Where
 
* db is the database object
* filename is the name of the file in GridFS that needs to be accessed/created
* mode indicated the operation, can be one of:
** "r" (Read): Looks for the file information in fs.files collection, or creates a new id for this object.
** "w" (Write): Erases all chunks if the file already exist.
** "w+" (Append): Finds the last chunk, and keeps writing after it.
* options can be used to specify some metadata for the file, for example content_type, metadata and chunk_size
 
Example:
 
var gs = new mongodb.GridStore(db, "test.png", "w", {
    "content_type": "image/png",
    "metadata":{
        "author": "Daniel"
    },
    "chunk_size": 1024*4
});
 
When GridStore object is created, it needs to be opened.
 
gs.open(callback);
 
callback gets two parameters - and error object (if error occured) and the GridStore object.
 
Opened GridStore object has a set of useful properties
 
* gs.length - length of the file in bytes
* gs.contentType - the content type for the file
* gs.uploadDate - when the file was uploaded
* gs.metadata - metadata that was saved with the file
* gs.chunkSize - chunk size
 
Example
 
gs.open(function(err, gs){
    console.log("this file was uploaded at "+gs.uploadDate);
});
 
== Writing to GridStore ==
Writing can be done with write
 
gs.write(data, callback)
 
where data is a Buffer or a string, callback gets two parameters - an error object (if error occured) and result value which indicates if the write was successful or not.
 
While the GridStore is not closed, every write is appended to the opened GridStore.
 
== Writing a file to GridStore ==
This function opens the GridStore, streams the contents of the file into GridStore, and closes the GridStore.
 
gs.writeFile( file, callback )
 
where
 
* file is a file descriptor, or a string file path
* callback is a function with two parameters - error object (if error occured) and the GridStore object.
 
== Reading from GridStore ==
Reading from GridStore can be done with read
 
<nowiki>gs.read([size], callback)</nowiki>
 
where
 
* size is the length of the data to be read
* callback is a callback function with two parameters - error object (if an error occured) and data (binary string)
 
== Streaming from GridStore ==
You can stream data as it comes from the database using stream
 
<nowiki>gs.stream([autoclose=false])</nowiki>
 
where
 
* autoclose If true current GridStore will be closed when EOF and 'close' event will be fired
 
The function returns [http://nodejs.org/docs/v0.4.12/api/streams.html#readable_Stream read stream] based on this GridStore file. It supports the events 'read', 'error', 'close' and 'end'.
 
== Delete a GridStore ==
GridStore files can be unlinked with unlink
 
mongodb.GridStore.unlink(db, name, callback)
 
Where
 
* db is the database object
* name is either the name of a GridStore object or an array of GridStore object names
* callback is the callback function
 
== Closing the GridStore ==
GridStore needs to be closed after usage. This can be done with close
 
gs.close(callback)
 
== Check the existance of a GridStore file ==
Checking if a file exists in GridFS can be done with exist
 
mongodb.GridStore.exist(db, filename, callback)
 
Where
 
* db is the database object
* filename is the name of the file to be checked or a regular expression
* callback is a callback function with two parameters - an error object (if an error occured) and a boolean value indicating if the file exists or not
 
== Seeking in a GridStore ==
Seeking can be done with seek
 
gs.seek(position);
 
This function moves the internal pointer to the specified position.

Версия от 16:26, 16 октября 2016

Исходные данные

Для корректной работы DNS нем необходимо иметь настроенную сеть. DNS в текущей статье будет настроен на дистрибутиве Debian, особенности других дистрибутивов тоже будут отмечены. Конфиг сети стенда следующий:

dns:~# cat /etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
 address 10.0.0.152
 netmask 255.255.255.0
 gateway 10.0.0.254

auto eth1
iface eth1 inet static
 address 192.168.1.1
 netmask 255.255.255.0

где 10.0.0.152/24 - внешний интерфейс (подсеть, выделенная провайдером), 192.168.1.1/24 - внутренний (Локальная сеть). Настраиваемая зона будет иметь имя example.com. В примере со slave сервером, вторичный сервер будет расположен на IP 10.0.0.191.

Установка BIND9

Для работы DNS сервера необходимо установить пакет bind9 (в некоторых дистрибутивах - bind). Как отмечено на схеме - основным конфигурационным файлом BIND является файл named.conf (данный файл может быть размещен в каталоге /etc, иногда в /etc/bind ).

Параметры (синтаксис) named.conf

Синтаксис файла named.conf придерживается следующих правил:

IP-адреса - список IP должен быть разделен символом ";" , возможно указывать подсеть в формате 192.168.1.1/24 или 192.168.1.1/255.255.255.0, (для исключения IP перед ним нужно поставить знак !), возможно указывать имена "any", "none", "localhost" в двойных кавычках.

Комментарии - строки начинающиеся на #, // и заключенные в /* и */ считаются комментариями.

В файлах описания зон - символ @ является "переменной" хранящей имя зоны, указанной в конфигурационном файле named.conf или в директиве @ $ORIGIN текущего описания зоны.

Каждая завершенная строка параметров должна завершаться символом ; .

Раздел Acl Acl (access control list) - позволяет задать именованный список сетей. Формат раздела: acl "имя_сети" {ip; ip; ip; };

Раздел Options Раздел Options задает глобальные параметры конфигурационного файла, управляющие всеми зонами. Данный раздел имеет формат: options {операторы_раздела_Options};. Options может быть "вложен" в раздел Zone, при этом он переопределяет глобальные параметры. Часто используемые операторы options:

allow-query {список_ip} - Разрешает ответы на запросы только из список_ip. При отсутствии - сервер отвечает на все запросы.
allow-recursion {список_ip} - На запросы из список_ip будут выполняться рекурсивные запросы. Для остальных - итеративные. Если  не задан параметр, то сервер выполняет рекурсивные запросы для всех сетей.
allow-transfer {список_ip} - Указывает список серверов, которым разрешено брать зону с сервера (в основном тут указывают slave сервера)
directory /path/to/work/dir - указывает абсолютный путь к рабочему каталогу сервера. Этот оператор допустим только в разделе  options.
forwarders {ip порт, ip порт...} - указывает адреса хостов и если нужно порты, куда переадресовывать запросы (обычно тут указываются DNS провайдеров ISP).
forward ONLY или forward FIRST - параметр first указывает, DNS-серверу пытаться разрешать имена с помощью DNS-серверов, указанных в параметре forwarders, и лишь в случае, если разрешить имя с помощью данных серверов не удалось, то будет осуществлять попытки разрешения имени самостоятельно.
notify YES|NO - YES - уведомлять slave сервера об изменениях в зоне, NO - не уведомлять.
recursion YES|NO - YES - выполнять рекурсивные запросы, если просит клиент, NO - не выполнять (только итеративные запросы). Если ответ найден в кэше, то возвращается из кэша. (может использоваться только в разделе Options)

Раздел Zone Определяет описание зон(ы). Формат раздела: zone {операторы_раздела_zone}; Операторы, которые наиболее часто используются:

allow-update {список_ip} - указывает системы, которым разрешено динамически обновлять данную зону.
file "имя_файла" - указывает путь файла параметров зоны (должен быть расположен в каталоге, определенном в разделе options оператором directory)
masters {список_ip} -указывает список мастер-серверов. (допустим только в подчиненных зонах)
type "тип_зоны" - указывает тип зоны, описываемой в текущем разделе,тип_зоны может принимать следующие значения:
forward - указывает зону переадресации, которая переадресовывает запросы, пришедшие в эту зону.
hint - указывает вспомогательную зону (данный тип содержит информацию о корневых серверах, к которым сервер будет обращаться в случае невозможности найти ответ в кэше)
master - указывает работать в качестве мастер сервера для текущей зоны.
slave - указывает работать в качестве подчиненного сервера для текущей зоны.

Дополнительные параметры конфигурации Значения времени в файлах зон по умолчанию указывается в секундах, если за ними не стоит одна из следующих букв: S - секунды, M - минуты, H- часы, D - дни, W - недели. Соответственно, запись 2h20m5s будет иметь значение 2 часа 20 минут 5 секунд и соответствовать 8405 секунд.

Любое имя хоста/записи, не оканчивающиеся точкой считается неFQDN именем и будет дополнено именем текущей зоны. Например, запись domen в файле зоны examle.com будет развернуто в FQDN-имя domen.examle.com. .

В конфигурационных файлах BIND могут применяться следующие директивы:

$TTL - определяет TTL по-умолчанию для всех записей в текущей зоне.
$ORIGIN - изменяет имя зоны с указанного в файле named.conf. При этом, область действия данной директивы не распространяется  "выше" (то есть если файл включен директивой $INCLUDE, то область действия$ORIGN не распространяется на родительский)
$INCLUDE - включает указанный файл как часть файла зоны.

Для того чтобы локальный резолвер сервера тоже использовал локальный DNS, необходимо привести файл resolv.conf к следующему виду:

dns:~# cat /etc/resolv.conf
nameserver 127.0.0.1

Если в имени ресурсной записи встречается символ "*", то это он означает что вместо него можно подразумевать любую разрешенную последовательность символов. Такую запись называют "wildcard запись". Однако, символ "*" не может быть использован где угодно. Это может быть только первый символ в поле Name текущего домена, отделенный от остальных символом "."

Настройка кэширующего DNS сервера

После установки bind, он полностью готов работать как кэширующий DNS сервер без дополнительной настройки. Единственный недостаток - он обрабатывает запросы на всех интерфейсах, что нам абсолютно не нужно, поэтому мы немного подредактируем настройки сервера.

Для того, чтобы BIND работал в качестве кэширующего сервера, необходимо иметь конфигурационные файлы заполненные необходимой информацией:

named.conf;
описание серверов корневой зоны (зона типа hint);
описание зоны 127.in-addr.arpa.
dns:~# cat /etc/bind/named.conf
acl "lan" {
           192.168.1.1/24;
           127.0.0.1;
};

options {
           directory "/var/cache/bind";

          // If there is a firewall between you and nameservers you want
          // to talk to, you may need to fix the firewall to allow multiple
          // ports to talk.  See http://www.kb.cert.org/vuls/id/800113
          /*
          * Тут сказано, что если используется фаерволл, то необходимо
          *  нашему серверу создать соответствующие правила
          *  то есть открыть доступ по 53 TCP и UDP порту
          */

          forward first;              // задаем пересылку только первого запроса

          forwarders {                // указываем DNS сервера для пересылки
                     83.239.0.202;    // предоставленные провайдером
                     213.132.67.110;  // ибо до них ближе чем до корневых
          };

         listen-on { lan; };        // пусть слушает только нужные интерфейсы
         allow-query { lan; };      // разрешить запросы только из локальной сети
         allow-recursion { lan; };  // рекурсивные запросы тоже только из локальной
         allow-transfer { none; };  // трансфер зон нам не нужен

         version "unknown";         // не отображать версию DNS сервера при ответах

         auth-nxdomain no;    # для совместимости RFC1035
         listen-on-v6 { none; };    //IPv6 нам не нужен
         };

// описание настроек корневых серверов
zone "." {
         type hint;
         file "db.root";
};

// нижеописанные зоны определяют сервер авторитетным для петлевых
// интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)

zone "localhost" {
         type master;
         file "localhost";
};

zone "127.in-addr.arpa" {
         type master;
          file "127.in-addr.arpa";
};

zone "0.in-addr.arpa" {
         type master;
         file "0.in-addr.arpa";
};

zone "255.in-addr.arpa" {
         type master;
         file "255.in-addr.arpa";
};

В данном примере приведен кэширующий DNS сервер, обрабатывающий запросы из списка сетей lan, в которую входит только одна локальная сеть 192.168.1.1/24 и петлевой интерфейс. При необходимости можно включить туда и другие сети. После определения списка сетей в директиве acl, в любом месте конфига можно будет ссылаться на этот список по имени (в нашем примере имя - lan), что, собственно и сделано в разделе options. Большинство параметров я прокомментировал, но отдельного внимания требует раздел, описывающий зону корневых серверов. В параметре file задан относительный путь к файлу описания корневых серверов (путь, относительно рабочего каталога сервера). За обновлениями данного файла необходимо следить, хотя он обновляется довольно редко (откуда брать обновленный файл я писал в теории DNS). Как вы заметили, имеется так же две записи для зоны localhost и две записи обратных зон для бродкаст доменов. Назначение этих зон состоит в том, чтобы избежать трансляции случайных запросов имен соответствующих IP-адресов на серверы, обслуживающие корневую зону.

Чтобы не вносить неразбериху в куче конфигурационных файлов, в статье я привожу примеры на основе единого конфигурационного файла. На самом деле, в последних версиях Debian (и других дистрибутивах Linux), файл named.conf выглядит следующим образом:

root@master:~# cat /etc/bind/named.conf // This is the primary configuration file for the BIND DNS server named. // // Please read /usr/share/doc/bind9/README.Debian.gz for information on the // structure of BIND configuration files in Debian, *BEFORE* you customize // this configuration file. // // If you are just adding zones, please do that in /etc/bind/named.conf.local

include "/etc/bind/named.conf.options"; include "/etc/bind/named.conf.local"; include "/etc/bind/named.conf.default-zones"; То есть основной файл не содержит конфигураций, а включает в себя более узко специализированные файлы, которые отвечают за свои задачи, например named.conf.options - содержит глобальные параметры конфигурации, named.conf.default-zones - содержит описание localhost и broadcast зон, а named.conf.local содержит описания зон, за которые отвечает данный сервер.


Далее, хочу обратить внимание на наличие файлов зон в каталоге, указанном в разделе options в параметре directory с именами, соответствующими параметрам file в разделах, описывающих зоны:

dns:~# ls -l /var/cache/bind/ итого 24 -rw-r--r-- 1 root root 237 Май 28 01:28 0.in-addr.arpa -rw-r--r-- 1 root root 271 Май 28 01:28 127.in-addr.arpa -rw-r--r-- 1 root root 237 Май 28 01:28 255.in-addr.arpa -rw-r--r-- 1 root root 2994 Май 28 01:28 db.root -rw-r--r-- 1 root root 270 Май 28 01:28 localhost dns:~# cat /var/cache/bind/127.in-addr.arpa

BIND reverse data file for local loopback interface

$TTL 604800 @ IN SOA localhost. root.localhost. (

                             1         ; Serial
                             604800    ; Refresh
                             86400     ; Retry
                             2419200   ; Expire
                             604800 )  ; Negative Cache TTL

@ IN NS localhost. 1.0.0 IN PTR localhost. Рассматривать файлы "петлевых" и бродкастовых зон не вижу смысла, т.к. после установки пакета bind настройки заданные по умолчанию в данных файлах вполне приемлемы. Далее, при организации мастер сервера мы рассмотрим пример описания файла зоны. Хочу обратить внимание, что мы настраиваем кэширующий сервер, а определяем мы его и как master для некоторых из зон. В нашем случае "кэширующий" говорит о том, что наш сервер не поддерживает ни одну из реально существующих зон, т.е. ему не делегировано прав на такое обслуживание.

Да, чуть не забыл, демон named должен быть разрешен для запуска на необходимых уровнях выполнения ОС (команда в RedHat - /sbin/chkconfig bind9 on, в Debian - /usr/sbin/update-rc.d bind9 defaults). После изменения конфигурационных файлов можно добавить сервис в автозагрузку и запустить демон:

dns:~# update-rc.d bind9 defaults Adding system startup for /etc/init.d/bind9 ... /etc/rc0.d/K20bind9 -> ../init.d/bind9 /etc/rc1.d/K20bind9 -> ../init.d/bind9 /etc/rc6.d/K20bind9 -> ../init.d/bind9 /etc/rc2.d/S20bind9 -> ../init.d/bind9 /etc/rc3.d/S20bind9 -> ../init.d/bind9 /etc/rc4.d/S20bind9 -> ../init.d/bind9 /etc/rc5.d/S20bind9 -> ../init.d/bind9 dns:~# /etc/init.d/bind9 start Starting domain name service...: bind9. На этом настройка кэширующего DNS завершена. Все запросы, которые попадают в кэш DNS сервера он хранит в оперативной памяти компьютера и при перезапуске демона эти данные обнуляются. Для проверки работы кэша можно выполнить команду nslookup mail.ru example.com., если в ответе содержится строка Non-authoritative answer, то адрес пришел из кэша, а так же если выполнить dig www.ru. (или другой домен, которого еще нет в кэше) и через некоторое время повторить команду, то время ответа должно быть гораздо меньше.

Давайте рассмотрим другие варианты сервера.

Главный (master) сервер зоны

Основной конфиг содержит следующие настройки:

dns:~# cat /etc/bind/named.conf acl "lan" {

         192.168.1.1/24;
         127.0.0.1;

};

options {

         directory "/var/cache/bind";
         allow-query { any; };       // отвечать на зпросы со всех интерфейсов
         recursion no;               // запретить рекурсивные запросы
         auth-nxdomain no;           // для совместимости RFC1035
         listen-on-v6 { none; };     // IPv6 нам не нужен
         version "unknown";          // не отображать версию DNS сервера при ответах
         /*
         *  Раскомментируйте строки ниже, если
         *  хотите разрешить рекрусивные запросы
         *  из локальной сети.
         *  (так же, необходимо закомментировать
         *  recursion no; )
         */
         # forwarders {                 // указываем DNS сервера для пересылки
         #         83.239.0.202;        // предоставленные провайдером
         #         213.132.67.110;      // ибо до них ближе чем до корневых
         # };
         # allow-recursion { lan; };    // рекурсивные запросы тоже только из локальной

};

// описание настроек корневых серверов zone "." {

         type hint;
         file "db.root";

};

// нижеописанные зоны определяют сервер авторитетным для петлевых // интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)

zone "localhost" {

         type master;
         file "localhost";

};

zone "127.in-addr.arpa" {

         type master;
         file "127.in-addr.arpa";

};

zone "0.in-addr.arpa" {

         type master;
         file "0.in-addr.arpa";

};

zone "255.in-addr.arpa" {

         type master;
         file "255.in-addr.arpa";

};

// описание основной зоны zone "example.com" {

         type master;
         file "example.com";
         allow-transfer { 10.0.0.191; };

};

//описание обратных зон zone "0.0.10.in-addr.arpa" {

         type master;
         file "0.0.10.in-addr.arpa";
         allow-transfer { 10.0.0.191; };

};

zone "1.168.192.in-addr.arpa" {

         type master;
         file "1.168.192.in-addr.arpa";
  1. allow-transfer { 10.0.0.191; }; // зона описывает локальную сеть поэтому ее не передаем

};

// настройки логирования logging {

         channel "misc" {
                   file "/var/log/bind/misc.log" versions 4 size 4m;
                   print-time yes;
                   print-severity yes;
                   print-category yes;
         };
         channel "query" {
                   file "/var/log/bind/query.log" versions 4 size 4m;
                   print-time yes;
                   print-severity no;
                   print-category no;
         };
         category default {
                   "misc";
         };
         category queries {
                   "query";
         };

}; Давайте кратко разберем конфигурационный файл и настройки master сервера: мы настраиваем мастер сервер для зоны example.com. . Согласно конфига, наш BIND имеет рабочий каталог /var/cache/bind, сервер отвечает на запросы со всех интерфейсов (allow-query {any ;};), рекурсивные запросы обрабатывает как итеративные (recursion no), является мастер-сервером для зоны example.com и локальных служебных зон (type master). При этом, если необходимо разрешить кэширование (то есть рекурсивные запросы) для локальной сети, то необходимо раскомментировать параметры forwarders и allow-recursion и закомментировать recursion no;.

Так же, для примера, я привел возможности BIND логировать все происходящее при работе сервера (можно для этой цели использовать syslog). В разделе logging задаются 2 параметра channel (можно и больше двух - на ваше усмотрение), эти параметры дословно можно назвать "канал" записи. Каждый канал определяет имя канала и настройки параметров записи (что записывать, а что - нет и куда писать). Директива category задает какую категорию сообщений в какой канал отправлять. Исходя из этого, мы имеем: запись стандартной информации в канал misc, а приходящие запросы посылаются в канал query. При этом, если файлы журнала достигают 4Мб (size 4m), он переименовывается добавлением к имени .1 и начинается запись в новый журнал, числа в конце других журналов увеличиваются. Журналы с номером, более указанного в version (в нашем случае 4) удаляются (Управлять ротацией логов можно так же с помощью logrotate). Параметры print* определяют заносить ли в журнал время появления, важность и категорию информации. Более подробно про настройки раздела logging можно почитать в man (5) named.conf.

Отдельно хочется описать параметр allow-transfer { 10.0.0.191; };. Данный параметр описывает серверы, которым разрешено скачивать копию зоны - т.н. slave серверА. В следующем примере мы разберем настройку slave DNS.

Для корректной работы логирования необходимо создать соответствующий каталог и присвоить необходимые права:

dns:~# mkdir /var/log/bind/ dns:~# chmod 744 /var/log/bind/ dns:~# ps aux | grep named bind 4298 0.0 3.4 46792 13272 ? Ssl Jul05 0:00 /usr/sbin/named -u bind root 4815 0.0 0.1 3304 772 pts/4 S+ 18:19 0:00 grep named dns:~# chown bind /var/log/bind/ dns:~# ls -ld /var/log/bind/ drwxr--r-- 2 bind root 4096 Июл 6 18:18 /var/log/bind/ Давайте далее рассмотрим наш файл описания зоны example.com.:

dns:~# cat /var/cache/bind/example.com $TTL 3D @ IN SOA ns.example.com. root.example.com. (

                                       2011070601      ; serial
                                       8H              ; refresh
                                       2H              ; retry
                                       2W              ; expire
                                       1D)             ; minimum

@ IN NS ns.example.com. @ IN NS ns2.example.com. @ IN A 10.0.0.152 @ IN MX 5 mx.example.com. ns IN A 10.0.0.152 ns2 IN A 10.0.0.191 mx IN A 10.0.0.152 www IN CNAME @ а так же в домене in-addr.arpa.

dns:~# cat /var/cache/bind/0.0.10.in-addr.arpa $TTL 3600 @ IN SOA ns.examle.com. root.example.com. (

            2007042001 ; Serial
            3600       ; Refresh
            900        ; Retry
            3600000    ; Expire
            3600 )     ; Minimum
       IN      NS      ns.examle.com.
       IN      NS      ns2.example.com.

152 IN PTR examle.com. 191 IN PTR ns.example.com.

  • IN PTR examle.com.

dns:~# cat /var/cache/bind/1.168.192.in-addr.arpa $TTL 3600 @ IN SOA ns.examle.com. root.example.com. (

            2007042001 ; Serial
            3600       ; Refresh
            900        ; Retry
            3600000    ; Expire
            3600 )     ; Minimum
       IN      NS      ns.examle.com.
       IN      NS      ns2.example.com.
  • IN PTR examle.com.

Наша сеть небольшая, предполагается, что в сети совсем мало машин. Все сервисы сети размещены на одном хосте example.com., поэтому и master DNS (ns.example.com.) и почтовый сервер (mx.example.com.) указывает на одну машину (10.0.0.152).

Вторичный (secondary, slave) авторитетный сервер зоны

Основная функция slave сервера - автоматическая синхронизация описания зоны с master сервером. Данная задача регламентируется документом RFC 1034 в разделе 4.3.5. Согласно данному документу обмен данными между серверами рекомендовано производить по протоколу TCP, посредством запроса AXFR. По этому запросу за одно TCP соединение должна передаваться вся зона целиком (RFC 1035).

Так же, slave DNS-сервер делит нагрузку с master сервером или принимает на себя всю нагрузку в случае аварии па первом сервере.

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

root@debian:~# dig @10.0.0.152 example.com. axfr

<<>> DiG 9.7.3 <<>> @10.0.0.152 example.com. axfr
(1 server found)
global options
+cmd

example.com. 259200 IN SOA ns.example.com. root.example.com. 2011070801 28800 7200 1209600 86400 example.com. 259200 IN NS ns.example.com. example.com. 259200 IN NS ns2.example.com. example.com. 259200 IN A 10.0.0.152 example.com. 259200 IN MX 5 mx.example.com. mx.example.com. 259200 IN A 10.0.0.152 ns.example.com. 259200 IN A 10.0.0.152 ns2.example.com. 259200 IN A 10.0.0.191 www.example.com. 259200 IN CNAME example.com. example.com. 259200 IN SOA ns.example.com. root.example.com. 2011070801 28800 7200 1209600 86400

Query time
14 msec
SERVER
10.0.0.152#53(10.0.0.152)
WHEN
Fri Jul 8 15:33:54 2011
XFR size
11 records (messages 1, bytes 258)

Получение зоны прошло успешно. Далее, для настройки подчиненного сервера, алгоритм следующий:

Скопировать конфигурационный файл named.conf с master сервера; Заменить параметр type master на type slave в тех зонах, для которых он будет вторичным; Параметр allow-transfer { 10.0.0.191; }; заменить на masters { 10.0.0.152;}; в тех зонах, для которых он будет вторичным; Удалить зоны, которые не будет обслуживать текущий сервер, в том числе и корневую, если slave не будет отвечать на рекурсивные запросы; Создать каталоги для логов, как в предыдущем примере. Итого, мы получаем конфиг slave сервера:

root@debian:~# cat /etc/bind/named.conf options {

         directory "/var/cache/bind";
         allow-query { any; };      // отвечать на запросы со всех интерфейсов
         recursion no;              // запретить рекурсивные запросы
         auth-nxdomain no;          // для совместимости RFC1035
         listen-on-v6 { none; };    // IPv6 нам не нужен
         version "unknown";         // не отображать версию DNS сервера при ответах

};

// нижеописанные зоны определяют сервер авторитетным для петлевых // интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)

zone "localhost" {

         type master;
         file "localhost";

};

zone "127.in-addr.arpa" {

         type master;
         file "127.in-addr.arpa";

};

zone "0.in-addr.arpa" {

         type master;
         file "0.in-addr.arpa";

};

zone "255.in-addr.arpa" {

         type master;
         file "255.in-addr.arpa";

};

// описание основной зоны zone "example.com" {

         type slave;
         file "example.com";
         masters { 10.0.0.152; };

};

//описание обратной зоны zone "0.0.10.in-addr.arpa" {

         type slave;
         file "0.0.10.in-addr.arpa";
         masters { 10.0.0.152; };

};

// настройки логирования logging {

         channel "misc" {
                   file "/var/log/bind/misc.log" versions 4 size 4m;
                   print-time YES;
                   print-severity YES;
                   print-category YES;
         };
         channel "query" {
                   file "/var/log/bind/query.log" versions 4 size 4m;
                   print-time YES;
                   print-severity NO;
                   print-category NO;
         };
         category default {
                   "misc";
         };
         category queries {
                   "query";
         };

}; после перезапуска наш slave сервер благополучно скопирует необходимую ему информацию с главного сервера, о чем будет говорить наличие файлов в каталоге:

root@debian:~# ls -la /var/cache/bind/ итого 28 drwxrwxr-x 2 root bind 4096 Июл 8 18:47 . drwxr-xr-x 10 root root 4096 Июл 8 15:17 .. -rw-r--r-- 1 bind bind 416 Июл 8 18:32 0.0.10.in-addr.arpa ...... -rw-r--r-- 1 bind bind 455 Июл 8 18:32 example.com ........ В принципе,/stroallow-transfer {pngp slave сервер может не хранить копию зоны у себя в файловой системе. Эта копия нужна только в момент старта DNS. Наличие копии зоны в файловой системе может избавить от сбоя при недоступности master сервера во время запуска slave DNS. Если не указать опцию file в разделе zone, то копия не создается.

Настройка netfilter (iptables) для DNS BIND

Собственно, настроив работу сервера, неплохо было бы его защитить. Мы знаем, что сервер работает на 53/udp порту. Почитав статью о том, что такое netfilter и правила iptables и ознакомившись с практическими примерами iptables, можно создать правила фильтрации сетевого трафика:

dns ~ # iptables-save

  1. типовые правила iptables для DNS
  • filter
INPUT DROP [7511:662704]
FORWARD DROP [0:0]
OUTPUT DROP [0:0]

-A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP

  1. разрешить доступ локальной сети к DNS серверу:

-A INPUT -s 192.168.1.1/24 -d 192.168.1.1/32 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT -A OUTPUT -o lo -j ACCEPT -A OUTPUT -p icmp -j ACCEPT -A OUTPUT -p udp -m udp --sport 32768:61000 -j ACCEPT -A OUTPUT -p tcp -m tcp --sport 32768:61000 -j ACCEPT -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

  1. разрешить доступ DNS серверу совершать исходящие запросы

-A OUTPUT -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT COMMIT Это типовой пример! Для задания правил iptables под Ваши задачи и конфигурацию сети, необходимо понимать принцип работы netfilter в Linux, почитав вышеуказанные статьи.

Устранение неполадок

Основным источником для выявления проблем с DNS является системный лог. Вот пример ошибок при запуске, когда я ошибся с путем к файлу зоны коревых серверов:

Jul 5 18:12:43 dns-server named[4224]: starting BIND 9.7.3 -u bind Jul 5 18:12:43 dns-server named[4224]: built with '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' '--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' '--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' '--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE -O2' 'LDFLAGS=' 'CPPFLAGS=' Jul 5 18:12:43 dns-server named[4224]: adjusted limit on open files from 1024 to 1048576 Jul 5 18:12:43 dns-server named[4224]: found 1 CPU, using 1 worker thread Jul 5 18:12:43 dns-server named[4224]: using up to 4096 sockets Jul 5 18:12:43 dns-server named[4224]: loading configuration from '/etc/bind/named.conf' Jul 5 18:12:43 dns-server named[4224]: reading built-in trusted keys from file '/etc/bind/bind.keys' Jul 5 18:12:43 dns-server named[4224]: using default UDP/IPv4 port range: [1024, 65535] Jul 5 18:12:43 dns-server named[4224]: using default UDP/IPv6 port range: [1024, 65535] Jul 5 18:12:43 dns-server named[4224]: listening on IPv4 interface lo, 127.0.0.1#53 Jul 5 18:12:43 dns-server named[4224]: listening on IPv4 interface eth1, 192.168.1.1#53 Jul 5 18:12:43 dns-server named[4224]: generating session key for dynamic DNS Jul 5 18:12:43 dns-server named[4224]: could not configure root hints from '/etc/bind/db.root': file not found Jul 5 18:12:43 dns-server named[4224]: loading configuration: file not found # файл не найден Jul 5 18:12:43 dns-server named[4224]: exiting (due to fatal error) Jul 5 18:15:05 dns-server named[4298]: starting BIND 9.7.3 -u bind Jul 5 18:15:05 dns-server named[4298]: built with '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' '--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' '--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' '--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE -O2' 'LDFLAGS=' 'CPPFLAGS=' Jul 5 18:15:05 dns-server named[4298]: adjusted limit on open files from 1024 to 1048576 Jul 5 18:15:05 dns-server named[4298]: found 1 CPU, using 1 worker thread Jul 5 18:15:05 dns-server named[4298]: using up to 4096 sockets Jul 5 18:15:05 dns-server named[4298]: loading configuration from '/etc/bind/named.conf' Jul 5 18:15:05 dns-server named[4298]: using default UDP/IPv4 port range: [1024, 65535] Jul 5 18:15:05 dns-server named[4298]: using default UDP/IPv6 port range: [1024, 65535] Jul 5 18:15:05 dns-server named[4298]: listening on IPv4 interface lo, 127.0.0.1#53 Jul 5 18:15:05 dns-server named[4298]: listening on IPv4 interface eth1, 192.168.1.1#53 Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 254.169.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 2.0.192.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 100.51.198.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 113.0.203.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 255.255.255.255.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: D.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 8.E.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 9.E.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: A.E.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: B.E.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 8.B.D.0.1.0.0.2.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: zone 0.in-addr.arpa/IN: loaded serial 1 Jul 5 18:15:05 dns-server named[4298]: zone 127.in-addr.arpa/IN: loaded serial 1 Jul 5 18:15:05 dns-server named[4298]: zone 255.in-addr.arpa/IN: loaded serial 1 Jul 5 18:15:05 dns-server named[4298]: zone localhost/IN: loaded serial 2 Jul 5 18:15:05 dns-server named[4298]: running # запуск прошел удачно Отличным инструментом для диагностики являются команды диагностики DNS.