Использование MongoDB в связке с PHP

В одном маленьком, но очень гордом проекте программисты столкнулись с производительностью классической реляционной базы данных PostgreSQL, оказалось, что она (база) не может быстро выбрать сотни тысяч строк, накопленные за много лет в один красивый отчёт быстро (например за несколько секунд), часто бывало, что php5-fpm просто убивал сессию по timeout.

Короче было решено перекинуть данные из таблицы PostgreSQL в которой они находились в MongoDB ну и на всякий случай настроить репликацию (о том как настраивать репликацию MongoDB я уже рассказывал). А также научить web-приложение (которое написано на языке PHP) в дальнейшем работать с Mongo.

Для ознакомления с общей концепцией:

http://ru.wikipedia.org/wiki/MongoDB

Полная официальная документация:

http://docs.mongodb.org/manual/tutorial/getting-started/

Установка MongoDB

Импортируем ключ репозитория пакетов

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10

Добавим в список источников репозиторий со свежей Mongo

echo 'deb http://downloads-distro.mongodb.org/repo/debian-sysvinit dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list

Обновим список пакетов и установим стабильную версию MongoDB, так как самые последние сборки (mongodb-org) имеют ряд критических ошибок (например нельзя создать пользователя, сломана авторизация и прочее подобное), не позволяющих использовать их на боевых серверах.

sudo apt-get update
sudo apt-get install mongodb-10get

(Не обязательно) Запретим системе выполнять обновление пакета с базой:

echo "mongodb-10get hold" | sudo dpkg --set-selections

Установка необходимых модулей PHP

Установка модуля для php (на новых дистрибутивах, например Debian 7.0):

sudo apt-get install php5-dev php5-mongo

Установка модуля для php (на старых дистрибутивах, например Debian 6.0):

sudo apt-get install php-pear php5-dev
sudo pecl install mongo

Настройка модулей PHP для работы с MongoDB

В конфигурационных файлах php.ini:

sudo mcedit /etc/php5/apache2/php.ini
sudo mcedit /etc/php5/cli/php.ini
sudo mcedit /etc/php5/fpm/php.ini

Нужно добавить строку:

extension=mongo.so

Управление пользователями сервера

Откроем командную строку для работы с базой и выполним переход в нужную базу:

$ mongo
> use testdb

Что интересно, если указанной базы данных нет - она будет создана автоматически если мы попытаемся что-то в ней делать, например создадим пользователя или коллекцию.

Пользователь с правами "read/write"

> db.addUser("test", "test_pwd123")

Пользователь с правами "readonly"

> db.addUser("new", "webinar111", true)

Третий аргумент функции addUser задаёт тип доступа для пользователя (по умолчанию - false).

Изменение пароля пользователя

Обновление пароля выглядит ровно так же как и создание пользователя.

> db.addUser("new", "new^QWE", true)

Удаление пользователя

Все наши пользователи расположены тут system.users. Для их удаления нужно выполнить:

> db.system.users.remove({"user" : "new"});

Авторизация в MongoDB по умолчанию для всех

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

sudo mcedit /etc/mongodb.conf

Найдём и исправим в нём одну строку

auth = true

После чего сохраним изменения в конфиге и перезапустим базу данных:

sudo /etc/init.d/mongodb restart

Оптимизация работы MongoDB (создание индексов)

Нам известно, что очень часто в некоторой коллекции countrys необходимо искать данные отсортированные по date_add, но если данных много, то как правило скорость работы существенно падает. Для того чтобы этого не происходило воспользуемся индексацией коллекции по полю date_add.

Отобразим список индексов:

> db.countrys.getIndexes()

Проиндексируем:

> db.countrys.ensureIndex({"date_add":1})

Подключение к MongoDB из PHP

Простейший класс работы с базой MongoDB из PHP, сохраним его в файл Database_Mongo.class.php:

class Database_Mongo {
public function __construct($Hostname, $Port, $Database, $Username, $Password) {
// Stupid spike-hack
global $mongo_db;
global $mongo_database;
// Store database name
$mongo_database = $Database;
// Connect to database
$mongo_db = new Mongo("mongodb://$Username:$Password@$Hostname:$Port/$Database");
}
public function select_collection($collection) {
// Stupid spike-hack
global $mongo_db;
global $mongo_database;
// Select collection
return $mongo_db->selectCollection($mongo_database,$collection);
}
}

Как видно, тут нет ничего лишнего, только подключение и выбор таблицы (коллекции).

Как подключить в коде

Сначала подключимся, потом выберем коллекцию:

// Тут подключаем класс
define('__ROOT__', dirname(dirname(__FILE__)));
require_once(__ROOT__.'/Database_Mongo.class.php');
// Тут создаём подключение к базе
$mongo = new Database_Mongo($Hostname, $Port, $Database, $Username, $Password);
// Тут выбираем нужную коллекцию
$db = $mongo->select_collection('countrys');