分布式聊天系统

175 阅读4分钟

背景:

公司是做电视应用系统,最新需要设计一个功能,主要是,用户可以通过手机和电视好友进行聊天和视频通话、手机和手机聊天和视频通话、电视和电视聊天和视频通话,目前公司已经售卖出去的电视机数30万台,每天晚上上线电视20万台,每月新增1.5万台;

名词说明:

IM Server:客户端和服务端保持连接的服务器,为了保证连接的效率和逻辑的简单,只负责数据的接收和分发不做任何逻辑的判断;

Name Server:负责IM Server之间协调,主要包括:IMServer上下线,客户端和IM Server的对应关系,定时检查机制,Name Server之间是相互独立的,数据记录在Redis;

终端设备:电视机、IPhone、Android上的客户端应用;

业务系统:非IM Server的其他系统;

核心问题和架构设计

交互方法:可以采用Netty长连接或者HTTP轮询的方式。经过分析和考量轮询的方式不太合适,对服务的压力和延时都不可接受,所以采用Netty长连接的机制。

流量预估:预估当前同时在线用户20万,系统设计必须执行60万的设计。测试环境主机主要是4核8G,通过测试,单机最大稳定支持10万链接同时在线。因此IM Server最低6台主机;

传输协议采用:Protobuf,主要两个原因:1、传输高效;2、支持多种语言(Java、Android、swift)

用户上线的流程:

用户下线流程

用户下线有下面几种情况

  1. 用户主动下线
  2. 心跳检查用户不在线
  3. 客户端和服务端连接断开

用户发送消息流程

问题点

  1. 为了保证高可用,客户端和服务链接服务必须要保留2台(假如用A和B标记),那么用户上线之后,用户连接了A这台机器,好友在B这台主机上,怎么进行通信;
  2. 如果多台主机提供IM Server,怎么保证Channel中心的负载均衡;
  3. 如果一台IM Server重启之后,和它建立的channel连接会断开重连;
  4. 服务端口时,会不会存在丢失消息;

思考

1、为了解决用户之前跨主机的通信,我们采取的方式

  • 用户注册之后,记录下用户Id和主机IP对应关系;
  • 每个业务系统当成Netty的一个客户端和IM Server建立连接;
  • 每个业务系统和IM Server连接之后,本地保存IP和Channel的对应关系;

这样就可以通过用户ID->IP->Channel传输数据了;这个设计存在一个问题,当业务系统非常多时,会对Channel中心产生压力,所幸我们后台服务总共不超过40个服务,所以这问题暂时不考虑。

2、为了保证服务链接的均衡性,引入了Name Server,当客户端建立连接时,需要到Name Server进行注册,当Channel断开时,也需要从Name Server注销掉,同时Name Server还会定时检查当前Channel的状态;当服务需要和IM Server连接时,需要先通过Name Server下发链接地址,Name Server会根据当前IM Server的负载情况,下发负载最低的服务给客户端连接;

3、当主机重启时,和这台主机连接的消息都会丢失,会不会大量链接重连对系统造成很大的压力,默认情况下,IM Server保证6台主机,机器监控报警设置为70%,依靠2的负载均衡,基本可以避免重连对系统的压力;

4、消息丢失问题,聊天的消息都会先保存在数据库中,再进行消息推送,当用户连接时,会把用户的消息拉取出俩重新发送给用户;

消息系统的设计:

举例说明,张三给李四发送了一个消息您好。涉及消息表设计

一般请求下,消息记录都会非常大,我们会把消息表基于消息id进行分库分表;

因为张三和李四都需要查询对话内容,一般我们需要建立一个关联表。如下:

这个表会更大,为了方便查询,我们需要基于用户进行分库分表。这样就可以先通过用户查询消息ID,再通过消息Id查询消息内容。根据消息内容和用户Id就可以区分用户是发送方和接收方了。