Развитие рынка систем управления базами данных (СУБД) привело к тому, что разошедшиеся «по идейным соображениям» в начале 2000-х годов классические реляционные и NoSQL решения, спустя 15 лет стремятся перенять лучшие свойства друг друга. В погоне за эффективностью разработчики in-memory СУБД хотят убрать из памяти на диск неиспользуемые данные и тем самым повысить эффективность работы системы. А создатели классических СУБД по той же самой причине хотят быстрее работать в случае, когда данные обрабатываются исключительно или преимущественно в памяти. Но пока что никто из гигантов рынка не достиг на этом пути значительных результатов.
Начиная с 2017 года, коллектив Центра разработки СУБД воронежской компании РЕЛЭКС создаёт собственную вычислительную среду – платформу для построения готового продукта. При проектировании системы мы исходили из предпосылок, что достичь по-настоящему выдающихся результатов можно при соблюдении двух условий:
На данный момент нами разработан прототип, подтверждающий возможность комбинации неблокирующих и блокирующих алгоритмов. Сформированы ключевые API и примитивы платформы. Разработан прототип транзакционного кешируемого B+-tree хранилища. Прототип протестирован по сценарию Hammer DB – варианту общепринятого индустриального стандарта TPC-C. Согласно результатам тестирования, скорость работы прототипа близка к скорости работы in-memory СУБД.
Далее мы расскажем об основных принципах архитектуры нашей платформы, наиболее «горячих» компонентах, приведём подробные результаты тестирования прототипа.
Платформа, разработанная нами, запускает несколько системных потоков, выделенных для СУБД, и распределяет те же 200 задач по несколько задач на один поток. В ходе исполнения каждая задача периодически передаёт управление другой задаче. Главный плюс такого решения – все переключения происходят внутри платформы, без взаимодействия с ОС. Это даёт определённый (хотя и небольшой) выигрыш в скорости и возможность построить свои, более лёгкие алгоритмы для синхронизации между задачами и с ОС.
Рис.1 Кооперативная многозадачность
Задачи сами передают управление друг другу, не обращаясь к средствам ОС
Контроль доступа к памяти – важнейший элемент СУБД: от него зависит консистентность данных и корректность работы с ними. Контроль доступа осуществляется при помощи критических секций, которые в классическом варианте реализованы при помощи блокировок. Задача обращается в секцию, если секция свободна – получает доступ к ресурсу (блоку данных) в памяти, выполняет с ним требуемые действия. В этот момент секция и ресурс закрыты для других задач.
На этом принципе в классических СУБД построен одновременный доступ и к журналу транзакций и к кешу страниц, связи между компонентами. Это и порождает основную проблему – невозможность параллельной работы нескольких ядер (потоков) с общим ресурсом и, как следствие, низкую скорость обработки данных.
Наша платформа разрешает доступ к одному ресурсу всем задачам, которым это требуется, и гарантирует, что все задачи «увидят» этот ресурс консистентным пока им это нужно. Критическая секция, разработанная специалистами РЕЛЭКС, представляет собой комбинацию неблокирующего механизма «эпох» и блокировки на основе «счётчика ссылок». Упрощённо работу механизма можно описать так. Представим, что в системе есть глобальный счётчик времени. Несколько процессов обратились к одному объекту в памяти и остановили для себя этот счётчик. Пока все задачи работают с объектом, они видят его консистентным. Когда задача закончила работать с объектом – эпоха заканчивается. Если объект больше никому не нужен – он сперва укладывается в список «на удаление», а спустя некоторое время – освобождается.
Если на протяжении эпохи задаче требуется выполнить «долгую» операцию (например, прочитать данные с диска или отправить данные на диск) – эпоха досрочно завершается. Для защиты объекта включается блокирующий алгоритм. По завершении операции задача «выходит» из блокировки в новую эпоху.
Рис. 2 Механизм эпох и блокировка
Общий объект освобождается только при отсутствии ссылок на него. Если задаче Е нужно выполнить «долгую» операцию – эпоха 2 завершается, для защиты объекта включается блокировка.
Естественно, работа такого сложного механизма влечёт за собой определённые «накладные расходы». Однако, преимущества такого решения, на наш взгляд, перевешивают сложность реализации. Во-первых, за счёт того, что каждая эпоха обслуживает множество операций в рамках одной защитной секции, итоговая эффективность работы механизма равна работе без блокировок. А во-вторых, мы имеем возможность работать и с диском, и с памятью, но на новой, более эффективной микроархитектуре.
Неблокирующий подход нашёл отражение в каждом из разработанных компонентов платформы. Каждый из компонентов – это «горячее» место системы, а их работа напрямую влияет на скорость обработки данных и на производительность системы.
В условиях системы, где несколько сотен задач работают параллельно друг другу, наша задача состояла в том, чтобы привести параллельные записи в линейную последовательность в журнале. Для этого в нашей платформе реализован собственный инструмент – буфер для последовательной конкурентной записи. Пишущие задачи наполняют буфер, а специальная задача – опустошает, последовательно записывая содержимое буфера в файл журнала. Преимущественный режим работы – неблокирующий. Система переходит на работу с блокировками при переполнении буфера или ожидании фиксации данных на диск.
Полученная реализация параллельной работы с кешем революционна – стоимость обращения к кешу приближается к стоимости обращения к странице в in-memory решениях, где понятие кеша и вытеснения отсутствует в принципе.
Для параллельной работы нескольких задач со страницей она может быть представлена в памяти в двух видах. Первый – базовый вариант, как на диске. Изменённая страница в памяти выглядит как цепочка дельт изменений страницы, которая заканчивается базовой страницей. Каждое изменение записывается в изолированном буфере без конкуренции. Периодически страница консолидируется в новом буфере. Данные никогда не меняются «in place».
Таким образом, разные способы представления страницы позволяют применять различные методики и алгоритмы обработки, каждый из которых оптимизирован под использование в памяти или при работе с диском. При работе с деревом полностью отсутствуют какие-либо блокировки, даже для модификации структуры. Поддерживается масштабируемость на несколько ядер.
Отметим, что транзакционное хранилище использует запатентованное компанией РЕЛЭКС хранилище исторических дельт записей.
Для испытания прототипа мы использовали сценарий Hammer DB теста TPC-C. Для выполнения замеров была использована мультипроцессорная система с NUMA (Non-Uniform Memory Architecture) архитектурой. Характеристики: Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz, Cache 25MB, 2 Sockets x 10 Cores x 2 Thread = 40 logical CPUs.512 GB RAM. Память: 512 GiB DDR4 Synchronous 2133 MGz. Диск: Linux Software RAID 0 with 5 SSD.
Тестируемый прототип включает в себя все основные элементы традиционной СУБД: журнал, MVCC, ACID транзакции, Pessimistic concurrency control, инкрементный checkpointing, исполняющую систему, реализованную на операторной модели.
Было выполнено три замера с разным объёмом оперативной памяти, выделяемым для работы. Результаты сравнивались с аналогичными замерами для современных реляционных СУБД: Oracle, PostgreSQL и MS SQL. Результаты представлены на графиках.
Рис. 3 Соотношение 20/100 (оперативная память/объём БД)
Для первого замера оперативная память предоставлялась в объёме 20% от размера БД на диске.
Рис. 4 Соотношение 50/100 (оперативная память/объём БД)
Для второго замера оперативная память предоставляется в объёме 50% от размера БД на диске.
Рис. 5 Соотношение 100/100 (оперативная память/объём БД)
Для третьего замера оперативная память предоставляется с избытком для устранения необходимости вытеснения данных.
Также мы заинтересованы в привлечении разработчиков и пользователей СУБД для тестирования и дальнейшего развития нашего решения. Свои вопросы можете задать в телеграм @den_relex.
Предыстория
Причина кроется во внутренней архитектуре СУБД – в устройстве отдельных компонентов и связях между этими компонентами. А точнее – в алгоритмах, которые применяются для контроля доступа нескольких задач к общему х ресурсу (например, блоку данных), а также для синхронизации работы этих задач. Классические дисковые реляционные СУБД создавались для одноядерных процессоров. Они основаны на блокирующем подходе – задачи конкурируют за доступ к ресурсу, который закрыт для всех задач, кроме той, что в данный момент работает с ресурсом. Современные in memory-решения оптимизированы для работы с многоядерными процессорами. Они основаны на неблокирующем подходе – задачи работают с ресурсом параллельно, для них гарантируется «одинаковое», консистентное состояние ресурса. Сочетать работу неблокирующих и блокирующих алгоритмов мешает необходимость или желание работать с диском и наличие конкуренции на любом уровне системы. (Подробнее об алгоритмах синхронизации и их влиянии на производительность СУБД – в предыдущей статье https://www.tadviser.ru/a/556149 ).Начиная с 2017 года, коллектив Центра разработки СУБД воронежской компании РЕЛЭКС создаёт собственную вычислительную среду – платформу для построения готового продукта. При проектировании системы мы исходили из предпосылок, что достичь по-настоящему выдающихся результатов можно при соблюдении двух условий:
- общее использование единого неблокирующего подхода от самого верхнего уровня до самого нижнего;
- при необходимости – возможность перехода от быстрых алгоритмов к медленным без потери свойств быстрых алгоритмов.
На данный момент нами разработан прототип, подтверждающий возможность комбинации неблокирующих и блокирующих алгоритмов. Сформированы ключевые API и примитивы платформы. Разработан прототип транзакционного кешируемого B+-tree хранилища. Прототип протестирован по сценарию Hammer DB – варианту общепринятого индустриального стандарта TPC-C. Согласно результатам тестирования, скорость работы прототипа близка к скорости работы in-memory СУБД.
Далее мы расскажем об основных принципах архитектуры нашей платформы, наиболее «горячих» компонентах, приведём подробные результаты тестирования прототипа.
Основные принципы архитектуры
Чтобы неблокирующие алгоритмы работали эффективно, они должны исполняться процессором непрерывно без передачи управления другому потоку или задаче. Но в стандартном случае, всеми процессами управляет операционная система. Например, СУБД отправляет вызов ОС с просьбой прочитать данные с диска. ОС «идёт» читать данные, а задачу отправляет в «сон» до тех пор, пока не придёт сообщение о том, что данные прочитаны. В «сон» отправляется практически любой системный вызов, требующий ожидания. В условиях, когда одновременно работают, например, 200 задач, ОС по собственному таймеру усыпляет и пробуждает задачи, давая поработать всем, понемногу.Платформа, разработанная нами, запускает несколько системных потоков, выделенных для СУБД, и распределяет те же 200 задач по несколько задач на один поток. В ходе исполнения каждая задача периодически передаёт управление другой задаче. Главный плюс такого решения – все переключения происходят внутри платформы, без взаимодействия с ОС. Это даёт определённый (хотя и небольшой) выигрыш в скорости и возможность построить свои, более лёгкие алгоритмы для синхронизации между задачами и с ОС.
Рис.1 Кооперативная многозадачность
Задачи сами передают управление друг другу, не обращаясь к средствам ОС
Контроль доступа к памяти – важнейший элемент СУБД: от него зависит консистентность данных и корректность работы с ними. Контроль доступа осуществляется при помощи критических секций, которые в классическом варианте реализованы при помощи блокировок. Задача обращается в секцию, если секция свободна – получает доступ к ресурсу (блоку данных) в памяти, выполняет с ним требуемые действия. В этот момент секция и ресурс закрыты для других задач.
На этом принципе в классических СУБД построен одновременный доступ и к журналу транзакций и к кешу страниц, связи между компонентами. Это и порождает основную проблему – невозможность параллельной работы нескольких ядер (потоков) с общим ресурсом и, как следствие, низкую скорость обработки данных.
Наша платформа разрешает доступ к одному ресурсу всем задачам, которым это требуется, и гарантирует, что все задачи «увидят» этот ресурс консистентным пока им это нужно. Критическая секция, разработанная специалистами РЕЛЭКС, представляет собой комбинацию неблокирующего механизма «эпох» и блокировки на основе «счётчика ссылок». Упрощённо работу механизма можно описать так. Представим, что в системе есть глобальный счётчик времени. Несколько процессов обратились к одному объекту в памяти и остановили для себя этот счётчик. Пока все задачи работают с объектом, они видят его консистентным. Когда задача закончила работать с объектом – эпоха заканчивается. Если объект больше никому не нужен – он сперва укладывается в список «на удаление», а спустя некоторое время – освобождается.
Если на протяжении эпохи задаче требуется выполнить «долгую» операцию (например, прочитать данные с диска или отправить данные на диск) – эпоха досрочно завершается. Для защиты объекта включается блокирующий алгоритм. По завершении операции задача «выходит» из блокировки в новую эпоху.
Рис. 2 Механизм эпох и блокировка
Общий объект освобождается только при отсутствии ссылок на него. Если задаче Е нужно выполнить «долгую» операцию – эпоха 2 завершается, для защиты объекта включается блокировка.
Естественно, работа такого сложного механизма влечёт за собой определённые «накладные расходы». Однако, преимущества такого решения, на наш взгляд, перевешивают сложность реализации. Во-первых, за счёт того, что каждая эпоха обслуживает множество операций в рамках одной защитной секции, итоговая эффективность работы механизма равна работе без блокировок. А во-вторых, мы имеем возможность работать и с диском, и с памятью, но на новой, более эффективной микроархитектуре.
Неблокирующий подход нашёл отражение в каждом из разработанных компонентов платформы. Каждый из компонентов – это «горячее» место системы, а их работа напрямую влияет на скорость обработки данных и на производительность системы.
Буфер журнала
Журнал операций (Write Ahead Log) – это самая горячая точка конкурентной записи в СУБД. Каждая задача, прежде чем выполнить какую-то операцию, делает запись об этом в журнал. В случае сбоя системы в журнале сохранятся последние операции в том порядке, в котором они выполнялись.В условиях системы, где несколько сотен задач работают параллельно друг другу, наша задача состояла в том, чтобы привести параллельные записи в линейную последовательность в журнале. Для этого в нашей платформе реализован собственный инструмент – буфер для последовательной конкурентной записи. Пишущие задачи наполняют буфер, а специальная задача – опустошает, последовательно записывая содержимое буфера в файл журнала. Преимущественный режим работы – неблокирующий. Система переходит на работу с блокировками при переполнении буфера или ожидании фиксации данных на диск.
Кеш страниц
Упрощённо, кеш страниц – это контейнер в памяти, куда система подгружает нужную страницу с диска, чтобы процессор мог работать с ней. Страница, загруженная в кеш, имеет буфер, где располагаются данные. Доступ к буферу защищён описанной выше критической секцией. Каждое изменение записывается без конкуренции. В момент, когда изменения завершены, содержимое обновлённой страницы формируется в новом буфере.Полученная реализация параллельной работы с кешем революционна – стоимость обращения к кешу приближается к стоимости обращения к странице в in-memory решениях, где понятие кеша и вытеснения отсутствует в принципе.
Хранилище
Основное хранилище страниц с данными в платформе представлено в виде сбалансированного дерева (B+-Tree). Упрощённо, страница представлена в виде древовидной структуры в «узлах» которого помещены со смещением значения ключевых полей, облегчающие поиск данных. Данные находятся в «листьях» дерева. Работа с хранилищем осуществляется через кеш страниц.Для параллельной работы нескольких задач со страницей она может быть представлена в памяти в двух видах. Первый – базовый вариант, как на диске. Изменённая страница в памяти выглядит как цепочка дельт изменений страницы, которая заканчивается базовой страницей. Каждое изменение записывается в изолированном буфере без конкуренции. Периодически страница консолидируется в новом буфере. Данные никогда не меняются «in place».
Таким образом, разные способы представления страницы позволяют применять различные методики и алгоритмы обработки, каждый из которых оптимизирован под использование в памяти или при работе с диском. При работе с деревом полностью отсутствуют какие-либо блокировки, даже для модификации структуры. Поддерживается масштабируемость на несколько ядер.
Отметим, что транзакционное хранилище использует запатентованное компанией РЕЛЭКС хранилище исторических дельт записей.
Методика и результаты тестирования
Для оценки производительности СУБД существует целый ряд комплексных тестов. Индустриальным стандартом на сегодня де-факто являются тесты TPC. Тест генерирует многопользовательскую OLTP-нагрузку, состоящую из различных транзакций. Для его прохождения в базе данных формируется набор данных, характерный для ИТ-систем, связанных с продажами или производством товаров и сервисов.Для испытания прототипа мы использовали сценарий Hammer DB теста TPC-C. Для выполнения замеров была использована мультипроцессорная система с NUMA (Non-Uniform Memory Architecture) архитектурой. Характеристики: Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz, Cache 25MB, 2 Sockets x 10 Cores x 2 Thread = 40 logical CPUs.512 GB RAM. Память: 512 GiB DDR4 Synchronous 2133 MGz. Диск: Linux Software RAID 0 with 5 SSD.
Тестируемый прототип включает в себя все основные элементы традиционной СУБД: журнал, MVCC, ACID транзакции, Pessimistic concurrency control, инкрементный checkpointing, исполняющую систему, реализованную на операторной модели.
Было выполнено три замера с разным объёмом оперативной памяти, выделяемым для работы. Результаты сравнивались с аналогичными замерами для современных реляционных СУБД: Oracle, PostgreSQL и MS SQL. Результаты представлены на графиках.
Рис. 3 Соотношение 20/100 (оперативная память/объём БД)
Для первого замера оперативная память предоставлялась в объёме 20% от размера БД на диске.
Рис. 4 Соотношение 50/100 (оперативная память/объём БД)
Для второго замера оперативная память предоставляется в объёме 50% от размера БД на диске.
Рис. 5 Соотношение 100/100 (оперативная память/объём БД)
Для третьего замера оперативная память предоставляется с избытком для устранения необходимости вытеснения данных.
Заключение
Как видно из результатов тестирования, платформа, созданная специалистами РЕЛЭКС, демонстрирует большой потенциал не только как уникальная разработка, делающая большой шаг в развитии решений по управлению данными, но и прежде всего, как самостоятельный конкурентоспособный продукт мирового уровня. Сейчас идёт процедура патентования ключевых идей и разработок.Также мы заинтересованы в привлечении разработчиков и пользователей СУБД для тестирования и дальнейшего развития нашего решения. Свои вопросы можете задать в телеграм @den_relex.