【问题标题】:Suggested Golang architecture for polling user accounts frequently建议频繁轮询用户帐户的 Golang 架构
【发布时间】:2016-08-17 21:20:48
【问题描述】:

我正在创建一个小型服务,我经常(每 5 秒左右)轮询大约 100 个帐户(在类似 Twitter 的服务中)以检查新消息,因为该服务尚未提供流 API(就像 Twitter 一样)。

在我的脑海中,我将架构计划为每个用户每 5 秒排队 Tickers。一旦滴答声触发,我对服务进行 API 调用,检查他们的消息,然后将 SELECT 调用到我的 Postgres 数据库以获取特定的用户详细信息并检查最新消息的日期,以及是否有比该消息更新的消息UPDATE 进入并通知用户。重复令人作呕。

我在后端事物和架构方面不是很有经验,所以我想确保这不是一个绝对荒谬的设置。对数据库的调用量是否合理?我在滥用 goroutines 吗?

【问题讨论】:

    标签: postgresql go architecture goroutine ticker


    【解决方案1】:

    让我根据你的描述来回答。

    我想确保这不是一个绝对荒谬的设置。

    我了解以下内容。对于每个用户,您在一个 goroutine 中每 5 秒创建一个刻度。另一个 goroutine 使用这些刻度,执行轮询并将最后一条消息的日期与您在 PostgreSQL 数据库中记录的日期进行比较。

    答案是:视情况而定。您有多少用户,您的应用程序可以支持多少用户?根据我的经验,回答这个问题的最佳方法是衡量您的应用程序的性能。

    对数据库的调用量合理吗?

    这取决于。为了让您放心,我已经看到单个 PostgreSQL 数据库每秒需要数百个 SELECT。我没有发现设计错误,因此对您的应用程序进行基准测试是可行的方法。

    我在滥用 goroutines?

    你的意思是喜欢执行太多? I think it is unlikely that you are abusing goroutines that way. 如果您认为有特殊原因,请发布相应的代码 sn-p 可以使您的问题更加准确。

    【讨论】:

    • 好的,非常棒,谢谢。我实际上会完成构建它,如果我遇到任何性能问题,我会相应地发布。只是想确保我没有犯任何极其愚蠢的错误。
    • 关于您对 Clément 回答的评论,“所以我所说的没有什么让您惊恐地畏缩吗?”我没有看到类似的东西。我没有看到您正在应用 goroutines 是有原因的。 goroutines 中的代码不会并行执行,除非您的机器可以这样做并且您告诉 Go 并行执行 goroutines。即使 goroutines 不并行执行,并发执行 goroutines 也开启了在任何给定时间等待多个 SQL 查询完成的可能性。对不起,我不能评论其他答案,我还没有足够的积分。
    • 有关 Go 中并发与并行性的更多信息,我建议阅读blog.golang.org/concurrency-is-not-parallelism 指示的材料
    • 不要忽视 Clément 或 Icza 的回答。它们触及道格问题的互补方面。
    【解决方案2】:
    • 您的架构是最有效的方式吗?
    • 你现在应该做点什么吗? ,您应该测试您的解决方案。

    您始终可以进行更深入的优化,在您的情况下,您需要客户端吞吐量,因此您可以使用一系列众所周知的优化,例如切换到反应式模型、添加一些缓存服务器、将负载分散到多个数据库从属服务器上,...... .

    您应该大规模测试您的解决方案,如果它在用户吞吐量和服务器成本方面满足您的需求,那么您的解决方案就是正确的。

    【讨论】:

    • 听起来不错!所以,我说的任何话都没有让你惊恐地畏缩吗?
    • 不,间隔轮询对于开始项目恕我直言是一个完全有效的选项。它易于设置和维护。另外,正如@mrrusof 所说,SQL 数据库擅长处理许多并发读/写请求,而 golang 可以承受很多 goroutine。
    【解决方案3】:

    您提出的解决方案:每个用户每 5 秒查询 1 次。有 100 个用户:

    1 * 100 / 5 seconds = 20 queries / second
    

    如果查询速度很快,这不会被视为大负载。

    但是为什么您需要分别为每个用户执行此操作?如果您需要以 5 秒的粒度获取更新,您可以每 5 秒执行 1 次查询,该查询不会按用户过滤,而是检查来自所有用户的更新。

    如果上述查询给出了结果,您可以遍历结果并为在过去 5 秒内有更新的每个用户执行必要的操作。这导致:

    1 query / 5 seconds = 0.2 query / second
    

    查询量减少了一百倍,仍然以相同的时间粒度为您提供所有更新。

    如果要为更新执行的任务很长或依赖于外部系统(例如调用另一个服务器),您可以在单独的 goroutine 中执行这些任务。您可以选择为每个任务启动一个新的 goroutine,或者您可以有一个工作 goroutine 池来消耗这些排队的任务,然后将任务排队(使用通道)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-14
      • 1970-01-01
      • 1970-01-01
      • 2015-01-07
      相关资源
      最近更新 更多