天天看点

Go程序在容器中部署需要注意的小问题问题描述造成的后果解决方法

引用书籍<<GO语言编程之旅>>

问题描述

在Go语言中,Go scheduler的P数量非常重要,因为它会极大地影响Go在运行时的表现。

在目前的Go语言中,P的数量默认是系统的CPU核数。在容器化的环境中,Go程序所获取的CPU核数是错误的,它所获取的是宿主机的CPU核数。即使容器和宿主机的CPU核数是共享的,但在集群中我们会针对每个Pod分配指定的核数,因此实际上我们需要的是Pod的核数,而不是宿主机的CPU核数。

造成的后果

曾提到Go的M:N调度模型,其要求M必须与P进行绑定,然后才能不断地在M上循环寻找可运行的G来执行相应的任务。

注意,M必须与P进行绑定,其绑定的这个P,要求必须是空闲状态。

但在容器化的部署环境中,P 的数量由于被“错误”设置,因此拥有大量空闲的 P。可以这样理解,只要有足够多的M,那么P就可以都被绑定。这时又产生了另外一个问题,M的数量是否会不断增加呢?答案是会的。在程序运行过程中,由于产生了网络I/O阻塞,导致M会随着程序的不断执行而不断增加,,即能够达到前面假设的情况。最终导致Go程序的延迟加大,程序响应缓慢。

解决方法

产生这个问题的本质原因是Go程序没有正确地获得我们所期望的CPU核数(应当获取具体分配给Pod的配额),因此解决方案有两种:· 结合部署情况,主动设置正确的GOMAXPROCS核数。· 通过cgroup信息,读取容器内的正确GOMAXPROCS核数。

目前,Go 尚没有非常完美的办法来解决这个问题,因此这里推荐使用 Uber 公司推出的uber-go/automaxprocs 开源库,它会在 Go 程序运行时根据 cgroup 的挂载信息来修改GOMAXPROCS核数,并基于一定规则选择一个最合适的数值

在main里面初始化导入这个包

Go程序在容器中部署需要注意的小问题问题描述造成的后果解决方法

我们只需在 Go 程序启动时进行引用即可,如果有特殊的需求,那么主动设置GOMAXPROCS也是可以的。