这主要是理论,所以如果它变得冗长,我很抱歉。
背景
我正在做的这个项目从其他网站(外部,不是由我们主持)获取信息。我们希望有尽可能接近现场的信息,以便我们的用户能够立即得到相关的信息。这意味着要不断地监视和更新表。
很难展示我以前在这方面所做的工作,但在过去几周中,我一直在搜索“在数据库中维护实时数据”和“在外部更改时立即更新数据库”等内容。但都没有用。我想保持最新记录的问题是常见的,所以我不知道为什么彻底的解决办法似乎如此罕见。
为了遵守这样的指导方针,我不是在寻找意见,而是寻找当前的最佳实践和业界最常用的、最有效的方法。
目前,使用cron job,我们所能做的最好是每分钟运行一个进程。
* * * * * cd /home/.../public_html/.../ && /usr/bin/php .../robot.php >/dev/null 2>&1问题是,我们正在从数千个其他站点(每行都是一个站点)中提取数据,有时更新可能需要几分钟或更长时间。每分钟只调用一次函数是不够的。理想情况下,我们想要的是几乎即时的分辨率。
检查一行是否需要更新是快速的。本质上只是简单的哈希比较:
if(hash(current) != hash(previous)){
... update row ...
}使用独占由cron作业触发的进程意味着,如果一行最终被更新,则进程将被搁置,直到它完成,或者直到cron作业在一分钟后触发一个新进程。
不,布诺!帕斯宾!如果通过某种可怕的命运转折,每一行都需要更新,那么所有记录可能需要几个小时(或更长时间)才能更新。在这段时间里,已经过去的那些行将过时。
注意: DB的设置方式使当前正在更新的行无法被新进程访问。该函数实质上沿着表爬行,查找未被读取/更新的下一个可用行,然后深入其中。一旦完成更新,它将继续到下一个可用行。
当每个进程到达表的末尾,或者当表中的所有行标记为read时,都会被终止。此时,所有行都重置为未读,进程将重新启动。
随着数据量的收集,提高分辨率的唯一方法是同时运行多个进程。
但多少才是太多呢?
可能的解决方案(方法)
到目前为止,我想出的最好的方法是,尽可能快地完成所有行,这是:
..。诸若此类。
本质上,每当进程进入行以更新它时,就会调用一个新进程继续进行。
但是..。父进程没有死。这意味着,一旦他们完成了他们的更新,他们开始再次爬行,寻找下一个可用的行。
还有..。最重要的是,每分钟都有一份新的工作被解雇。
这意味着可能有数千个相同的进程同时运行。进程数不能超过表中的记录数。最坏的情况是,每行同时更新,在任何更新完成之前触发一两个cron作业。cron作业将立即死亡,因为没有任何行可供更新。当每个进程完成其更新时,它也会因为同样的原因而立即死亡。
上述情况是最坏的情况。每次传递都不太可能需要更新超过5或10行,但从理论上讲,可以同时更新每一行。
可能的改进(主要是资源,而不是速度或分辨率)
正如我在一开始所说的,这无疑是数据库架构师的一个常见问题。在维护当前记录方面,是否有比我所阐述的更好/更快/更有效的方法?
谢谢你跟我在一起!
发布于 2016-05-22 07:33:51
首先,我全都看过了!为此,我不得不拍拍自己的背:)
您可能要寻找的是一个工作队列。排队基本上是一种排队,就像你在超市里看到的那样,一个工人是在柜台上接受钱并为每个顾客做任何事情的女人。当没有顾客的时候,她就不工作,当有了,她就做工作。
当商场里有很多顾客时,更多的工人会走在空荡荡的柜台上,而购买食品杂货的人也会在他们中间分配。
最近我写了很多关于队列的文章,我最推荐的是Bean秸秆。它使用起来很简单,如果您计划在php中创建队列和工作人员,那么它使用的是 API (并从那里控制MySQL数据库中发生的事情)。
队列脚本和员工脚本的外观与以下类似(显然,您将添加自己的代码以适应您的特定需求,您将生成任意数量的工作人员。您甚至可以让您的员工根据您队列中的需求而有所不同):
向队列添加作业
<?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
?>从您的描述来看,您似乎正在设置事务,这将禁止在实现其他更新的同时进行某些更新。这实际上是使用队列的一个很好的理由,因为如果队列作业超时,则会将其发送到队列的顶部(至少在我所描述的斐然队列中),这意味着在超时的情况下不会丢失队列。
辅助脚本:
<?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个或更多作业的情况下提供帮助。管理队列的方法很多,但在您所描述的情况下,这是经常使用的方法。
从库中获得的队列的另一个好处是,它具有很强的通用性,这被推荐为斐然茎。如果将来你决定以不同的方式组织你的员工,你可以很容易地做到这一点,而且有很多功能可以让你的工作变得更容易。没有理由重新发明轮子。
https://stackoverflow.com/questions/37371598
复制相似问题