Хоть Келлан и упомянул, что ticket серверы не являются чем-то особенно интересным, но учитывая тот факт, что они являются основными для генерации глобальных уникальных ключей, думаю узнать как они работают будет все-таки очень интересно.
Базовой технологией масштабирования баз данных Flickr является шардинг. Вместо хранения данных в одной большой базе данных, данные разделяются между серверами. Соответственно распределяется между ними и нагрузка. В данной ситуации появляется необходимость, чтобы первичные ключи были уникальны глобально для всего кластера во избежании коллизий ключей.
Можно задать вполне резонный вопрос: а почему бы не использовать GUID для этих целей? Основная причина заключается в том, что GIUD достаточно большой по размеру и индексация его в MySQL не самое лучшее решение. Размер ключа играет ключевое значение в больших системах хранения данных. Если нет возможности хранить индекс в памяти, соответственно возможности сохранения и увеличения быстродействие базы данных существенно снижаются.
Одно из самых эффективных методов генерации уникальных ключей - это авто инкремент первичных ключей, но проблема в том, что MySQL не обеспечивает уникальности ключа для физически и логически разнесенных баз данных. Основная идея решения данного вопроса, которое нашло применение в Flickr заключается в использовании централизованного сервера, обеспечивающего и контролирующего авто инкремент значений первичных ключей для всех баз данных (фотографий, комментариев, групп, пользователей, тегов и т.д.)
Рассмотрим детали решения. В MySQL есть нестандартное расширение ANSI SQL REPLACE INTO. Оно позволяет автоматически обновить строку в таблице базы данных и получить инкремент первичного ключа:
REPLACE INTO ticket (stub) VALUES (‘a’); RETURN LAST_INSERT_ID();
Flickr ticket сервер представляет собой выделенный сервер базы данных, в котором хранятся таблицы для генерации ключей
CREATE TABLE `tickets` ( `id` bigint unsigned NOT NULL auto_increment, `stub` char(1) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `stub` (`stub`) ) ENGINE=MyISAM;
SQL запрос SELECT * FROM tickets; возвращает одну единственную строку
mysql> select * from tickets; +--------+------+ | id | stub | +--------+------+ | 325688 | a | +--------+------+
Для упрощения генерации нового ключа можно воспользоваться следующей функцией
CREATE FUNCTION ticket() RETURNS BIGINT() BEGIN REPLACE INTO ticket (stub) VALUES (‘a’); RETURN LAST_INSERT_ID(); END
после этого получение ключа будет выглядеть
mysql> SELECT ticket(); +----------+ | ticket() | +----------+ | 325689 | +----------+
Конечно же наличие такого сервера приводит к появлению single point of failure. Для того чтобы избежать нарушение функционирования работы системы в целом в случае выхода ticket сервера, используется несколько ticket серверов. Для того, чтобы не возникало коллизий ключей, их пространство разделяют на части. Для случая Flickr, ticket серверов два, следовательно и пространство разделено на две части, один сервер генерирует четные ключи, другой нечетные.
TicketServer1: auto-increment-increment = 2 auto-increment-offset = 1 TicketServer2: auto-increment-increment = 2 auto-increment-offset = 2
Используя балансировку round robin между ticket серверами можно добиться разделения нагрузки и обеспечить отказоустойчивость системы в случае выхода из строя одного из серверов.
В качестве примера можно воспользоваться простым HTTP ticket сервером, который возвращает значение ticket в JSON формате
Зависимости: python, MySQLdb, asynchttpsrv
Запустить сервер: python ticketserver.py
Выполнить запрос на получение нового ключа: curl http://localhost:8080/
Пример возвращаемого результата: {"ticket":"62395"}



0 комментариев:
Отправить комментарий