尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
TigerBeetle 限流实践:用漏桶算法与两阶段转账实现请求速率、带宽与转账金额限流
TigerBeetle 限流实践用漏桶算法与两阶段转账实现请求速率、带宽与转账金额限流【免费下载链接】tigerbeetleThe financial transactions database designed for mission critical safety and performance.项目地址: https://gitcode.com/GitHub_Trending/ti/tigerbeetleTigerBeetle 的核心数据模型是账户Account、转账Transfer与账本Ledger但这套复式记账模型不仅能记录资金也能用来计量任何可量化的资源。本文基于 限流配方文档完整讲解如何用漏桶leaky bucket算法的思想借助带超时timeout的挂起转账pending transfer与账户余额约束在 TigerBeetle 上实现请求速率限流、带宽限流和转账金额限流并深入到 src/state_machine.zig 的校验与过期清理源码说明其背后的确定性与悲观校验原理。读完本文你将掌握一套不需要外部限流中间件、天然具备审计与幂等保证的限流建模方案。为什么可以用 TigerBeetle 做限流限流的本质是配额的分配与回收在每个时间窗口内用户能消费多少资源消费后配额减少窗口结束后配额恢复。这恰好对应复式记账中的两个动作配额发放 → 贷记credit用户账户配额消耗 → 借记debit用户账户TigerBeetle 可以为非金融资源记账见 recipes 目录本配方即用这一思想实现基于用户请求速率、带宽和金额的限流。它的核心优势在于确定性所有判定都由 TigerBeetle 集群在提交时完成不存在分布式系统中常见的竞态窗口可审计每次配额消耗都是一条不可变的转账记录天然形成审计轨迹幂等转账 ID 由客户端指定配合幂等提交语义可以安全重试见 可靠事务提交。核心机制配额账户 自动过期的挂起转账整个方案的机制非常简单分为四步按资源建账本每一种要限流的资源请求速率、带宽、金额各建一个专属账本ledger。账本用来隔离不同类型的资源避免请求次数与字节数混淆账本定义见 Account.ledger。建账户对每个账本上有一个运营方Operator账户和每个用户一个账户。加余额约束给每个用户账户设置debits_must_not_exceed_credits标志使其借记总额不能超过贷记总额即已消费 已挂起 ≤ 已发放配额。发放配额 挂起消耗先把资源限额一次性贷记给用户随后每个请求创建一个指向运营方的 挂起转账pending transfer 并带上 超时timeout。永远不 post 也不 void 这些转账让它们超时自动过期。为什么选择让挂起转账过期挂起转账会将其金额计入账户的debits_pending/credits_pending预留金额而不改动debits_posted/credits_posted已入账金额详见 两阶段转账。其效果是发起请求 → 创建挂起转账 → 用户的可用余额被扣减计入 pending超时到期 → TigerBeetle 自动把挂起金额归还到原账户配额恢复配额用尽 → 新的挂起转账因debits_must_not_exceed_credits约束被拒绝create_transfers返回exceeds_credits。整个过程不需要应用侧做任何回收工作——回收由集群在提交时间戳推进到到期时刻时自动完成。关键挂起转账在校验时就是悲观的与先通过、post 时再失败的乐观方案不同TigerBeetle 对带余额约束账户的挂起转账做悲观校验debits_must_not_exceed_credits的判定在挂起转账创建时就执行见 Account 标志说明 中account.debits_pending account.debits_posted transfer.amount account.credits_posted的判定式。因此配额超限的请求在提交时立刻失败绝不会出现先扣了、到 post 时才发现超限的情况。请求速率限流每用户每分钟 10 次假设我们要把每个用户限制为每分钟 10 次请求。账户设置为 Request Rate 资源建立一个账本其中运营方账户不设约束用户账户设置debits_must_not_exceed_creditsLedgerAccountFlagsRequest RateOperator0Request RateUserdebits_must_not_exceed_credits初始化先从运营方向用户转账 10 个配额单位TransferLedgerDebit AccountCredit AccountAmount1Request RateOperatorUser10每个请求创建一个金额为 1、超时为 60 秒的挂起转账方向是用户 → 运营方TransferLedgerDebit AccountCredit AccountAmountTimeoutFlags2...NRequest RateUserOperator160pending注意这里超时取 60秒正是因为我们想要的窗口是每分钟。超时是以秒为单位的相对间隔而非绝对时间戳这一设计对集群与应用之间的时钟偏差更稳健见 TigerBeetle 的时间模型 与 Transfer.timeout。就这么简单每个挂起转账预占用户的一部分配额超时后自动归还。用户在窗口内发起第 11 个请求时因为 10 个配额单位全部被挂起新转账会被拒绝60 秒后挂起金额逐批归还配额恢复限流自动漏掉。带宽限流每用户每分钟 10 MB基于带宽限流与基于请求速率限流的差别只在于金额的含义不再用每次请求记 1 单位而是用请求的实际大小作为转账金额。假设要把每个用户限制为每分钟 10 MB10,000,000 字节账户设置与请求速率场景一致只是换一个账本LedgerAccountFlagsBandwidthOperator0BandwidthUserdebits_must_not_exceed_credits初始化从运营方向用户转账 10,000,000 个单位这里单位就是字节TransferLedgerDebit AccountCredit AccountAmount1BandwidthOperatorUser10000000每个请求创建挂起转账金额等于本次请求的大小超时仍为 60 秒TransferLedgerDebit AccountCredit AccountAmountTimeoutFlags2...NBandwidthUserOperatorRequest Size60pending这里依然使用 60 秒超时但你可以根据业务需要把它调整成任意时间窗口例如按秒限流就调小按小时限流就调大。原理完全一致一个 3 MB 的请求会挂起 3,000,000 个配额单位当窗口内累计请求大小达到 10,000,000 字节时后续请求会因为exceeds_credits被拒绝。转账金额限流每账户每天最多 1000 USD前两种方案限的是资源消耗而有时我们需要限的是用户实际转账的金额——例如限制每个账户每天最多转出 1000 USD。这需要两个账本限流账本 资金账本和 链接事件linked transfers 配合使扣减配额与真实转账要么同时成功、要么同时失败。账户设置LedgerAccountFlagsRate LimitingOperator0Rate LimitingUserdebits_must_not_exceed_creditsUSDOperator0USDUserdebits_must_not_exceed_credits初始化在 Rate Limiting 账本上从运营方向用户转账 1000TransferLedgerDebit AccountCredit AccountAmount1Rate LimitingOperatorUser1000每次用户发起转账同时创建 2 个转账并通过linked标志链在一起|表示同时设置多个标志TransferLedgerDebit AccountCredit AccountAmountTimeoutFlags\|表示同时设置多个标志2NRate LimitingUserOperatorTransfer Amount86400pending|linked2N 1USDUserDestinationTransfer Amount00这里超时取 86400 秒因为这是一天的秒数。链路语义根据 链接事件flags.linked会把当前事件的结果与下一个事件绑定整条链要么全部成功、要么全部失败且链内事件按顺序执行、出错即回滚。因此第 2N 条挂起转账在 Rate Limiting 账本上消耗配额限额判定的关键一步第 2N 1 条是 USD 账本上的真实转账如果用户当天已经转出了太多金额第 2N 条会因exceeds_credits失败链接的第 2N 1 条真实转账也随之失败返回linked_event_failed。需要注意链中最后一个事件不能带linked标志否则会返回linked_event_chain_open错误。另外链中若存在多组链接各组可以独立成败。源码视角限流判定与自动过期如何落地校验发生在挂起转账创建时账户余额约束的实际判定位于 src/state_machine.zig 的create_transfer执行路径if (dr_account.debits_exceed_credits(amount_actual)) return .exceeds_credits; if (cr_account.credits_exceed_debits(amount_actual)) return .exceeds_debits;debits_exceed_credits即debits_pending debits_posted amount credits_posted的封装其含义与 Account 标志文档 完全一致。紧接着L3927-L3934挂起转账会把金额计入账户的debits_pending/credits_pending从而冻结这部分配额if (t.flags.pending) { dr_account_new.debits_pending amount_actual; cr_account_new.credits_pending amount_actual; ... }也就是说限流拒绝在提交时刻即生效且是集群内确定性串行化的判定多个并发请求之间不存在同时通过再超卖的窗口。过期金额由集群自动归还挂起转账的过期不是应用侧轮询的结果而是由状态机在提交时间戳推进到到期时刻时触发。在 src/state_machine.zig 的execute_expire_pending_transfers中TigerBeetle 找出所有到期未决的挂起转账并把金额从debits_pending/credits_pending中减去const expires_at p.timestamp p.timeout_ns(); assert(expires_at timestamp_event); ... dr_account_new.debits_pending - p.amount; cr_account_new.credits_pending - p.amount;关于过期语义有几点需要结合 Transfer.timeout 的文档说明理解转账在timestamp timeout时刻精确到期到期之前挂起余额绝不会被提前移除已到期的挂起转账不能再被手动 post 或 void会返回pending_transfer_expired集群对过期清理是best-effort不保证余额在到期那一刻被立即移除客户端请求在短时间内仍可能观察到已到期但尚未清理的挂起余额。因此应用侧不应依赖过期后余额立刻可用的强实时性。这正是限流配方选择只挂起、不结算方案的底层依据无需任何后台任务过期即自动回补配额。落地要点与注意事项金额语义与资源单位TigerBeetle 的金额是128 位无符号整数。限流资源请求次数、字节数、货币金额都必须映射为整数单位带宽场景直接把字节数作为金额货币场景参照 小数金额与资产缩放 的建议把最小有用单位映射为 1例如 1000 USD 记作1000_00分或按你的资产缩放系数换算避免浮点精度问题。转账 ID 与幂等重试每个请求的挂起转账都要生成唯一的转账 ID参考 数据建模中的 ID 建议如使用时间基 ID。同一请求重试时必须复用同一个 IDcreate_transfers会返回exists而不是重复扣减配额如果一条转账因瞬时错误如exceeds_credits、debit_account_not_found失败用相同 ID 重试会得到相同的失败结果id_already_failed机制见 create_transfers 结果说明这保证了配额不足时反复重试不会绕过限流。配额发放与重置的建模本文中的初始转账是给用户发放窗口配额。更复杂的场景如定期重置配额、多档套餐、租户隔离可以进一步参考 余额上下界配方、货币兑换配方 与 多借多贷转账配方 的组合用法多个限流账本也可以放进同一次create_transfers批量请求中一次提交。客户端接入各语言客户端均提供了与账户/转账/链接事件对应的 API可直接调用create_accounts与create_transfers实现上述流程具体接口见.NET 客户端Go 客户端Java 客户端Node.js 客户端Python 客户端更多客户端与示例可浏览 Clients 目录 及各子目录下的 samples。小结本文给出的三种限流方案共用同一套机制按资源建账本 → 给用户账户加debits_must_not_exceed_credits约束 → 发放配额 → 每次消耗创建带 timeout 的挂起转账并让其自动过期。请求速率限流与带宽限流只差金额的语义转账金额限流则通过两个账本加链接事件实现配额扣减与真实转账原子绑定。由于所有判定都发生在集群提交路径上src/state_machine.zig且过期回补由状态机自动执行src/state_machine.zig这套方案无需额外的限流组件即可获得确定性、可审计、天然幂等的限流能力。更完整的账本与数据建模思路可继续阅读 数据建模 与 两阶段转账。【免费下载链接】tigerbeetleThe financial transactions database designed for mission critical safety and performance.项目地址: https://gitcode.com/GitHub_Trending/ti/tigerbeetle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

H5棋牌系统二次开发:WebSocket保活与状态一致性重构

H5棋牌系统二次开发:WebSocket保活与状态一致性重构

1. 为什么一个“修好了就能跑”的H5棋牌系统,反而最难二次开发?我接手这个项目时,客户发来一句:“GitHub上拉下来的开源H5棋牌系统,本地能跑,但加个新玩法就崩,改个结算逻辑就串号,W…

📅 2026/9/14 3:00:34
TOOMOSS CAN卡LabVIEW句柄管理:UDS刷写稳定性的底层保障

TOOMOSS CAN卡LabVIEW句柄管理:UDS刷写稳定性的底层保障

1. 项目概述:这不是一个“LabVIEW调用CAN设备”的简单例子,而是一套面向汽车电子量产级UDS刷写场景的底层句柄治理方案图莫斯(TOOMOSS)这个品牌在汽车电子测试圈子里,老手们基本都绕不开。它家的CAN卡——尤其是带硬件…

📅 2026/9/14 3:00:34
WiFi接收机时频同步详解:从帧结构到工程实现

WiFi接收机时频同步详解:从帧结构到工程实现

做WiFi接收机,尤其做OFDM物理层的时候,“时频同步”这四个字几乎就是第一道门槛。不管你是写嵌入式平台上的协议栈,还是在FPGA里写RTL,还是在PC上搭软件无线电原型,只要信号从天线进来,接收机要做的第一件事…

📅 2026/9/14 3:00:34
MORE NEWS

更多资讯

📰

VOC数据转YOLO训练:类别映射、坐标归一化与数据体检实战指南

简介:面向交通道路目标检测任务的多类别标注数据集,覆盖车辆、行人、自行车与摩托车等常见交通参与者,适合计算机视觉初学者入门实践,也适合自动驾驶、智慧交通等方向的开发者在真实道路场景下进行模型训练与算法验证。压缩包约12…

📰

ARM交叉编译本质:ABI对齐与架构直觉

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

AI英语学习APP开发:核心技术架构与实战经验

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

基于STM32计算器实战:LCD1602与矩阵键盘驱动全解析

做单片机课设的时候,老师给的题目单里十有八九有一项“基于STM32的计算器”,甚至很多初学嵌入式的朋友第一个上手项目也是它。这题目看起来没什么技术含量,但真动手做起来,从硬件到软件全是细节——LCD1602这个经典老屏幕的驱动时…

📰

COMSOL晶圆Bow提取:总位移云图≠翘曲度的物理本质与工业级方法

1. 为什么总位移云图≠晶圆Bow?一个被90%初学者误解的物理本质刚接触COMSOL做晶圆薄膜应力仿真的朋友,几乎都会在结果后陷入困惑:明明模型里施加了几十MPa的残余应力,总位移云图上也显示中心隆起几微米,可一查文献或工…

📰

Multisim 14.3 安装配置指南:数据库报错与元件库修复全攻略

打开搜索引擎搜“Multisim 14.3 安装步骤”,能翻到大量提问帖,大家问的问题高度相似:装完打不开、打开后弹“访问数据库发生错误”、元件库空了一半、安装界面全英文找不到语言选项。这台经典的电路仿真软件,其实安装逻辑本身并不…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬