我目前正在开展一个大项目,需要实施服务器发送事件。我决定使用事件源传输,并从简单的聊天开始。目前,客户端仅侦听新的聊天消息事件,但项目将来会有更多事件。首先,我真的很关心服务器端脚本和循环,其次,我不确定使用 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()
。
那么,对那些有服务器端事件经验的人提出的问题是:
感谢任何帮助,因为问题非常复杂,搜索信息不会给我任何提示或测试方法。
答案 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秒。哎呀!这改变了一切:
我使用队列服务而不是memcached,你可以找到现成的东西,或者很容易在PHP中编写自定义的东西。您仍然可以将MySQL作为主数据库并让您的队列服务轮询MySQL;这里的区别是你只有一个进程密集地轮询它,而不是一千个。队列服务是一个简单的套接字服务器,它接受来自每个前端PHP脚本的连接。每次轮询发现新消息时,它都会将其广播到已连接到它的所有客户端。 (有不同的方法来构建它,但我希望这能为你提供一般的想法。)
在前面的PHP脚本上,您使用socket_select()
调用,并且超时为15秒。它只在没有数据时唤醒,所以在其余时间使用零CPU。 (15秒超时是这样你可以发送SSE保持活动。)
答案 1 :(得分:2)
除非您将刷新计时器放在客户端并且仅将服务器端用作Web服务,否则几乎是唯一的方法。使用该数量的用户负载会很高但是你只能通过纯粹的php解决方案来限制我宁愿看一下服务器和原始套接字上的c / c ++守护进程
memcached作为临时存储然后是一个后端进程,每小时/每分钟提交一次存档到mysql db
是的,但取决于您愿意为解决方案投入多少硬件,或者使用一个读取和一个写入db来设置诸如主从复制之类的东西有多大信心
希望有所帮助