即时通讯im服务器架构设计
简单架构
最初的IM聊天服务器可能像下图所示:
由于仅有一台im服务器,一台mysql,一旦任何一个服务出现故障,不得不对外停止服务.因此参考官方文档,做了ejabberd集群调研.
内部模块
ejabberd是一个高度模块化的服务器,它允许你按照自己实际需求,自由组合模块来实现功能,内部常见模块如下图所示:
集群目的
ejabberd集群的目的是为了容错和可伸缩性,能够为单个或一小组大型域使用多个服务器。
几点建议:
- 如果您想独立运行两个大型域,则不一定需要群集。您可能只想运行两个不同的独立服务器。
- 但是,要构建可靠的服务并支持庞大的用户群,群集是必须具备的功能。
- 另外,如果只做推送服务的化,建议不要用集群,详见ejabberd推送优化.
集群工作
ejabberd集群和erlang服务器集群类似,XMPP域由一个或多个ejabberd节点提供服务。这些节点可以在通过网络连接的不同机器上运行。它们都必须能够连接到所有其他节点的端口4369,并且必须具有相同的魔术cookie(请参阅Erlang / OTP文档,换句话说~ejabberd/.erlang.cookie
,所有节点上的文件必须相同)。因为所有节点交换关于连接用户,s2s连接,注册服务等的信息……
搭建集群需要用到的端口和防火墙设置:
Port | Description |
---|---|
5222 | Standard port for Jabber/XMPP client connections, plain or STARTTLS. |
5223 | Standard port for Jabber client connections using the old SSL method. |
5269 | Standard port for Jabber/XMPP server connections. |
4369 | Standard port for Jabber/XMPP server connections. |
4369 | EPMD (see epmd) listens for Erlang node name requests. |
port range(4200-4210) | Used for connections between Erlang nodes. This range is configurable (see epmd). |
注:
如果你打算docker部署,必须指定节点端口范围并映射到容器内部并修改命令脚本防火墙配置,如修改/ejabberd/path/ejabberdctl.cfg
中的配置项:FIREWALL_WINDOW:4200-4210
集群部署忠告
在开始实施集群之前,需要考虑几件事情:
- 集群应该设置在单个数据中心中:ejabberd Community Edition中的集群依赖于低延迟网络。虽然它可能跨地区使用,但建议在单个地区运行ejabberd集群。
- 集群依赖于Erlang特性和Mnesia共享模式。
- 部署的时候记得选集群模式。
集群内部负载均衡
- 使用 SRV DNS 负载均衡: 它非常简单,只需设置几个SRV记录指向您的节点,DNS会自动负载(采用轮询调度round-robin算法)。
- 使用负载均衡器(如haproxy),参见haproxy,但是要注意解决方案的成本,xmpp是长连接的。
- 自定义实现,有些客户端是提供域名和ip选择的。
一台4核16RAM的单节点一般来说可以处理20w-30w在线用户,这种架构适合10个节点以内的集群。
架构改进方案
一般来讲,架构设计之初是为了满足当前及未来一段时间内的业务增长,理论上来说没有什么架构一定是完美的,适当的时候选择性价比最好的方案才是智者,结合当前用户量,维护成本及复杂度,打算采用下面架构:
ejabberd大型架构
官方也推荐了一套大型集群的解决方案,如下:
集群聊天记录
集群聊天记录要想保持完整,要么写在同一台db中,要么做db集群,至于MMM,还是MMA,看自己情况。
当前计划是共用一台云数据库实现,由于ejabberd并没有对MYSQL有类似中间件的功能可以实现自动分库分表,
随着聊天记录的增加,现在的单表会慢慢出现瓶颈,考虑廉价解决方案是,每月末将上个月的聊天记录导出到当月单表,库中只保留当月记录,每年的服务记录导出到一个库中。如果MYSQL无法满足的时候,考虑时序列数据库,如TSDB等。