ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

TigerBeetle 参考指南:Account / Transfer 数据结构、客户端会话与八类请求 API 全解析

2026/9/14 6:19:38 拓冰建站 浏览量
TigerBeetle 参考指南:Account / Transfer 数据结构、客户端会话与八类请求 API 全解析 TigerBeetle 参考指南Account / Transfer 数据结构、客户端会话与八类请求 API 全解析【免费下载链接】tigerbeetleThe financial transactions database designed for mission critical safety and performance.项目地址: https://gitcode.com/GitHub_Trending/ti/tigerbeetleTigerBeetle 的 Reference 参考文档 面向在其之上构建应用的开发者与 Coding 系列按主题组织的实战指南不同它以穷举式的方式完整记录 TigerBeetle 的每一个细节核心数据结构Account、Transfer、AccountBalance、AccountFilter、QueryFilter、客户端会话Client Sessions机制以及全部八类请求 APIcreate_accounts、create_transfers、lookup_*、get_account_*、query_*。读完本文你将掌握每个字段的约束条件、每种 flag 的行为语义、各类请求的入参Event与返回值Result并能结合源码理解这些约定在 TigerBeetle 内部的真实实现。Reference 与 Coding两种阅读姿势Reference 与 Coding 的定位互补Coding按主题组织的一系列教程数据建模、两阶段转账、链路事件、可靠提交等解决怎么做的问题Reference逐项穷举 TigerBeetle 的每一个细节是任何问题的最终答案所在地——官方原话是Any answer can be found here, but it might take some digging!即覆盖面最全但需要按条目检索。Reference 目录下包含 Client Sessions、Account、Transfer、AccountBalance、AccountFilter、QueryFilter以及 Requests 下的八个请求文档。本文即以此为骨架展开。核心数据结构AccountAccount是一条记录某个账户在已提交转账累计作用下净效果的记录。从源码看其定义位于 src/tigerbeetle.zig#L10-L43 的const Account extern struct { ... }共 128 字节、16 字节对齐。更新与删除语义不可更新除debits/credits余额字段外账户字段在创建后用户无法修改余额由 TigerBeetle 在转账移动资金时自动更新。不可删除账户创建后无法删除——这是审计追踪audit trail的强保证。若账户不再使用可参考 close-account 配方 将余额清零。不变量保证Guarantees账户不可变余额字段除外由转账修改同一id的账户至多存在一个所有账户debits_pending之和恒等于所有账户credits_pending之和所有账户debits_posted之和恒等于所有账户credits_posted之和。字段详解字段类型约束idu12816 字节客户端自定义唯一标识不能为 0 或2^128 - 1集群内不可与其他账户冲突debits_pendingu128被待定pending转账预留的借方金额创建时必须为 0debits_postedu128已过账的借方金额创建时必须为 0credits_pendingu128被待定转账预留的贷方金额创建时必须为 0credits_postedu128已过账的贷方金额创建时必须为 0user_data_128u128可选外部关联标识为 0 时不可作为查询过滤条件user_data_64u64可选外部关联标识如外部时间戳同上user_data_32u32可选外部关联标识如时区/地区码同上reserved4 字节预留必须为 0ledgeru32账本分区标识不能为 0codeu16用户自定义的账户类别枚举不能为 0flagsu16行为开关位域timestampu64账户创建时间UNIX 纪元纳秒关于id的补充账户 ID 在整个集群内唯一而非按账本唯一。若要在多个账本上的账户之间表达同属一个用户的关系应把用户 ID 存放在user_data_*字段中。ID 方案选择的建议见 数据建模文档。pending字段的含义debits_pending/credits_pending中的资金是**被预留reserved**的——在对应 pending 转账被 post、void 或超时之前不可动用一旦解决金额即从 pending 计数中移除。flags位域Flag语义linked将本条账户创建结果与下一条事件联动全部成功或全部失败链尾事件不得设置此 flag。详见 linked eventsdebits_must_not_exceed_credits拒绝会导致debits_pending debits_posted amount credits_posted的转账不可与credits_must_not_exceed_debits同时设置credits_must_not_exceed_debits拒绝会导致credits_pending credits_posted amount debits_posted的转账不可与debits_must_not_exceed_credits同时设置history保留该账户每次转账后的余额历史get_account_balances仅对设置了该 flag 的账户生效imported允许以原始timestamp导入历史账户closed拒绝后续转账正在待定的两阶段转账的 void 除外closed的设置途径可在创建时设置也可通过发送带Transfer.flags.closing_debit/closing_credit的待定转账 来设置通过 void 掉那条 closing 待定转账可以解除该 flag。flags.imported的约束导入历史数据以维护审计与可追溯性需要满足禁止混批同批次内不得混用设置了imported与未设置的事件应用必须分开提交时间戳唯一用户自定义时间戳必须唯一即使是不同类型对象如Account与Transfer也不能共享同一时间戳且为 UNIX 纪元纳秒必须是过去时间不得早于/晚于集群时钟到达请求时的时刻不能是未来时间严格递增用户时间戳必须至少比集群最后提交账户的时间戳晚 1 纳秒。由于时间戳不能回退官方建议仅在新集群或维护窗口导入事件建议以 linked chain 提交整个批次保证任一账户失败则全部不提交从而保持最后时间戳不变给应用修正后以相同时间戳重提的机会。timestamp账户创建时刻UNIX 纪元纳秒。未设置imported时创建必须为 0由 TigerBeetle 在事件到达集群时赋值设置imported时必须在(0, 2^63)区间内。时间机制详见 Time in TigerBeetle。核心数据结构TransferTransfer是两个账户之间金融交易的不可变记录。TigerBeetle 用 transfer 而非 transaction 称呼金融交易是为了避免与数据库中已被过度使用的 transaction 一词混淆。其定义位于 src/tigerbeetle.zig#L85-L116。单笔转账只在同一账本内借记一个账户、贷记一个账户更复杂的交易可组合实现见 Currency Exchange 与 Multi-Debit, Multi-Credit Transfers 配方。更新与删除语义不可修改转账创建后无法修改若某细节错误需要修正使用修正转账不可删除转账创建后无法删除若转账有误同样用修正转账逆转其效果。不变量保证转账不可变同一id的转账至多存在一个一条待定转账最多被 post 一次timeout 由集群时间戳驱动确定性触发。模式Modes与字段适用性转账分为单阶段Single-Phase立即执行与两阶段Two-Phase先 Pending 再 Posted/Voided详见两阶段转账指南。各模式下字段的适用性如下必读字段Single-PhasePendingPost-PendingVoid-Pendingidrequiredrequiredrequiredrequireddebit_account_idrequiredrequiredoptionaloptionalcredit_account_idrequiredrequiredoptionaloptionalamountrequiredrequiredrequiredoptionalpending_idnonenonerequiredrequireduser_data_128optionaloptionaloptionaloptionaluser_data_64optionaloptionaloptionaloptionaluser_data_32optionaloptionaloptionaloptionaltimeoutnoneoptional¹nonenoneledgerrequiredrequiredoptionaloptionalcoderequiredrequiredoptionaloptionalflags.linkedoptionaloptionaloptionaloptionalflags.pendingfalsetruefalsefalseflags.post_pending_transferfalsefalsetruefalseflags.void_pending_transferfalsefalsefalsetrueflags.balancing_debitoptionaloptionalfalsefalseflags.balancing_creditoptionaloptionalfalsefalseflags.closing_debitoptionaltruefalsefalseflags.closing_creditoptionaltruefalsefalseflags.importedoptionaloptionaloptionaloptionaltimestampnone²none²none²none²¹ 设置flags.imported时为 none。 ² 设置flags.imported时为 required。字段详解idu128转账唯一标识不能为 0 或2^128 - 1集群内不可冲突。注意转账 ID 在整个集群唯一而非按账本若要在多个转账之间表达属于同一笔交易应把交易 ID 存入user_data_*字段。debit_account_id/credit_account_idu128借方/贷方账户。普通模式下必须匹配已存在账户且两者不同post/void 模式下为 0 时自动继承 pending 转账对应账户非 0 时必须与 pending 转账一致imported模式下账户timestamp必须 ≤ 转账timestamp。amountu128借记与贷记的金额无符号。要点设置balancing_debit时这是最大转账金额实际金额由借方账户约束决定设置balancing_credit时同理由贷方账户约束决定post 时若amount为AMOUNT_MAX2^128 - 1则自动取 pending 转账金额否则必须 ≤ pending 金额void 时为 0 则自动取 pending 金额非 0 必须等于 pending 金额金额表示正负借方/贷方、小数与资产缩放的方法见 debits vs credits 与 Fractional Amounts。pending_idu128post/void pending 转账时引用该 pending 转账的id非 post/void 场景必须为 0。使用方式见两阶段转账。user_data_128/64/32可选外部关联标识。为 0 时不可作为查询过滤条件post/void 时若为 0 会自动继承 pending 转账的对应字段。示例用法用 TigerBeetle 时间型标识符 关联一组转账。timeoutu32秒pending 转账自到达集群起可以被 post/void 的时间间隔0 表示无超时。非 pending 转账、imported 转账不能有 timeout。TigerBeetle 对过期转账的 pending 余额做尽力自动清理转账在timestamp timeout换算为纳秒时刻精确过期过期前 pending 余额绝不会被提前移除过期的转账不可再被手动 post 或 void不保证余额恰在过期时刻被移除——客户端请求仍可能观察到过期转账的 pending 余额按过期时间升序清理同时过期则按创建timestamp排序若 B 的 pending 余额已移除则更早过期的 A 一定也已移除。使用相对秒数而非绝对时间戳是为了对集群与应用间的时钟偏差更鲁棒。ledgeru32账本分区标识。post/void 模式为 0 时继承 pending 转账的 ledger非 0 必须与 pending 转账的 debit/credit 账户 ledger 一致普通模式下不能为 0且必须与两个账户的 ledger 一致。codeu16用户自定义的转账原因/类别枚举。post/void 模式为 0 时继承 pending 转账的 code非 0 必须一致普通模式下不能为 0。flags位域Flag语义linked与下一条转账联动全部成功或失败链尾不得设置。示例见 Currency Exchangepending标记为待定转账post_pending_transfer标记为post-pending 转账void_pending_transfer标记为void-pending 转账balancing_debit至多转账amount自动调整为满足debit_account.debits_pending debit_account.debits_posted ≤ debit_account.credits_posted的实际金额实际金额会写回记录的amount。与 post/void 互斥因为 post/void 永不会超出账户限制与balancing_credit正交可叠加。示例见 Close Accountbalancing_credit对称地调整满足credit_account.credits_pending credit_account.credits_posted ≤ credit_account.debits_posted与balancing_debit同理closing_debit/closing_credit转账成功后为借方/贷方账户设置Account.flags.closed。必须配合flags.pending两阶段保证 closing 可通过 void 反转且反转操作必须引用对应 closing 转账防止 close/unclose 意外交错imported允许以原始timestamp导入历史转账balancing_debit/credit的重试语义重试平衡转账仅在传入的最大金额不足以覆盖实际转账金额时返回exists_with_different_amount否则即使重试金额与原始值不同也可能返回exists。flags.imported对 Transfer 的额外约束除与 Account 相同的禁止混批、时间戳唯一/过去/严格递增、建议 linked chain 提交外imported 转账不能有timeout。可以导入带用户时间戳的 pending 转账但因其不受集群时钟驱动、无法定义自动过期timeout此时两阶段的 post/rollback 必须手动完成。timestamp语义与 Account 相同——未设置imported时创建必须为 0由集群赋值设置时必须在(0, 2^63)。核心数据结构AccountBalanceAccountBalance记录Account在某个时间点的余额快照定义见 src/tigerbeetle.zig#L70-L83。只有设置了historyflag 的账户才保留历史余额。timestampu64余额更新时间对应改变账户的那笔Transfer.timestamp金额是转账执行之后记录的余额debits_pending/debits_posted/credits_pending/credits_postedu128四个余额分量reserved56 字节预留必须为 0。核心数据结构AccountFilter与QueryFilterAccountFilter用于 get_account_transfers 与 get_account_balances 的过滤参数account_idu128目标账户标识不能为 0 或2^128 - 1user_data_128u128/user_data_64u64/user_data_32u32按Transfer对应字段过滤为 0 禁用codeu16按Transfer.code过滤为 0 禁用reserved58 字节必须为 0timestamp_min/timestamp_maxu64按Transfer.timestamp过滤闭区间为 0 禁用下限/上限且必须 2^63limitu32最大返回条数受最大消息尺寸限制不能为 0flagsu32flags.debits是否包含debit_account_id匹配account_id的结果flags.credits是否包含credit_account_id匹配account_id的结果flags.reversed按时间戳升序默认最早在前或降序最新在前排序。QueryFilter用于 query_accounts 与 query_transfersuser_data_128/64/32按Account或Transfer对应字段过滤为 0 禁用ledgeru32按Account.ledger或Transfer.ledger过滤为 0 禁用codeu16按对应code过滤为 0 禁用reserved6 字节必须为 0timestamp_min/timestamp_maxu64按对象timestamp过滤闭区间为 0 禁用且不能为2^64 - 1limitu32最大返回条数不能为 0flagsflags.reversed语义同AccountFilter。客户端会话Client Sessions客户端会话是客户端与集群之间的一串请求/应答序列。会话机制详见 sessions.md。关键性质每个会话至多一个在途请求in-flight简化一致性并让集群能在入站消息队列上静态保证容量应用追加的请求由客户端排队等前一个请求收到应答后再发出。与多数数据库一样TigerBeetle 对并发会话数有硬限制为最大化吞吐官方鼓励减少并发客户端数量并在每次请求中尽量批量打包事件。生命周期会话始于客户端向集群注册每个会话有唯一的临时随机 128 位 client id客户端发送特殊 register 消息由集群提交后即已注册收到应答后即可开始发请求注册由 TigerBeetle 客户端实现自动处理客户端初始化时、发送首个请求前客户端重启如应用服务重启不会恢复旧会话而是以新的随机 client id 开启新会话会话结束于被**驱逐evicted**或客户端终止二者先到先触发。驱逐Eviction当新会话注册时若活跃会话数已达集群并发上限config.clients_max默认64见 src/config.zig#L228必须驱逐一个旧会话腾出空间被驱逐后该会话未来的请求永远不会执行被选中的是最久未提交请求的会话集群会通知被驱逐会话若该客户端仍活跃会自终止并向应用抛出session evicted错误。若活跃客户端频繁出现session evicted大概率是并发客户端过多应增加每个客户端的批量打包数量。重试Retries会话会自动重试请求直到收到对应应答或客户端终止。与大多数数据库/RPC 客户端不同永不超时没有重试上限不向上暴露网络错误。理由在 TigerBeetle 的严格一致性模型下暴露这些错误会产生误导——网络延迟的请求可能超时后才执行延迟的应答也可能在其超时前执行错误并不代表请求未执行。会话保证Guarantees至多一个在途请求会话读到自己写入的内容read-your-writes写操作之后的读操作能看到该写的效果会话按集群上的发生顺序观察写入会话观察到的debits_posted/credits_posted单调递增绝不会回退会话永不观察到未提交更新、也永不观察到被破坏的不变量如credits_must_not_exceed_debits、linked等不同会话之间的应答可能乱序到达会话收到应答即可视为请求已执行会话终止重启后保证看到重启前已收到应答的更新效果不保证看到未收到应答的更新效果这些更新可能在未来任意时刻发生或永不发生。应用崩溃恢复的安全做法是使用id做幂等重试见 reliable-transaction-submission。请求 API 总览TigerBeetle 目前支持八类请求Requests 目录请求作用create_accounts创建Accountcreate_transfers创建Transferlookup_accounts按id获取Accountlookup_transfers按id获取Transferget_account_transfers按debit_account_id或credit_account_id获取Transferget_account_balances获取Account的历史余额query_accounts查询Accountquery_transfers查询Transfer官方同时注明更多请求类型包括更强大的查询即将推出批量大小限制Batch Size所有请求都以批量事件提交默认配置下各请求类型的最大批量为数据来源docs/coding/requests.md#batching-events请求最大输入最大输出lookup_accounts81898189lookup_transfers81898189create_accounts81898189create_transfers81898189get_account_transfers1†8189get_account_balances1†8189query_accounts1†8189query_transfers1†8189† 每次仅接受一个过滤条件单个账户/单条查询输出仍可分批返回。create_accountsEvent一批待创建的Account约束见 Account。Result与批次中每个账户一一对应的结果数组。timestamp创建成功时为分配给该账户的时间戳已存在exists时为原始对象的时间戳其余结果为校验发生时刻。status状态码按优先级降序排列——若多个错误同时适用只返回列表中最靠前的那个。create_accounts的状态码完整枚举见 src/tigerbeetle.zig#L153-L215 的CreateAccountStatuscreated创建成功此前不存在linked_event_failed链接链中某账户无效导致整条链失败linked_event_chain_open批次最后一个事件设置了flags.linked非法链必须是闭合的imported_event_expected批次首账户设置了imported但并非批次内所有账户都设置不允许混批imported_event_not_expected批次首账户未设置imported但后续出现设置了的账户同样禁止混批timestamp_must_be_zero非 imported 场景下timestamp非 0imported_event_timestamp_out_of_range/imported_event_timestamp_must_not_advance/imported_event_timestamp_must_not_regressimported 场景下时间戳越界 / 超前 / 回退reserved_field/reserved_flag预留字段或预留 flag 非 0id_must_not_be_zero/id_must_not_be_int_maxid非法exists_with_different_flags/exists_with_different_user_data_128/64/32/exists_with_different_ledger/exists_with_different_code同id已存在但相应字段不同exists同id已存在且完全一致flags_are_mutually_exclusive互斥 flag 被同时设置debits_pending_must_be_zero/debits_posted_must_be_zero/credits_pending_must_be_zero/credits_posted_must_be_zero余额字段创建时非 0ledger_must_not_be_zero/code_must_not_be_zeroledger或code为 0。create_transfersEvent一批待创建的Transfer。成功创建的转账会修改其借方与贷方账户的金额字段。Result与批次一一对应的结果数组timestamp与status的语义同create_accounts。create_transfers的状态码在 src/tigerbeetle.zig#L220-L315 的CreateTransferStatus中完整枚举除与create_accounts同名者外还包括id_already_failed该id此前已提交过失败结果debit_account_id_must_not_be_zero/credit_account_id_must_not_be_zero/..._int_max账户 ID 非法accounts_must_be_different借贷方为同一账户pending_id_must_be_zero/pending_id_must_not_be_zero/pending_id_must_not_be_int_max/pending_id_must_be_differentpending_id使用不当timeout_reserved_for_pending_transfer非 pending 转账设置 timeoutclosing_transfer_must_be_pendingclosing 转账未设置pendingledger_must_not_be_zero/code_must_not_be_zerodebit_account_not_found/credit_account_not_found账户不存在accounts_must_have_the_same_ledger/transfer_must_have_the_same_ledger_as_accounts账本不一致pending_transfer_not_found/pending_transfer_not_pendingpending_id不存在或非 pending 状态pending_transfer_has_different_*post/void 字段与 pending 转账不一致debit/credit 账户、ledger、code、amountexceeds_pending_transfer_amountpost 金额超过 pending 金额pending_transfer_already_posted/pending_transfer_already_voided/pending_transfer_expiredpending 转账已处理或已过期imported_event_timestamp_must_postdate_debit_account/..._credit_account/imported_event_timeout_must_be_zeroimported 转账的时间戳/超时约束debit_account_already_closed/credit_account_already_closed账户已关闭overflows_debits_pending/overflows_credits_pending/overflows_debits_posted/overflows_credits_posted/overflows_debits/overflows_credits/overflows_timeout各类数值溢出exceeds_credits/exceeds_debits超出账户余额约束如 balance 限制 flagexists_with_different_pending_id/exists_with_different_timeout/exists_with_different_debit_account_id/exists_with_different_credit_account_id/exists_with_different_amount/exists_with_different_ledger同id已存在但字段不同deprecated_18原amount_must_not_be_zero已废弃保留。源码还定义了transient()判断src/tigerbeetle.zig#L320-L362debit_account_not_found、credit_account_not_found、pending_transfer_not_found、exceeds_credits、exceeds_debits、debit_account_already_closed、credit_account_already_closed属于瞬时错误——用相同数据重试同一转账可能得到不同结果其余错误对相同输入是确定性的。lookup_accounts按id批量获取账户。Event一个或多个Account.idResult存在则返回Account不存在则什么都不返回。两点重要提醒不要在创建转账前用本请求检查余额再转账——这不具备原子性检查与转账之间余额可能变化。应改用账户上的debits_must_not_exceed_credits/credits_must_not_exceed_debitsflag 来限制余额更复杂的条件转账见 balance-conditional-transfers 配方目前无法原子地查询超过一整批8189 个的账户多次lookup_accounts之间其他操作可能穿插导致读偏斜read skew可考虑用historyflag 启用原子查询。lookup_transfers按id批量获取转账。Event一个或多个Transfer.idResult存在返回Transfer不存在不返回。get_account_transfers获取与某账户相关的转账。EventAccountFilterResult匹配过滤条件的Transfer数组可能为空约束违规则什么都不返回。默认按timestamp升序可用reversed反转结果始终有大小上限超出需用timestamp_min/timestamp_max翻页。get_account_balances获取账户历史AccountBalance。只有创建时设置了historyflag 的账户才保留历史余额默认关闭。注意每个返回的余额对应一笔相同timestamp的转账金额是转账执行之后的余额因timeout到期而自动移除的 pending 余额不会改变历史余额未设置history、无匹配余额或约束违规时都不返回任何结果。query_accounts/query_transfers按若干字段的交集与时间戳范围查询对象。EventQueryFilterResult匹配对象数组默认按timestamp升序可用reversed反转结果有大小上限超出用timestamp_min/timestamp_max翻页。query_accounts同样受单次最多原子查询一整批8189 个限制多批次查询间可能读偏斜。源码级印证从文档到实现文档中的约定在源码中都有直接对应extern struct定义src/tigerbeetle.zig 中的const Account extern struct、const Transfer extern struct、const AccountBalance extern struct与文档字段一一对应并通过编译期断言保证无填充字节、结构体恰为 128 字节、16 字节对齐如sizeOf(Account) 128。文档中账户记录只有 128 字节的表述正源于此。flag 位域AccountFlags与TransferFlags均为packed struct(u16)对应文档中 16 位的flags字段如Account.debits_exceed_credits()/credits_exceed_debits()src/tigerbeetle.zig#L34-L42正是debits_must_not_exceed_credits等余额限制 flag 的判定实现。状态码枚举CreateAccountStatus与CreateTransferStatus都是enum(u32)注释明确状态码按优先级降序排列与文档若多个错误适用只返回最靠前一个的说明一致created被映射为u32最大值。超时换算Transfer.timeout_ns()src/tigerbeetle.zig#L106-L109将秒级timeout安全地转为纳秒u64防溢出支撑文档中到期时间 timestamp timeout纳秒的语义。执行入口账户/转账的创建与查询逻辑位于 src/state_machine.zig搜索fn create_account(、fn create_transfer(、fn execute_lookup_accounts(、fn execute_lookup_transfers(状态机按文档所述完成字段校验与余额更新。会话容量config.clients_max默认 64src/config.zig#L228是驱逐机制中并发客户端会话上限的配置来源且该参数会进一步影响消息尺寸下限计算message_size_max_minsrc/config.zig#L185-L191。各语言的客户端文档八类请求在各语言客户端中均有对应用法示例可查阅.NETAccount Lookup / Transfer Lookup / Get Account Transfers / Get Account Balances / Query Accounts / Query TransfersJavaGoNode.jsPython小结Reference 是 TigerBeetle 面向应用的全量规范Account与Transfer定义了不可变账本的最小事实单元及其全部约束AccountBalance/AccountFilter/QueryFilter支撑余额历史与过滤查询Client Sessions 定义了严格一致性下的会话、驱逐与重试语义八类请求则构成完整的读写 API。无论是选择id方案、配置history保留余额历史、用余额限制 flag 实现原子性约束还是组合两阶段转账与 linked chain本文所整理的字段、flag、状态码与源码位置都能作为你继续深入的起点——更细的建模讨论与实战配方可继续阅读 数据建模、两阶段转账、链路事件 与 可靠提交 等 Coding 文档。【免费下载链接】tigerbeetleThe financial transactions database designed for mission critical safety and performance.项目地址: https://gitcode.com/GitHub_Trending/ti/tigerbeetle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考