解读 | TARS开源项目发布Go语言版本(2)
对于流量控制,服务发布上线主要面对的问题是“如何做对业务无损的服务变更”与“如何做灰度验证”,在 Tars 中,可通过 Registry 和开发框架配合实现按需进行流量控制,达到无损发布和灰度流量的目的。 语言支持方面,除了此前已经支持的 PHP、C++、NodeJS 与 Java,此次还加入了 Golang 支持。 此外,Tars 还提供一个 OSS 平台,可使运营可视化、Web 化。 它主要包含以下特点:
Tars-Go,Tars Go!多语言支持是 Tars 的一大优势,在此之前 Tars 已经推出了 C++、Java、PHP、NodeJS 版本。Go 语言的协程并发机制使它非常适用于大规模高并发后端服务器程序开发,同时随着容器化技术的飞速发展,诸如 Docker、Kubernetes 与 Etcd 等项目兴起,使得 Go 语言越来越流行,并成为云原生的首选语言。Tars 的 Go 语言版本也因此应运而生,此次 Tars-Go 的推出,在大环境整体逐渐走向云原生的当下,意义非凡。 此次新推出的 Go 版本 Tars-Go 整体架构主要可以分为三个部分,如下图所示:
编者了解到,Tars 开源团队在研发 Tars-Go 的过程中经历的对其各个方面的性能调优改造,Tars-Go 在早先的版本注重于功能的开发和完善,没有体系化地进行压测和性能分析。在业务使用一段时间后,开始注重性能优化。Tars 开源团队对 tars2go 工具先进行了一轮优化,在生成语树的时候生成好了类型信息,避免使用反射进行类型判断,编解码的效率提升了 2 倍,然后对再对整体 servant 进行了一轮轮压测,并进行 CPU profile 性能分析。 下面是性能提升优化的几个实例: Timer 性能问题 每个请求进来,Tars-Go 会创建一个协程进行处理,因为要处理调用超时,会创建一个 timer,在结束的时候会删掉 timer,当并发量一上来,就会频繁创建和删除 timer,占用服务大量 CPU 时间。 研发团队在一个 issue 中发现 ,在多 CPU 的场景下,如果存在大量的 timer,性能就会大量损耗,优化方式是每个 p 有自己的 timer,这样可以大幅提升整体并发性能。于是 Tars-Go 将编译环境升级至 1.10.3,从 profile 来看,性能得到了很大的提升,并且基于时间轮询算法实现了自己的 timer,以精度换取性能和效率。 net 包的 SetDeadline 调用性能问题 为了设置网络连接的读写超时,Tars-Go 使用了 net 包的 SetReadDeadline/SetWriteDeadline 等相关调用,但从 profile 发现,当并发非常大的时候,会导致这两个调用占用了大量的 CPU 时间。为了绕开这两个相关调用,使用了 Sysfd 进行 Socket 读写超时的设置。 bytes 的 Buffer 带来的性能问题 从下图可以看出,有相当大的一部分时间耗在了 slice 相关的操作上,原来在包的编解码过程中,使用 bytes.Buffer 进行临时存放,当 bytes.Buffer 底层用的 byte slice 大小不够的时候,就会分配一定的内存空间,频繁地分配效率很低,所以导致大包情况下性能下降比较明显。 联想到了 Redis 的内存模型和 Linux 的 slab 机制,对于频繁创建销毁的对象,采用预先创建和重复利用的方式。而 Go 本身提供了一种 sync.Pool 机制,供临时对象的复用,以减少 GC,Tars-Go 在此基础上,实现了类似 Linux slab 机制分配的 buffer 管理方案,通过这种方案,性能大幅提高。 其他方面的优化 (编辑:ASP站长网) |