针对容器的nginx优化

本篇文章介绍了 Nginx 在容器内使用遇到的CPU核数获取问题以及对应的解决方法。

回顾上篇文章:TCP 半连接队列和全连接队列

背景

容器技术越来越普遍,很多公司已经将容器技术作为基础架构的一部分,容器中可以运行任何软件,包括 Web Server、Application Server、数据库和存储系统等,其中 Nginx 作为 Web Server 使用也非常的普遍,接下来本文简要分析下 Nginx 在容器内使用遇到的一点小问题。

我们在物理机上配置 Nginx 时通常会将 Nginx 的 worker 进程数配置为 CPU 核心数并且会将每个 worker 绑定到特定 CPU 上,这可以有效提升进程的 Cache 命中率,从而减少内存访问损耗,不放过任何能够榨取系统性能的机会;对于需要手动配置 Nginx 进程个数的场景不在本文的讨论范畴内,例如:磁盘 IO 密集型业务可能会导致 Nginx 进程阻塞,我们通常会将 Nginx 的进程数设置为 CPU 核数的 2 倍,用于提高整体的并发。

在 Nginx 配置中指定 worker_processes 指令的参数为 auto 来自动检测系统的 CPU 核心数从而启动相应个数的 worker 进程,那么在 Linux 系统上 Nginx 是怎样获取 CPU 核心数的呢?答案是通过系统调用 sysconf(_SC_NPROCESSORS_ONLN) 获取到系统当前可用的 CPU 核心数。如果我们在一个 CPU 是 32 cores 的物理机上启动 Nginx,那么 sysconf(_SC_NPROCESSORS_ONLN) 返回值为 32。

存在问题

假如我们将 Nginx 放进 Docker 启动的容器内,sysconf(_SC_NPROCESSORS_ONLN) 的返回值是多少呢?

通过 docker run 启动一个带有 Nginx 的容器,暂时不对此容器的 CPU 资源做任何限制也就是可以使用物理机上的所有资源,我们来观察 Nginx 进程启动的进程数(确认 Nginx 配置中的 worker_processes 指令设置为 auto),答案其实大家都清楚的 Nginx 启动了 32 个 worker 进程。

接下来我们对容器的 CPU 资源做限制,通过 docker run 时指定 --cpuset-cpus="0,1" 参数绑定容器内的进程到 CPU-0 和 CPU-1 上,然后再来观察 Nginx 进程启动的进程数,同样还是 32 个 worker 进程;对容器设置 cpu-shares 和 cpu-quota 也会得到同样的结果。

那么问题来了:

1. 与我们预期的相符吗?

2. 指定了 --cpuset-cpus 能使用的核心数为 2 个,为什么获取到的 CPU 核心数还是 32 呢?

第 1 个问题:

很多人都是知道的,我们更期望的结果对于上边的设置只启动两个 worker 进程,进程得到的 CPU 时间片期望被 2 个进程分摊,现在需要被 32 个进程分摊;从 Nginx 角度来看想要获得更多的时间片就需要减少在这个 CPU 上运行的进程,这样整体性能才会提升。对于 Nginx 来说也就是期望根据可用的 CPU 核数启动相应的进程数,而不是根据物理机上可用的 CPU 核数来设置进程数。

第 2 个问题:

对于容器来说目前还只是一个轻量级的隔离环境,它并不是一个真正的操作系统,那么在容器中获取可用 CPU 核心数和 Memory 大小均是物理机配置。在没有容器的时候很多软件依赖于操作系统的资源进行初始化配置的,例如:JVM 根据 CPU 核数启动相应的 gc 线程,根据物理机的 memroy 设置堆大小。

压测对比

我们通过一个简单的压测对比一下在容器中 Nginx 启动不同 worker 进程对 QPS 和 Latency 影响有多大。

物理机:32cores

容器参数:

cpu-quota=400000(即容器内的进程最多可以使用 400% 的 CPU)

压测指令:

wrk -t 32 -c 500 -d 180 http://container_ip

提前准备:

容器内安装 Openresty、将 worker_processes 修改为 4 和 32,关闭 access 日志,响应数据为 541byte。

以下是 Nginx 的 QPS 和 Latency 压测结果,QPS 从 12 万 + 降到了 4 万 +,Latency 也从 6+ms 降到了 25+ms。

解决方法

从以上压测数据可以看出,Nginx 在设置 worker 进程数为 4 和 32 时 QPS 和 Latency 有很大的差距的,了解了以上问题我们该如何解决呢?

方法 1:

先来说一下普遍使用的 Lxcfs,对于上边提到的场景是不适用的,Lxcfs 目前仅支持改变容器的 CPU 视图(/proc/cpuinfo 文件内容)并且只有 --cpuset-cpus 参数可以生效,对于系统调用 sysconf(_SC_NPROCESSORS_ONLN) 返回的同样还是物理机的 CPU 核数。

方法 2:

通过创建引导程序根据容器可以使用的物理资源自动计算出合理值并设置应用程序的启动参数,例如:通过 shell 脚本动态修改 Nginx 的 worker 进程数。

方法 3:

应用程序自行解析容器内的 cgroup 信息,并设置程序的启动参数。Docker 在 1.8 版本以后将容器分配的 cgroup 信息挂载进了容器内部,在容器内可以通过解析 cgroup 信息获取到当前容器可以使用的资源信息。例如:JDK 10 中引入了支持 Docker 容器的资源检测并配置 JVM 的运行时参数,它的原理就是解析容器内的 cgroup 信息配置 gc 线程数以及堆大小。

方法 4:

劫持系统调用 sysconf,在类 Unix 系统上可以通过 LD_PRELOAD 这种机制预先加载个人编写的的动态链接库,在动态链接库中劫持系统调用 sysconf 并根据 cgroup 信息动态计算出可用的 CPU 核心数。

小结

我们团队也参考了 JVM 的实现并根据 Nginx 的代码风格给 Nginx 打了一个 patch,使 Nginx 的 worker_processes auto 参数能够根据当前容器的可用资源自动计算出合理的 worker 进程数,同时也提交给了 Nginx 社区,但是很遗憾 Nginx 社区负责人 Maxim 并不愿意接受这种实现方式,他更希望的是容器能透明支持 sysconf(_SC_NPROCESSORS_ONLN) 系统调用的功能,而不是用这种解析 cgroup 文件的方式实现,于是我们就实现了一个可以劫持系统调用 sysconf 的动态链接库。

可能有人会有疑问,为什么 JVM 能接受解析 cgroup 文件这种方式,而 Nginx 却不能接受这种方式呢?

根据我的理解目前这个小问题对 Nginx 不是最痛的,不支持也不妨碍使用,另一点是 Nginx 作者以及现在的主要维护者 Maxim 都有重度代码洁癖,从代码风格以及代码中几乎无注释可以感受的到,Nginx 推崇的是代码即文档,要求写代码的人像写文档一样使代码的可读性非常高,对于这种用几百行代码解决的问题他们更不能忍受。而 JVM 支持的这种方式很大原因是这个问题的确很痛,网上有很多人都有报 JVM 在容器内的配置不合理导致运行时出现各种问题,所以目前通用的解决方案也只能是解析 cgroup 文件来自动化支持。

其他

如果你对 Nginx 容器内自动检测可用 CPU 核数的功能感兴趣可以自行patch:

http://mailman.nginx.org/pipermail/nginx-devel/2018-April/011078.html

如果你对容器内劫持系统调用 sysconf 的功能感兴趣可以从这里下载到源码:

https://github.com/agile6v/container_cpu_detection

JDK10 支持检测容器资源的 patch 看这里:

https://bugs.openjdk.java.net/browse/JDK-8146115

[转帖]针对容器的nginx优化的更多相关文章

  1. 2.Nginx优化

    [教程主题]:Nginx优化 [课程录制]: 创E [主要内容] Nginx 优化 nginx介绍 Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx,它的发音为"engine ...

  2. Nginx优化(十七)

    [教程主题]:Nginx优化 [课程录制]: 创E [主要内容] Nginx 优化 nginx介绍 Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx,它的发音为“engine X”,是 ...

  3. 高并发下的 Nginx 优化与负载均衡

    高并发下的 Nginx 优化   英文原文:Optimizing Nginx for High Traffic Loads 过去谈过一些关于Nginx的常见问题; 其中有一些是关于如何优化Nginx. ...

  4. 高并发下的Nginx优化

    高并发下的Nginx优化 2014-08-08 13:30 mood Nginx    过去谈过一些关于Nginx的常见问题; 其中有一些是关于如何优化Nginx. 很多Nginx新用户是从Apach ...

  5. CentOSLinux系统Nginx优化

    Nginx优化 Auther:Rich七哥 Nginx优化一.Nginx隐藏版本号:二.网页缓存.连接超时.网页压缩传输:配置连接超时:3.网页压缩传输:三.访问控制.定义错误页面.自动索引.目录别名 ...

  6. web服务器-nginx优化

    web服务器-nginx优化 一 并发优化 nginx工作模式: 主进程 + 工作进程 启动工作进程数量 worker_processes 4; #指定运行的核的编号,采用掩码的方式设置编号 work ...

  7. 16.Nginx优化与防盗链

    Nginx优化与防盗链 目录 Nginx优化与防盗链 隐藏版本号 修改用户与组 缓存时间 日志切割 小知识 连接超时 更改进程数 配置网页压缩 配置防盗链 配置防盗链 隐藏版本号 可以使用 Fiddl ...

  8. String字符串针对常量池的优化

    String对象是java语言中重要的数据类型,但是不是基本数据类型.相对于c语言的char java做了一些封装和延伸. 针对常量池的优化:当两个String拥有相同的值时,它们只引用常量池中的同一 ...

  9. nginx优化

    此文章非原创,出自鸟哥之手~ http://blog.chinaunix.net/uid-25266990-id-2985541.html 改排版改得多,当然红色部分要注意下,用得较多 ------- ...

  10. Nginx优化具体,应对高并发

     nginx指令中的优化(配置文件) worker_processes 8; nginx进程数,建议依照cpu数目来指定.一般为它的倍数. worker_cpu_affinity 00000001 ...

随机推荐

  1. JavaFx css样式(三)

    JavaFx css样式(三) JavaFX 从入门入门到入土系列 JavaFx css样式,前面我说过它类似html,他有css控制样式,不过最新的css标准并不支持,同时javafx的css样式都 ...

  2. 【Python】人工智能-机器学习——不调库手撕贝叶斯分类问题

    1. 作业内容描述 1.1 背景 数据集大小150 该数据有4个属性,分别如下 Sepal.Length:花萼长度(cm) Sepal.Width:花萼宽度单位(cm) Petal.Length:花瓣 ...

  3. TextCNN和TextRNN:原理与实践

    1.TextCNN原理 CNN的核心点在于可以捕获信息的局部相关性,具体到文本分类任务中可以利用CNN来提取句子中类似N-Gram的关键信息. (1)一维卷积:使用不同尺寸的kernel_size来模 ...

  4. 使用 Python 将数据写入 Excel 工作表

    在数据处理和报告生成等工作中,Excel 表格是一种常见且广泛使用的工具.然而,手动将大量数据输入到 Excel 表格中既费时又容易出错.为了提高效率并减少错误,使用 Python 编程语言来自动化数 ...

  5. GaussDB(DWS)集群中寻找节点CPU占用高的语句

    摘要:本文主要通过实例讲解如何通过gs_cpuwatcher.sh 脚本寻找CPU占用高语句. 本文分享自华为云社区<GaussDB(DWS) gs_cpuwatcher.sh 脚本如何寻找CP ...

  6. DevOps敏捷60问,一定有你想了解的问题

    摘要:问题覆盖了规划设计.开发集成.测试.部署发布.运维监控等DevOps落地实践中的关键疑点与难点. "DevOps的价值是又快又好地交付软件" --<凤凰项目>的作 ...

  7. 教你用Java7的Fork/Join框架开发高并发程序

    摘要:Fork/Join框架位于J.U.C(java.util.concurrent)中,是Java7中提供的用于执行并行任务的框架,其可以将大任务分割成若干个小任务,最终汇总每个小任务的结果后得到最 ...

  8. 云图说 | 分布式缓存服务DCS—站在开源Redis前辈的肩膀上,扬帆起航

    阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:DCS基于开源Re ...

  9. Open vSwitch系列之十 调用北向接口下发流表

    Open vSwitch系列之一 Open vSwitch诞生 Open vSwitch系列之二 安装指定版本ovs Open vSwitch系列之三 ovs-vsctl命令使用 Open vSwit ...

  10. 从数据链路到神秘的MAC地址和ARP协议

    引言 链路是指从一个结点到相邻结点的一段物理线路.数据链路是在链路的基础上增加了一些必要的硬件和软件.这些硬件包括网络适配器,而软件则包括协议的实现.在网络中,主机.路由器等设备都必须实现数据链路层. ...