gpt4 book ai didi

php - 关于排队系统的问题

转载 作者:行者123 更新时间:2023-11-29 13:10:34 25 4
gpt4 key购买 nike

我有一个 mysql为多个 php 管理任务的队列通过 cron 作业每分钟运行的工作人员。
我将简化所有内容以使其更易于理解。

对于mysql我有两张 table :

worker_info

worker_id | name | hash | last_used
1 | worker1 | d8f9zdf8z | 2014-03-03 13:00:01
2 | worker2 | odfi9dfu8 | 2014-03-03 13:01:01
3 | worker3 | sdz7std74 | 2014-03-03 13:02:03
4 | worker4 | duf8s763z | 2014-03-03 13:02:01
...

tasks

task_id | times_run | task_id | workers_used
1 | 3 | 2932 | 1,6,3
2 | 2 | 3232 | 6,8
3 | 6 | 5321 | 3,2,6,10,5,20
4 | 1 | 8321 | 3
...

Tasks 是一个用于跟踪任务的表:

task_id 标识每个任务,times_run 是任务成功执行的次数。 task_id 是 php 脚本执行其例程所需的数字。
workers_used 是一个文本字段,其中包含已为此任务处理的所有 worker_infos 的 ID。我不希望每个任务多次使用相同的 worker_info,只需要一次。

worker_info 是一个表,其中包含 php 脚本完成其工作所需的一些信息以及 last_used ,后者是最后一次使用此工作人员的全局指示器。

几个 php 脚本在相同的任务上工作,我需要精确的值,因为每个 worker_info 应该只为每个任务使用 1 次。

PHP cron 作业包括所有相同的例程:

该脚本执行 mysql 查询以获取任务。
1. SELECT * FROM tasks ORDER BY times_run ASC LIMIT 1我们总是一次只做一份工作

该脚本锁定 worker_info 表以避免从任务查询中多次选择一个 worker_info
2. LOCK TABLES worker_info WRITE
然后它获取所有未用于此任务的 worker_info 的列表,按 last_used 排序
3. SELECT * FROM worker_info WHERE worker_id NOT IN($workers_used) ORDER BY last_used ASC LIMIT 1
然后它更新 last_used 参数,以便在任务仍在运行的同时不会选择相同的 worker_info
4. UPDATE workder_info Set last_used = NOW() WHERE worker_id = $id
最后锁被释放
5. UNLOCK TABLES
php 脚本执行其例程,如果任务成功,它将被更新
6. UPDATE tasks SET times_run = times_run + 1, workers_used = IF(workers_used = '', '$worker_id', CONCAT(workers_used,', $worker_id'))我知道以这种方式执行workers_used 而不使用第二个表来声明依赖项是非常糟糕的做法,但我有点害怕它会占用的空间。
一个任务可以有几千个workers_used,而我自己有几千个任务。这样表格会很快变得超过 100 万个条目,我担心这会减慢速度,所以我采用了这种存储方式。

然后脚本为每个任务执行步骤 2-6 10 次,然后返回到步骤 1,选择一个新任务并再次执行所有操作。

现在这个设置已经为我服务了大约一年,但是现在我需要在这个队列系统上激活 50 多个 php 脚本,我在性能方面遇到了越来越多的问题。
PHP 查询最多需要 20 秒,而且我无法像我需要的那样扩展,如果我只运行更多 PHP 脚本,mysql 服务器就会崩溃。
如果系统崩溃,我不希望数据丢失,因此我将每次更改都写入数据库。此外,当我创建系统时,worker_used 出现问题,因为当 10 个 php 脚本处理 1 个任务时,经常会在同一个任务中多次使用一个 worker_info 数据,这是我不想要的。

因此我引入了 LOCK 来解决这个问题,但我怀疑它是系统的瓶颈。如果一个工作人员锁定表以执行其操作,则所有其他 49 个 php 工作人员都需要等待那个不好的工作。

现在我的问题是:

这个实现甚至好吗?我应该坚持下去还是把它扔掉去做别的事情?

这是 LOCK甚至我的问题或其他问题可能会减慢系统速度?

如何改进此设置以使其更快?

//根据jeremycole的建议编辑:

我想我需要更新 worker_info 表以实现更改:
worker_info

worker_id | name | hash | tasks_owner | last_used
1 | worker1 | d8f9zdf8z | 1 | 2014-03-03 13:00:01
2 | worker2 | odfi9dfu8 | NULL | 2014-03-03 13:01:01
3 | worker3 | sdz7std74 | NULL | 2014-03-03 13:02:03
4 | worker4 | duf8s763z | NULL | 2014-03-03 13:02:01
...

然后将例程更改为:
SET autocommit=0将自动提交设置为 0,这样查询就不会自动提交
1. SELECT * FROM tasks ORDER BY times_run ASC LIMIT 1选择要处理的任务
2. START TRANSACTION 3. SELECT * FROM worker_info WHERE worker_id NOT IN($workers_used) AND tasks_owner IS NULL ORDER BY last_used ASC LIMIT 1 FOR UPDATE 4. UPDATE worker_info SET last_used = NOW(), tasks_owner = $task_id WHERE worker_id = $worker_id 5. COMMIT
执行 PHP 例程,如果成功:
6. UPDATE tasks SET times_run = times_run + 1, workers_used = IF(workers_used = '', '$worker_id', CONCAT(workers_used,', $worker_id'))
应该是这样,还是我在某些时候错了?
tasks_owner 真的需要还是更改 last_used 日期就足够了?

最佳答案

在这里阅读我对如何在 MySQL 中实现作业队列的另一个问题的回答可能会很有用:

MySQL deadlocking issue with InnoDB

简而言之,使用 LOCK TABLES因为这是完全没有必要的,而且不太可能产生好的结果。

关于php - 关于排队系统的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22156312/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com