33|固若金汤:限速器与错误处理
郑建勋
你好,我是郑建勋。
我们前面的课程,由于一直都是不加限制地并发爬取目标网站,很容易导致被服务器封禁。为了能够正常稳定地访问服务器,我们这节课要给项目增加一个重要的功能:限速器。同时,我们还会介绍在 Go 中进行错误处理的最佳实践。
限速器
先来看限速器。很多情况下,不管你是想防止黑客的攻击,防止对资源的访问超过服务器的承载能力,亦或是防止在爬虫项目中被服务器封杀,我们都需要对服务进行限速。
在爬虫项目中,保持合适的速率也有利于我们稳定地爬取数据。大多数限速的机制是令牌桶算法(Token Bucket)来完成的。
令牌桶算法的原理很简单,我们可以想象这样一个场景,你去海底捞吃饭,里面只有 10 个座位,我们可以将这 10 个座位看作是桶的容量。现在,由于座位已经满了,服务员就帮我们叫了个号,我们随即进入到了等待的状态。
一桌客人吃完之后,下一位并不能马上就座,因为服务员还需要收拾饭桌。由于服务员的数量有限,因此即便很多桌客人同时吃完,也不能立即释放出所有的座位。如果每 5 分钟收拾好一桌,那么“1 桌 /5 分钟”就叫做令牌放入桶中的速率。轮到我们就餐时,我们占据了一个座位,也就是占据了一个令牌,这时我们就可以开吃了。
通过上面简化的案例能够看到,令牌桶算法通过控制桶的容量和令牌放入桶中的速率,保证了系统能在最大的处理容量下正常工作。在 Go 中,我们可以使用官方的限速器实现:golang.org/x/time/rate,它提供了一些简单好用的 API。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文深入介绍了在Go语言中使用限速器和错误处理的最佳实践。首先,详细讲解了限速器的原理和在Go中的实现方式,包括使用令牌桶算法和官方库提供的API实现限速器,以及如何应用多层限速器于爬虫任务中。其次,探讨了Go语言中的错误处理机制,强调了强制调用者检查错误的哲学,并指出这种方式保证了代码的可读性和健壮性。最后,提到了一些技术手段,可以帮助降低错误处理的重复性。文章还介绍了错误链处理方式和减少错误处理的实践,为读者提供了关于限速器和错误处理在Go语言中的最佳实践,为他们在实际项目中的应用提供了有益的指导。 在错误处理方面,Go语言吸收了当前软件开发中的经验与教训,强调函数的调用者应对错误进行处理。然而,这种方式有时会导致错误处理冗长的问题。因此,文章介绍了一些最佳实践,包括错误的包装、错误中间件以及通过defer来减少错误的处理等。此外,还提到了panic的特性,通过defer+recover可以防止程序异常退出,但需要注意对异常进行捕获时只能对单个协程生效。 总的来说,本文通过深入讲解限速器和错误处理的最佳实践,为读者提供了在Go语言中应用这些技术的有益指导。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Go 进阶 · 分布式爬虫实战》,新⼈⾸单¥68
《Go 进阶 · 分布式爬虫实战》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(4)
- 最新
- 精选
- viclilei老师,为什么我按照代码写完后,请求数据还是有1s20条左右。可以帮忙判断我大概是什么地方写错了吗?
作者回复: 一步步测试和调试一下代码即可,这个没有想象中那么难哈
2023-01-09归属地:广东2 - Realm在程序中应该避免使用野生的goroutine带来的panic,可以放在一个有个异常捕获的Go函数中来执行goroutine。姿势如下: ``` func Go(f func()) { go func() { // defer recover 捕获panic defer func() { if err := recover(); err != nil { log.Printf("panic: %+v", err) } }() f() }() } func main() { f := func() { panic("xxx") } Go(f) time.Sleep(1 * time.Second) } ```2022-12-24归属地:浙江1
- 大毛1 - 官方的 golang.org/x/time/rate 实现限流是通过记录最后操作的时间+计算完成的,感觉这种处理方式让人耳目一新。以前我一直觉得这种令牌限流的算法就是使用 ticker 定时向一个 chan 中放入令牌,然后让获取令牌的人阻塞然后自行争抢,计算的方式毫无疑问比 ticker 的方式更优。另外这种计算的实现让这个limiter 有了一个有趣的特点,就是当调用 Wait(ctx context.Context) 的时候,如果 ctx 设置了过期时间,limiter 可以立即计算出这个调用者是否有机会获取到令牌(如果下一个令牌生成时间是 3 秒后,而 ctx 的过期时间是 1 秒,limiter 会立即返回一个错误,表示这个调用者不可能在过期时间内获取令牌),这不会让调用者一直在 Wait 方法上阻塞,也算是提升性能的一个小技巧 2 - 课程中自行实现的多个级别的 limiter 感觉是有一个 bug?即如果设置了 5 个级别的 limiter,用户已经获得了前 3 个 limiter 的令牌,但是在尝试获取第 4 个令牌的时候出错,那是否应该将前三个令牌放回去? 3 - error 推荐使用 github.com/pkg/errors 4 - 一个 goroutine 如果没有使用 defer + recover 的方式来捕获 panic,这个 goroutine 将导致整个程序直接崩溃,如果你不想这样,要记得添加 defer + recover2024-01-29归属地:新疆
- 卢承灏老师,appHandler 讲解那里,viewUsers还有下面那个方法是不是漏了error 返回2022-12-26归属地:广东
收起评论