事件源的表现

时间:2013-12-09 12:45:15

标签: php performance server-sent-events

我目前正在开展一个大项目,需要实施服务器发送事件。我决定使用事件源传输,并从简单的聊天开始。目前,客户端仅侦听新的聊天消息事件,但项目将来会有更多事件。首先,我真的很关心服务器端脚本和循环,其次,我不确定使用 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()以外的预备声明和合理的(?)usleep()

那么,对那些有服务器端事件经验的人提出的问题是:

  1. 这种技术是否适用于中等负载的网站(1000-5000用户在线)?
  2. 如果是,有什么办法可以提升表现吗?
  3. 在这种情况下 mySQL 数据库会成为瓶颈吗?
  4. 感谢任何帮助,因为问题非常复杂,搜索信息不会给我任何提示或测试方法。

2 个答案:

答案 0 :(得分:4)

是否会同时连接所有1000多个用户?你使用Apache与PHP?如果是这样,我认为你真正关心的是内存:每个用户都持有一个套接字,一个Apache进程和一个PHP实例。对于你自己的设置,你需要自己测量,但如果我们说每个20MB,那就是1000个用户的20GB内存。如果你收紧东西,那么每个进程都是12MB,仍然是每1000个用户12GB。 (一个m2.xlarge EC2实例有17GB的内存,所以如果你预算每500-1000个用户中的一个,我想你会好的。)

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


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

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

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

在前面的PHP脚本上,您使用socket_select()调用,并且超时为15秒。它只在没有数据时唤醒,所以在其余时间使用零CPU。 (15秒超时是这样你可以发送SSE保持活动。)


Source for the 20MB and 12MB figures

答案 1 :(得分:2)

  • 是适合在中等载荷下使用的技术 网站(1000-5000用户在线)?

除非您将刷新计时器放在客户端并且仅将服务器端用作Web服务,否则几乎是唯一的方法。使用该数量的用户负载会很高但是你只能通过纯粹的php解决方案来限制我宁愿看一下服务器和原始套接字上的c / c ++守护进程

  • 如果是,有什么方法可以提高性能吗?

memcached作为临时存储然后是一个后端进程,每小时/每分钟提交一次存档到mysql db

  • 在这种情况下mySQL数据库可能成为瓶颈吗?

是的,但取决于您愿意为解决方案投入多少硬件,或者使用一个读取和一个写入db来设置诸如主从复制之类的东西有多大信心

希望有所帮助