Классика баз данных - статьи

       

DBInputFormat


Основная идея состоит в том, что программист MapReduce через класс DBInputFormat представляет SQL-запрос. Последующее выполнение производится реализацией DBInputFormat и является прозрачным для программиста MapReduce. Класс DBInputFormat ассоциирует некоторый модифицированный SQL-запрос с каждым Mapper'ом, запущенным Hadoop. Затем каждый Mapper посылает запрос в СУБД через стандартный драйвер JDBC, получает в ответ часть результатов запроса и в параллель с другими Mapper'ами обрабатывает результаты. Подход DBInputFormat является корректным, поскольку объединение всех запросов, посылаемых всеми Mapper'ами, эквивалентно исходному SQL-запросу.

В подходе DBInputFormat обеспечиваются два интерфейса для обеспечения прямого доступа программам MapReduce к данным из СУБД. Мы посмотрели на исходный код реализации подхода DBInputFormat. Основная реализация является одной и той же для обоих интерфейсов. Эту реализацию можно резюмировать следующим образом. В первом интерфейсе программа MapReduce обеспечивает имя пользователя, пароль и URL СУБД, а также имя таблицы T, список P имен столбцов, которые следует выбрать, необязательные фильтрующие условия C и список имен столбцов O для использования в разделе ORDER BY. Реализация DBInputFormat сначала генерирует запрос "SELECT count(*) from T where C" и посылает его в СУБД для получения числа строк (R) в таблице T. Во время выполнения реализация DBInputFormat знает число Mapper'ов (M), запущенных Hadoop (это число либо обеспечивается пользователем в командной строке, либо берется из конфигурационного файла Hadoop) и ассоциирует с каждым Mapper'ом следующий запрос Q. Каждый Mapper подключается к СУБД, посылает Q через JDBC-подключение и получает результаты.

SELECT P FROM T WHERE C ORDER BY O LIMIT L

OFFSET X (Q)

При получении запроса Q СУБД реально выполняет запрос SELECT P FROM T WHERE C ORDER BY O, но возвращаются только L строк результата со смещением X. M запросов, посылаемых в СУБД M Mapper'ами, являются почти идентичными, за исключением того, что значения L и X в них различны.
Для i-го Mapper'а (где 1 ≤ i ≤ M - 1), который не является последним Mapper'ом, L = ⌊R / M⌋, и X = (i - 1) × ⌊R / M⌋. Для последнего Mapper'а L = R - (M - 1) × ⌊R / M⌋, и X = (M - 1) × ⌊R / M⌋.

Во втором интерфейсе класса DBInputFormat программа MapReduce может предоставить произвольный SQL-запрос SQ на выборку данных, результаты которого являются входными данными для Mapper'ов. В этом случае программа MapReduce должна предоставить и запрос со счетчиком (count query) QC, который должен возвращать целочисленное значение, являющееся числом строк в результате запроса SQ. Класс DBInputFormat посылает в СУБД запрос QC, чтобы получить число строк (R), а дальнейшая обработка – та же самая, что и в первом интерфейсе.

Хотя понятно, что подход DBInputFormat, обеспечиваемый компанией Claudera, упрощает процесс доступа к реляционным данным, он не обеспечивает должного роста производительности при увеличении числа Mapper'ов. С подходом DBInputFormat связано несколько проблем производительности. В обоих интерфейсах каждый Mapper для получения своего поднабора реляционных данных посылает в СУБД, по существу, один и тот же запрос, только с разными значениями в разделах LIMIT и OFFSET. Требуются и указываются программой MapReduce столбцы упорядочивания, которое используется для корректного разделения результатов запроса между всеми Mapper'ами, даже если самой программе MapReduce не нужны отсортированные входные данные. За счет этого достигается параллельность обработки реляционных данных Mapper'ами. СУБД приходится выполнять столько запросов, сколько Mapper'ов имеется в системе Hadoop, и, конечно, это не эффективно, особенно, если число Mapper'ов велико.

Отмеченные проблемы производительности особенно серьезны для параллельной СУБД, в которой, как правило, имеются много одновременно выполняемых запросов и крупные наборы данных. Кроме того, требуемое упорядочивание/сортировка – это дорогостоящая операция в параллельных СУБД, поскольку строки таблицы не сохраняются в каком-либо одном узле, и для сортировки требуется перераспределение строк по узлам.


Содержание раздела