IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    关于nginx-ingress-controller中worker参数的差异分析

    蔡晓建发表于 2021-03-24 00:00:00
    love 0

    问题描述

    生产上发现ingress有个pod超时,重启pod正常以后过几十秒状态又变为异常,检查容器日志报错项:

    2021/03/19 01:51:07 [emerg] 263#263: epoll_create() failed (24: No file descriptors available)
    

    对比POD里边的nginx.conf参数,发现有些worker开头的参数比较奇怪。例如worker_processes很大,但是worker_rlimit_nofile很小。

    daemon off;
    worker_processes 64;
    worker_rlimit_nofile 1024;
    worker_shutdown_timeout 240s ;
    events {
            multi_accept        on;
            worker_connections  16384;
            use                 epoll;
    }
    

    临时将worker_rlimit_nofile的值设置为102400,再reload了nginx发现就正常了。

    分析过程

    • 由于对nginx-ingress-controller不是很熟悉,所以查看了部署的chart包,发现是没有任何相关配置的。猜想应该是自动生成的。
    • 根据docker部署的经验,worker_processes应该是根据宿主机的cpu计算出来的,而不是通过POD的资源限制。
    • 查看了POD的部署情况,发现的确是没有设置资源限制。
    • 尝试进行资源限制后,发现就正常了。

    细节分析

    翻了一下nginx-ingress-controller的源码,查找这些值是怎么计算出来的。其中重要的文件如下:

    • configmap相关的配置
    • 具体的计算方式
    • 生成nginx.conf的模板

    可以发现一些细节。

    worker参数的计算方式

    • worker_processes 等于 cpu core
    • worker_rlimit_nofile 等于 最大打开文件数(ulimit –n)/ worker_processes - 1024(如果计算出来小于1024就设置为1024)
    • worker_connections 默认是16384,如果设置0的话,会被调整为worker_rlimit_nofile*3.0/4.0;

    由于当前Ingress controller没有资源限制,看到的资源是看到宿主机的cpu core,一般都挺大的,例如64。根据实现规则,假设系统的open files限制,假设配置102400,那么 1024000/64-1024 =576.小于1024,那么就设置为1024。所以会看到一个很小的nofile设置。

    关键参数的获取细节

    • 关于cpu core的获取方式,最初也是用直接用的宿主机的,后面就支持了cgroup了,见PR2990。
    • 关于最大打开文件数的获取方式,也是变过几次,可以参考追踪nginx ingress最大打开文件数问题,最新的方式和ulimit -n是一致的,和sysctl没有关系。

    当前的nginx-ingress-controller增加了一个init容器来进行最大打开文件数的控制:

    sysctl -w fs.file-max=1048576
    

    最终在容器里边看到的情况是

    bash-5.0$ ulimit -n
    809600
    bash-5.0$ sysctl fs.file-max
    fs.file-max = 1048576
    

    程序读取的就是809600,这个值是怎么来的呢。宿主机看到的是,也是完全不搭边,如下所示。

    dggpsprahi09192:~ # ulimit -n 
    1024
    dggpsprahi09192:~ # sysctl  fs.file-max
    fs.file-max = 1048576
    

    那么肯定是docker还做了一点手脚了。查阅suse、docker的材料。最终发现还有几个地方可以控制。

    • 通过docker服务设置
    dggpsprahi09192:~ # grep Limit /usr/lib/systemd/system/docker.service
    # Having non-zero Limit*s causes performance problems due to accounting overhead
    LimitNOFILE=1048576
    LimitNPROC=infinity
    LimitCORE=infinity
    StartLimitBurst=3
    StartLimitInterval=60s
    
    • 通过docker daemon设置

    路径在/etc/docker/daemon.json,不过这个宿主机没有这个文件。

    	"default-ulimits": {
    		"nofile": {
    			"Name": "nofile",
    			"Hard": 64000,
    			"Soft": 64000
    		}
    	},
    
    • 通过docker启动参数设置
    dggpsprahi09192:/opt/docker # cat /etc/sysconfig/docker
    DOCKER_OPTS=" -b none --icc=false --log-level='info' --iptables=true -s devicemapper --default-ulimit nofile=809600:809600 --default-ulimit nproc=131072:131072 --live-restore --storage-driver=devicemapper --storage-opt dm.basesize=10G --storage-opt dm.mountopt=nodiscard --storage-opt dm.fs=ext4 --storage-opt dm.blkdiscard=false --storage-opt=dm.thinpooldev=/dev/mapper/docker-thinpool --log-opt max-size=10m --log-opt max-file=5 --log-driver=json-file --log-level=info --userland-proxy=false"
    

    注意里边有设置–default-ulimit nofile=809600:809600,就是控制最大打开文件数的,和docker中看到的保持一致。

    worker参数的手工配置

    可以直接通过configmap来配置,覆盖自动计算的方式。参数如下:

    • WorkerProcesses string json:"worker-processes,omitempty"
    • MaxWorkerConnections int json:"max-worker-connections,omitempty"
    • MaxWorkerOpenFiles int json:"max-worker-open-files,omitempty"

    详细可以参考官方文档的ConfigMaps。

    总结

    了解nginx-ingress-controller的参数是如何设置之后,考虑到宿主机上的docker都是标准设置的,所以容器里边看到的ulimit -n是一致,结果是可预计的。 另一方面ingress controller不是独享宿主机资源的,还是要限制资源。最终决定通过限制资源来解决,保持资源是Guaranteed的,其他具体的worker参数根据资源自动计算。



沪ICP备19023445号-2号
友情链接