• Go 的连接池、重试和超时


    在这里插入图片描述

    这是一个来自 API 的间歇性 500 个内部服务器错误的故事,这些错误最终是由 Go 包中的硬编码常量引起的database/sql。我将主要为您省去冗长的故事,并直接讨论问题以及我们发现的原因。我们注意到来自特定 API 端点的 500 错误数量有所增加,并开始进行故障排除。我们最初发现了一些奇怪的事情。当我们重试失败的调用时,有时会成功。几分钟后,我们发现只需对失败的 API 调用进行 CURL 几次,就可以轻松地“解决”问题。之后,就会一次又一次的成功。这让我们一时感到困惑,但随后我们意识到,在让 API 闲置一段时间后,调用会再次失败。与此同时,另一位团队成员查看了我们在该 API 开始失败时所做的更改。(我们使用chatops和其他技术来帮助解决此类故障。)事实证明,这个糟糕的更改将API请求的并行度从10个增加到25个。我们并行执行一些大规模时间序列操作,并将其提高以及其他一些变化。该解释与以下事实有关:
    我们database/sql为每个客户环境使用单独的连接池,以确保资源隔离并避免饥饿和嘈杂邻居影响等问题。
    我们将连接池的大小database/sql从 10 个增加到 25 个,以提高并行度。
    因为我们有很多客户和很多 API 服务,每个服务都有单独的池,所以我们在服务器端设置了一个较短的连接超时,以避免wait_timeoutMySQL 端的连接过多。
    在内部,当它遇到从池中获取的连接database/sql时,具有硬编码的重试功能。driver.ErrBadConn删除失败的连接并获取另一个连接后,它将重试查询,最多 10 次。
    问题是这样发生的:
    API 请求最多打开 25 个与数据库的连接,完成后将它们返回到池中。
    API 闲置了一会儿,数据库上的所有连接都超时并被关闭。
    API 收到另一个请求并开始尝试来自池的连接。
    尝试 10 次后,它放弃了(这又是database/sql行为,而不是 API 本身)并返回错误 500。
    如果您立即再次运行该请求,它将从池中清除另外 10 个连接。第三个请求将丢弃最后 5 个连接,然后在第六次重试时,将打开新的有效连接并成功。
    由于我们无法在不更改database/sql代码的情况下更改 10 次重试的硬编码限制,因此我们选择暂时减少并行度。归根结底,我们的硬件还不支持这么高的并行度;这是为未来的一些变化做准备的步骤。我们计划使重试次数可配置(可能通过暂时更改供应商database/sql并向上游提交)。这个故事的道德意义是什么?只是平常的事情:了解您的工具,让合适的人员参与故障排除等。这里没有惊天动地的教训;只是一些有趣的事情,我认为值得分享,以防对其他人有所帮助。

  • 相关阅读:
    Docker-介绍及生命周期
    使用huggingface的text embedding models
    redis 常用方法
    使用文本分析识别一段文本中的主要性别
    什么是回调函数?
    静态时序分析简明教程(六)]时钟组与其他时钟特性
    泛型和包装类
    [创业-38]:公司、企业、组织的本质与层次
    【Unity程序技巧】 资源加载管理器
    单片机实验(一)
  • 原文地址:https://blog.csdn.net/itopit/article/details/134066880