【问题标题】:php/timeout/connection to server reset?php/超时/连接到服务器重置?
【发布时间】:2010-12-09 06:52:30
【问题描述】:

我有一个需要运行一段时间的 php 脚本。

脚本的作用:

  • 连接到mysql
  • 发起 100 到 100,000 个 cURL 请求
  • 每个 cURL 请求都返回 1 到 2000 个房地产列表的压缩解码数据 - 我使用 preg-match-all 获取所有数据并为每个列表执行一个 mysql 插入。每个查询永远不会超过 1mb 的数据。

所以有很多循环、mysql 插入和 curl 请求正在进行。 php 安全模式已关闭,我能够成功地将最大执行时间 ini_set 设置为荒谬的东西,以允许我的脚本一直运行。

好吧,我的问题是脚本或 apache 或脚本中间有中风,屏幕转到“与服务器的连接已重置”屏幕。

有什么想法吗?

【问题讨论】:

    标签: php mysql apache reset


    【解决方案1】:

    好吧,不管尝试 100,000 个 cURL 请求绝对是疯狂的事实,你可能已经达到了内存限制。

    尝试将内存限制设置为更合理的值:

    ini_set('memory_limit', '256M');
    

    作为一个小贴士,不要将执行时间设置为荒谬的,你最终可能会找到一种方法来使用这样的脚本来解决这个问题。 ;]

    相反,只需将其设置为0,它在功能上相当于完全关闭执行限制:

    ini_set('max_execution_time', 0);
    

    【讨论】:

    • 是的,我现在知道我需要增加内存限制,但这是个坏主意吗?
    • @John:是也不是。不要一直将它设置得比你需要的高,因为它可以防止脚本错误永远运行。想象一下,如果您关闭了脚本执行时间限制器和内存限制,并且不小心运行了一个无限循环的脚本!这里的故事的寓意:在这种情况下谨慎使用它,除了编写它以随着时间的推移分发或执行之外,没有其他方法可以真正起作用。顺便说一句,我赞同 timdev 关于设置工作排队系统的评论,这确实是这样做的方法。
    • 这是一个比我更好的答案——我忘了​​你可以使用 ini_set 覆盖 memory_limit
    • 只是想补充一点,您不仅可以在运行时设置memory_limit,还可以在同一个调用中多次调整它。再加上memory_get_peak_usage/memory_get_usage,您实际上可以在整个执行过程中根据需要动态增加内存限制。
    【解决方案2】:

    很多想法:

    1) 不要在 HTTP 请求中执行此操作。编写一个命令行 php 脚本来驱动它。如有必要,您可以使用网络绑定脚本启动它。

    2) 您应该能够将 max_execution_time 设置为零(或调用 set_time_limit(0))以确保您不会因超过时间限制而被关闭

    3) 听起来您真的想将其重构为更理智的东西。考虑设置一个小的作业排队系统,并有一个 php 脚本分叉几个孩子来仔细检查所有的工作。

    正如 Josh 所说,查看您的 error_log 并了解您现在被关闭的原因。试着弄清楚你正在使用多少内存——这可能是个问题。尝试将 max_execution_time 设置为零。也许这会让你快速到达你需要的地方。

    但从长远来看,听起来您在一个 http 请求中要做的工作太多了。把它从http中拿出来,分而治之!

    【讨论】:

    • 不知道那个 0 技巧,很高兴知道。不知道如何在 php 脚本中执行此操作。
    【解决方案3】:

    您可以通过修改您的 PHP.ini 并设置脚本执行变量来将超时设置为不确定。

    但您可能还需要考虑对架构进行轻微的更改。首先考虑获取 100,000 个 curl 请求的“启动后忘记”方法。其次,考虑使用“wget”而不是 curl。

    您可以发出一个简单的“wget URL -o UniqueFileName &”,这将检索一个网页,将其保存为一个“唯一”文件名并在后台进行。

    然后您可以遍历文件目录、greping (preg_matching) 数据并进行数据库调用。在处理文件时将文件移动到存档并继续迭代,直到没有更多文件为止。

    将目录想象成一个“队列”,让一个进程只处理文件。让第二个进程简单地出去获取网页数据。您可以添加第三个进程,它可以作为您的“监控器”,它独立工作并简单地报告快照统计信息。其他两个可以只是没有接口的“网络服务”。

    这种类型的多线程确实很强大,但恕我直言,它没有得到充分利用。对我来说,这就是网络的真正力量。

    【讨论】:

      【解决方案4】:

      当我通过 PHP 从 MySQL 获取包含特殊字符(如变音符号 ä、ö、ü、& 符号等)的数据时遇到了同样的问题。连接已重置,我在 apache 日志和 php 日志中都没有发现错误。首先,我确保在 PHP 中正确访问了数据库中设置的字符:

      mysql_query("SET NAMES 'latin1' COLLATE 'latin1_german2_ci'");
      
      mysql_query("SET CHARACTER SET 'latin1'");
      
      Then, finally, I resolved the problem with this line in PHP:
      
      mysql_query("SET character_set_connection='latin1'");
      

      【讨论】:

        【解决方案5】:

        100,000 个 cURL 请求???你疯了。分解这些数据!

        【讨论】:

        • 每次客户添加新的 MLS 时,它必须获得 1000 到 10,000 个列表 - 我可以在大约 5 个 cURL 请求中获取所有列表.. 但我必须为每个列表执行 1 个 cURL 请求为它获取图像。
        • @John:然后编写一个包含一次检索一个项目的功能的类怎么样。您可以遍历所有列表并为每个列表实例化一次类,确保在该过程中,当类被销毁时,cURL 内存也被释放。
        • @John:基本上,您只是想确保不会一遍又一遍地检索相同的数据,从而在此过程中浪费周期和带宽。通过设置某种描述的作业队列,并将每个检索到的页面存储在数据库中,您可以轻松地防止这种情况发生。
        • 这将使脚本运行时间更长,因为现在它执行一个 cURL 请求登录,然后循环执行所有 cURL 请求,然后执行一个 cURL 请求注销。所以不是登录(循环 20 次)注销 //22 个 curl 请求,而是执行 20*3 //60 个 curl 请求 - 你的建议肯定会帮助解决内存问题:( 必须有一种方法来释放我不再需要的部分内存不存在了吗?在它做了一件事之后,我想知道为什么 php 试图记住它直到最后,似乎过分了。
        • 我从不两次检索相同的数据。
        【解决方案6】:

        apache error_log 中有什么内容?是否达到内存限制?

        编辑:看起来您已达到内存限制。您可以访问 PHP.ini 吗?如果是这样,你can raise the memory_limit there。如果没有,请尝试使用 execshell_exec 函数运行 curl 或 wget 二进制文件,这样它们会作为单独的进程运行,而不是使用 PHP 的内存。

        【讨论】:

        • 是的。我是菜鸟对不起:允许的内存大小为 100663296 字节已用尽(试图分配 2975389 字节)
        • 这听起来可能更无聊,但我不能只在整个脚本或其中的某些部分使用 ob_flush/flush 吗?
        • @John:不,缓冲区只是正在使用的内存的一部分。 cURL 函数自己使用了相当多的内存。
        • 那么为什么它将每个请求都保存在内存中?启动一个新的请求,是不是就把内存中的旧请求去掉了?
        • @John:不。因为 cURL 是一个外部库,所以 PHP 的内存管理模型很难正确处理。这通常意味着如果 cURL 调用没有包含在块(类,甚至函数)中,它们将不会被正确处理。
        猜你喜欢
        • 1970-01-01
        • 2018-08-16
        • 1970-01-01
        • 2017-08-30
        • 2018-03-30
        • 1970-01-01
        • 1970-01-01
        • 2016-03-27
        • 1970-01-01
        相关资源
        最近更新 更多