GitHub 开源高可用协作式限流器服务 Freno
速览
GitHub 正式开源 Freno 限流器服务,该服务采用协作式设计,具备高可用特性,可有效防止系统过载。Freno 通过动态调整请求速率,保障后端服务的稳定性,适用于分布式系统架构。这一开源项目丰富了云原生生态中的限流方案。
AI 深度解读
背景
在现代大规模分布式系统中,数据库写入操作常常面临复制延迟、资源争用和系统过载等问题。尤其是当执行批量数据操作(如大量数据加载、归档、模式迁移、批量更新)时,这些操作会遍历成千上万行甚至数百万行数据,可能导致 MySQL 复制延迟急剧上升,进而影响数据库性能和依赖该数据库的应用。传统的做法是手动或通过笨重的限流机制控制写入速率,但缺乏灵活性、可扩展性和高可用性。GitHub 工程团队为了解决这一问题,开发了 freno——一个合作式、高可用的限流服务,专门用于在 MySQL 集群场景下基于复制状态动态调节写入速率。
核心内容
freno 是一个合作式(cooperative)限流服务,客户端通过它来限制对资源的写入操作。当前实现可以基于多个 MySQL 集群的复制状态,控制对这些集群的写入。当复制延迟超过预定义的阈值时,freno 会通知合作客户端进行限流。
freno 能够动态适应服务器清单的变化,用户也可以手动强制对某些应用进行限流。freno 本身是高可用的,它使用 Raft 共识协议来决定领导节点,并在成员节点之间传递用户事件。
freno 从后端存储(目前仅支持 MySQL)收集数据,并具备逻辑判断能力来回答“我是否可以写入后端存储?”这个问题。客户端(应用、脚本、任务)需要主动咨询 freno。freno 不是客户端与后端存储之间的代理,它只是观察存储状态,并返回“可以写入”或“应该停止写入”的建议。客户端需要遵守这些建议。
freno 按数据存储独立收集数据。例如,当探测多个 MySQL 集群时,它会为每个集群独立收集复制延迟。后端存储的指标自动收集,并被视为绝对真值。
freno 以应用(app)的身份标识来服务客户端。由于是合作式,freno 信任应用自行标识自己。应用可以被管理:管理员可以指示 freno 强制限流某个应用,以便让其他高优先级应用能够正常运行完成。freno 仅接受关于限流谁的命令,本身不包含调度或优先级逻辑。
freno 最初设计目的是为 MySQL 限流提供统一、自适应的解决方案:在保持低复制延迟的同时控制写入。freno 配置了一个预定义的 MySQL 集群列表,包括凭证、延迟(或其他)检查查询以及预期阈值。对于每个集群,freno 需要知道要探测哪些服务器并收集数据。服务器列表可以是静态的(硬编码的 hostname:port 列表),也可以是动态的(支持通过 haproxy 动态发现:提供 haproxy 的 URL 和后台/池名称,freno 会定期解析该池中启用的服务器列表并动态适应探测)。
freno 对批量操作非常有用:大规模加载/归档任务、模式迁移、批量更新。通过将这些任务分解为小任务(例如每次处理 100 行),并在每应用子任务之前咨询 freno,能够在没有不良影响的情况下完成相同的结果。freno 也可用于确定实际延迟以推断副本的有效性,帮助缓解主从读写的“写后读”问题。
freno 通过 HTTP 提供服务。最重要的请求是检查请求:“这个应用可以写入这个存储吗?”freno 支持 HEAD 请求(GET 也接受但开销更大),并返回以下状态码:
- 200 (OK):应用可以写入数据存储。
- 404 (Not Found):未知的指标名称。
- 417 (Expectation Failed):请求的应用被明确禁止写入。
- 429 (Too Many Requests):不要写入。这是正常状态,表示存储的状态未达到预期阈值。
- 500 (Internal Server Error):内部错误,不要写入。
客户端通常通过 HEAD 方法发起 /check/... 请求。客户端每秒可能发起大量请求(数百次/秒),freno 资源消耗轻量,可以承受。客户端应根据所需粒度调整请求频率:例如,如果目标复制延迟阈值为 1000ms,每秒检查 200 次可能过度,但若希望客户端保持简单而不缓存,这也无妨。
freno 使用 Raft 实现高可用。freno 节点会竞争领导权,只有领导者会收集指标并服务客户端。
freno 提供了示例配置文件、通用/Raft 配置说明、MySQL 特定配置说明、部署文档建议。freno-client 是 Ruby 客户端,作为 Ruby Gem 开源。
“freno” 是西班牙语中“刹车”的意思(如汽车刹车)。项目名称来源于查找字典时看到的句子 “Echa el freno, magdaleno!”(拉紧刹车,马格达莱诺!),让人联想到 80 年代,因此得名。
该项目处于活跃开发中,欢迎贡献,并遵守行为准则。项目采用 MIT 许可证发布,包含第三方依赖。
关键要点
- 合作式限流模型:freno 不强制拦截写入,而是向客户端提供建议(“可以写入”或“应该停止”),客户端需主动咨询并遵守。
- 基于 Raft 的高可用:多个 freno 节点通过 Raft 选举领导者,只有领导者提供服务,保证可用性和一致性。
- 动态适应:服务器清单可静态或动态配置,支持通过 haproxy 动态发现,限流阈值自动适应变化。
- 多集群独立管理:每个 MySQL 集群独立配置和探测,复制延迟等指标独立收集,互不影响。
- 应用级限流:客户端以应用身份标识,freno 可强制限流特定应用,以便让高优先级应用运行,但自身不包含调度逻辑。
- 轻量级 HTTP 接口:主要使用 HEAD 请求检查状态,响应状态码语义明确(200、404、417、429、500),支持高频率请求(数百次/秒)。
- 批量操作的理想工具:通过将大任务分解为小事务,结合 freno 检查,在保持低复制延迟的同时完成大量写入。
- 开源与贡献:由 GitHub 工程团队开发,采用 MIT 许可证,提供 Ruby 客户端,文档完善,社区可参与。
意义与影响
freno 的出现解决了大规模 MySQL 环境下写入限流缺乏统一、自适应、高可用解决方案的问题。它通过简洁的合作式设计,将限流决策与执行分离,降低了系统耦合度,允许客户端灵活选择是否遵守建议。动态适应能力使得运维人员无需频繁调整配置,即可应对集群扩缩容。基于 Raft 的高可用机制保证了关键限流服务不成为单点故障。freno 的设计理念(只观察、不代理)避免了性能瓶颈,其轻量级 HTTP 接口也易于集成到各种语言和框架中。对于依赖 MySQL 的大型互联网公司(如 GitHub 自身),freno 提供了可靠且可扩展的写入控制手段,有助于提升数据库稳定性和整体系统可靠性。该项目开源后,社区可以借鉴其设计思路,甚至将其理念扩展到其他后端存储(如 Redis、Kafka 等),推动限流基础设施的标准化。
