我应该在社交网络应用程序中使用 WebSockets,还是 PHP/AJAX 就足够了?

Should I use WebSockets in a social network app, or will PHP/AJAX suffice?

我想听听您对一个项目的看法。我开始自己的方式,慢慢地提出许多差距和问题,无论是现在还是将来,它们都会造成大问题。

系统会有通知系统、好友系统、留言系统(私密),一般都是这样的系统。我已经设置了所有这些: jQuery, PHP, mysqli round-trips 避免冗长。我明白标题的意思了。

如果所有这些都做一个简单的 PHP 代码和 post 并获取 3-4 个在线用户的方法,那将是惊人的!问题是当我有多个用户时,我该怎么做才能更好地利用服务器的资源?所以我开始寻找更多并发现这样 socket.io

我只是想让知道更多的人告诉我最好寻找什么。想一想更新通知系统现在是如何工作的。 jQuery 与 post 并每 3-5 秒重复一次,但这绝不是正确的。

如果您的目标是设置高度可扩展的通知服务,那么可能不是。

这不是严格的否定,因为除了速度之外还有其他因素需要考虑,但说到速度,请继续阅读。

WebSockets 确实为用户提供了一个持续开放的双向连接,就其本质而言,这种连接速度非常快。此外,客户端不需要请求新信息;在任何一方认为合适的时候发送。

但是,就生成内容的成本而言,连接本身节省的时间可以忽略不计。您调用了多少次数据库调用来检查新通知?您生成多少结构化数据让客户知道更改通知图标?您从磁盘或通过网络读取数据多少次?

使用任何 WebSocket 服务器时,这些相同的成本不会消失;它只是使一种缓解技术更加明显:将用户的通知状态保存在内存中并在通知更改时更新它,以防止昂贵的磁盘、数据库和服务器本地网络访问。

减少为快速变化的 Web 内容提供服务的时间成本的已知成熟技术:

反向代理(清漆缓存)

位于端口 80 上,充当非常瘦的 Web 服务器。如果请求是针对不在代理的内存缓存中的内容,它会将请求发送到 "real" 网络服务器。这对于提供很少更改的内容特别有用,例如您的图像和脚本,并且边缘包含内容大部分保持不变但有一些无法缓存的小元素......例如,在电子商务网站、产品描述、图像等都可以缓存,但显示用户购物车内容的 HTML 不能,因此是边缘端包含的理想候选者.

这将有助于大大减少系统负载,因为使用磁盘 IO 的请求会少得多,磁盘 IO 是一种比内存 IO 更有限的资源。 (硬盘不能在寻找 cat jpeg 的同时寻找数据库资源。)

内存键值存储 (Memcached)

就创建可扩展的通知系统而言,这可能会给您带来最大的收益。

还有其他内存中的键值存储系统,但是这个 PHP 内置了支持,不是一次,而是两次! (在 PHP 核心开发的伟大传统中,他们没有修复损坏的实现,而是决定将损坏的版本视为已弃用,而不实际将该系统标记为已弃用并发出适当的警告等,这会让人们停止使用损坏的系统。mysql_ v. mysqli_,我在看着你...)(使用 memcached 版本,而不是 memcache。)

总之,很简单:当您进行频繁的数据库、文件系统或网络调用时,将结果存储在 Memcached 中。当您通过网络更新记录、文件或推送数据,并且该数据用于存储在 Memcached 中的结果时,请更新 Memcached。

然后,当你需要数据的时候,先检查Memcached。如果不存在,然后 进行耗时长的磁盘、数据库或网络访问。

请记住,Memcached 不是持久性数据存储...也就是说,如果您重新启动服务器,Memcached 将完全变空。你仍然需要一个持久的数据存储,所以仍然使用你的数据库、文件和网络。此外,Memcached 专门设计为易失性存储,仅快速提供最常访问和最新更新的数据。如果数据变旧,可以将其擦除以为新数据腾出空间。毕竟,RAM 速度很快,但它远不如磁盘便宜 space,所以这是一个很好的权衡。

此外,没有键值存储系统是关系数据库。关系数据库是有原因的。您不想围绕键值存储编写自己的 ACID 保证包装器。您不想在键值存储上强制执行参照完整性。键值存储的别名是 No-SQL 数据库。请记住这一点:您可能会从 Cassandra 之类的软件中获得水平可扩展性,您可能会从 Memcached 之类的软件中获得惊人的速度,但您不会获得 SQL 以及所有许多、许多、许多几十年的发展RDBMS 已经拥有。

最后:

不要混合语言

如果在实施反向代理和内存缓存后您仍想实施 WebSocket 服务器,那么您将获得更多权力。请记住您选择的服务器的含义。

如果您想将 Socket.io 与 Node.js 一起使用,请在 Javascript 中编写您的整个应用程序。否则,请选择使用与系统其余部分相同语言编写的 WebSocket 服务器。

1 种语言解决方案示例:

<?php // ~/projects/MySocialNetwork/core/users/myuser.php
class MyUser {
    public function getNotificationCount() {
        // Note: Don't got to the DB first, if we can help it.
        if ($notifications = $memcachedWrapper->getNotificationCount($this->userId) !== null) // 0 is false-ish. Explicitly check for no result.
            return $notifications;
        $userModel = new MyUserModel($this->userId);
        return $userModel->getNotificationCount();
    }
}
... 
<?php // ~/projects/WebSocketServerForMySocialNetwork/eventhandlers.php
function websocketTickCallback() {
    foreach ($connectedUsers as $user) {
        if ($user->getHasChangedNotifications()) {
            $notificationCount = $user->getNotificationCount();
            $contents = json_encode(array('Notification Count' => $notificationCount));
            $message = new WebsocketResponse($user, $contents);
            $message->send();
            $user->resetHasChangedNotifications();
        }
    }
}

如果我们使用 socket.io,我们必须将 MyUser class 写两次,一次在 PHP 中,一次在 Javascript 中。谁敢打赌 classes 会在两种语言中以相同的方式实现相同的逻辑?如果两个开发人员正在处理 classes 的不同实现怎么办?如果对 PHP 代码应用了错误修复,但没有人记得 Javascript 怎么办?