当时出现问题,现在总结起来,大概以下几点
1.散落在协程里的I/O,Buffer和对象不复用 。
当时(12年)由于对go的gc效率理解有限,比较奔放,程序里大量short live的协程,对内通信的很多io操作,由于不想阻塞主循环逻辑或者需要及时响应的逻辑,通过单独go协程来实现异步 。这回会gc带来很多负担 。
针对这个问题,应尽量控制协程创建,对于长连接这种应用 , 本身已经有几百万并发协程情况下,很多情况没必要在各个并发协程内部做异步io,因为程序的并行度是有限,理论上做协程内做阻塞操作是没问题 。
如果有些需要异步执行 , 比如如果不异步执行,影响对用户心跳或者等待response无法响应,最好通过一个任务池,和一组常驻协程,来消耗,处理结果,通过channel再传回调用方 。使用任务池还有额外的好处,可以对请求进行打包处理,提高吞吐量 , 并且可以加入控量策略.
2.网络环境不好引起激增
go协程相比较以往高并发程序,如果做不好流控 , 会引起协程数量激增 。早期的时候也会发现,时不时有部分主机内存会远远大于其他服务器,但发现时候,所有主要profiling参数都正常了 。
后来发现,通信较多系统中,网络抖动阻塞是不可免的(即使是内网),对外不停accept接受新请求,但执行过程中,由于对内通信阻塞,大量协程被 创建 , 业务协程等待通信结果没有释放,往往瞬时会迎来协程暴涨 。但这些内存在系统稳定后,virt和res都并没能彻底释放,下降后 , 维持高位 。
处理这种情况,需要增加一些流控策略,流控策略可以选择在rpc库来做,或者上面说的任务池来做,其实我感觉放在任务池里做更合理些,毕竟rpc通信库可以做读写数据的限流,但它并不清楚具体的限流策略,到底是重试还是日志还是缓存到指定队列 。任务池本身就是业务逻辑相关的,它清楚针对不同的接口需要的流控限制策略 。
3.低效和开销大的rpc框架
早期rpc通信框架比较简单,对内通信时候使用的也是短连接 。这本来短连接开销和性能瓶颈超出我们预期,短连接io效率是低一些,但端口资源够,本身吞吐可以满足需要 , 用是没问题的,很多分层的系统,也有http短连接对内进行请求的
但早期go版本,这样写程序,在一定量级情况,是支撑不住的 。短连接大量临时对象和临时buffer创建 , 在本已经百万协程的程序中,是无法承受的 。所以后续我们对我们的rpc框架作了两次调整 。
第二版的rpc框架,使用了连接池,通过长连接对内进行通信(复用的资源包括client和server的:编解码Buffer、Request/response),大大改善了性能 。
但这种在一次request和response还是占用连接的,如果网络状况ok情况下,这不是问题,足够满足需要了 , 但试想一个room实例要与后面的数百个的register,coordinator,saver,center,keeper实例进行通信,需要建立大量的常驻连接 , 每个目标机几十个连接,也有数千个连接被占用 。
非持续抖动时候(持续逗开多少无解),或者有延迟较高的请求时候 , 如果针对目标ip连接开少了 , 会有瞬时大量请求阻塞 , 连接无法得到充分利用 。第三版增加了Pipeline操作 , Pipeline会带来一些额外的开销,利用tcp的全双特性,以尽量少的连接完成对各个服务集群的rpc调用 。
4.Gc时间过长
Go的Gc仍旧在持续改善中,大量对象和buffer创建,仍旧会给gc带来很大负担,尤其一个占用了25G左右的程序 。之前go team的大咖邮件也告知我们,未来会让使用协程的成本更低,理论上不需要在应用层做更多的策略来缓解gc.
推荐阅读
- 扶绥小程序开发吧,扶绥微服务的微信号
- 银河系下载,银河系软件
- gis图例中删除图层名,arcgis删除图例项
- linux命令入门 linux入门基础命令
- gis如何计算两点间距离,gis点距离分析
- 搭建睡眠直播教程,直播睡眠的叫什么
- python2的延时函数的简单介绍
- 一帆短视频号怎么赚钱,一帆视频注册
- excel或者符号怎么用,excel或者符号运算