![](https://habrastorage.org/webt/w_/iy/86/w_iy86aeei2csgk9nnajkutpbmo.jpeg)
В этой статье мы продолжаем рассказывать о том, как можно хранить метаданные в СХД при помощи баз данных key-value.
На этот раз в центре нашего внимания выделенные БД: Aerospike и RocksDB. Описание значимости метаданных в СХД, а также результаты тестирования встроенных БД можно посмотреть тут.
Параметры тестирования key-value БД
Кратко напомним основные параметры, по которым мы проводили тестирование (подробности в предыдущей статье).
Основной workload — Mix50/50. Дополнительно оценивали: RR, Mix70/30 и Mix30/70.
Тестирование проводили в 3 этапа:
- Заполнение БД — заполняем в 1 поток БД до необходимого количества ключей.
1.1 Сбрасываем кэши! Иначе тесты будут нечестными: БД обычно пишут данные поверх файловой системы, поэтому срабатывает кэш операционной системы. Важно сбрасывать его перед каждым тестом. - Тесты на 32 потока — прогоняем workload'ы
2.1 Random Read
• Сбрасываем кэши!
2.2 Mix70/30
• Сбрасываем кэши!
2.3 Mix50/50
• Сбрасываем кэши!
2.4 Mix30/70
• Сбрасываем кэши! - Тесты на 256 потоков.
3.1 То же самое, что и на 32 потока.
Измеряемые показатели
- Пропускная способности/throughput (IOPS/RPS — кто какие обозначения больше любит).
- Задержки/latency (msec):
• Min.
• Max.
• Среднее квадратическое значение — более показательное значение, чем среднее арифметическое, т.к. учитывает квадратичное отклонение.
• Перцентиль 99.99.
Тестовое окружение
Конфигурация:
CPU: | 2x Intel Xeon E5-2620 v4 2.10GHz |
RAM: | 16GB |
Disk: | [2x] NVMe HGST SN100 1.5TB |
OS: | CentOS Linux 7.2 kernel 3.11 |
FS: | EXT4 |
Объем доступной RAM регулировался не физически, а программно — часть заполнялась искусственно скриптом на Python, а остаток был свободен для БД и кэшей.
Выделенные БД. Aerospike
Чем Aerospike отличается от движков, которые мы до этого тестировали?
- Индекс в RAM
- Использование RAW дисков (= нет ФС)
- Не дерево, а хэш.
Так сложилось, что в индексе Aerospike на каждый ключ хранится 64Б (а сам ключ у нас всего 8Б). При этом индекс всегда полностью должен быть в RAM.
Это означает, что при нашем количестве ключей индекс не поместится в памяти, которую мы выделяем. Надо уменьшить количество ключей. И наши данные это позволяют!
![](https://habrastorage.org/webt/xx/am/ny/xxamny5d3hid9dtbenwr5jog6cy.png)
Рис. 1. Схема упаковки 1
![](https://habrastorage.org/webt/_r/dd/xk/_rddxkq7q0n45xbv2-dizbdfy2i.png)
Рис. 2. Схема упаковки 2
Итак, с помощью такой упаковки мы уменьшили количество ключей в 4 раза. Таким же образом можем уменьшить их количество в k раз. Тогда размер значения будет 16*k Б.
Тестирование. 17 млрд ключей
Чтобы индекс Aerospike на 17 млрд ключей (17 млрд сопоставлений lba->metadata) поместился в RAM, надо упаковать это всё в 64 раза.
В итоге получим 265 625 000 ключей (каждому из ключей будет соответствовать значение размером 1024Б, содержащее 64 экземпляра метаданных).
Тестировать будем с помощью YCSB. Он не выдаёт среднюю квадратическую задержку, поэтому её не будет на графиках.
Заполнение
Aerospike показал неплохой результат на заполнение. Ведёт себя очень стабильно.
Но заполнение проводилось в 16 потоков, а не в один, как было с движками. В один поток Aerospike выдавал около 20k IOPS. Скорее всего, дело в бенчмарке (т.е. в один поток бенчмарк просто не «выжимает» БД). Либо же Aerospike любит много потоков, а в один не готов выдавать большую пропускную способность.
![](https://habrastorage.org/webt/fr/9a/eu/fr9aeuwcr1vji8gn5n16pumtndw.png)
Рис. 3. Производительность заполнения базы
Максимальная задержка также держалась на примерно одинаковом уровне на протяжении всего заполнения.
![](https://habrastorage.org/webt/h2/k4/o5/h2k4o5xqoowfr5sdmc1dnhdhhn0.png)
Рис. 4. Latency заполнения базы
Тесты
Здесь важно отметить, что на этих графиках нельзя напрямую сравнивать Aerospike и RocksDB, т.к тесты проводились в разных условиях и разными бенчмарками – Aerospike использовался «с упаковкой», а RocksDB — без.
Также стоит учесть, что 1 IO у Aerospike = извлечение 64 значений (экземпляров метаданных).
Результаты RocksDB здесь приведены в качестве опорных.
![](https://habrastorage.org/webt/go/wv/sa/gowvsa9dgdllgqyrxm135ymnane.png)
Рис. 5. Сравнение Aerospike и RocksDB.100% Read
![](https://habrastorage.org/webt/fx/ex/t2/fxext2hg_p1nzhj7gf18aewoaos.png)
Рис. 6. Сравнение Aerospike и RocksDB. Mix 70%/30%
![](https://habrastorage.org/webt/gn/km/in/gnkminften1qb9gvukrhbnoskpa.png)
Рис. 7. Сравнение Aerospike и RocksDB Mix 50%/50%
![](https://habrastorage.org/webt/mb/cg/ki/mbcgkiyipk8znmver7u8f9uribo.png)
Рис. 8. Сравнение Aerospike и RocksDB Mix 30%/70%
В итоге запись на малом количестве потоков получилась медленнее, чем у RocksDB (при этом следует помнить, что в случае Aerospike за один раз записывается сразу 64 значения).
Но на большом количестве потоков Aerospike всё же выдаёт более высокие значения.
![](https://habrastorage.org/webt/j4/ly/g5/j4lyg5vuaslhyfepf-cmeg9i4sg.png)
Рис. 9. Aerospike. Latency Read 100%
Тут мы, наконец-то, смогли получить приемлемый уровень задержки. Но только в тесте на чтение.
![](https://habrastorage.org/webt/gc/si/k7/gcsik7n7ustrrphuue4iz0whg9k.png)
Рис. 10. Aerospike.Latency Mix 50%/50%
Теперь можно обновить список выводов:
- Запись + мало потоков => WiredTiger
- Запись + много потоков => RocksDB
- Чтение + DATA > RAM => RocksDB
- Чтение + DATA < RAM => MDBX
- Много потоков + DATA > RAM + Упаковка => Aerospike
Итоговый вывод по выбору БД для метаданных: в таком виде ни один из претендентов не достигает нужных нам показателей. Ближе всех Aerospike.
Ниже мы расскажем о том, что с этим можно делать, и что нам дает хранение данных в прямой адресации.
Прямая адресация. 137 млрд ключей
Рассмотрим системы хранения объемом 512 ТВ. Метаданные такой системы хранения как раз помещаются на одну NVME и соответствуют 137 млрд ключей для key-value базы данных.
Рассмотрим простейшую реализацию прямой адресации. Для этого на одном узле создадим SPDK NVMf таргет, на другом узле возьмем локальную NVMe и этот NVMf таргет и объединим их в логический RAID1.
Такой подход позволит записывать метаданные и защищать их репликой на случай отказа.
При тестировании производительности в несколько потоков каждый поток будет писать в свою область и эти области не будут пересекаться.
Тестирование проводилось с помощью бенчмарка FIO в 8 потоков с глубиной очереди 32. В таблице ниже представлены результаты тестирования.
Таблица 1. Тестирование прямой адресации
rand read 4k (IOPS) | rand write 4k (IOPS) | rand r/w 50/50 4K(IOPS) | rand r/w 70/30 4K(IOPS) | rand r/w 30/70 4K(IOPS) | |
---|---|---|---|---|---|
spdk | 760 — 770 K | 350 — 360 K | 400 — 410 K | 520 — 540 K | 410 — 450 K |
lat (ms) avg/max | 0.3 / 5 | 0.4 / 23 | 0.3 / 19 | 0,5 / 21 | 1,2 / 28 |
Теперь протестируем Aerospike в аналогичной конфигурации, где 137 млрд ключей как раз также помещаются на одну NVMe и реплицируются на другую NVMe.
Тестируем с помощью «родного» бенчмарка Aerospike. Берем два бенчмарка – каждый на своем узле – и 256 потоков, чтобы выжать максимальную производительность.
Получаем следующие результаты:
Таблица 2. Тестирование Aerospike c репликацией
R/W | IOPS | >1ms | >2ms | >4ms | 99.99 lat <= |
---|---|---|---|---|---|
100/0 | 635000 | 7% | 1% | 0% | 50 |
70/30 | 425000 | 8% | 3% | 1% | 50 |
50/50 | 342000 | 8% | 4% | 1% | 50 |
30/70 | 271000 | 8% | 4% | 1% | 40 |
0/100 | 200000 | 0% | 0% | 0% | 36 |
Ниже приведены результаты тестирования без репликации, один бенчмарк в 256 потоков.
Таблица 3. Тестирование Aerospike без репликации
R/W | IOPS | <=1ms | >1ms | >2ms | 99.99 lat <= |
---|---|---|---|---|---|
100/0 | 413000 | 99% | 1% | 0% | 5 |
70/30 | 376000 | 95% | 5% | 2% | 7 |
50/50 | 360000 | 92% | 8% | 3% | 8 |
30/70 | 326000 | 93% | 7% | 3% | 8 |
0/100 | 260000 | 94% | 6% | 2% | 5 |
Заметим, что Aerospike c репликацией работает не хуже, а даже лучше. При этом возрастает latency по сравнению с тестированием Aerospike без репликации.
Также приведем результаты тестирования RocksDB без репликации (у RocksDB нет родной встроенной репликации) своим бенчмарком в 256 потоков, 137 млрд ключей с упаковкой.
Таблица 4. Тестирование RocksDB без репликации
R/W | IOPS | <=1ms | >1ms | >2ms | 99.99 lat <= |
---|---|---|---|---|---|
100/0 | 444000 | 93% | 7% | 2% | 300 |
70/30 | 188000 | 86% | 14% | 4% | 2000 |
50/50 | 107000 | 75% | 25% | 3% | 1800 |
30/70 | 73000 | 85% | 15% | 0% | 1200 |
0/100 | 97000 | 74% | 26% | 17% | 2500 |
Выводы
- RocksDB «c упаковкой» не проходит тесты по latency
- Aerospike c репликацией почти удовлетворяет критериям
- Простейшая реализация прямой адресации соответствует всем критериям по производительности и задержкам.
Постскриптум. Ограничения
Отметим важные параметры, которые остались за рамками данного исследования:
- Файловая система (ФС) и её настройки
- Настройки виртуальной памяти
- Настройки БД.
1. ФС и её настройки
- Есть мнение, что для RocksDB, например, хорошо подходит F2FS или XFS
- Также выбор ФС зависит от того, какие накопители используются в системе
- Размер страницы (блока) ФС
2. Настройки виртуальной памяти
- Можно почитать тут.
3. Настройки БД
- MDBX. От разработчика этого движка была получена рекомендация попробовать другой размер страниц в движке: 2 килобайта или размер кластера в NVME. В целом этот параметр важен и у других БД (даже в Aerospike).
- WiredTiger. Кроме параметра cache_size, который мы меняли, есть ещё масса параметров. Читать тут.
- RocksDB.
• Можно попробовать Direct IO: т.е. общение с диском, минуя page cache. Но тогда, скорее всего, надо будет увеличить block cache, встроенный в RocksDB. Об этом тут.
• Есть информация о том, как настроить RocksDB для NVME. Тут, кстати, используется XFS. - Aerospike. Также имеет много настроек, но их тюнинг за несколько часов не принёс ощутимых результатов.