【问题标题】:How to avoid many connections when using high number of queue workers?使用大量队列工作人员时如何避免大量连接?
【发布时间】:2023-03-23 15:21:01
【问题描述】:

我可能遗漏了一些明显的东西,但我遇到了架构问题。

我正在构建正常运行时间监控服务。

我有监视器表,每个监视器代表一个 URL。我的任务是将http请求发送到url。我从多个服务器发送 http 请求。每台服务器每分钟将处理数千个网址。

因此,在每台服务器中,我都有 supervisord,它会产生 50-100 个队列工作人员。每分钟一次,我将所有监视器推送到队列中,然后队列工作人员正在检查这些监视器。

但是,每个队列工作者都会创建一个到 MySQL 的连接。我认为这是因为我将 Monitor 模型传递给队列 Job,而 Laravel 仅将监视器 id 放入队列中。然后在处理作业时从数据库中检索整个监视器模型。

或者可能我弄错了,原因只是因为 laravel 在运行任何类型的代码时默认连接,包括排队的作业。

但是 10 个服务器 * 100 个工作人员 = 1000 个连接,这可能很糟糕(我不确定,但我认为它不可扩展)。

我的队列基于本地redis。

所以我觉得把序列化的模型数据放到redis里面是合理的。然后,我把http请求的结果放到redis中。然后在 MySQL 中一次推送一堆结果。

那么如何实现呢?

【问题讨论】:

  • 为什么网络请求通过工作队列系统而不是内联处理请求? Web 请求已经是一种衍生的工作线程。确保您的数据库检索快速(它看起来像一个简单的索引查找)并且连接网络连接将显着高于数据库连接。
  • 感谢您的回复!我不确定我明白你的意思。就像,好的,每分钟一次我需要运行 1000 个请求。如果我在 for 循环中的 php 脚本中执行此操作,那么它们将是同步的,不是吗?我看到 guzzle 有某种异步请求,但是将排队的作业作为我处理 1 个监视器的单个对象/位置处理会更容易,不是吗?
  • 对不起,我搞砸了我对你的架构的理解。它看起来像每个工作人员,根据 monitor_id 拉出一个监视器信息(为什么不只是这个在队列中?),执行需要一些时间的探测,然后将结果推送回 mysql。
  • 1000 个连接在大部分时间处于空闲状态或进行简单的插入/单行选择/更新时并不算太糟糕。
  • 它从有监视器的队列中提取作业(我认为 Laravel 只保留 monitor_id 然后从 mysql 获取整个模型),然后执行探测,然后将结果推送到 Redis。然后每秒一次,我将所有保存在 Redis 中的检查推送到 mysql(一种插入而不是单个,以提高性能)好吧,如果我有大量监视器,那么这些连接将执行很多操作,比如从数据库中进行 3000 次选择.虽然我不确定一切是如何运作的,但我认为将整个监视器模型保留在 redis 队列中是合理的,不是吗?

标签: mysql laravel redis


【解决方案1】:

在调度作业之前,您获取所有相关模型(以块的形式)并使用作业中需要的模型实例来调度作业。因此,您在处理作业时无需再次从数据库中获取模型。

其中一个关键是,如果要发送模型实例,则不应在作业类中使用 SerializesModels 特征。正如documentation中所述

如果您的队列作业在其构造函数中接受 Eloquent 模型,则只有模型的标识符会被序列化到队列中。实际处理作业时,队列系统会自动从数据库中重新检索完整的模型实例及其加载的关系。

如果handle 方法没有任何与数据库相关的依赖项,则它不会打开与您的数据库的连接。如果您使用的是mysql,则可以尝试SHOW PROCESSLIST 来检查它。我检查了我的本地(sleep),它没有显示任何 mysql 进程。

【讨论】:

  • ERSOY!当我自己弄清楚然后阅读您的帖子时,感觉真是太好了,您逐行证明了我所做的一切!我删除了 SerializesModels,现在我在 redis 中有完整的模型信息。但我也设法将一个普通的对象/数组传递给工作,所以现在它在没有模型的情况下工作得很好。谢谢!!!
猜你喜欢
  • 1970-01-01
  • 2021-08-03
  • 2014-02-12
  • 2017-12-26
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多