2021年11月

一、消息通道高可用设计。

1、连的上

  • HTTP Tunnel:在部分公司或酒店的网络代理,只允许通过HTTP访问外网。这时就需要用HTTP Tunnel。就是用HTTP协议封装私有的TCP或UDP等不被网关认可的协议。
  • 多端口备用
  • 多IP:HTTPDNS提供IP列表

2、连的快:

  • 跨网延迟:用户和机房在同一个运营商。
  • 跑马竞速:链接前遍历HTTPDNS的IP列表,选一个最快的。

3、通道保持稳定:

  • 接入层和业务层解耦:业务层功能迭代发布重启,不会影响接入层,用户的长链接也就不会断开。接入层还可以多节点分别接入不同运营商。
  • 上下行通道隔离:大型直播中,下行推送量很大,上行很少。因此,短连接上行,避免维护长链接的开销,可以优化为短连接发完不立即断开,上行消息到达上行业务层,进行业务处理和存储,通过消息给到下行业务层,进行分发,下行是一个长链接。
  • 多媒体资源会用新通道,避免占用上下行通道。

二、文件上传

1、直接传到文件存储,返回唯一标识,这个表示作为文本消息进行下发。
2、分片上传:客户端分块并标记,服务器收到后按编号组装存储。重试也只重传一个分片。
3、分片大小:太小时TCP链接太多,报文也是浪费。可以粗略分:wift下2M,4G下1M,3G/2G下256K等。
4、断点续传:每个文件的多个块,都有同一个唯一标记,暂停时告诉服务器这个唯一标记的所有资源先别删(不能永久放)。
5、秒传:微博统计一周30%的图片和视频是重复的,所以先计算MD5并存储,如果已经有了,就不需要传文件了。

三、水平扩展

1、接入层:

  • 入口 VIP 瓶颈可以通过 DNS 轮询;
  • 接入层服务通过中央的“在线状态”资源,来解耦业务层的依赖。

2、业务层:通过“服务化”改造,用“注册发现”解决接入层寻址问题。
3、资源层:数据分片缓解主从库压力。

四、监控

1、系统层监控:Nagios、Zabbix等工具上报CPU内存等信息。
2、应用层监控:QPS、耗时、推送失败等。为数据规模和聚合查询,一般使用时序数据库,如 OpenTSDB、InfluxDB 等。
3、常见方案:

  • Statsd + Graphite + Grafana 方案
  • ELK(Elasticsearch + Logstash + Kibana)方案

4、trace链路追踪:

  • trace:一个完整的链路,携带一个统一的traceId。
  • span:一个服务的请求/响应叫做一个span。一个trace由多个span组成。
  • annotation:自定义事件和参数,如房间ID用户ID等。
  • 成熟系统:Twitter 的 Zipkin、Uber 的 Jaeger、阿里的鹰眼、美团的 Mtrace等。

5、回环探测:主动监控,模拟真实场景调用服务。

五、万人群聊

1、存储:存一份群消息,一份群最新消息id。先获取最新消息id,把群排序展示,再获取每个群的消息。
2、新入群只看新消息:用加群时间做条件。
3、未读数:对高热度群,通过应用层的“合并变更”,来缓解未读资源的写入压力。
4、离线消息:只存消息ID。
5、ACK:参考TCP的Delay ACK机制,在接收方批量ACK。
6、中央全局的在线状态:超大群用户一般分布在多台网关机中,群聊中优化成“网关机本地自治维护”的方式,以解决高并发下推时全局资源的瓶颈。

六、直播间和群聊的在线关系:

  • 直播间:房间之间状态隔离。每次用户进入新房间时,需要“加入房间”、“切换房间”等信令告诉网关机当前连接的是哪个房间。网关机才能够在服务端标记这个“用户 -> 房间 -> 连接”的映射关系。消息从业务层给到网关机时,服务端只需要按房间维度下发消息即可。所以在直播互动场景中,消息的扇出是可以推迟到网关机层的。
  • 群聊:群和群之间并不是隔离状态。对于任何群的消息,服务端都需要通过一条长连接通道来进行消息的下推。所以在 App 打开建立好长连后,客户端发出的“上线”这个操作,只是会上报一个当前用户信息,不需要、也没有办法再告知自己当前进入了哪个群,因而在服务端网关机也只会建立一个“用户” -> “连接”的映射。因此,在群聊场景中,当某一个群有一条消息发出时,我们需要在业务层将这条消息从群维度扇出成 UID 维度,再下发给网关机。我们尽量不在网关机做业务逻辑,所以在业务层扇出后,再提交到网关机进行处理。