diff --git a/SUMMARY.md b/SUMMARY.md index e2e1ac5..d0c6567 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -45,6 +45,7 @@ * [5.3. Middleware中间件](ch5-web/ch5-03-middleware.md) * [5.4. Validator请求校验](ch5-web/ch5-04-validator.md) * [5.5. Database和数据库打交道](ch5-web/ch5-05-database.md) + * [# 5.6. Ratelimit 服务流量限制](ch5-web/ch5-06-ratelimit.md) * [5.7. Layout大型web项目分层](ch5-web/ch5-07-layout-of-web-project.md) * [5.9. 灰度发布和 A/B test](ch5-web/ch5-09-gated-launch.md) * [5.11. Load-balance负载均衡](ch5-web/ch5-11-load-balance.md) diff --git a/ch5-web/ch5-06-ratelimit.md b/ch5-web/ch5-06-ratelimit.md index 98bbff8..d950a2f 100644 --- a/ch5-web/ch5-06-ratelimit.md +++ b/ch5-web/ch5-06-ratelimit.md @@ -244,7 +244,14 @@ func TakeAvailable(block bool) bool{ 一些公司自己造的限流的轮子就是用上面这种方式来实现的,不过如果开源版 ratelimit 也如此的话,那我们也没什么可说的了。现实并不是这样的。 -TODO +我们来思考一下,令牌桶每隔一段固定的时间向桶中放令牌,如果我们记下上一次放令牌的时间为 t1,和当时的令牌数 k1,放令牌的时间间隔为 ti,每次向令牌桶中放 x 个令牌,令牌桶容量为 cap。现在如果有人来调用 `TakeAvailable` 来取 n 个令牌,我们将这个时刻记为 t2。在 t2 时刻,令牌桶中理论上应该有多少令牌呢? + +> cur = k1 + ((t2 - t1)/ti) * x +> cur = cur > cap ? cap : cur + +我们用两个时间点的时间差,再结合其它的参数,理论上在取令牌之前就完全可以知道桶里有多少令牌了。那劳心费力地像本小节前面向 channel 里填充 token 的操作,理论上是没有必要的。只要在每次 `Take` 的时候,再对令牌桶中的 token 数进行简单计算,就可以得到正确的令牌数。是不是很像 `惰性求值` 的感觉? + +在得到正确的令牌数之后,再进行实际的 Take 操作就好,这个 Take 操作只需要对令牌数进行简单的减法即可,记得加锁以保证并发安全。`github.com/juju/ratelimit` 这个库就是这样做的。 ## 服务瓶颈和 QoS