事件源的性能 [英] Performance of event-source

查看:51
本文介绍了事件源的性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm currently working on a large project, which requires server-sent events implementation. I've decided to use event-source transport for it, and started from simple chat. Currently client side listens only to a new chat message event, but project will have a lot more events in the future. First of, I'm really concerned about a server-side script and loop in it, and second, I'm not sure that using mySQL database as storage(in this case, for chat messages) is actually a good practice. Current loop gives away new messages as they appear in database:

$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() 之外使用准备好的语句.

From what I've read such loop is inevitable, and my task is to optimize it's performance. Currently I'm using prepared statement outside of while() and reasonable(?) usleep().

那么,向那些在服务器端事件中获得经验的人提出问题:

So, the questions to those who got experience in server-side events:

  1. 在中等负载的网站(在线 1000-5000 个用户)中使用这种技术是否合理?
  2. 如果是,有什么方法可以提高性能?
  3. 在这种情况下,mySQL 数据库会成为瓶颈吗?
  1. Is such technique reasonable to use in moderately loaded web-sites(1000-5000 users on-line)?
  2. If yes, is there any way to boost performance?
  3. Could mySQL database be a bottleneck in this case?

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

Appreciate any help, as question is quite complex and searching info won't give me any tips or ways to test it.

推荐答案

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

Will all 1000+ users be connected simultaneously? And are you using Apache with PHP? If so, I think the thing you should really be concerned about is memory: each user is holding open a socket, an Apache process, and a PHP instance. You'll need to measure yourself, for your own setup, but if we say 20MB each, that is 20GB of memory for 1000 users. If you tighten things so each process is 12MB that is still 12GB per 1000 users. (A m2.xlarge EC2 instance has 17GB of memory, so if you budget one of those per 500-1000 users I think you will be okay.)

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

In contrast, with your 10 second poll time, CPU usage is very low. For the same reason, I would not imagine polling the MySQL DB will be the bottleneck, but at that level of use I would consider having each DB write also do a write to memcached. Basically, if you don't mind throwing a bit of hardware at it, your approach looks doable. It is not the most efficient use of memory, but if you are familiar with PHP it will probably be the most efficient use of programmer time.

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

UPDATE: Just saw OP's comment and realized that was usleep(10000) is 0.01s, not 10s. Oops! That changes everything:

  • 您的 CPU 使用率现在很高!
  • 您需要一个 set_time_limit(0) 在脚本的顶部:在这个严格的限制下,您将很快达到默认的 30 秒 CPU 使用率.
  • 您应该使用通知队列服务而不是轮询数据库.
  • your CPU usage is now high!
  • You need a set_time_limit(0) at the top of your script: you are going to hit the default 30 second CPU usage very quickly with that tight limit.
  • Instead of polling a DB you should use a notification queue service.

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

I'd use the queue service instead instead of memcached, and you could either find something off the shelf, or write something custom in PHP fairly easily. You can still keep MySQL as the main DB and have your queue service poll MySQL; the difference here is you only have one process polling it intensively, not one thousand. The queue service is a simple socket server, that accepts a connection from each of your front-facing PHP scripts. Each time its polling finds a new message, it broadcasts that to all the clients that have connected to it. (There are different ways to architect it, but I hope that gives you the general idea.)

在前端 PHP 脚本上,您使用 socket_select() 调用,超时为 15 秒.它仅在没有数据时唤醒,因此其余时间使用零 CPU.(15 秒超时是为了让您可以发送 SSE 保持连接.)

Over on the front-facing PHP script, you use a socket_select() call with a 15-second timeout. It only wakes up when there is no data, so is using zero CPU the rest of the time. (The 15-second timeout is so you can send SSE keep-alives.)

(20MB 和 12MB 数据的来源)

这篇关于事件源的性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆