2009-07-20

ZF + Горизонтальная масштабируемость

Написал адапnер для ZF предоставляющий функционал горизотального маштабирования данных бд. Основной зарачей горизотального маштабирования является возможно разнесения бд, путем разрезания таблиц с данными на части. Таким образом появляется возможность гибко маштабировать операции записи, выборки из больших таблиц содержащих свыше 10 млн. записей или размером свыше 5 Гб.

Примеры (можно также посмотреть тесты):
Создание и конфигурирование адаптера:



$db = new Core_Db_Adapter_Scale(array(
//список таблиц с которыми работает адаптер
"tables" => array(
"users" => array(
"scale"=> array(
// по какому полю ведется скайлинг
"field" => "id",
// какую стратегию использовать
"strategy" => "Core_Db_Adapter_Scale_Strategy",
),
"primary" => array(
// примари ключ
"field"=>"id",
// включить эмуляцию автоинкремента
"autogenerate" => true,
// стратегия генерации автонреметного ключа
"strategy" => "Core_Db_Adapter_Scale_Primary_Generate_Strategy"
)
),
),
// список шардов (соединений к БД в которых располагаются данные)
"shards" => array(
0 => Zend_Db::factory(
"Pdo_Mysql",
array(
"host" => "127.0.0.1",
"username" => "root",
"password" => "",
"dbname" => "test1",
)
),
1 => Zend_Db::factory(
"Pdo_Mysql",
array(
"host" => "127.0.0.1",
"username" => "root",
"password" => "",
"dbname" => "test2",
)
),
)));


Пример работы с стандартным ОРМ:

class Users extends Zend_Db_Table_Abstract {}

$Users = new Users($db);

$Users->insert(array("name"=>"joseph"));

$UsersRowset = $Users->find(1);
$User = $UsersRowset->current();
$User->name = "peter";
$User->save();

Тоесть никаких отличий для приложения нет. что используется стандарный один адаптер, что используется Core_Db_Adapter_Scale. Что позволяет гибко внедрять туда где он нужен без переписывания большой чати приложения.

Бонусы:
  1. Возможность хранить в таблице неограниченое количество строк милиарды и более
  2. Возможность хранить в таблице неограниченое количесво данных Тб и более
  3. Возможность гибко размазывать нагрузку по всем шардам
  4. Возможность задать неграниченое количество частей разбиения
  5. Адаптер не зависит от БД, в качестве шардом может использоваться любая БД
  6. Возможность задания пользовательского алгоритма выбора шарда
  7. Эмуляция автоикрементного поля
  8. Интерфейс Zend_Db_Adapter

Ограничения:
  1. Во всех запросах требутся использовать поле по которому идет скайлинг.
  2. Не возможность выборки всех данных из таблицы
  3. Не возможность JOIN

Исходные коды: #svn/trunk/Vendor/Core/Db/Adapter

Глосарий
Горизонтальная масштабируемость
Разбиение системы на более мелкие структурные компоненты и разнесение их по отдельным физическим машинам (или их группам) и/или увеличение количества серверов параллельно выполняющих одну и ту же функцию. Подробнее ...

2009-07-03

Как работает MogileFS


  • Установка.

  • Настройка.

  • Основные понятия Хост/Устройство Домен/Класс. Как хранятся данные и каким образом отдаются.

  • Внутреннее устройство.

  • Выводы.


Установка


Весь процесс установки для Ubuntu можно прочесть тут: http://code.google.com/p/mogilefs/wiki/InstallOnUbuntu

Настройка


И привожу примеры своих рабочих конфигов (хранятся по-умолчанию в /etc/mogilefs).

---mogilefsd.conf ---
#daemonize = 1
db_dsn = DBI:mysql:mogilefs:host=127.0.0.1
db_user = root
#db_pass =
listen = 127.0.0.1:7001
conf_port = 7001
listener_jobs = 10
delete_jobs = 1
replicate_jobs = 5
mog_root = /mnt/mogilefs
reaper_jobs = 1

---mogstored.conf ---
maxconns = 10000
httplisten = 0.0.0.0:7500
mgmtlisten = 0.0.0.0:7501
docroot = /var/mogdata

Установить mogadm для администрования сервера MogileFS
Документация, исходные тексты и инструкция по инсталляции тут: http://search.cpan.org/~dormando/MogileFS-Utils/mogadm

Модуль для php: http://pecl.php.net/package/mogilefs/
Установка: http://projects.usrportage.de/index.fcgi/php-mogilefs/wiki/installation

Также по требуется nginx собранный с модулем mogilefs
Установка, конфигурация, исходники: http://grid.net.ru/nginx/mogilefs.ru.html
Стоит учесть, что порт трекера по-умолчанию 7001, в случае другого порта требуется указать его в настройках nginx

Основные понятия Хост/Устройство Домен/Класс. Как хранятся данные и каким образом отдаются.


domain> - глобальный неймспейс для трекера.
class - уникальный относительно домена идентификатор класса объекта, для которого могут быть настроены кастомные политики репликации. Обычно соответствует определенному типу файлов, скажем mp3, картинки.

host - физический сервер (коннектор трекера)
device - устройство для хранения данных при надлежащее некоторому хосту. На физическом уровне соответствует под папке в папке docroot(/var/mogdata) с соответствущим идентификатору названию + префикс dev (пример: dev1).

Для начала создадим хост:

# mogadm host add 127.0.0.1 --status=alive
# mogadm host list
127.0.0.1 [1]: alive
IP: 127.0.0.1:7500

Теперь добавим устройства с уникальным идентификатором "1" и "2" на сервере 127.0.0.1:

# mogadm device add 1 127.0.0.1 --status=alive
# mogadm device add 2 127.0.0.1 --status=alive
# mkdir /var/mogdata/dev1
# mkdir /var/mogdata/dev2
# chmod -R 700 /var/mogdata
# chown -R mogstored:nobody /var/mogdata
# cat /var/mogdata/dev1/usage
available: 13116348
device: /dev/sda6
disk: /var/mogdata/dev1
time: 1246615145
total: 21568432
use: 36%
used: 7356456

# mogadm device list
127.0.0.1 [1]: alive
used(G) free(G) total(G)
dev1: alive 7.016 13.553 20.568
dev2: alive 7.016 13.553 20.568

Все на этом законфилось конфигурирование физической части , теперь перейдем к добавлению домена (test) и класса(default1) с минимальным кочичеством копий данных на разных устройствах равным = 2

# mogadm domain add test
# mogadm class test default1 --mindevcount=2
# mogadm domain list
domain class mindevcount
-------------------- -------------------- -------------
test default1 2

Собственно все. На текущий момент у Вас работающая копия MogileFS с одним трекером 1 стораджем и 2 девайсами :)

Теперь напишем простой сркипт который положит себя в сторадж и достанет:

connect('127.0.0.1', 7001, 'test');
$client->put(__FILE__, 'self', 'default1');
$metadata = $client->get('self');
var_dump($metadata);
$client->close();
/*
array(3) {
["path2"]=>
string(51) "http://127.0.0.1:7500/dev2/0/000/000/0000000004.fid"
["path1"]=>
string(51) "http://127.0.0.1:7500/dev1/0/000/000/0000000004.fid"
["paths"]=>
string(1) "2"
}
*/

Тоесть видно что файлы хратся сразу на 2х устройствах, что соотвествует конфигурации, и их можно получить через веб напрямую с 7500 порта. Физически файлы также расположены оп приведенным путям. Балансирование через nginx позволяет стрыть реальные пути, и организовать контроль отдачи файлов, для защиты от скачивания или предоставления платного контента.

Внутреннее устройство





Рис. 1 Внутрее устройство MogileFS

Суть работы следующая существет множество трекеров и множество стораджей и всего одна база данных которая говрит, что и где сосбтвенно лежит.

Структура БД mogileFS

mysql> show tables;
+----------------------+
| Tables_in_mogilefs |
+----------------------+
| class | список классов
| device | список устройств
| domain | список доменов
| file | список файлов с уникальными ключами
| file_on | связка файл - устройство
| file_on_corrupt | связка файл -устройство
| file_to_delete | файлы для удаления
| file_to_delete_later | файлы для отложенного удаления
| file_to_replicate | файлы требующие репликации
| fsck_log | лог fsck
| host | список хостов
| server_settings | версия схемы данных
| tempfile | временные файлы
| unreachable_fids | битые файлы
+----------------------+


Put file:

  1. Файл загружается в трекер.

  2. Трекер создает запись в таблице file и загружает в сторадж после этого id файла помещается в таблицу file_to_replicate для репликации с другими серверами.

  3. Каждая реплика вычитает 1 из записи в таблице file_to_replicate. Производя копирование файла тебе отмечает в таблице file_on места хранения файла.

  4. Так продолжатся до тех пока запись в таблице file_to_replicate не достигнет 0, после чего запись удаляется и процесс реплицирования прекращается.



Get get:

  1. Идет подключение к одному из трекеров.

  2. Если файл не менялся данные берутся из кеша, если менялся трекер лезет в БД и смотрит где лежат файлы.

  3. После чего проверяется статус устройств alive/down

  4. Для живых устройств достаются сервера

  5. Трекер запрашивает сторадж для того, чтоб узнать жив он или нет.

  6. Найденные пути отдаются клиенту.


Выводы


Плюсы:

  • простота установки и поддержки

  • настройка параметров репликации

  • API библиотеки для всех популярных языков программирования


Минусы:

  • Как видно из архитектуры сервер БД - единая точка отказа. При выходе его из строя падает все.

  • Производительность решения ограничена производительностью сервера БД.

  • Не нативный интерфейс для загрузки и получения файлов.