2

我对日志结构化合并树(LSM 树)的理解是,它利用了附加到磁盘非常快的事实(因为它不需要搜索),只需将更新附加到预写日志并返回到客户端。我的理解是,这仍然提供了即时的持久性,同时仍然非常快。

我认为不使用 LSM 树的 Redis 似乎有一种模式,您可以在每次写入时进行 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.

我很困惑为什么这会很慢,因为原则上您仍然只是在每次更新时附加到一个文件,就像 Cassandra 等 LSM-tree 数据库正在做的那样。

4

2 回答 2

1

LSM 是您有时想要实际阅读的 AOF。你做了一些额外的工作,这样你以后可以更快地阅读它。Redis 的设计使您永远不会或仅在特殊情况下阅读它。另一方面,Cassandra 经常读取它来处理请求。

对于像 Cassandra 这样的数据库,Redis 所谓的慢实际上是非常非常快的。

==============================更新

事实证明,我太早下结论了。从设计的角度来看,以上所有内容都是正确的,但实现差异很大。尽管 Cassandra 声称绝对耐用,但它并没有fsync在每笔交易上,没有办法强制它这样做(但每笔交易都可以同步)。我能做的最好的事情是'在批处理模式下 fsync 在上一次 fsync 之后至少 1ms'。这意味着对于 4 线程基准测试,我使用的是每个 fsync 进行 4 次写入,并且线程正在等待 fsync 完成。另一方面,Redis 在每次写入时都会进行 fsync,因此频率提高了 4 倍。随着更多线程和更多表分区的增加,Cassandra 可以赢得更大的胜利。但请注意,您描述的用例并不典型。其他架构差异(Cassandra 擅长分区,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 1tb)

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)

Cassandra,每秒 fsync,硬盘

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)

Cassandra,fsync 每批次,但至少等待 1ms,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)
于 2018-05-23T07:54:08.670 回答
1

这有点像苹果和橙子的比较,它们解决了不同的问题。

Redis 应该适合内存,速度非常快。如果配置为每秒 fsync 一次 AOF,它仍然会非常快,并且通过一些巧妙的客户端复制可以为您提供与 Cassandra 基本相同的持久性。

Cassandra 的设计更多围绕多个节点和数据中心的数 TB 或 PB 数据。您可以期望每个节点都有 tb,您不能只 fsync 整个数据集,并且在提交日志中拟合整个数据集会使重播时间过长。因此,使用 LSM 树,您只需同步更改并将成本推到读取和读/写路径压缩之外。

我的理解是,这仍然提供了即时的持久性,同时仍然非常快。

默认情况下,提交日志是定期 fsync,而不是每个请求,因此它只是一个内存附加,这就是为什么它大约 10 微秒来进行写入。您将需要使用批处理(或组以获得更好的延迟/吞吐量)来保证每个副本级别的持久性,这会将写入时间提高到约 10 毫秒(非常手动)。这在实践中通过更高的复制因子(包括跨 DC)来处理,但是如果整个副本集瞬间崩溃(不是流星证明),您仍然可能会丢失数据。因此,具有默认设置的单个主机集群不是耐用的。强烈建议不要使用少于三个节点的集群或 RF<3,因为它根本不安全。我会说高可用性是 Cassandras 的卖点,而不是它的性能,而可用性部分地提供了它的一些耐用性。

于 2018-05-23T15:02:28.757 回答