go语言实现在线聊天 go语言教程( 六 )


改善方式,一种是多实例的拆分,如果公司没有端口限制,可以很快部署大量实例,减少gc时长 , 最直接方法 。不过对于360来说 , 外网通常只能使用80和433 。因此常规上只能开启两个实例 。当然很多人给我建议能否使用SO_REUSEPORT,不过我们内核版本确实比较低,并没有实践过 。
另外能否模仿nginx,fork多个进程监控同样端口,至少我们目前没有这样做,主要对于我们目前进程管理上,还是独立的运行的,对外监听不同端口程序,还有配套的内部通信和管理端口 , 实例管理和升级上要做调整 。
解决gc的另两个手段 , 是内存池和对象池,不过最好做仔细评估和测试,内存池、对象池使用,也需要对于代码可读性与整体效率进行权衡 。
这种程序一定情况下会降低并行度 , 因为用池内资源一定要加互斥锁或者原子操作做CAS,通常原子操作实测要更快一些 。CAS可以理解为可操作的更细行为粒度的锁(可以做更多CAS策略,放弃运行,防止忙等) 。这种方式带来的问题是 , 程序的可读性会越来越像C语言,每次要malloc,各地方用完后要free,对于对象池free之前要reset,我曾经在应用层尝试做了一个分层次结构的“无锁队列”
上图左边的数组实际上是一个列表,这个列表按大小将内存分块,然后使用atomic操作进行CAS 。但实际要看测试数据了,池技术可以明显减少临时对象和内存的申请和释放,gc时间会减少,但加锁带来的并行度的降低,是否能给一段时间内的整体吞吐量带来提升 , 要做测试和权衡…
在我们消息系统,实际上后续去除了部分这种黑科技,试想在百万个协程里面做自旋操作申请复用的buffer和对象,开销会很大,尤其在协程对线程多对多模型情况下,更依赖于golang本身调度策略 , 除非我对池增加更多的策略处理,减少忙等,感觉是在把runtime做的事情,在应用层非常不优雅的实现 。普遍使用开销理论就大于收益 。
但对于rpc库或者codec库,任务池内部,这些开定量协程,集中处理数据的区域,可以尝试改造~
对于有些固定对象复用,比如固定的心跳包什么的,可以考虑使用全局一些对象,进行复用 , 针对应用层数据,具体设计对象池,在部分环节去复用,可能比这种无差别的设计一个通用池更能进行效果评估.
消息系统的运维及测试
下面介绍消息系统的架构迭代和一些迭代经验,由于之前在其他地方有过分享,后面的会给出相关链接,下面实际做个简单介绍,感兴趣可以去链接里面看
架构迭代~根据业务和集群的拆分 , 能解决部分灰度部署上线测试,减少点对点通信和广播通信不同产品的相互影响,针对特定的功能做独立的优化.
消息系统架构和集群拆分,最基本的是拆分多实例 , 其次是按照业务类型对资源占用情况分类,按用户接入网络和对idc布点要求分类(目前没有条件,所有的产品都部署到全部idc)
系统的测试go语言在并发测试上有独特优势 。
对于压力测试,目前主要针对指定的服务器,选定线上空闲的服务器做长连接压测 。然后结合可视化,分析压测过程中的系统状态 。但压测早期用的比较多 , 但实现的统计报表功能和我理想有一定差距 。我觉得最近出的golang开源产品都符合这种场景,go写网络并发程序给大家带来的便利,让大家把以往为了降低复杂度,拆解或者分层协作的组件,又组合在了一起 。
QA
Q1:协议栈大?。?超时时间定制原则?
移动网络下超时时间按产品需求通常2g , 3G情况下是5分钟 , wifi情况下5~8分钟 。但对于个别场景,要求响应非常迅速的场景,如果连接idle超过1分钟,都会有ping , pong,来校验是否断线检测,尽快做到重新连接 。

推荐阅读