我目前正在开发一个大型项目,需要实现服务器发送的事件。我决定使用事件源传输,并从简单的聊天开始。目前客户端仅监听新的聊天消息事件,但项目将来会有更多事件。首先,我真的很关心服务器端脚本及其循环,其次,我不确定使用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()
.
因此,对于那些有服务器端事件经验的人来说,问题是:
- 这种技术在中等负载的网站(1000-5000 个在线用户)中使用是否合理?
- 如果是的话,有什么办法可以提高性能吗?
- Could mySQL在这种情况下数据库会成为瓶颈吗?
感谢任何帮助,因为问题非常复杂,搜索信息不会给我任何提示或测试方法。
所有 1000 多个用户都会同时连接吗?您是否将 Apache 与 PHP 结合使用?如果是这样,我认为您真正应该关心的是内存:每个用户都打开一个套接字、一个 Apache 进程和一个 PHP 实例。您需要根据自己的设置自行测量,但如果我们说每个 20MB,则 1000 个用户需要 20GB 内存。如果你把事情收紧,每个进程都是 12MB,那么每 1000 个用户仍然是 12GB。 (m2.xlarge EC2 实例有 17GB 内存,因此,如果您为每 500-1000 个用户预算其中一个实例,我认为您会没问题。)
相比之下,轮询时间为 10 秒,CPU 使用率非常低。出于同样的原因,我不会想象轮询 MySQL DB 将成为瓶颈,但在这种使用级别上,我会考虑让每个数据库写入也对 memcached 进行写入。基本上,如果您不介意添加一些硬件,那么您的方法看起来是可行的。它不是最有效地利用内存,但如果您熟悉 PHP,它可能是最有效地利用程序员时间。
UPDATE:刚刚看到OP的评论并意识到这是usleep(10000)
是0.01s,而不是10s。哎呀!这改变了一切:
- 您的 CPU 使用率现在很高!
- 你需要一个设置时间限制(0)在脚本的顶部:在这个严格的限制下,您将很快达到默认的 30 秒 CPU 使用率。
- 您应该使用通知队列服务,而不是轮询数据库。
我会使用队列服务而不是 memcached,您可以找到现成的东西,或者相当容易地用 PHP 编写一些自定义的东西。您仍然可以将 MySQL 作为主数据库,并让您的队列服务轮询 MySQL;这里的区别是只有一个进程对其进行密集轮询,而不是一千个。队列服务是一个简单的套接字服务器,它接受来自每个前端 PHP 脚本的连接。每次轮询发现一条新消息时,它都会将该消息广播给所有连接到它的客户端。 (构建它的方法有多种,但我希望这能给您一个总体思路。)
在前面的 PHP 脚本中,您使用socket_select()
调用时有 15 秒超时。它仅在没有数据时才会唤醒,因此其余时间都使用零 CPU。 (15 秒超时是为了让您可以发送 SSE keep-alive。)
(20MB 和 12MB 数据的来源)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)