Изменения

Производительность Ceph

4437 байтов добавлено, 21:41, 11 ноября 2018
Нет описания правки
# Опять отключаю кэш журнальным LVM-девайсам: <tt>for i in `ls /dev/ceph-journals/lvol*`; do j=readlink $i; echo write through > /sys/block/${j##../}/queue/write_cache; done</tt> — никакого улучшения, всё та же жопа (но с ними это точно безопасно, так как они с конденсаторами :))
# Отключаю кэш HDD LVM-разделам (<tt>for i in `ls /dev/ceph-*/osd-block*`; do j=readlink $i; echo write through > /sys/block/${j##../}/queue/write_cache; done</tt>) — бинго, iops=603, avg lat = 1.65ms
# Ага. Простите. Обнаруживаю, что просто писать куда-то write through небезопасно без <tt>hdparm -W 0 /dev/sd*</tt>, т.к. так как https://www.kernel.org/doc/Documentation/block/queue-sysfs.txt - Writing to this file can change the kernels view of the device, but it doesn't doesn’t alter the device state. ок, добавляю <tt>for i in /dev/sd?; do hdparm -W 0 $i; done</tt> (отключаю все кэши) -  — результат похуже, iops=405, avg lat = 2.47ms - 47ms — но это всё равно лучше, чем изначальная жопа.
Виртуалку, в которой тестировал — даже не перезапускал между тестами.
{{Box|{{Note}} Мораль — отключайте кэш записи всем устройствам}}
 
== Почему вообще Ceph такое медленный? ==
 
Речь о random iops. Вкратце: потому что писано всё кривым **ем.
 
Например Bluestore. Все мы знаем, что 1 7200rpm HDD может выдать примерно 100—120 iops. Дальше нам говорят — ну, там типа журналирование.
 
Ну ок, как мы рассуждаем — ну, типа, есть журнал, есть диск. Значит типа вроде как синхронно записало в журнал, потом асинхронно постепенно перенесло на диск.
 
А там кривее.
 
Журнала собственного нет, вместо него RocksDB. Она как бы keyvalue база, но она же LSM, она же так и работает — типа до лимита пишет в память+журнал, потом когда упирается в лимит — делает compaction по уровням. По сути как бы БД-журнал. Вот они её как журнал и юзают.
 
В той же RocksDB метаданные, и их дохрена, ибо виртуальные клоны и всякое такое. Плюс чексуммы. Плюс идея, что надо побыстрее закоммитить запрос в минимальном виде и ответить «ок». Плюс два варианта записи — прямой и отложенный.
 
В итоге алгоритм записи примерно такой:
 
# Пришла транзакция — писнулась в журнал. Sync.
# Если запись мелкая, она откладывается и на время «откладывания» записывается в ту же rocksdb в отдельное место. Sync.
# Упёрлись в лимит сброса отложенных транзакций. Прочитали порцию из rocksdb, смержили, отправили в диск. С*ка опять sync, чтобы понимать, когда уже можно будет обновить метаданные.
# Обновляем метаданные. Sync.
# Если запись крупная, то она сразу отправляется на диск. Потом Sync.))). и потом тоже обновляем метаданные. Sync.
 
И ещё всё это приправлено тредами, блокировками…
 
То есть получается, что есть как бы журнал, есть данные и есть метаданные. И ещё если мелкие записи то есть очередь отложенной записи (в той же бд, но отдельная), её сначала надо писать, а потом сбрасывать и очищать. В итоге получается на 1 входящую транзакцию штук 5 реальных транзакций.
 
Без отложенной записи (на SSD это дефолт) поэтому всё и легче — остаётся только журнал, данные и метаданные — это хотя бы 3 транзакции, а не 5. А когда нет SSD, то казалось бы журнал хоть немного должен помогать, авотх*й, потому что seek-ов то меньше, но зато транзакций не 3, а 5.
 
Смысл видимо именно в отсутствии собственного журнала. Если бы он был и они работали как традиционная СУБД, то по идее, они могли бы делать примерно так:
 
* приняли операцию
* BEGIN
* UPDATE метаданные
* UPDATE данные
* COMMIT = ОДНА синхронная запись в журнал
* ответили клиенту «ок»
 
Ну а потом журнал просто потихоньку чистим. А у них так не получается — у них rocksdb, данные и метаданные в логически разных местах, а журналирование — фактически отдельная транзакция.
== DPDK и SPDK ==