TigerBeetle Python 客户端入门:用 basic 示例跑通“建账户—转账—校验余额“全流程
2026/9/14 6:09:10 网站建设 项目流程

TigerBeetle Python 客户端入门:用 basic 示例跑通"建账户—转账—校验余额"全流程

【免费下载链接】tigerbeetleThe financial transactions database designed for mission critical safety and performance.项目地址: https://gitcode.com/GitHub_Trending/ti/tigerbeetle

导读

本文以 TigerBeetle 仓库中 basic 示例 为骨架,完整讲解如何使用 Python 客户端(tigerbeetlepip 包)连接 TigerBeetle 数据库:安装客户端、启动服务端、创建两个账户、发起一笔转账,最后回查账户余额并用断言逐项校验借方(debits)与贷方(credits)的变化。读完本文,你将掌握 Python 客户端的最小可用闭环,并理解账户/转账的数据结构、状态码枚举与批处理(batching)等底层约定,可以直接照抄代码跑通你的第一个 TigerBeetle 事务。


1. 示例概览:这个 basic 项目做了什么

示例代码位于 src/clients/python/samples/basic/main.py,整个流程只有三步,却覆盖了 TigerBeetle 最核心的三种操作:

  1. 创建账户:用create_accounts批量创建两个账户,id 分别为12
  2. 创建转账:用create_transfers将金额10从账户1(debit,借方)转到账户2(credit,贷方);
  3. 回查并校验余额:用lookup_accounts取回两个账户,断言账户1debits_posted = 10credits_posted = 0,账户2debits_posted = 0credits_posted = 10

这本质上就是一个"最小双账户转账"用例,是理解 TigerBeetle 借贷记账模型(double-entry bookkeeping)最快的入口。仓库里还有两个进阶示例与之对照:two-phase(两阶段转账:先 PENDING 再 POST)和 two-phase-many(多条待定转账交替 post/void),可在跑通 basic 后继续阅读。

2. 环境与前置条件

根据 basic 示例 README 与 tigerbeetle-python 客户端文档,运行本示例需要满足:

  • 操作系统:Linux >= 5.6 是唯一的生产环境支持平台;为便于开发,macOS 与 Windows 也受支持。
  • Python:>=3.7(PyPy 等实现亦可)。

Python 包内部通过 ctypes 加载随包分发的原生共享库(tb_client)。从 src/clients/python/src/tigerbeetle/lib.py 的加载逻辑可以看到,它按平台自动选择动态库文件:

  • 架构仅支持x86_64/amd64aarch64/arm64
  • Linux 下区分 glibc(-gnu.2.27后缀)与 musl(-musl后缀),其他 libc 会抛出NativeError: Unsupported libc
  • 系统仅支持 Linux、Darwin、Windows,其他平台会抛出NativeError: Unsupported system

也就是说,只要你的机器满足上述架构与系统组合,pip install tigerbeetle后无需任何额外编译即可使用。

3. 安装 Python 客户端

进入示例目录后直接安装:

$ cd tigerbeetle/src/clients/python/samples/basic $ pip install tigerbeetle

安装完成后,在 Python 中做一次冒烟测试即可确认环境正常:

import os import tigerbeetle as tb print("Import OK!") # 如需开启调试日志,可通过 Python 内置 logging 模块: # logging.basicConfig(level=logging.DEBUG) # tb.configure_logging(debug=True)

tb.configure_logging(debug=True)来自 src/clients/python/src/tigerbeetle/client.py,它把 TigerBeetle 原生层的日志回调桥接到 Python 的logging体系,排查问题时非常有用。

4. 启动 TigerBeetle 服务端

示例 README 要求先按仓库主 README 的步骤启动 TigerBeetle。单副本集群的最小启动方式(见 README.md):

$ curl -Lo tigerbeetle.zip https://linux.tigerbeetle.com && unzip tigerbeetle.zip $ ./tigerbeetle version $ ./tigerbeetle format --cluster=0 --replica=0 --replica-count=1 --development 0_0.tigerbeetle $ ./tigerbeetle start --addresses=3000 --development 0_0.tigerbeetle

关键点:

  • cluster:示例使用cluster_id=0,与format --cluster=0保持一致;
  • 地址:默认监听localhost:3000。如果服务端不在该地址,设置环境变量TB_ADDRESS指向完整地址即可:
    $ export TB_ADDRESS="127.0.0.1:3000"
  • 地址的合法写法(来自客户端文档):
    • 3000→ 解释为127.0.0.1:3000
    • 127.0.0.1:3000→ 保持不变
    • 127.0.0.1→ 解释为127.0.0.1:30013001是默认端口)

5. 运行示例

服务端就绪后,在示例目录下执行:

$ python3 main.py

程序用assert做自我校验,全部通过后打印ok。整个 main.py 的运行逻辑如下节所示。

6. 逐行拆解 main.py

6.1 创建客户端

import os import tigerbeetle as tb with tb.ClientSync(cluster_id=0, replica_addresses=os.getenv("TB_ADDRESS", "3000")) as client: ...
  • cluster_id必须与启动集群时指定的 cluster 一致;
  • replica_addresses是所有副本的地址列表(本例单副本,取环境变量TB_ADDRESS,缺省"3000");
  • ClientSync是同步客户端,用with语句进入上下文,退出时自动close()(见 src/clients/python/src/tigerbeetle/client.py 中__exit__close()的实现)。

6.2 创建账户

account_results = client.create_accounts([ tb.Account( id=1, ledger=1, code=1, ), tb.Account( id=2, ledger=1, code=1, ), ])

tb.Account是 Python 客户端定义的 dataclass(src/clients/python/src/tigerbeetle/bindings.py),字段与 wire 格式一一对应:

字段位宽说明
idu128账户唯一标识,示例用1/2;生产环境建议用tb.id()生成基于 ULID 的 128 位可排序 ID
debits_pending/debits_postedu128借方待定/已过账金额,新建账户必须为 0(服务端会校验)
credits_pending/credits_postedu128贷方待定/已过账金额,同上
user_data_128/user_data_64/user_data_32u128/u64/u32应用自定义数据,可用于关联业务 ID、做过滤查询
ledgeru32账本号,转账双方必须在同一 ledger,且与账户 ledger 一致
codeu16业务编码(如账户类型、币种),用于查询过滤
flagsu16位标志,见下文"Flags"小节
timestampu64必须为 0,由服务端分配(见TIMESTAMP_MUST_BE_ZERO错误码)

示例中所有金额/用户数据字段都取默认值 0,仅显式设置idledgercode,这是最简单合法的账户。

6.3 校验建账结果

print(account_results) assert len(account_results) == 2 assert account_results[0].status == tb.CreateAccountStatus.CREATED assert account_results[1].status == tb.CreateAccountStatus.CREATED

create_accounts的返回结果与请求一一对应,每个结果包含:

  • statusCreateAccountStatus枚举。成功为CREATED(数值0xFFFFFFFF,见 bindings.py);
  • timestamp:本次操作由服务端分配的时间戳。

值得注意的是,重复提交相同id的账户不会报"失败",而是返回EXISTS(携带原账户的时间戳),这正是 TigerBeetle 幂等语义的基础——重试是安全的。

6.4 创建转账

transfers_results = client.create_transfers([ tb.Transfer( id=1, debit_account_id=1, credit_account_id=2, amount=10, ledger=1, code=1, ), ])

tb.Transfer同样是与 wire 格式对应的 dataclass:

字段位宽说明
idu128转账唯一标识;TigerBeetle 用它做幂等去重,同 id 的转账只能提交一次
debit_account_idu128借方账户(资金流出方)
credit_account_idu128贷方账户(资金流入方),必须与借方不同
amountu128转账金额,0 < amount(普通转账金额不能为 0)
pending_idu128两阶段转账时指向 PENDING 转账的 id,普通转账为 0
timeoutu32仅对 PENDING 转账有意义(到期自动过期),单位秒(纳秒见源码语义),普通转账为 0
ledger/codeu32/u16同账户;转账 ledger 必须等于双方账户 ledger
flagsu16位标志,普通转账为 0
timestampu64必须为 0,由服务端分配

6.5 校验转账结果

print(transfers_results) assert len(transfers_results) == 1 assert transfers_results[0].status == tb.CreateTransferStatus.CREATED

CreateTransferStatus.CREATED同样是0xFFFFFFFF。与账户类似,若同 id 转账已存在,会返回EXISTS系列状态码。完整错误码枚举(如DEBIT_ACCOUNT_NOT_FOUNDCREDIT_ACCOUNT_NOT_FOUNDACCOUNTS_MUST_HAVE_THE_SAME_LEDGEREXCEEDS_CREDITS等)都在 bindings.py 中定义,可用于精细化错误处理。

6.6 回查账户并校验余额

accounts = client.lookup_accounts([1, 2]) assert len(accounts) == 2 for account in accounts: if account.id == 1: assert account.debits_posted == 10 assert account.credits_posted == 0 elif account.id == 2: assert account.debits_posted == 0 assert account.credits_posted == 10 else: raise Exception("Unexpected account: " + account) print("ok")

这里体现了 TigerBeetle 记账模型的核心语义:

  • debit 是"钱从哪来":账户 1 是借方,debits_posted从 0 变为 10;
  • credit 是"钱到哪去":账户 2 是贷方,credits_posted从 0 变为 10;
  • 借贷平衡debits_posted(账户 1)=credits_posted(账户 2)= 10,系统内部保证总借方恒等于总贷方。

lookup_accounts也是批处理接口,返回的账户顺序不一定与请求 id 顺序一致,因此代码用account.id做区分而不是依赖索引——这一点在客户端 README 的 Account Lookup 一节中有明确说明。

7. 关键 API 与常量速查

示例之外,同一个 Python 客户端还提供以下操作(均来自 bindings.py 的StateMachineMixin/AsyncStateMachineMixin,与 client.py 的同步/异步封装):

方法说明
create_accounts/create_transfers批量创建账户/转账
lookup_accounts/lookup_transfers按 id 批量查询(无匹配则不返回,顺序不保证)
get_account_transfers/get_account_balances按账户过滤查询流水/时点余额(预览 API,要求账户带HISTORY标志)
query_accounts/query_transfers按字段交集 + 时间范围查询(预览 API)

常用常量:

  • tb.id():生成基于 ULID 的 128 位全局唯一、按时间可排序 ID(实现见 client.py 的_IDGenerator);
  • tb.AMOUNT_MAX2**128 - 1,两阶段转账 post 时表示"post 掉整个 pending 金额";
  • tb.AccountFlags/tb.TransferFlagsenum.IntFlag位标志,可用|组合,例如:
    • AccountFlags.LINKED/TransferFlags.LINKED:链接事件(链上全部成功或全部回滚);
    • AccountFlags.DEBITS_MUST_NOT_EXCEED_CREDITS/CREDITS_MUST_NOT_EXCEED_DEBITS:余额约束;
    • AccountFlags.HISTORY:开启历史余额保留;
    • TransferFlags.PENDING/POST_PENDING_TRANSFER/VOID_PENDING_TRANSFER:两阶段转账三要素。

8. 从 basic 到生产:必须了解的批处理与幂等

basic 示例只提交了 2 个账户和 1 笔转账,但 TigerBeetle 的性能模型高度依赖批处理(客户端文档 "Batching" 一节):

  • 客户端实例是线程安全的,多个并发请求可被客户端自动合并批处理
  • 应用侧仍应尽量在单次调用中提交尽可能多的事件。例如插入 100 万笔转账,如果逐笔串行提交,插入速率将只是潜在能力的零头;应始终"尽可能多地批量提交";
  • 单批最大条数由服务端配置决定,默认值为8189(与测试文件 src/clients/python/tests/test_basic.py 中BATCH_MAX = 8189一致)。超过上限会抛出TooMuchDataError
batch = [] # 待创建的转账列表 BATCH_SIZE = 8189 for i in range(0, len(batch), BATCH_SIZE): transfers_results = client.create_transfers( batch[i:min(len(batch), i + BATCH_SIZE)], ) # 结果处理略

另一个生产级要点是幂等:TigerBeetle 以id作为去重键,重复提交同 id 的账户/转账会返回EXISTS(或EXISTS_WITH_DIFFERENT_*系列),而不会重复入账。因此应用可以用业务幂等键作为 id,配合 可靠事务提交 的指引实现"重试安全"的提交。此外,客户端"无限重试、不设单请求超时",关闭客户端时所有在途请求被取消并向调用方返回错误——即使收到错误,请求仍可能已被服务端处理,这正是需要用 id 幂等兜底的原因。

9. 进阶:两阶段转账(Pending → Post/Void)

basic 示例是"即时过账"的单阶段转账。如果业务需要"预授权—确认/取消"(如押金、扣款审批),TigerBeetle 原生支持两阶段转账,可参考 two-phase 示例:

  1. 发起待定转账flags=tb.TransferFlags.PENDING):金额进入双方的debits_pending/credits_pending,不计入已过账余额;
  2. 确认(post)flags=tb.TransferFlags.POST_PENDING_TRANSFERpending_id指向待定转账):系统原子地把pending回滚、把金额应用到debits_posted/credits_posted
  3. 取消(void)flags=tb.TransferFlags.VOID_PENDING_TRANSFER):只回滚pending应用到posted

post 时amount可设为tb.AMOUNT_MAX表示"全部确认"。待定转账还可设置timeout,到期后自动过期(测试 test_basic.py 的test_cannot_void_an_expired_transfer展示了过期语义)。更复杂的交替 post/void 场景可参考 two-phase-many 示例。

10. 常见错误与排查

  • InitErrorClientSync初始化失败。多为 cluster id 不匹配、地址不可达或原生库未加载(检查平台/架构是否受支持,见 lib.py)。
  • IntegerOverflowError:字段超出位宽。ctypes 绑定在提交前会对每个整数字段做范围校验(如 u128、u64、u32、u16),负数或过大值都会抛出该异常(对应测试 test_basic.py 的test_range_check_*系列)。
  • TooMuchDataError:单批请求超过服务端client_request_batch_max(默认 8189)。
  • ClientClosedError/ClientEvictedError/ClientReleaseTooLowError/ClientReleaseTooHighError:客户端关闭后被使用、被服务端淘汰、或客户端库版本与服务端不兼容(版本过旧/过新)。这些异常类型定义在 client.py。
  • TIMESTAMP_MUST_BE_ZERO:手动给Account.timestamp/Transfer.timestamp传了非 0 值,时间戳一律由服务端分配。

11. 小结

通过 basic 示例 与 main.py,你已经跑通了 TigerBeetle Python 客户端的最小闭环:ClientSync连接 →create_accounts建账 →create_transfers转账 →lookup_accounts校验借贷余额。在此基础上,结合 tigerbeetle-python 客户端文档 中关于 Flags、两阶段转账、批处理、链式事件与导入事件的章节,即可将这套最小示例扩展为具备余额约束、预授权、历史查询的生产级记账系统。

相关资源

  • basic 示例 README(本文主体来源)
  • basic 示例代码 main.py
  • tigerbeetle-python 客户端完整文档
  • Python 客户端核心实现 client.py
  • Python 客户端数据类型与状态码 bindings.py
  • 原生库加载与整型校验 lib.py
  • Python 客户端集成测试 test_basic.py
  • 两阶段转账示例
  • 仓库主 README 的服务端启动步骤

【免费下载链接】tigerbeetleThe financial transactions database designed for mission critical safety and performance.项目地址: https://gitcode.com/GitHub_Trending/ti/tigerbeetle

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询