直播聊天系统本质上也是一种推送系统,所谓推送系统就是,当你发送一条消息时,它可以将这个消息推送给所有人。对于直播弹幕来说,用户在不断地发送消息,不断地进行广播,当一个房间里面有 10 万人时,一个消息就要发出 10 万次请求。在 GOIM 出现之前,也用过另一个名为 Gopush 的项目,这个项目推出的目的就是进行推送。在此之后,基于一些针对性的应用场景,GOIM 对 Gopush 进行了优化,从而出现在我们视野当中。GOIM 主要包含以下几个模块(图 1):
Kafka(第三方服务)
消息队列系统。Kafka 是一个分布式的基于发布/订阅的消息系统,它是支持水平扩展的。每条发布到 Kafka 集群的消息都会打上一个名为 Topic(逻辑上可以被认为是一个 queue)的类别,起到消息分布式分发的作用。
Router
存储消息。Comet 将信息传送给 Logic 之后,Logic 会对所收到的信息进行存储,采用 register session 的方式在 Router 上进行存储。Router 里面会收录用户的注册信息,这样就可以知道用户是与哪个机器建立的连接。
Logic
对消息进行逻辑处理。用户建立连接之后会将消息转发给 Logic ,在 Logic 上可以进行账号验证。当然,类似于 IP 过滤以及黑名单设置此类的操作也可以经由 Logic 进行。
Comet
维护客户端长链接。在上面可以规定一些业务需求,比如可以规定用户传送的信息的内容、输送用户信息等。Comet 提供并维持服务端与客户端之间的链接,这里保证链接可用性的方法主要是发送链接协议(如 Socket 等)。
Client
客户端。与 Comet 建立链接。
Jop
消息分发。可以起多个 Jop 模块放到不同的机器上进行覆盖,将消息收录之后,分发到所有的 Comet 上,之后再由 Comet 转发出去。
以上就是 GOIM 系统实现客户端建立链接,并进行消息转发的一个具体过程。一开始这个结构并不完善,在代码层面也存在一些问题。鉴于这些问题,B 站提供了一些相关的优化操作。在高稳定性方面,提供了内存优化、模块优化以及网络优化,下面是对这些优化操作的介绍。
GOIM 系统的优化之路
内存优化
内存优化主要分为以下三个方面:
1.一个消息一定只有一块内存
使用 Job 聚合消息,Comet 指针引用。
2.一个用户的内存尽量放到栈上
内存创建在对应的用户 Goroutine(Go 程)中。
3.内存由自己控制
主要是针对 Comet 模块所做的优化,可以查看模块中各个分配内存的地方,使用内存池。
模块优化
模块优化也分为以下三方面:
1.消息分发一定是并行的并且互不干扰
要保证到每一个 Comet 的通讯通道必须是相互独立的,保证消息分发必须是完全并列的,并且彼此之间互不干扰。
2.并发数一定是可以进行控制的
每个需要异步处理开启的 Goroutine(Go 协程)都必须预先创建好固定的个数,如果不提前进行控制,那么 Goroutine 就随时存在爆发的可能。
3.全局锁一定是被打散的
Socket 链接池管理、用户在线数据管理都是多把锁;打散的个数通常取决于 CPU,往往需要考虑 CPU 切换时造成的负担,并非是越多越好。
模块优化的三个方面,主要考虑的问题就是,分布式系统中会出现的单点问题,即当一个用户在建立链接后,如果出现故障,其余用户建立的链接不能被影响。
测试是实践过程中最不可缺少的一部分,同时,测试的数据也是用来进行参考比照的最好工具。