【问题标题】:What is the purpose of Cassandra's commit log?Cassandra 的提交日志的目的是什么?
【发布时间】:2016-04-08 04:07:23
【问题描述】:

请有人澄清一下,让我了解提交日志及其用途。

在 Cassandra 中,写入磁盘是提交日志的第一个入口点或 MemTables。

如果 Memtables 是要刷新到磁盘的,那么提交日志有什么用,提交日志的唯一目的是在数据节点关闭时解决服务器同步问题吗?

【问题讨论】:

    标签: cassandra


    【解决方案1】:

    您可以将提交日志视为一种优化,但如果没有它,Cassandra 会非常缓慢。当 MemTables 被写入磁盘时,我们称它们为 SSTables。 SSTables 是不可变的,这意味着一旦 Cassandra 将它们写入磁盘,它就不会更新它们。所以当一个列发生变化时,Cassandra 需要将一个新的 SSTable 写入磁盘。如果 Cassandra 在每次更新时都将这些 SSTable 写入磁盘,那么它将完全受 IO 限制并且非常慢。

    因此,Cassandra 使用了一些技巧来获得更好的性能。它不是在每次列更新时将 SSTables 写入磁盘,而是将更新保存在内存中并定期将这些更改刷新到磁盘以将 IO 保持在合理的水平。但这会导致一个明显的问题,即如果机器出现故障或 Cassandra 崩溃,您将丢失该节点上的数据。为了避免丢失数据,除了在内存中保留最近的更改外,Cassandra 还将更改写入其 CommitLog。

    您可能会问,为什么写入 CommitLog 比写入 SSTable 更好。 CommitLog 针对写入进行了优化。与以排序顺序存储行的 SSTable 不同,CommitLog 以 Cassandra 处理更新的顺序存储更新。 CommitLog 还将所有列族的更改存储在单个文件中,因此磁盘在同时接收多个列族的更新时不需要执行一堆查找。

    基本上将 CommitLog 写入磁盘会更好,因为它必须写入比写入 SSTable 更少的数据,并且它将所有数据写入磁盘上的一个位置。

    Cassandra 会跟踪哪些数据已刷新到 SSTables,并且一旦所有早于某个时间点的数据都已写入,Cassandra 就能够截断提交日志。

    当 Cassandra 启动时,它必须从最后一个已知的良好时间点(我们知道所有以前的写入都写入 SSTable 的时间点)读回提交日志。它将提交日志中的更改重新应用到其 MemTables,以便在停止时可以进入相同的状态。这个过程可能会很慢,因此如果您要停止 Cassandra 节点进行维护,最好在关闭它之前使用nodetool drain,这会将 MemTables 中的所有内容刷新到 SSTables,并使启动时的工作量大大减少。

    【讨论】:

    • 停止节点时使用nodetool flush而不是nodetool drain有什么区别?
    • nodetool flush 只是将内存表刷新到磁盘。 nodetool drain 刷新内存表并停止接受来自客户端和其他节点的连接。
    • 提交日志是否被复制?否则提交日志是单点故障,对吧?
    • 一旦该部分被添加到 SSTable 中,提交日志也会被删除。否则提交日志将不断增加,最终磁盘空间不足。
    【解决方案2】:

    cassandra 中的写入路径是这样的:

    Cassandra Node ---->Commitlog-----------------> Memtable
                             |                       |
                             |                       |
                             |---> Periodically      |---> Periodically
                                  sync to  disk          flush to SSTable
    

    Memtable 和 CommitLog 是并行编写的(有点)。写入 CommitLog 必须在开始写入 Memtable 之前完成。相关源码栈为:

    org.apache.cassandra.service.StorageProxy.mutateMV:mutation.apply->
    org.apache.cassandra.db.Mutation.apply:Keyspace.open(keyspaceName).apply->
    org.apache.cassandra.db.Keyspace.apply->
    org.apache.cassandra.db.Keyspace.applyInternal{
        Tracing.trace("Appending to commitlog");
        commitLogPosition = CommitLog.instance.add(mutation)
        ...
        Tracing.trace("Adding to {} memtable",...
        ...
        upd.metadata().name(...);
        ...
        cfs.apply(...);
        ...
    }
    

    提交日志的目的是能够在节点崩溃或重新启动后重新创建内存表。这很重要,因为 memtable 只有在“满”时才会刷新到磁盘——这意味着配置的 memtable 大小已超出——或者刷新是由 nodetool 或 opscenter 执行的。所以memtable中的数据不会直接持久化。

    话虽如此,重新启动节点之前的一件好事是调用“nodetool flush”以确保您的内存表被持久化。这也将减少节点再次出现后提交日志的播放时间。

    【讨论】:

    • 提交日志是否被复制?否则提交日志是单点故障,对吧?
    • 每个节点都有自己的提交日志。这不是单点故障。
    • 是在commitlog和memtable都更新之后对客户端的ack吗?如果是这样,那为什么不同时做呢?
    • @psanford 在将数据写入提交日志时发送一个 ack,无论数据是否实际在数据库中因此被复制。如果带有未提交的提交日志到数据库的服务器崩溃,并且 ack 已经发送,会发生什么?
    猜你喜欢
    • 2011-02-04
    • 2016-11-25
    • 1970-01-01
    • 2013-04-06
    • 2015-10-28
    • 2015-10-19
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    相关资源
    最近更新 更多