欢迎来到涵盖质量属性/非功能要求的系列的另一个帖子,这次我说的是一种提高可扩展性和安全性的云设计模式,叫做:节流。
什么是节流?
Throttling 是一种在一段时间内限制资源访问的方式。定义如何限制这些资源取决于具体的用例,例如,我们可以按用户ID、按应用程序名称来限制,或者根本不做区分,对进入我们服务的所有请求进行节流。

Throttling 这是一种提高可扩展性的方法,因为它允许我们目前的服务在处理负载高峰时不会失败,同时弹性启动;也是一种提高安全性的方法,因为它允许我们检测来自同一来源的请求,这些请求可能导致使用过多的资源。
货币化也是使用Throttling 的另一个原因,但实际上这并不是一个质量属性/非功能需求,但它仍然是你可以考虑使用这种模式的另一个用例。
节流的工作原理是什么?
在最基本的形式下,Throttling ,包括跟踪一个具体用户访问一个资源的次数,我们定义一个用户的方式取决于我们的用户案例,它可以基于IP地址,头文件或甚至资源路径。
- 用户请求一个资源。
- 节流层决定是否允许它继续。
- 它允许请求继续,最后
- 将结果反馈给用户。

在Throttling 已经被触发的情况下,步骤被简化。
- 用户请求一个资源。
- 节流层确定它不允许继续,并将其阻断,最后
- 向用户返回一个错误信息。

如何在Go中实现节流?
在Go中,有多个实现Throttling 的包,这里仅举几例。
我在这篇文章中使用的是didip/tollbooth包中实现的,它很容易使用,并且已经实现了一个可以添加到HTTP处理程序中的中间件,关于这个包的一个重要的事情是它不支持持久化存储,所以负载平衡器后面的不同HTTP服务器不能共享节流的细节。
使用它真的很简单。
lmt := tollbooth.NewLimiter(3, &limiter.ExpirableOptions{DefaultExpirationTTL: time.Second})
lmtmw := tollbooth.LimitHandler(lmt, r)
然后在你的HTTP服务器中使用它作为一个处理程序。
return &http.Server{
Handler: lmtmw, // Using handler throttling requests!
Addr: conf.Address,
ReadTimeout: 1 * time.Second,
ReadHeaderTimeout: 1 * time.Second,
WriteTimeout: 1 * time.Second,
IdleTimeout: 1 * time.Second,
}, nil
结论
Throttling 模式提高了可扩展性,因为它允许在非恶意的 "尖峰 "负载发生时停止处理请求,它也提高了恶意用户试图故意使我们的服务过载的情况下的安全性。