首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PHP,MySQL,Cron作业-在大表中维护当前/活动数据的有效方法?

PHP,MySQL,Cron作业-在大表中维护当前/活动数据的有效方法?
EN

Stack Overflow用户
提问于 2016-05-22 07:17:07
回答 1查看 934关注 0票数 2

这主要是理论,所以如果它变得冗长,我很抱歉。

背景

我正在做的这个项目从其他网站(外部,不是由我们主持)获取信息。我们希望有尽可能接近现场的信息,以便我们的用户能够立即得到相关的信息。这意味着要不断地监视和更新表。

很难展示我以前在这方面所做的工作,但在过去几周中,我一直在搜索“在数据库中维护实时数据”和“在外部更改时立即更新数据库”等内容。但都没有用。我想保持最新记录的问题是常见的,所以我不知道为什么彻底的解决办法似乎如此罕见。

为了遵守这样的指导方针,我不是在寻找意见,而是寻找当前的最佳实践和业界最常用的、最有效的方法。

目前,使用cron job,我们所能做的最好是每分钟运行一个进程。

代码语言:javascript
复制
* * * * * cd /home/.../public_html/.../ && /usr/bin/php .../robot.php >/dev/null 2>&1

问题是,我们正在从数千个其他站点(每行都是一个站点)中提取数据,有时更新可能需要几分钟或更长时间。每分钟只调用一次函数是不够的。理想情况下,我们想要的是几乎即时的分辨率。

检查一行是否需要更新是快速的。本质上只是简单的哈希比较:

代码语言:javascript
复制
if(hash(current) != hash(previous)){
    ... update row ...
}

使用独占由cron作业触发的进程意味着,如果一行最终被更新,则进程将被搁置,直到它完成,或者直到cron作业在一分钟后触发一个新进程。

不,布诺!帕斯宾!如果通过某种可怕的命运转折,每一行都需要更新,那么所有记录可能需要几个小时(或更长时间)才能更新。在这段时间里,已经过去的那些行将过时。

注意: DB的设置方式使当前正在更新的行无法被新进程访问。该函数实质上沿着表爬行,查找未被读取/更新的下一个可用行,然后深入其中。一旦完成更新,它将继续到下一个可用行。

当每个进程到达表的末尾,或者当表中的所有行标记为read时,都会被终止。此时,所有行都重置为未读,进程将重新启动。

随着数据量的收集,提高分辨率的唯一方法是同时运行多个进程。

但多少才是太多呢?

可能的解决方案(方法)

到目前为止,我想出的最好的方法是,尽可能快地完成所有行,这是:

  1. 进程(P1)
  2. P1移除表,直到它找到未读且需要更新的行,然后跳入
  3. 一旦P1进入行,它就调用第二个完全相同的进程(P2)从该点继续。
  4. P2移除表,直到它找到未读且需要更新的行,然后跳入
  5. 一旦P2进入行,它就调用第三个完全相同的进程(P3)从那个点继续

..。诸若此类。

本质上,每当进程进入行以更新它时,就会调用一个新进程继续进行。

但是..。父进程没有死。这意味着,一旦他们完成了他们的更新,他们开始再次爬行,寻找下一个可用的行。

还有..。最重要的是,每分钟都有一份新的工作被解雇。

这意味着可能有数千个相同的进程同时运行。进程数不能超过表中的记录数。最坏的情况是,每行同时更新,在任何更新完成之前触发一两个cron作业。cron作业将立即死亡,因为没有任何行可供更新。当每个进程完成其更新时,它也会因为同样的原因而立即死亡。

上述情况是最坏的情况。每次传递都不太可能需要更新超过5或10行,但从理论上讲,可以同时更新每一行。

可能的改进(主要是资源,而不是速度或分辨率)

  1. 监视和限制允许的活动进程的数量,并杀死任何被触发的新进程。但是,这就引出了这样的问题:“多少是太多?”和“达到某一解决方案所需的最低数目是多少?”
  2. 让每个进程一次标记多行(5-10行),直到处理完集合中的所有行后才继续。这将减少同步进程的最大数量,使每次标记的行数增加一倍。

正如我在一开始所说的,这无疑是数据库架构师的一个常见问题。在维护当前记录方面,是否有比我所阐述的更好/更快/更有效的方法?

谢谢你跟我在一起!

EN

回答 1

Stack Overflow用户

发布于 2016-05-22 07:33:51

首先,我全都看过了!为此,我不得不拍拍自己的背:)

您可能要寻找的是一个工作队列。排队基本上是一种排队,就像你在超市里看到的那样,一个工人是在柜台上接受钱并为每个顾客做任何事情的女人。当没有顾客的时候,她就不工作,当有了,她就做工作。

当商场里有很多顾客时,更多的工人会走在空荡荡的柜台上,而购买食品杂货的人也会在他们中间分配。

最近我写了很多关于队列的文章,我最推荐的是Bean秸秆。它使用起来很简单,如果您计划在php中创建队列和工作人员,那么它使用的是 API (并从那里控制MySQL数据库中发生的事情)。

队列脚本和员工脚本的外观与以下类似(显然,您将添加自己的代码以适应您的特定需求,您将生成任意数量的工作人员。您甚至可以让您的员工根据您队列中的需求而有所不同):

向队列添加作业

代码语言:javascript
复制
<?php
$pheanstalk = new Pheanstalk('127.0.0.1:11300');
$pheanstalk
  ->useTube("my_queue")
  ->put("UPDATE mytable SET price = price + 4 WHERE stock = GOOG");//sql query for instance
?>

从您的描述来看,您似乎正在设置事务,这将禁止在实现其他更新的同时进行某些更新。这实际上是使用队列的一个很好的理由,因为如果队列作业超时,则会将其发送到队列的顶部(至少在我所描述的斐然队列中),这意味着在超时的情况下不会丢失队列。

辅助脚本:

代码语言:javascript
复制
<?php
    $pheanstalk = new Pheanstalk('127.0.0.1:11300');

    if ($job = $pheanstalk
    ->watch('my_queue')
    ->ignore('default')
    ->reserve())//retreives the job if there is one in the queue
    {
        echo $job->getData();//instead of echoing you would 
                             //have your query execute at this point

        $pheanstalk->delete($job);//deletes the job from the queue
    }
}
?>

你必须做一些改变,比如设计有多少工人。您可以将一个worker放在一个while循环中,以获得所有的作业并逐个执行它们,然后调用其他辅助脚本,以便在您看到执行了3个或更多作业的情况下提供帮助。管理队列的方法很多,但在您所描述的情况下,这是经常使用的方法。

从库中获得的队列的另一个好处是,它具有很强的通用性,这被推荐为斐然茎。如果将来你决定以不同的方式组织你的员工,你可以很容易地做到这一点,而且有很多功能可以让你的工作变得更容易。没有理由重新发明轮子。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37371598

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档