草庐IT

php - 事件源的性能

coder 2024-04-28 原文

我目前正在从事一个大型项目,该项目需要实现服务器发送的事件。我决定为此使用事件源传输,并从简单的聊天开始。目前客户端只监听一个新的聊天消息事件,但项目将来会有更多的事件。首先,我真的很关心服务器端脚本和其中的循环,其次,我不确定使用 mySQL 数据库作为存储(在本例中,用于聊天消息)是否可行实际上是一个很好的做法。 当前循环在新消息出现在数据库中时泄露它们:

$statement = $connect->prepare("SELECT id, event, user, message FROM chat WHERE id > :last_event_id");
while(TRUE) {
    try {
        $statement->execute(array(':last_event_id' => $lastEventId));
        $result = $statement->fetchAll();
        foreach($result as $row) {
            echo "id: " . $row['id'] . "\n";
            echo "event: " . $row['event'] . "\n";
            echo "data: |" . $row['user'] . "| >>> \n";
            echo "data: " . $row['message'] . "\n\n";
            $lastEventId++;
        }
    } catch(PDOException $PDOEX) {
        echo $PDOEX->getMessage();
    }
    ob_flush();
    flush();
    usleep(10000);
}

据我所知,这样的循环是不可避免的,我的任务是优化它的性能。目前我在 while() 和 reasonable(?) usleep() 之外使用准备好的语句。

所以,对于那些有服务器端事件经验的人的问题:

  1. 这种技术在中等负载的网站(1000-5000 在线用户)中使用是否合理?
  2. 如果是,有什么方法可以提高性能吗?
  3. 在这种情况下,mySQL 数据库会不会成为瓶颈?

感谢任何帮助,因为问题非常复杂,搜索信息不会给我任何提示或测试方法。

最佳答案

是否会同时连接所有 1000 多个用户?您是否将 Apache 与 PHP 一起使用?如果是这样,我认为您真正应该关心的是内存:每个用户都持有一个打开的套接字、一个 Apache 进程和一个 PHP 实例。您需要针对自己的设置自行衡量,但如果我们说每个 20MB,那么 1000 个用户需要 20GB 的内存。如果你收紧事情,那么每个进程都是 12MB,每 1000 个用户仍然是 12GB。 (一个 m2.xlarge EC2 实例有 17GB 的内存,所以如果你预算每 500-1000 个用户一个,我认为你会没问题。)

相比之下,对于 10 秒的轮询时间,CPU 使用率非常低。出于同样的原因,我不认为轮询 MySQL 数据库会成为瓶颈,但在这种使用级别上,我会考虑让每个数据库写入也对 memcached 进行写入。基本上,如果您不介意投入一些硬件,您的方法看起来是可行的。它不是最有效的内存使用方式,但如果您熟悉 PHP,它可能是最有效地使用程序员时间的方式。


更新:刚看到 OP 的评论,意识到 usleep(10000) 是 0.01s,而不是 10s。哎呀!这改变了一切:

  • 您的 CPU 使用率现在很高!
  • 你需要一个 set_time_limit(0)在你的脚本的顶部:你将很快达到默认的 30 秒 CPU 使用率,并且有这么严格的限制。
  • 您应该使用通知队列服务而不是轮询数据库。

我会使用队列服务而不是 memcached,您可以找到现成的东西,或者很容易地用 PHP 编写自定义的东西。您仍然可以将 MySQL 作为主数据库并让您的队列服务轮询 MySQL;这里的区别是你只有一个进程集中轮询它,而不是一千个。队列服务是一个简单的套接字服务器,它接受来自每个前端 PHP 脚本的连接。每次轮询发现一条新消息时,它都会将其广播给所有连接到它的客户端。 (有不同的方法来构建它,但我希望这能给你一个大概的想法。)

在面向前端的 PHP 脚本中,您使用了具有 15 秒超时的 socket_select() 调用。它仅在没有数据时唤醒,其余时间使用零 CPU。 (15 秒超时是为了让您可以发送 SSE keep-alives。)


( Source for the 20MB and 12MB figures )

关于php - 事件源的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20471034/

有关php - 事件源的性能的更多相关文章

  1. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  2. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  3. ruby-on-rails - 事件管理员和自定义方法 - 2

    这是我在ActiveAdmin中的自定义页面ActiveAdmin.register_page"Settings"doaction_itemdolink_to('Importprojects','settings/importprojects')endcontentdopara"Text"endcontrollerdodefimportprojectssystem"rakedataspider:import_projects_ninja"para"OK"endendend我想做的是,当我单击“导入项目”按钮时,我想在Controller中执行rake任务。但是我无法访问该方法。可能是什

  4. Ruby 的数字方法性能 - 2

    我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0

  5. ruby - Ruby 性能中的计时器 - 2

    我正在寻找一个用ruby​​演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent

  6. ruby-on-rails - 如果条件与 &&,是否有任何性能提升 - 2

    如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:

  7. ruby-on-rails - 在不重新查询数据库的情况下重新排序 Rails 中的事件记录? - 2

    例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果

  8. ruby-on-rails - Ruby 长时间运行的进程对队列事件使用react - 2

    我有一个将某些事件写入队列的Rails3应用。现在我想在服务器上创建一个服务,每x秒轮询一次队列,并按计划执行其他任务。除了创建ruby​​脚本并通过cron作业运行它之外,还有其他稳定的替代方案吗? 最佳答案 尽管启动基于Rails的持久任务是一种选择,但您可能希望查看更有序的系统,例如delayed_job或Starling管理您的工作量。我建议不要在cron中运行某些东西,因为启动整个Rails堆栈的开销可能很大。每隔几秒运行一次它是不切实际的,因为Rails上的启动时间通常为5-15秒,具体取决于您的硬件。不过,每天这样做几

  9. ruby-on-rails - 使用 Rails 事件记录获取二级模型 - 2

    我有一个帖子属于城市的关系,城市又属于一个州,例如:classPost现在我想找到所有帖子及其所属的城市和州。我编写了以下查询来获取带有城市的帖子,但不知道如何在同一查找器中获取带有城市的相应州:@post=Post.find:all,:include=>[:city]感谢任何帮助。谢谢。 最佳答案 Post.all(:include=>{:city=>:state}) 关于ruby-on-rails-使用Rails事件记录获取二级模型,我们在StackOverflow上找到一个类似的问

  10. ruby - 在没有数据库的情况下伪造一个事件记录模型 - 2

    我觉得我错过了什么。我正在编写一个ruby​​gem,它允许与事件记录进行交互,作为其主要功能的附加功能。在为其编写测试用例时,我需要能够指定虚拟事件记录模型来测试此功能。如果我可以获得一个事件记录模型的实例,它不需要与数据库的任何连接,可以有关系,所有这些东西,但不需要我在数据库中设置表,那就太棒了。我对测试还很陌生,在Rails测试之外我也很陌生,但似乎我应该能够相当轻松地完成类似的事情,但我什么也没找到。谁能告诉我我错过了什么?我看过工厂、制造商、固定装置,所有这些似乎都想达到目标。人们如何在您只需要AR对象进行测试的地方测试gem? 最佳答案

随机推荐