Pull to refresh

RocksDB сервер – быстрое key-value хранилище для SSD накопителей

Reading time 5 min
Views 36K
RocksDB RocksDB – постоянное хранилище «ключ-значение» для быстрых накопителей. Основное ее предназначение — хранение данных на flash дисках.

Узким местом в производительности часто является обращение к БД.
Эта проблема может решаться по разному.
Использование кэша решает проблему производительности, но существенно усложняет архитектуру программы. Графовые базы данных выходят из ситуации за счет оптимальных для данной задачи алгоритмов. Другим типом решений являются хранилища, достигающие высокой производительности за счет использования быстрого носителя.
В последнее время появилось много NoSQL хранилищ полностью хранящих данные в памяти. Но память все еще стоит дорого и ее объем ограничен. Увеличение памяти за счет шардинга опять таки упирается в стоимость.
Логичным выходом из ситуации было бы использование SSD дисков. Они имеют относительно невысокую стоимость и при этом вполне небольшое время отклика.



К сожалению, не смотря на то что SSD диски существуют уже несколько лет, не так много баз данных оптимизированы для работы с ними. Основная проблема при использовании SSD диска в качестве носителя для БД – это многократная перезапись одних и тех же блоков. Т.н.з. «замозоливание».

RocksDB – гибкое производительное встраиваемое NoSQL хранилище. Расчитана она на использование на быстрых носителях, таких как SSD диски. Она написана в Facebook и базируется на гугловской LevelDB.
Если не углубляться в детали, то главными отличиями от LevelDB являются оптимизированный для работы с флеш-накопителями движок; оптимизация для работы с большими объемами данных; большая гибкость и расширяемость и как следствие много вкусных плюшек, отсутствующих в LevelDB.

Как я уже говорил, RocksDB – встраиваемое решение. И для того что бы ее можно было использовать ее нужно либо встроить в свое приложение, либо обернуть в сервер. Мне она нужна была для использования в веб-приложениях. И, по определенным причинам, связанным с тем что одновременно доступ к ней может иметь только один процесс (но не поток), мне нужен был именно сервер.
Я узнал о RocksDB примерно год назад и терпеливо ждал пока кто-нибудь начнет писать для нее сервер. Все что появилось за это время в полной мере меня не устроило. Поэтому я решил написать собственную серверную обертку над RocksDB.

RocksServer – однопоточный http сервер реализующий доступ к RocksDB.

Сервер написан на C++. Для реализации http слоя был использован Libevent.
Кроме Libevent и RocksDB код не содержит никаких других зависимостей.

RocksDB обладает весьма богатыми возможностями. Я реализовал только базовый, необходимый мне в настоящий момент, функционал. В дальнейшем, конечно, по мере возможностей, я планирую расширять функциональные возможности сервера.

Я не проводил масштабных бенчмарков, но предварительные замеры производительности показали вполне приличные результаты.

Поддерживаемые в настоящий момент операции:
Get получить одно значение по ключу
Multi get атомарно получить несколько значений по набору ключей
Set установить одно значение по ключу
Multi set атомарно установить несколько значений по набору ключей
Delete key удалить ключ из БД
Multi delete атомарно удалить несколько ключей
Check key exist быстрая проверка существования ключа в БД (с возможностью быстрого извлечения значения)
Imcrement атомарное увеличение/уменьшение значения на заданную величину

В случае необходимости список операций можно легко расширить. Для этого всего лишь нужно реализовать интерфейс:

    struct RequestBase 
    { 
        virtual ~RequestBase() {} 

        /** 
         *  Runs request listener 
         *  @param       event request object 
         *  @param       event buffer object 
         */ 
        virtual void run(const EvRequest &, const EvBuffer &) = 0; 
    }; 


Например, в зависимости от вашей схемы данных, вам может понадобиться реализовать атомарную вставку/обновление набора ключей.
Подключить ваш обработчик к серверу тоже не сложно. Делается это одной строчкой:

server.onRequest("/castom_handler",   new RequestСastom());


Компиляция/Установка


Как я уже говорил, RocksServer имеет две зависимости: собственно RocksDB и http слой в виде Libevent. Можно установить их отдельно, а можно обойтись без установки ограничившись компиляцией (за счет статического связывания). Лично для меня последний способ предпочтительней т. к. позволяет запускать RocksServer в т.ч. на старых серверах не имеющих всех необходимых подзависимостей.

Итак.
Клонируем репозитарий:

git clone --recursive git@github.com:valmat/RocksServer.git
cd RocksServer

или
git clone git@github.com:valmat/RocksServer.git
cd RocksServer
git submodule update

После клонирования Libevent и RocksDB окажутся в каталоге deps.
Затем компилируем зависимости:

./deps/make.sh

После этого шага можно, если хотите, запустить тесты либо установить Libevent и RocksDB в вашу систему.
А можно сразу перейти к компиляции RocksServer

cd src
make

Ваш компилятор должен поддерживать стандарт C++11
Срузу после компиляции RocksServer можно запускать, предварительно отредактировав конфигурационный файл:

./RocksServer.bin config.ini

А можно произвести его установку.
make install

В последнем случая для запуска/перезапуска/остановки нужно использовать init.d скрипт:
/etc/init.d/rocksserver start

Скорее всего, вы захотите настроить сервер под себя. Все имеющиеся настройки записаны в файле config.ini.

Для тестирования я положил простенький драйвер на php (да я знаю что его надо переписать) либо вы можете напрямую использовать протокол. В том числе и с помощью таких программ как Curl и Wget.
Протокол очень простой. При выборе между RPC и HTTP простота протокола обмена была одним из решающих моментов.

В настоящий момент, не смотря на не очень богатый функционал, RocksServer полностью готов к работе. Во всяком случае, я планирую использовать его в продакшене в проекте над которым сейчас работаю (для этого и писал).

Кроме меня Valgrind'а и CppCheck'а ревью кода никто не проводил. Поэтому опасения что, что-то может пойти не так вполне нормальны.
На этот случай есть возможность логгирования RocksServer'а и возможность делать бэкапы в том числе в человекочитаемом формате.

Для включения логгирования в конфигурационном файле нужно просто указать лог файл:

; Error log file name 
; default value: /var/log/rocksserver/error.log 
; 
; error_log = 

И указать уровень подробности лога:
; Error level 
; Possible values: debug | msg |  warn | error | fatal | none 
; default value: none 
; 
; log_level = 

Для бэкапа вам нужно указать каталог, в который будут складываться бэкапы:
; RocksDB backup path 
; The directory in which a backup will be stored
; default value: /var/rocksserver/backup 
; 
; backup_path = 

и выполнить POST запрос к 127.0.0.1:5577/backup

Для восстановления БД из бэкапа используйте команду
restore -f/path/to/backup -t/path/to/db

Для конвертирования БД в человекочитаемый вид:
human_readable -f/path/to/db  -t/path/to/restore_file

У себя я планирую следующую схему бэкапов:
wget "http://localhost:5577/backup" --post-data="" -O -
restore -f/path/to/backup -t/path/to/db_on_hdd
human_readable -f/path/to/db_on_hdd  -t/path/to/restore_file


Буду признателен за конструктивную критику.
Готов помочь с установкой и настройкой.
Ну и, разумеется, Pull Requests приветствуются.
Спасибо за внимание.
Tags:
Hubs:
+39
Comments 39
Comments Comments 39

Articles