Redis AOF fsync (ВСЕГДА) против дерева LSM

Мое понимание структурных деревьев слияния журналов (деревьев LSM) заключается в том, что он использует тот факт, что добавление на диск происходит очень быстро (поскольку оно не требует поиска), просто добавляя обновление в журнал записи с опережением и возвращая клиенту. Насколько я понимаю, это по-прежнему обеспечивает немедленную настойчивость, хотя и очень быстро.

Redis, который, я думаю, не использует деревья LSM, похоже, имеет режим, в котором вы можете AOF+fsync при каждой записи. https://redis.io/topics/latency. В документации сказано:

AOF + fsync always: this is very slow, you should use it only if you know what you are doing.

Я запутался, почему это будет очень медленно, поскольку в принципе вы все еще добавляете файл только при каждом обновлении, как это делают базы данных LSM-дерева, как это делает Кассандра.

2 ответа

Решение

LSM - это AOF, которую вы иногда хотите прочитать. Вы выполняете некоторую служебную работу, чтобы позже ее можно было прочитать быстрее. Redis разработан так, что вы никогда или только в особом случае не читаете его. С другой стороны, Кассандра часто читает это, чтобы обслужить запросы.

И то, что Редис называет медленным, на самом деле очень и очень быстро для БД, как Кассандра.

============================ ОБНОВЛЕНИЕ

Оказывается, я пришел к выводам слишком рано. С точки зрения дизайна все вышеизложенное верно, но реализация так сильно отличается. Несмотря на то, что Кассандра претендует на абсолютную долговечность, она не fsync на каждую транзакцию, и нет никакого способа заставить это сделать (но каждая транзакция может быть fsynced). Лучшее, что я мог сделать, это "fsync в пакетном режиме, по крайней мере, через 1 мс после предыдущего fsync". Это означает, что для теста с 4 потоками, который я использовал, он выполнял 4 записи на fsync, а потоки ожидали выполнения fsync. С другой стороны, Redis делал fsync при каждой записи, поэтому в 4 раза чаще. С добавлением большего количества потоков и большего количества разделов стола Кассандра могла выиграть еще больше. Но учтите, что описанный вами вариант использования не является типичным. И другие архитектурные различия (Кассандра хороша в разделении, Redis хороша в счетчиках, LUA и других) все еще применяются.

Числа:

Redis команда: set(KEY + (tstate.i++), TEXT);

Команда Кассандры: execute("insert into test.test (id,data) values (?,?)", state.i++, TEXT)

куда TEXT = "Wake up, Neo. We have updated our privacy policy."

Redis fsync каждую секунду, HDD

Benchmark              (address)   Mode  Cnt      Score      Error  Units
LettuceThreads.shared  localhost  thrpt   15  97535.900 ± 2188.862  ops/s

  97535.900 ±(99.9%) 2188.862 ops/s [Average]
  (min, avg, max) = (94460.868, 97535.900, 100983.563), stdev = 2047.463
  CI (99.9%): [95347.038, 99724.761] (assumes normal distribution)

Redis fsync каждую запись, HDD

Benchmark              (address)   Mode  Cnt   Score   Error  Units
LettuceThreads.shared  localhost  thrpt   15  48.862 ± 2.237  ops/s

  48.862 ±(99.9%) 2.237 ops/s [Average]
  (min, avg, max) = (47.912, 48.862, 56.351), stdev = 2.092
  CI (99.9%): [46.625, 51.098] (assumes normal distribution)

Redis, fsync каждая запись, NVMe (Samsung 960 PRO 1 ТБ)

Benchmark              (address)   Mode  Cnt    Score   Error  Units
LettuceThreads.shared     remote  thrpt   15  449.248 ± 6.475  ops/s

  449.248 ±(99.9%) 6.475 ops/s [Average]
  (min, avg, max) = (441.206, 449.248, 462.817), stdev = 6.057
  CI (99.9%): [442.773, 455.724] (assumes normal distribution)

Кассандра, fsync каждую секунду, HDD

Benchmark                  Mode  Cnt      Score     Error  Units
CassandraBenchMain.write  thrpt   15  12016.250 ± 601.811  ops/s

  12016.250 ±(99.9%) 601.811 ops/s [Average]
  (min, avg, max) = (10237.077, 12016.250, 12496.275), stdev = 562.935
  CI (99.9%): [11414.439, 12618.062] (assumes normal distribution)

Кассандра, fsync каждая партия, но подождите не менее 1 мс, HDD

Benchmark                  Mode  Cnt    Score   Error  Units
CassandraBenchMain.write  thrpt   15  195.331 ± 3.695  ops/s

  195.331 ±(99.9%) 3.695 ops/s [Average]
  (min, avg, max) = (186.963, 195.331, 199.312), stdev = 3.456
  CI (99.9%): [191.637, 199.026] (assumes normal distribution)

Это своего рода сравнение яблок и апельсинов, они решают разные проблемы.

Redis должен уместиться в памяти, очень быстро. Если он настроен на fsync каждую секунду AOF, он все равно будет очень быстрым и с некоторой продуманной репликацией на стороне клиента обеспечит вам практически такую ​​же стойкость, что и Cassandra.

Cassandra больше рассчитана на множество табличных или петабайтных данных в нескольких узлах и дата-центрах. Вы можете ожидать, что у вас будет tb на узел, где вы не можете просто fsync весь набор данных, и размещение всего набора в commitlog сделает повторы слишком длинными. таким образом, с помощью LSM-деревьев вы просто синхронизируете изменения и снижаете стоимость до тех пор, пока не будет выполнено чтение и запись из путей чтения / записи.

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

По умолчанию commitlog - это периодическая fsync, а не по запросу, поэтому это просто добавление памяти, поэтому для выполнения записи требуется ~10 микросекунд. Вам нужно будет использовать пакетную обработку (или группировку для лучшей задержки / пропускной способности), чтобы иметь гарантированную долговечность на уровне реплики, что увеличивает время записи до ~10 миллисекунд (очень громко). На практике это выполняется с более высоким коэффициентом репликации, включая перекрестный DC, но у вас все еще есть возможная потеря данных, если весь набор реплик мгновенно выходит из строя (не является метеорологическим). Таким образом, один хост-кластер с настройками по умолчанию не долговечен. Настоятельно рекомендуется использовать менее трех узловых кластеров или RF<3, поскольку это просто небезопасно. Я бы сказал, что высокая доступность - это точка продажи Cassandras, а не ее производительность, и эта доступность частично обеспечивает ее долговечность.

Другие вопросы по тегам