导读:本期聚焦于弥生美月创作的《Cassandra unlogged batch是什么?非日志批量写入的正确用法与性能陷阱》,敬请观看详情。为什么同样是批量写入,unlogged batch有时候比逐条写入还慢?Cassandra中的unlogged batch是一种跳过写前日志的非事务批量写入方式,它不会像logged batch那样保证原子性和隔离性,却能减少网络往返开销,特别适合向同一分区批量插入数据的场景。本文将深入讲解unlogged batch的底层原理,对比它与logged batch、同步批处理、异步批处理的差异,分析跨分区使用时的性能陷阱,并给出Java驱动中的正确代码示例和参数调优建议,帮助你写出高性能的Cassandra写入代码。

Cassandra的batch语句分为logged batch和unlogged batch两种,很多刚接触的开发者会误以为unlogged batch更简单就更应该随便用,结果线上出现了大量超时和性能抖动。unlogged batch本质上只是把多条语句打包在一个请求里发送,省去了logged batch需要维护的batchlog机制,因此它不具备原子性保证,但换来的是更低的服务端开销。理解它的适用边界,是用好它的第一步。

Cassandra unlogged batch是什么?非日志批量写入的正确用法与性能陷阱

unlogged batch的底层原理

当客户端提交一个logged batch时,Cassandra会先把整个批次写入一张系统表batchlog(位于system键空间),作为故障恢复的依据,然后再执行批次中的各条语句。如果某个节点在执行中途宕机,协调者可以利用batchlog重放整个批次,从而保证all-or-nothing的原子性。这个额外的写放大是logged batch代价高昂的根本原因。

而unlogged batch完全跳过了batchlog这一步。使用BEGIN UNLOGGED BATCH语法后,协调者只是简单地把批次里的每一条mutation分发到对应的副本节点,每条语句独立执行、独立生效。这意味着如果批次执行到一半失败,前面已经写入的数据不会回滚,你拿到的可能是部分成功的状态。

从网络层面看,unlogged batch的价值在于把N次网络往返压缩成1次。对于一次插入100条记录的场景,逐条发送需要100个请求的序列化和排队开销,而一个unlogged batch只需要一次请求。但要注意,这只是网络层面的优化,服务端每条语句的写入成本一点都没有减少,尤其是跨分区的批次,每个分区仍然要独立落盘。

与logged batch及逐条写入的对比

三种写入方式的差异可以用一张表来概括:

写入方式原子性网络往返服务端开销适用场景
logged batch1次高,需要写batchlog需要多表一致写入
unlogged batch1次中,逐条执行同分区大批量写入
逐条异步写入N次高并发分散写入

官方文档反复强调一个原则:batch的正确用途是同一分区的批量写入,而不是为了减少网络往返而盲目把不同分区的数据打包在一起。当批次中所有语句的主键都属于同一个分区时,服务端可以把这些mutation合并成一次顺序写,磁盘IO效率接近单条写入;一旦跨分区,协调者就要拆分批次、分别路由,批次越大,协调者节点的内存和CPU压力越大,很容易触发写超时。

Java驱动中的正确写法

下面演示DataStax Java驱动中构建unlogged batch的标准方式,注意所有语句的主键都落在同一个分区键上:

// 假设表结构:CREATE TABLE sensor_data (
//   sensor_id uuid, recorded_at timestamp, value double,
//   PRIMARY KEY (sensor_id, recorded_at));

UUID sensorId = UUID.randomUUID();
BatchStatement batch = BatchStatement.newInstance(
    BatchStatement.Type.UNLOGGED);

for (int i = 0; i < 50; i++) {
    SimpleStatement stmt = SimpleStatement.newInstance(
        "INSERT INTO sensor_data (sensor_id, recorded_at, value) VALUES (?, ?, ?)",
        sensorId,
        Instant.now().plusSeconds(i),
        Math.random() * 100
    );
    batch = batch.add(stmt);
}

session.execute(batch);

这里批次内50条语句的分区键都是同一个sensorId,它们会被合并为对单个分区的顺序写,这正是unlogged batch最能发挥价值的场景。反例是把50个不同sensor的数据塞进一个批次,这种写法在生产上几乎必然带来延迟尖刺。

如果确实需要批量写入大量跨分区的数据,更好的做法是使用异步执行配合并发控制,而不是依赖batch:

// 使用限流的异步写入替代跨分区batch
Semaphore semaphore = new Semaphore(1000);
List<CompletableFuture<Void>> futures = new ArrayList<>();

for (SensorReading reading : readings) {
    semaphore.acquire();
    futures.add(session.executeAsync(
            buildInsertStatement(reading))
        .whenComplete((rs, ex) -> semaphore.release())
        .toCompletableFuture());
}

CompletableFuture.allOf(
    futures.toArray(new CompletableFuture[0])).join();

这种模式下每个请求独立失败、独立重试,吞吐能力和稳定性都远好于巨型跨分区batch。如果使用的是配置文件驱动的应用,驱动参数一般在应用的配置目录中调整,例如Windows环境下可能位于C:\app\config\cassandra-driver.yaml,其中可以设置最大并发请求数和超时时间。

常见陷阱与调优建议

第一个陷阱是批次大小失控。unlogged batch没有原子性保护,但不代表可以无限大,单个批次的大小受限于请求帧大小限制(默认约为256MB,但实际建议控制在几百条以内),同时批次中每条语句在协调者内存里都要占用缓冲,过大的批次会直接拖垮协调节点。建议在客户端层面做分片,每100到500条切一个批次。

第二个陷阱是重试语义混乱。由于批次不是原子的,一条语句失败后简单重试整个批次,可能导致已经成功的语句被重复写入。如果你的写入是幂等的(相同主键覆盖相同值),这没有问题;否则应该记录失败的具体语句,只重试失败部分,或者干脆改用逐条异步写入让驱动自己处理幂等重试策略。

第三个陷阱是把unlogged batch和prepared statement的关系搞混。batch里添加的语句本身可以是prepared语句,这是推荐做法,能减少服务端解析开销。另外要留意DEFAULT UNLOGGED BATCH的一个细节:在不加关键字的情况下,很多驱动默认生成的是logged batch,如果你明确不需要原子性,一定要显式声明UNLOGGED,否则白白承担batchlog的写放大成本。

总结一下:unlogged batch是同分区批量写入的利器,是跨分区写入的隐形炸弹。判断标准很简单,看批次内所有语句是否落在同一个分区键上,是就用它,不是就换异步逐条写入。配合合理的批次分片和幂等设计,就能在Cassandra上获得稳定的高吞吐写入能力。

Cassandraunlogged batch批量写入修改时间:2026-08-31 01:44:40

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。