【问题标题】:Scalably processing large amount of comlpicated database data in PHP, many times a day每天多次在 PHP 中可扩展地处理大量复杂的数据库数据
【发布时间】:2011-06-09 14:30:43
【问题描述】:

我很快就要从事一个给我带来问题的项目。

这将需要在一天中定期处理数万条记录,可能超过一百万条。处理将涉及几个(可能很复杂)公式和几个随机因素的生成,将一些新数据写入单独的表,并用一些结果更新原始记录。这需要对所有记录进行,理想情况下,每三个小时进行一次。网站的每个新用户都会添加 50 到 500 条需要以这种方式处理的记录,因此这个数字不会稳定。

代码尚未编写,因为我仍在设计过程中,主要是因为这个问题。我知道我将需要使用 cron 作业,但我担心处理这种大小的记录可能会导致网站冻结、运行缓慢,或者每三个小时就惹恼我的托管公司。

我想知道是否有人对类似主题有任何经验或提示?我以前从来没有以这种规模工作过,据我所知,这对服务器来说是微不足道的,不会造成太大的问题。只要在接下来的三个小时之前处理所有记录,我不在乎它们是否没有同时处理(尽管理想情况下,属于特定用户的所有记录都应该在同一批次中处理),所以我'一直想知道我是否应该每 5 分钟、15 分钟、每小时分批处理一次,无论任何可行的方法,以及如何最好地处理这个问题(并以对所有用户公平的方式使其可扩展)?

【问题讨论】:

    标签: php mysql database-design optimization cron


    【解决方案1】:

    可能会使用多台服务器,每个服务器每小时可以处理 X 条记录,将来您将使用的记录越多,您需要的服务器就越多,否则您最终可能会处理数百万条记录,而最后 2-3 甚至第 4 次处理仍未完成......

    【讨论】:

    • 另外,也许可以将用户拆分到不同的数据库或至少表上,以使负载平衡和数据库同步更容易?
    【解决方案2】:

    您可能需要考虑使用哪种数据库。也许关系数据库不是最好的?

    找出答案的唯一方法是实际做一些基准测试来模拟你将要做什么。

    【讨论】:

    • Relational 没问题,我们得到了数万的 IOPS。这里的问题是免费软件。您可能无法获得 100 IOPS。
    【解决方案3】:

    对网站上使用的 MySQL 表进行许多更新的问题在于,更新数据会杀死您的查询缓存。这意味着即使在您更新完成后,这也会显着降低您的网站速度。

    我们之前使用过的一个解决方案是拥有两个 MySQL 数据库(在我们的例子中也是在不同的服务器上)。 Web 服务器仅主动使用其中一个。另一个只是一个后备,用于此类更新。两台服务器相互复制它们的数据。

    解决办法:

    • 复制已停止。
    • 网站被告知使用 Database1。
    • 您提到的这些大型更新在 Database2 上运行。
    • 许多常用查询在 Database2 上执行一次以预热查询缓存。
    • 告知服务器使用 Database2。
    • 重新开始复制​​。 Database2 现在主要用于读取(网站和复制),因此网站没有太多延迟。

    【讨论】:

      【解决方案4】:

      下面我将描述我将如何解决这个问题(但会花费你金钱并且可能不是理想的解决方案):

      1. 您应该使用 VPS(一些cheap VPS 的快速列表)。但我想你应该做更多的事情research 找到最适合你需求的 VPS,如果你想在不惹恼托管公司的情况下完成你的任务(我相信你会的)
      2. 您不应该使用 cronjobs 而是使用消息队列,例如 beanstalkd 来排队您的消息(任务)并改为离线处理。使用消息队列时,您还可以根据需要限制处理。

      不是很必要,但我会以这种方式解决它。

      1. 如果性能真的是一个关键问题,我将拥有两个 VPS(至少)实例。一个 VPS 实例来处理来自访问您站点的用户的 http 请求,一个 VPS 实例来执行您想要的离线处理。这样您的用户/访问者就不会注意到您正在执行的任何繁重的离线处理。
      2. 由于阻塞性质,我也可能不会使用 PHP 进行离线处理。我会使用 node.js 之类的东西来做这种处理,因为 node.js 中没有任何阻塞,这会快很多。
      3. 我也可能不会将数据存储在关系数据库中,而是使用闪电般快速的redis 作为数据存储。 node_redis 是一个非常快速的 node.js 客户端

      【讨论】:

      • “阻挡自然”是什么意思?
      • Beanstalkd 似乎解决了我的很多问题,尽管我知道这将比我最初想要的要多一点工作(意料之中,做任何正确的事)。我想我明天会更深入地研究一下,看看我能从中得到什么。出于我自己的原因,我更喜欢关系数据库——它在项目的每个方面都更有用(对我来说),除了这个处理问题,尽管我肯定会研究用 redis 可以完成什么。无论如何,在家用机箱上开发之后,我可能不得不硬着头皮买一台专用服务器。
      • @Eph 共享主机绝对不会喜欢你做那种处理。我想你可以找到一个价格约为每月 5 美元的盒子,如果你问我的话,这很便宜。但是您也可以只使用自己的计算机进行处理,因为它不必通过网络(端口开放等)访问来进行处理。
      • @frunsi php 中的每个调用都会阻塞,例如 fread。当它被调用并且没有数据可用时,您的脚本将停止并且不能同时执行任何其他任务。使用 node.js 时没有任何阻塞,因此您可以做其他事情。
      • @Alfred:谢谢,我明白了。我不太确定异步 I/O 是否适合这项任务,但它可能会有所帮助 - 取决于其他事情。
      【解决方案5】:

      在这种情况下,我会考虑使用 Gearman(它也有 PHP 扩展,但可以与多种语言一起使用)

      【讨论】:

        【解决方案6】:

        使用存储过程在服务器端执行所有操作,该存储过程选择数据子集,然后在内部处理数据。

        这是一个使用光标选择数据范围的示例:

        drop procedure if exists batch_update;
        
        delimiter #
        
        create procedure batch_update
        (
        in p_from_id int unsigned, -- range of data to select for each batch
        in p_to_id int unsigned
        )
        begin
        
        declare v_id int unsigned;
        declare v_val double(10,4);
        
        declare v_done tinyint default 0;
        declare v_cur cursor for select id, val from foo where id between = p_from_id and p_to_id;
        declare continue handler for not found set v_done = 1;
        
        start transaction;
        
        open v_cur;
        repeat
            fetch v_cur into v_id, v_val;
        
            -- do work...
        
            if v_val < 0 then
                update foo set...
            else
                insert into foo...
            end if;
        
        until v_done end repeat;
        close v_cur;
        
        commit;
        
        end #
        
        delimiter ; 
        
        call batch_update(1,10000);
        
        call batch_update(10001, 20000);
        
        call batch_update(20001, 30000);
        

        如果您可以完全避免使用游标 - 很好,但我建议的要点是将逻辑从应用程序层移回数据层。我建议您在数据库中创建一个原型存储过程,然后执行一些基准测试。如果该过程在几秒钟内执行,那么我认为您不会遇到很多问题,特别是如果您使用带有事务的 innodb 表。

        这是另一个可能证明感兴趣的示例,尽管它适用于 50+ 百万行的更大数据集:

        Optimal MySQL settings for queries that deliver large amounts of data?

        希望这会有所帮助:)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-02-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-15
          • 2010-09-18
          • 2014-06-12
          相关资源
          最近更新 更多