Centrifugo是一个实时消息服务器, 它与语言无关,可以与任何语言编写的应用程序后端(Python,Ruby,Perl,PHP,Javascript,Java,Objective-C等)结合使用。

Centrifugo作为单独的服务运行,并保持从应用程序客户端(从Web浏览器或其他环境,如iOS或Android应用程序)持续的WebSocket或SockJS连接。当发生某些事件时,您可以使用Centrifugo API将其广播给所有感兴趣的客户。

demo: https://github.com/pushiqiang/centrifugo_sanic_example

如何安装

只需下载适用于您的平台的最新版本,解包并运行即可。

如果你在MacOS上:

brew tap centrifugal/centrifugo https://github.com/centrifugal/centrifugo
brew install centrifugo
  • 1
  • 2

查看官方的Docker镜像和Kubernetes Helm Chart。

还有用于64位Debian,Centos和Ubuntu的软件包。

特点

  • 快速的处理数千个并发连接.
  • 轻松地与现有应用程序集成 - 不需要重写后端代码来引入实时事件
  • 应用程序后端通过HTTP API和centrifugo进行通信(在通道中发布消息等).拥有Python,Ruby,PHP,Go,NodeJS等语言的API客户端.
  • Javascript客户端通过SockJS或纯Websocket协议从Web浏览器进行连接。iOS和Android客户端通过Websocket连接
  • 使用Redis和Redis Sentinel扩展到多台机器,实现高可用性,一致的散列分片。
  • SHA-256基于HMAC的连接认证和专用信道授权
  • 不同类型的渠道 - 私人,用户限制,客户端限制的渠道
  • 通过命名空间灵活配置通道
  • 频道存在信息(显示频道中的所有活动客户端)
  • 频道的历史信息(最后发送到频道的讯息)
  • 加入/离开频道事件(客户端在线/离线)
  • 网络断开后恢复丢失的消息
  • 内置管理Web界面
  • 可以用作WebRTC信令服务器
  • 准备部署(docker映像,RPM / DEB包,Nginx配置,自动让我们加密TLS证书)
  • MIT许可证

Centrifugo背后的故事

大概在4年前,我开始研究Centrifuge/Centrifugo项目。这是相当长的一段时间,也是一个长期的发展过程,所以我认为现在是时候总结一下这段时期以及现在的情况。如果您对推送技术,Websocket,实时消息传递,PUB / SUB系统感兴趣,或者您只是对开源世界感乐趣- 本文可能会是有趣的文章。

作为一个简短的描述 - 在这里我正在讨论允许向应用程序客户端(通过Websocket或SockJS协议)发送实时JSON消息的服务器(请参阅Github), 在应用程序后端知道某个事件之后。聊天,通知,计数器,实时评论和图表,协作编辑,游戏等应用也许需要实时消息功能, 这是centrifugo的目的。我写在这里的大部分是在Web应用程序的上下文中,但是我也会提到移动和桌面应用。

请注意,我来自俄罗斯的莫斯科 - 英语不是我的母语 - 欢迎更正。 
所以…一切都从Centrifuge开始。

Centrifuge

Centrifuge从一开始就是一个相当独特的项目。 
首先 - 它一开始并不是一个实时的消息中间商。我开始工作并计划创建类似Sentry(顺便说一下,Centrifuge名称听起来像Sentry +fuge)的应用。但是有一些差异,这个想法必须要有一个服务器来监听互联网上发生的不同事件,聚合并显示它。我想监视PYPI(Python Package Index)上的新包版本,也许以后还会有其他的东西,当时除了取名为Centrifuge,实现了SockJS支持的Web界面,但是是写在Tornado中的。

与此同时,在我的工作中,我们在门户网中积极使用实时消息 - 评论,图表,日历事件,计数器等。为此,SSE(服务器发送事件)是一个不错的选择。所以我们使用了Cyclone Web服务器(Twisted之上的Tornado fork)构建的cyclone-sse守护进程,并且它工作的非常好。在Centrifuge中,我看到了更多的协议/传输支持,可扩展性,内置身份验证,管理Web界面,有用的实时特性等方面的潜力。所以从那一刻起,Centrifuge获得了一个发展历程。有一天Centrifuge完全取代了我们的SSE / long-polling守护进程。

Centrifugo

去年Centrifuge从Tornado迁移到Go语言。并将其名称从Centrifuge改为 Centrifugo。所以从这一刻起我只会告诉有关Centrifugo的平均实时服务器。我将在下面写到更多关于Go语言的迁移的事,本文写作的最后一个版本是v1.4.5

选择实时解决方案

在选择实时解决方案时,重要的是要考虑到您的生态系统。您使用哪种语言作为后端?你是从头开始项目还是有一个工作的应用程序。你准备好支付实时解决方案吗?

我只能从Python程序员的角度讲述我的故事。但即使你用PHP,Ruby等编写代码,我想我们最后有很多共同之处。

我们来谈谈一下Python中实时网页的状态。这个领域有很多文章讨论和介绍。讨论最多的话题之一是Django的实时web应用。如果您的Web应用程序使用Django构建,并且您希望实时向用户提供一些事件,该怎么办?你有几个选择,让我们来回顾一下。

用Tornado之类的异步框架或者支持并发的其他编程语言(NodeJS,Go,Erlang等)完全重写你的站点。我们都明白,在大多数情况下,这不是一个真正的选择, 这代价高昂,在很多情况下并不理想。

所以你应该调整你现有的Django应用程序。

您可以使用基于Gevent的解决方案。添加一行允许patch Python标准库的神奇代码,Django就可以处理大量的持续连接,而不用担心worker数量不足。有一些库被证明是解决这个问题的不错的选择。另一方面,这是您的项目理念的严重转变。 
其中一个选择是nginx-push-stream-module ,我听说过使用它的人的几个成功案例。但是对我而言,它并不那么灵活和透明,主要是因为我不是一个C程序员。

另一种方式为django-channels ,由安德鲁·戈德温(Andrew Godwin)开发)中。新的ASGI接口将Django转换为一群从Redis等消息代理那里监听事件的worker,所有客户端都通过单独的接口服务器进行通信,这些服务器通过消息代理将事件发送给Django worker. 在新项目中这是一个新的,不错的选择。但django-channel还没有准备好生产环境应用,还没有完全验证。 
django-channel的介绍视频

接下来的方法是使用独立的服务器或服务。这可以是像pusher.com或pubnub.com这样的云服务。客户端连接到云服务,该服务处理来自应用程序用户的大量连接。Service有一个API来发布新的事件给感兴趣的客户。非常好的解决方案,如果你准备付费。

或者,这可以在你的托管服务器机器上安装解决方案服务。它可以用任何异步语言或框架编写,即像Centrifugo。 对于非常复杂的实时应用程序,您可能需要更紧密地集成实时发布程序和应用程序后端,例如用于动态实时多人游戏.对于大多数使用情况来说都没问题。

在这里我写了关于Python / Django生态系统实时解决方案的选择。还有另外一种技术, 比如BOSH,但是我不能写很多关于它们的东西,因为没有经验。

即使您的应用程序使用Python以外的其他语言编写,都可以应用。Phil Leggetter创建了一个现代实时技术的精彩资源,大量的服务器/库/服务。如果你开始寻找实时解决方案, 从那里开始吧。

除了生态系统之外,还有一些应用程序,不仅需要从服务器到客户端的事件流,还需要与数据库进行复杂的数据同步。在这种情况下,您可能需要Firebase或最近发布的基于RethinkDB的Horizo​​n。所以也要考虑到你的应用需求!

客户端

让我们暂时放下后端, 添加实时功能时,您还应该决定在客户端使用哪种技术。您需要从浏览器到您的服务器的持久连接(顺便说一下,这就是为什么Django可以在这个时候自己做到这一点,只要有几个客户端连接到您的应用程序,您将耗尽worker)。

现代应用程序大部分是以读取为导向的。用户主要消耗内容而不是产生新内容, 我们可以很容易地创建新的内容/事件的请求 - 简单的HTTP POST请求,或者可能是RPC请求来做后端工作。所以实时消息中的主要问题是如何将消息从服务器传递到等待更新的客户端。我们必须解决这个问题?

最明显的选择是使用Websockets,但最好使用像Socket.io或SockJS这样的Websocket polyfill库来为使用旧浏览器(IE小于10的移动浏览器)的用户提供回退。

Centrifugo使用SockJS。这意味着,当没有Websockets支持可用的时候将选择使用下面的一些替代传输:

  • xhr-streaming(在IE中是xdr-streaming)
  • eventsource(SSE)
  • HTMLFILE
  • xhr-polling(IE中的xdr轮询)
  • jsonp-polling

其中一些传输工具如此古老而异乎寻常,很难找到使用它的设备。其中一些使用iframe对象来解决与另一个域的连接问题。希望有一天,web和Centrifugo能够摆脱所有这些传输,只使用纯Websockets。

这里有趣的是我们都在等待Websockets将被大量设备支持的时间。现在看来我们差不多等到这个时候了!只有Opera mini仍然缺乏完整的Websocket支持。这里有趣的是现在HTTP / 2越来越流行, 二进制协议通过一个真正的TCP会话复用到同一个域的所有连接。在打开Websocket应用程序的新选项卡时,您将建立到服务器的新TCP连接。这有点令人失望。HTTP / 2协议没有升级机制,因此现在不可能以任何方式在HTTP / 2上运行Websockets , 没有这样的规范。但是,作为一个解决方法(如果打开一个选项卡的新连接是一个问题),在一些浏览器中,我们可以利用SharedWorker 通过一个真正的WebSocket连接复用我们的标签会话。

如果您需要,您可以使用纯Websockets使用Centrifugo,而无需任何回退到基于HTTP的传输,因为Centrifugo服务器为纯Websocket连接提供端点。如果你的客户都拥有现代的浏览器,并且你将使用TLS的Websockets - 那么这是一个不错的选择。Javascript客户端称为centrifuge-js, 开发人员通过简单的API与Centrifugo进行通信。

当您想从非浏览器环境连接到Centrifugo 时,Websocket端点也很有用。为任何现有的编程语言找到一个好的websocket客户端并不是一件大事。这使得为Android和iOS设备创建Centrifugo客户端成为可能。我们现在也有Go客户端。这一切意味着Centrifugo可以在浏览器,手机和桌面应用程序中使用

在继续这篇文章之前,我强烈推荐阅读一些关于这个主题的精彩文章:

  • http://mrjoes.github.io/2013/06/21/python-realtime.html  - 如果你是Pythonista,希望使用实时功能, 你应该怎么做。
  • https://banksco.de/p/state-of-realtime-web-2016.html  - 关于可用于Web应用程序的现代传输的很好的总结 - 优点和缺点。
  • https://samsaffron.com/archive/2015/12/29/websockets-caution-required  - Ruby on Rails是否需要在只读应用程序中支持websocket?

Go语言给了项目什么?

正如我上面所承诺的那样,让我们​​来谈谈一下Go语言。我不能说出所有积极的方面,因为我们对这篇文章过于深刻。但是这里有一些关于服务器迁移到Go的最令人兴奋的笔记。

首先 -  表现。如果设计正确,静态类型和编译成机器代码现代语言不会很慢, Go语言由伟大的工程师Robert Griesemer,Rob Pike,Ken Thompson和其他有经验的开发人员设计。它比CPython快得多,并且具有内置的并发支持。所以不需要使用像Tornado这样的异步框架来开发应用程序。根据任务测试Centrifugo速度比Centrifugo快50倍。例如,在Tornado中,执行发布API操作需要大约5ms的时间, 现在大约100微秒!

接下来我要提到的是多核心支持。在Python中,我们应该启动多个服务器实例或者使用多处理器来运行,在Go运行时调度程序中,在所有可用的CPU核心之间分配goroutine。

Go允许将程序编译成一个二进制静态链接的可执行文件。对依赖说不。此外,您可以在几乎所有流行的现代平台上交叉编译您的应用程序。所以我在Mac OSX上开发,可以直接在Mac上为Linux,Windows等构建Centrifugo。 
另外,当我开始迁移到Go时,我对这门语言很陌生,所以我学到了很多东西。很多Python开发者隐藏的东西。现在我更关心性能,分配和协议设计。

Centrifugo如何适应应用?

那么Centrifugo究竟是如何运作的?我们来看下面的简化方案: 

在这里您可以看到3个实体:您的应用程序后端,您的客户端和Centrifugo。

一旦客户端打开应用程序,你应该给他们连接参数。然后客户端使用这些连接参数通过Websocket或SockJS协议连接到Centrifugo。我们来仔细看看参数。 
首先是用户 ID, 这是一个用户ID的字符串, 所以Centrifugo知道每个连接的应用程序用户ID。请注意,当您的应用程序没有用户或您允许每个人连接到您的流(这称为匿名访问,阅读文档中的更多)时,可以使用空字符串作为用户ID。

接下来是当前UNIX 时间戳秒作为字符串。例如“1465208781”。

另外一个参数是可选的信息字符串 - JSON编码的关于连接的附加信息。例如,您可以在其中包含用户名。

最后。我们不能只信任客户端说他是特定ID的用户。因此,最后所有的参数包括基于密钥(仅由Centrifugo和后端知道)生成的HMAC SHA-256 标记,用户标识,时间戳和信息字符串。

当客户端提供了有效的参数,并成功连接到Centrifugo, 只要您在后端发生任何事件,您就可以通过API将其发布到(Fan-in消息)Centrifugo中,Centrifugo会将该消息发送给所有感兴趣的客户端(fan-out消息)。看看有兴趣的关键词。我们不能把所有的消息发送给所有的客户。这里出现频道概念 - 一旦客户端连接到Centrifugo,它就会在接收新消息的频道上订阅。频道只是一个像“新闻”,“post_764_updates”等的字符串。这里没有什么新东西 - 这是几乎所有PUB / SUB系统的工作原理 - 客户订阅主题和PUB / SUB代理控制fan-out这种方式。

这里是一个示例代码, 如何使用我们的Javascript客户端从浏览器中使用Centrifugo: 

我们使用所需的连接参数进行连接,订阅频道“新闻”,并在订阅回调函数中处理来自此频道的消息。 
所以现在你可以看到Centrifugo是语言无关的 - 你的应用程序后端使用哪种语言并不重要。后端和Centrifugo之间的所有通信都通过API。 
我们现在有用于Python,Ruby,PHP,Go和NodeJS的 HTTP API客户端。但是,HTTP API非常简单,如果您对现有的库不满意或者使用其他不受支持的语言,那么使用不超过100行代码编写新的API客户端非常简单。

因此,与现有应用程序的集成非常简单 - 您无需以任何方式重写代码,也不需要更改语言/框架或项目的理念。

我还应该提到,Centrifugo中的消息传送模式是“最多一次” - 这意味着消息在理论上可能会丢失。但实际上,这就是大多数现代实时解决方案的工作原理 - 在实践中,对于大多数应用程序来说没有问题,所以没有必要为了可靠的消息传递而牺牲速度和简单性,这是很难正确实现。

简而言之

正如我之前展示的 - 有很多解决实时问题的项目。他们大多只提供PUB / SUB功能 - 即将消息传递给客户端的一种方式。Centrifugo有更多的开箱即用来构建实时应用程序。以下是Centrifugo主要功能的简短描述。

存在信息。这是关于当前连接到特定频道的信息。最明显的例子就是聊天室 - 我们希望看到在线时刻。

下一步 -  加入/离开事件 - 再次以聊天室为例,这是有人加入/离开房间时的通知。

另一件事是,Centrifugo允许在可配置的时间内和可配置的大小下保留通道的消息历史(缓存)。这并不是很有用,但可以恢复丢失的信息(例如在短暂的网络断开情况下)。

另一个常见问题是客户端负载平衡。如果我们的应用程序有10万客户在线?当然理论上我们只能用一台机器来处理所有的连接(甚至更多)。但这是不好的,主要有两个原因:

  • 服务可用性。如果你的Centrifugo机器坏了怎么办?

  • 更多的客户端意味着更多的CPU资源和更高的消息延迟 - 为什么不减轻您的实例压力,添加另一个呢?

因此,在多台机器上进行扩展并在它们之间进行负载均衡客户端连接。可以使用Redis引擎启动Centrifugo 。Centrifugo节点将通过Redis PUB / SUB机制连接,所有临时信息 
(如状态和消息历史信息)将保存在Redis中而不是进程内存中。Centrifugo与Redis Sentinel一起使用,以防止Redis成为单点故障。

水平可伸缩性现在受Redis实例吞吐量的限制。但Redis速度非常快。它每秒可以处理超过10万个 PUB / SUB消息,所以这对大多数应用程序来说应该足够了。我的个人应用程序甚至不需要每秒超过100条消息。但是,如果您正在使用Centrifugo并接近Redis实例的100%CPU限制,那么请在Github上打开一个问题,我们将尝试使用Redis分片来平衡不同Redis实例之间的负载。

感谢Go标准库 - Centrifugo具有HTTP / 2支持。这在使用基于HTTP的SockJS传输时非常有用 - 因为到不同选项卡中同一个域的所有连接都将被多路复用到一个TCP连接中,并且您摆脱了HTTP / 1.1规范中对同一个域的持续连接限制。 
Centrifugo也有内置的管理网页界面。这里是它的截图: 

这是MIT许可 - 可以免费使用,贡献,分叉,修改。

我们如何使用Centrifugo

还记得我说过我们在Mail.Ru的Intranet上使用Centrifugo吗?除此之外,它还被其他几个Mail.Ru项目(我所知道的大约5个不同的项目)所使用,也在世界上其他的的几个项目中使用。我知道的最高负载是在一个有5万用户在线的网站上,每秒新增6千条消息。

我个人使用Centrifugo自己制作的一个有趣的事情是合作网页游戏。人们来到特别的房间 - 每个人都有自己的设备 - 笔记本,智能手机,平板电脑。然后这些人分成队。这个实际的游戏开始后。玩家可以在设备屏幕上实时查询问题,并回答问题。

关于开源的悲哀之处在于,有时很难说出你的项目是由谁来使用的,究竟是如何使用的。所以,如果您正在阅读本文,并且已经在使用Centrifugo或将来会使用它 - 请找几分钟时间写下您的使用案例(请参阅我在Github的帐户中的邮件)。每一个这样的信息都给了很多继续开发项目的动力!

ref: https://medium.com/@fzambia/four-years-in-centrifuge-ce7a94e8b1a8 
github: https://github.com/centrifugal/centrifugo

demo: https://github.com/pushiqiang/centrifugo_sanic_example

Centrifugo(实时消息服务器)介绍+demo相关推荐

  1. ASP.NET Web实时消息后台服务器推送技术---GoEasy

    越来越多的项目需要用到实时消息的推送与接收,怎样用ASP.NET实现最方便呢?我这里推荐大家使用GoEasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送! 浏览器兼容性:GoEa ...

  2. PHP Web实时消息后台服务器推送技术---GoEasy

    越来越多的项目需要用到实时消息的推送与接收,怎样用PHP实现最方便呢?我这里推荐大家使用GoEasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送! 浏览器兼容性:GoEasy推送 ...

  3. Web实时消息后台服务器推送技术GoEasy(支持多语言)---附GoEasy web 推送实例

    越来越多的项目需要用到实时消息的推送与接收,怎样实现最方便呢?我这里推荐大家使用 GoEasy, 它是一款第三方推送服务平台,使用它的 API可以轻松搞定实时推送! 浏览器兼容性:GoEasy推送 支 ...

  4. Python Web实时消息后台服务器推送技术---GoEasy

    越来越多的项目需要用到实时消息的推送与接收,怎样实现最方便呢?我这里推荐大家使用GoEasy,它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送! 浏览器兼容性:GoEasy推送 支持we ...

  5. C# Web实时消息后台服务器推送技术---GoEasy

    越来越多的项目需要用到实时消息的推送与接收,怎样实现最方便呢?我这里推荐大家使用GoEasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送! 浏览器兼容性:GoEasy推送 支持w ...

  6. C# Web实时消息后台服务器推送技术-GoEasy

    越来越多的项目需要用到实时消息的推送与接收,怎样用C#实现最方便呢?我这里推荐大家使用GoEasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送! 浏览器兼容性:GoEasy推送 ...

  7. Ruby Web实时消息后台服务器推送技术---GoEasy

    越来越多的项目需要用到实时消息的推送与接收,怎样实现最方便呢?我这里推荐大家使用GoEasy,它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送! 浏览器兼容性:GoEasy推送 支持we ...

  8. .NET Web实时消息后台服务器推送技术-GoEasy

    越来越多的项目需要用到实时消息的推送与接收,怎样用.NET实现最方便呢?我这里推荐大家使用GoEasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送! 浏览器兼容性:GoEasy推 ...

  9. 从mq服务器中获取消息命令,MQ服务消息队列介绍

    MQ服务消息队列介绍 资源简介MQ服务器端和客户端通信浅谈 1. WebSphere MQ的服务端的安装和配置 (1)创建名为venus.queue.manager的默认队列管理器. 在DOS窗口命令 ...

最新文章

  1. mysql as 后面字段_mysql 字段as详解及实例代码
  2. 10小时,这回一次搞定 Kafka 源码!
  3. vue 判断是否位 float_VUE中条件注释法css,判断ie浏览器
  4. Redis数据结构:字典(hash表)
  5. C++primer 第 3 章 字符串、向量和数组 3 . 3 标准库类型vector
  6. [Vue.js]实战 -- 电商项目(五)
  7. 图解Linux内核:内核启动(1)从Bootloader到内核代码
  8. 支付,造就金融科技生态契机——保险科技生态建设...
  9. django日志使用TimeRotateFileHandler
  10. IDEA如何执行maven命令进行打包编译及常用命令
  11. Proteus 8.9下载安装指南
  12. 张宇1000题高等数学 第十三章 多元函数微分学
  13. go中使用protobuf
  14. Moses的安装、训练和优化
  15. 【NOTE】python3.6下scons运行提示找不到SCons.Script解决方式
  16. 广东小学几年级有计算机课,广州小学开设网络班:小学生人手一台手提电脑
  17. kafka按照时间查询记录
  18. 关于机器人状态估计(10)-VSLAM与VIO的3D建图,重定位与世界观综述
  19. KPA EtherCAT主站协议栈基准
  20. 【万字长文】史上最强css、html总结~看完涨薪不再是梦

热门文章

  1. 树莓派 4b 配置 USB 网络连接
  2. 10年资深DBA老郭(门下已出多位DBA学生)老男孩MySQL DBA标杆班实战视频教程
  3. 苞米豆MyBatis-plus代码生成器
  4. 计算机组成原理:循环冗余校验码CRC具备“一位纠错”功能的思考与探索
  5. FastReport动态改变字体颜色
  6. 席慕容《写给幸福》读记
  7. spark streamming + kafka + Redis 实践
  8. sam卡和sim卡区别_科普拍了拍你~PSAM卡\SIM与SAM卡有什么不同?
  9. m4a怎么转换成mp3
  10. Docker service命令详解