Redis AOF fsync(始终)与 LSM 树
Redis AOF fsync (ALWAYS) vs. LSM tree
我对日志结构化合并树(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.
我很困惑为什么这会很慢,因为原则上你仍然只是在每次更新时附加到一个文件,就像像 Cassandra 这样的 LSM-tree 数据库正在做的。
LSM 是你有时想真正阅读的 AOF。你做了一些开销工作,这样你以后可以更快地阅读它。 Redis 的设计使您永远不会或仅在特殊情况下阅读它。另一方面,Cassandra 经常读取它来满足请求。
对于像 Cassandra 这样的数据库来说,Redis 所说的慢实际上是非常非常快的。
============================更新
事实证明,我下结论太早了。从设计的角度来看,以上所有内容都是正确的,但实现差异很大。尽管 Cassandra 声称绝对持久性,但它不会在每个事务上 fsync
并且没有办法强制它这样做(但每个事务都可以 fsynced)。我能做的最好的就是 'fsync in batch mode at least 1ms after previous fsync'。这意味着我使用的 4 线程基准测试是每次 fsync 进行 4 次写入,并且线程正在等待 fsync 完成。另一方面,Redis 在每次写入时都执行 fsync,所以频率是原来的 4 倍。随着 table 的更多线程和更多分区的加入,Cassandra 可能会赢得更大的胜利。但请注意,您描述的用例并不典型。和其他架构差异(Cassandra 擅长分区,Redis 擅长计数器,LUA 等)仍然适用。
号码:
Redis 命令:set(KEY + (tstate.i++), TEXT);
Cassandra 命令: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(三星 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,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)
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)
这有点比较苹果和橘子,它们解决不同的问题。
Redis 应该适合内存,非常 快。如果配置为每秒 fsync 一次 AOF,它仍然会非常快,并且通过一些巧妙的客户端复制,您将获得与 Cassandra 基本相同的耐用性。
Cassandra 的设计更多地围绕多个节点和数据中心的许多 tb 或 PB 数据。您可以期望每个节点都有 tb,您不能只 fsync 整个数据集并且将整个数据集放入提交日志将使重播时间过长。因此,对于 LSM 树,您只需同步更改并推迟成本,直到读取并退出 read/write 路径压缩。
My understanding was that this still provides immediate persistence, while still being extremely fast.
默认情况下,提交日志是周期性的 fsync,而不是每个请求,所以它只是一个内存追加,这就是为什么它需要大约 10 微秒的时间来进行写入。您将需要使用批处理(或更好的组 latency/throughput)来保证每个副本级别的持久性,从而将写入时间提高到 ~10 毫秒(非常手波)。这在实践中是通过更高的复制因子来处理的,包括交叉 DC,但是如果整个副本集瞬间宕机(不是流星证明),您仍然有可能丢失数据。因此,具有默认设置的单个主机集群不持久。强烈建议不要使用少于三个节点的集群或 RF<3,因为这根本不安全。我会说高可用性是 Cassandras 的卖点,而不是它的性能,而可用性是它提供一些耐用性的部分原因。
我对日志结构化合并树(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.
我很困惑为什么这会很慢,因为原则上你仍然只是在每次更新时附加到一个文件,就像像 Cassandra 这样的 LSM-tree 数据库正在做的。
LSM 是你有时想真正阅读的 AOF。你做了一些开销工作,这样你以后可以更快地阅读它。 Redis 的设计使您永远不会或仅在特殊情况下阅读它。另一方面,Cassandra 经常读取它来满足请求。
对于像 Cassandra 这样的数据库来说,Redis 所说的慢实际上是非常非常快的。
============================更新
事实证明,我下结论太早了。从设计的角度来看,以上所有内容都是正确的,但实现差异很大。尽管 Cassandra 声称绝对持久性,但它不会在每个事务上 fsync
并且没有办法强制它这样做(但每个事务都可以 fsynced)。我能做的最好的就是 'fsync in batch mode at least 1ms after previous fsync'。这意味着我使用的 4 线程基准测试是每次 fsync 进行 4 次写入,并且线程正在等待 fsync 完成。另一方面,Redis 在每次写入时都执行 fsync,所以频率是原来的 4 倍。随着 table 的更多线程和更多分区的加入,Cassandra 可能会赢得更大的胜利。但请注意,您描述的用例并不典型。和其他架构差异(Cassandra 擅长分区,Redis 擅长计数器,LUA 等)仍然适用。
号码:
Redis 命令:set(KEY + (tstate.i++), TEXT);
Cassandra 命令: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(三星 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,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)
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)
这有点比较苹果和橘子,它们解决不同的问题。
Redis 应该适合内存,非常 快。如果配置为每秒 fsync 一次 AOF,它仍然会非常快,并且通过一些巧妙的客户端复制,您将获得与 Cassandra 基本相同的耐用性。
Cassandra 的设计更多地围绕多个节点和数据中心的许多 tb 或 PB 数据。您可以期望每个节点都有 tb,您不能只 fsync 整个数据集并且将整个数据集放入提交日志将使重播时间过长。因此,对于 LSM 树,您只需同步更改并推迟成本,直到读取并退出 read/write 路径压缩。
My understanding was that this still provides immediate persistence, while still being extremely fast.
默认情况下,提交日志是周期性的 fsync,而不是每个请求,所以它只是一个内存追加,这就是为什么它需要大约 10 微秒的时间来进行写入。您将需要使用批处理(或更好的组 latency/throughput)来保证每个副本级别的持久性,从而将写入时间提高到 ~10 毫秒(非常手波)。这在实践中是通过更高的复制因子来处理的,包括交叉 DC,但是如果整个副本集瞬间宕机(不是流星证明),您仍然有可能丢失数据。因此,具有默认设置的单个主机集群不持久。强烈建议不要使用少于三个节点的集群或 RF<3,因为这根本不安全。我会说高可用性是 Cassandras 的卖点,而不是它的性能,而可用性是它提供一些耐用性的部分原因。