> ## Content Index
> Fetch the complete content index at: https://huizhou92.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# 常见限速算法的分析与实现
- URL: https://huizhou92.com/e5-b8-b8-e8-a7-81-e9-99-90-e9-80-9f-e7-ae-97-e6-b3-95-e7-9a-84-e5-88-86-e6-9e-90-e4-b8-8e-e5-ae-9e-e7-8e-b0/
- Published: 2024-09-25T01:34:59.000Z
- Updated: 2026-09-06T11:38:44.000Z
- Description: 常见限速算法的分析与实现. 在软件架构中，限流是一种控制资源使用和保护系统安全的重要机制。它通过限制在一定时间内可以处理的请求数量，来防止系统过载，确保系统在高负载情况下仍能保持稳定运行。 本文的目标是分析和实现几种常见的限流算法，以及分析他们优缺点。最后我们探讨一下真实业务代码中的一些限流设计。 This。
- Author: huizhou92
- Tags: tech, go, 限流, #lang-zh-cn

在软件架构中，限流是一种控制资源使用和保护系统安全的重要机制。它通过限制在一定时间内可以处理的请求数量，来防止系统过载，确保系统在高负载情况下仍能保持稳定运行。  
本文的目标是分析和实现几种常见的限流算法，以及分析他们优缺点。最后我们探讨一下真实业务代码中的一些限流设计。

> This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on [Medium](https://medium.huizhou92.com/?ref=huizhou92.com). Thank you very much.

假设我们通过性能测试得出我们的系统最大的负载为10TPS。

## 流量计数器模式

最简单的做法，我们做一个计时器，每秒最多允许10个请求通过，超过这个数量的流量就拒绝。  
Code1 ： windows limit [run it](https://go.dev/play/p/o9GpZGJ8N7i?ref=huizhou92.com)

[https://gist.github.com/hxzhouh/51020e18622c2e38ebf21cd6a9dc5cc6](https://gist.github.com/hxzhouh/51020e18622c2e38ebf21cd6a9dc5cc6?ref=huizhou92.com)  
[View code snippet on GitHub Gist →](https://gist.github.com/hxzhouh/51020e18622c2e38ebf21cd6a9dc5cc6?ref=huizhou92.com)

但是这个做法是有问题的，假设我们2秒内收到了都收到了10TPS请求，但是是在 0.9s 与 1.1s 收到的，这样虽然每个周期的流量都不超过10 TPS请求的阈值，但是系统确实曾经在1s内发生了超过阈值的20TPS请求。  
流量计数器的缺陷根源在于它只是针对时间点进行离散的统计，为了弥补该缺陷，一种名为“滑动时间窗”的限流模式被设计出来，它可以实现平滑的基于时间片段统计。

## 滑动窗口机制

滑动窗口算法(Sliding Window Algorithm)在计算机科学的很多领域中都有成功的应用，譬如TCP协议的阻塞控制(Congestion Control)使用到滑动窗口算法

滑动窗口算法通过将时间分为多个小的时间段，每个时间段内维护一个独立的计数器。当一个请求到达时，它会被分配到当前时间所在的小时间段，并检查该时间段的计数器是否已达到限制。如果未达到，则允许请求并增加计数；如果已达到，则拒绝请求。随着时间的推移，旧的时间段会淡出窗口，新的时间段会加入。  
code2: sliding\_windows [try it](https://go.dev/play/p/kc-MacnzPTh?ref=huizhou92.com)  
[https://gist.github.com/hxzhouh/c5c79ea4b80ea5a026052471de07107f](https://gist.github.com/hxzhouh/c5c79ea4b80ea5a026052471de07107f?ref=huizhou92.com)  
[View code snippet on GitHub Gist →](https://gist.github.com/hxzhouh/c5c79ea4b80ea5a026052471de07107f?ref=huizhou92.com)  
[View code snippet on GitHub Gist →](https://gist.github.com/hxzhouh/c5c79ea4b80ea5a026052471de07107f?ref=huizhou92.com)

滑动窗口算法其实就是把流量计数器算法的时间窗口划分小一点，提供更细致的流量控制，并不能完全解决瞬时大流量。也很难在更细粒度上对流量曲线进行整形，起不到削峰填谷的作用。下面继续介绍两种适用于阻塞式限流的限流模式。

## 漏桶算法

漏桶算法是通过一个固定容量的队列来模拟桶，以恒定速率从桶中取出请求进行处理，无论请求到达的频率如何，都保证请求以均匀的速度被处理，从而平滑流量并防止流量突增。  
Code3: leakBucket [try it](https://go.dev/play/p/dbIFj2vCqFU?ref=huizhou92.com)  
[https://gist.github.com/hxzhouh/ba78993644ce58958127f64fc0976c55](https://gist.github.com/hxzhouh/ba78993644ce58958127f64fc0976c55?ref=huizhou92.com)  
[View code snippet on GitHub Gist →](https://gist.github.com/hxzhouh/ba78993644ce58958127f64fc0976c55?ref=huizhou92.com)

漏桶算法适用于需要强制执行固定速率处理的场景，如网络流量控制、API请求限制等。通过控制令牌的添加速率，漏桶算法能够有效地避免系统因瞬时流量高峰而过载。漏桶实现起来很容易，难点在于如何确定漏桶的两个参数：桶的大小和水的流出速率。如果桶设置得太大，那服务依然可能遭遇流量过大的冲击，不能完全发挥限流的作用；如果设置得太小，那很可能误杀掉一部分正常的请求。

## 令牌桶算法

令牌桶算法跟漏桶算法想法，更像现实生活中的排队算法，系统以固定的速率放号，我们首先要取号，然后再进行业务处理。 假设我们要限制系统在X秒内最大请求次数不超过Y，那就每间隔X/Y时间往桶中放一个令牌，当有请求进来时，首先要从桶中取得一个准入的令牌，然后才能进入系统进行处理。如果获取不到令牌就返回请求失败。

Code 4 ：token\_limit [try it ](https://go.dev/play/p/-JAqGoz2xK-?ref=huizhou92.com)  
[https://gist.github.com/hxzhouh/0c172824334aeea5ef101bd682fef59e](https://gist.github.com/hxzhouh/0c172824334aeea5ef101bd682fef59e?ref=huizhou92.com)  
[View code snippet on GitHub Gist →](https://gist.github.com/hxzhouh/0c172824334aeea5ef101bd682fef59e?ref=huizhou92.com)

令牌桶算法适用于**需要处理突发流量的场景**，如网络通信、API调用等。通过控制令牌的填充速率和桶的容量，令牌桶算法能够有效地平衡流量，防止系统过载，同时 如果系统资源富裕的情况下，允许在短期内处理更多的请求。跟漏桶算法类似，令牌生成的速度，也是需要重点考虑的。

## 实际业务中的限流算法

### 分布式限流算法

上面介绍的四个限流算法，状态都是存储在内存中的，我们可以理解为单机限流算法，微服务架构下，它们就最多只能应用于集群最入口处的网关上，对整个服务集群进行流量控制，无法细粒度地管理流量在内部微服务节点中的流转情况。如果我们需要实现一个服务的多个节点之间协同限流，那么我们需要将状态保存在集群中共享，下面是一个使用Redis 实现分布式 令牌桶算法的实现。实际上，我在业务中使用更多的是这种方式。

[View code snippet on GitHub Gist →](https://gist.github.com/hxzhouh/9aee69a3b24c38aa20274b726a596e2d?ref=huizhou92.com)

### 优先级

服务器资源是宝贵的，再资源紧张的情况下，我们更加希望宝贵的资源用于服务我们的vip客户。因此，我们可以设计一种基于“货币化额度”的分布式限流方案。不同于传统令牌桶算法中的“准入/拒绝”二元判定方式，这里的“货币额度”是一种更灵活的限流方式。用户在访问集群中的服务时，每次都会消耗一定的额度，类似于消耗资源的“货币”，并且可以根据用户的等级分配不同的额度。VIP用户可能拥有更高的额度，普通用户则有一定的额度限制。当额度耗尽后，用户需要重新向“令牌桶”申请额度，才能继续访问。  
code 5: quota [try it](https://go.dev/play/p/MxKsxKRx9L%5FJ?ref=huizhou92.com)  
[https://gist.github.com/hxzhouh/dc06a2947f4d436bdce9743d65b6c9e6](https://gist.github.com/hxzhouh/dc06a2947f4d436bdce9743d65b6c9e6?ref=huizhou92.com)  
[View code snippet on GitHub Gist →](https://gist.github.com/hxzhouh/dc06a2947f4d436bdce9743d65b6c9e6?ref=huizhou92.com)

## 结论

本文介绍了几种常见的限流算法，包括流量计数器、滑动窗口、漏桶、令牌桶等，并分析了它们在不同场景下的应用效果。流量计数器算法简单易用，但无法应对瞬时高峰流量，滑动窗口算法在一定程度上弥补了这一缺陷。漏桶算法通过固定速率处理请求，适合需要平滑流量的场景，而令牌桶算法则能够灵活处理突发流量，并允许系统在短时间内接收更多请求。

在实际业务中，尤其是微服务架构下，分布式限流是非常重要的。通过 Redis 等中间件的协同，分布式令牌桶算法能有效管理多个节点的流量。此外，基于优先级的“货币化额度”方案为限流设计提供了更多灵活性，有助于提升 VIP 客户体验。限流机制不仅能够保护系统免受过载，还能提升系统的整体稳定性与性能。

## 参考文档

\[1\] [限流设计模式](https://icyfenix.cn/distribution/traffic-management/traffic-control.html?ref=huizhou92.com#%E9%99%90%E6%B5%81%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F)

---

- [本文长期连接](https://huizhou92.com/e5-b8-b8-e8-a7-81-e9-99-90-e9-80-9f-e7-ae-97-e6-b3-95-e7-9a-84-e5-88-86-e6-9e-90-e4-b8-8e-e5-ae-9e-e7-8e-b0)
- 如果您觉得我的博客对你有帮助，请通过 [RSS](https://huizhou92.com/sitemap.xml)订阅我。
- 或者在[X](https://x.com/@piaopiaopig?ref=huizhou92.com)上关注我。
- 如果您有[Medium](https://medium.huizhou92.com/?ref=huizhou92.com)账号，能给我个关注嘛？我的文章第一时间都会发布在Medium。