当前位置:首页 > 文章列表 > Golang > Go教程 > Go Badger 怎么批量写入并处理 Flush 错误

Go Badger 怎么批量写入并处理 Flush 错误

来源:17golang原创 2026-10-13 16:58:35 0浏览 收藏

Go Badger 的批量写入关键不在于把更多的 Set 塞进一个对象,而在于把“收集写入”和“提交写入”分开处理。通常用 db.NewWriteBatch() 创建批次,在批次内逐条调用 Set 或 SetEntry,最后只把 Flush() 当作提交点;每一次写入和最终刷新都要保留错误。

官方地址:https://github.com/dgraph-io/badger/

本文只讨论 Badger v4 的 WriteBatch、Flush、Cancel 和错误处理,不把它扩展成数据库选型或通用事务教程。

先分清 Set 错误和 Flush 错误

WriteBatch.Set 的错误表示当前批次在收集数据时已经遇到问题,例如输入不符合 Badger 的写入约束;Flush 的错误则表示提交阶段返回了错误,或者返回了批次之前已经记录的错误。官方 API 还说明,一旦批次已经记录错误,后续不会继续执行提交。

因此,下面两件事不能混为一谈:

  • 某条记录调用 Set 失败:停止继续追加,记录这条输入的位置。
  • 所有 Set 都成功但 Flush 失败:把整个批次视为未完成,保留批次边界,再按业务策略恢复。
Badger WriteBatch 从输入记录到 Set、WriteBatch 和 DB 的静态调用关系说明图
图1:Badger 批量写入的静态结构图,展示输入记录、业务键、Set/SetEntry、WriteBatch 与 DB 之间的关系;这是说明图,不是运行截图。

用有限大小的 WriteBatch 收集写入

批量大小不要只按记录条数决定,还要考虑单条 value 的大小和失败后的恢复成本。可以先用固定数量作为业务层分块边界,再通过 SetMaxPendingTxns 调整待处理事务上限。该方法应在开始写入前调用,官方文档给出的默认值是 16。

下面的示例将一批输入转换为 Badger 写入。示例故意把批次的起始游标交给调用方保存,这样调用方可以在外层记录“哪一批已经完成”,而不是把恢复状态藏在数据库内部。

package batchwrite

import (
    "fmt"

    badger "github.com/dgraph-io/badger/v4"
)

type Item struct {
    Key   string
    Value []byte
}

// writeOneBatch 只负责收集并提交一个有限批次。
// 调用方应在 Flush 成功后再推进游标,避免把未完成批次误记为成功。
func writeOneBatch(db *badger.DB, items []Item, maxPending int) error {
    wb := db.NewWriteBatch()
    // 如果中途提前返回,Cancel 负责释放尚未提交的批次状态。
    defer wb.Cancel()

    if maxPending > 0 {
        // 该上限应在第一次 Set 前设置,避免批次已经开始后再改变策略。
        wb.SetMaxPendingTxns(maxPending)
    }

    for index, item := range items {
        if item.Key == "" {
            // 空键属于输入错误,不应继续把后续记录追加到同一批次。
            return fmt.Errorf("item %d has empty key", index)
        }
        if err := wb.Set([]byte(item.Key), item.Value); err != nil {
            // Set 错误要立即返回,外层可以记录当前批次和记录下标。
            return fmt.Errorf("set item %d (%s): %w", index, item.Key, err)
        }
    }

    // Flush 是批次提交点;只有它成功,外层才应推进批次游标。
    if err := wb.Flush(); err != nil {
        return fmt.Errorf("flush %d items: %w", len(items), err)
    }
    return nil
}

这个函数没有在内部自动重试。原因是 Flush 已经是提交边界,遇到错误时直接复制同一批次并重试,可能让调用方误以为所有记录都处于同一种状态。是否重试应由外层根据错误、幂等键和持久化游标决定。

把 Flush 当作批次提交点

使用 WriteBatch 时,最容易遗漏的是“创建了批次但既没有 Flush,也没有 Cancel”。官方文档明确提醒,这会让事务 oracle 无法清理行提交时间映射,长期运行可能造成内存持续增长。因此,defer wb.Cancel() 应紧跟在创建批次之后;正常路径仍然显式调用 Flush。

建议外层保存三个字段:

字段用途推进时机
batch_start本次批次的输入起点开始处理前确定
batch_end本次批次的输入终点按固定数量或字节预算切分
status记录 pending、success 或 failed只有 Flush 成功后写 success

这样即使应用在循环中途退出,也能从最后一个未完成批次开始处理,而不是凭“已经调用过多少次 Set”猜测进度。

Badger Flush 提交边界与错误记录、Cancel 兜底和外部批次游标的静态关系说明图
图2:Flush 提交边界的静态关系图,展示成功提交、错误记录、Cancel 兜底和外部游标之间的职责;这是结构图,不是运行结果。

Flush 出错时怎么恢复

恢复策略的核心是让每条输入拥有稳定、可重复计算的业务键。例如把订单号、对象版本或导入文件中的唯一行号编码到 key 中,而不是每次重试都生成新的随机 key。这样即使外层需要重新处理一个失败批次,也不会因为随机键产生一组无法覆盖的重复数据。

type Checkpoint struct {
    Start int
    End   int
}

// writeWithCheckpoint 只在整个批次 Flush 成功后返回新的游标。
// checkpoint 的持久化应由调用方完成,并与业务状态更新采用一致的顺序。
func writeWithCheckpoint(db *badger.DB, all []Item, start, size int) (Checkpoint, error) {
    if start >= len(all) {
        // 没有剩余输入时,返回空范围而不是创建空批次。
        return Checkpoint{Start: start, End: start}, nil
    }

    end := start + size
    if end > len(all) {
        // 最后一批只覆盖剩余数据,不人为填充占位记录。
        end = len(all)
    }
    if err := writeOneBatch(db, all[start:end], 16); err != nil {
        // 出错时保留原 start,下一次由调用方按幂等键决定是否恢复。
        return Checkpoint{Start: start, End: start}, err
    }
    return Checkpoint{Start: start, End: end}, nil
}

如果应用需要把 Badger 写入和外部检查点放进同一个不可分割的业务动作,就不能只依靠这个内存结构体;应把检查点设计成可重复写入的记录,并明确“Badger 成功、检查点失败”或相反顺序下的补偿方案。本文的示例只保证批次边界清楚,不声称跨系统事务。

常见误区和一张速查表

  • 只检查最后一次 Flush:前面的 Set 已经失败时,批次不会按预期提交。
  • 把 Cancel 当成回滚:官方说明已提交的写入仍会继续生效,Cancel 主要用于清理未完成的批次状态。
  • 无限增大单批数据:单次失败后的重试成本、内存占用和游标恢复范围都会变大。
  • 用随机键重试:同一业务记录可能被写成多条,后续无法判断哪条是有效版本。
现象处理方式
Set 返回错误停止当前批次,记录输入位置和原始错误。
Flush 返回错误不推进外部游标,保留批次边界,按幂等键决定恢复。
中途提前返回确保已注册 Cancel,避免遗留未完成批次状态。
批次长期占用内存缩小批次并合理设置 MaxPendingTxns,检查是否遗漏 Flush/Cancel。

总结一下:Badger 批量写入可以从 NewWriteBatch 开始,但可靠性取决于三个边界——每次 Set 的错误、最终 Flush 的提交结果,以及异常路径上的 Cancel。把批次游标和幂等键放在调用方,才有条件在 Flush 出错后安全恢复。

相关问题

WriteBatch 和普通事务 Set 有什么区别?

WriteBatch 面向一组批量写入,调用方最后显式 Flush;普通事务则围绕一次事务生命周期组织读写。选择哪一种,取决于你要处理的是批量导入边界,还是需要在事务内组合读取与写入。

Flush 成功后还需要调用 Cancel 吗?

代码可以保留创建后的 defer Cancel 作为提前返回的兜底,但真正的提交动作仍由 Flush 完成。不要把 Cancel 当作成功确认,也不要用它替代 Flush。

可以在 Flush 失败后直接再调用一次 Flush 吗?

不要把无条件重复 Flush 当作通用恢复方案。先记录错误和批次边界,再依据错误类型、幂等键和外部检查点设计恢复动作。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go Badger 怎么使用前缀迭代器读取一组记录Go Badger 怎么使用前缀迭代器读取一组记录
上一篇
Go Badger 怎么使用前缀迭代器读取一组记录
Go Badger 事务提交报冲突时应该怎样重新执行
下一篇
Go Badger 事务提交报冲突时应该怎样重新执行
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    460次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    522次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    541次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    488次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    307次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码