Gunicorn是用于Python应用程序的通用WSGI服务器,但是大多数在Docker容器中使用的gunicorn配置都是错误的。在容器中运行gunicorn与在虚拟机或物理服务器上运行不同,并且还需要考虑Linux环境之间的差异。

因此,为了保持你的Gunicorn设置正确和高效,在本文中,我将介绍:

  • 防止由于heartbeats心跳而导致缓慢。
  • 正确配置worker数。
  • 正确输出日志到标准输出。

为什么Gunicorn“有时会挂半分钟”

Gunicorn的master进程启动一个或多个worker进程,如果worker进程死亡,则master负责将其重新启动。为了确保worker一直工作,Gunicorn有一个心跳系统-通过使用文件系统上的文件来工作。因此,Gunicorn建议将此文件存储在文件系统的仅内存部分中。

正如Gunicorn常见问题解答所述,心跳文件的默认目录位于/tmp,在某些Linux发行版中,该目录通过tmpfs文件系统存储在内存中。但是,Docker容器默认情况下不启用tmpfs的/tmp:

$ docker run --rm -it ubuntu:18.04 df
Filesystem       1K-blocks     Used Available Use% Mounted on
overlay           31263648 25656756   3995732  87% /
tmpfs                65536        0     65536   0% /dev
tmpfs              4026608        0   4026608   0% /sys/fs/cgroup
/dev/mapper/root  31263648 25656756   3995732  87% /etc/hosts
shm                  65536        0     65536   0% /dev/shm

如您所见,/tmp正在使用标准的Docker overlay 文件系统:它由计算机正在使用的普通块设备或硬盘驱动器提供支持。

这可能会导致性能问题-引用常见问题解答:“在AWS中,EBS根实例卷有时可能会挂起半分钟,在此期间Gunicorn worker可能会完全阻塞。”

您不会想让您的Gunicorn worker阻塞30秒,那么您应该怎么办?一种选择是使用Docker的卷支持将一个内存中的tmpfs或ramfs文件系统挂载到/tmp上。这将起作用,但并非在所有地方都起作用:并非所有运行Docker容器的环境都支持任意卷。

一个更通用的解决方案是告诉Gunicorn将其临时文件存储在其他位置。特别是,如果您在上面看,您会看到/dev/shm使用了shm文件系统-共享内存和内存文件系统。

因此,您所需要做的就是告诉Gunicorn使用/dev/shm而不是/tmp。 (当19.9.0之后的版本发布时,这至少会在Gunicorn FAQ中有所记录,但是您仍然必须记住要这样做。)

在命令行上的操作方法如下:

$ gunicorn --worker-tmp-dir /dev/shm ...

正确配置worker数

如果您是直接在物理机或虚拟机上运行Gunicorn,则通常希望单个Gunicorn实例利用所有可用的CPU。由于Python不能很好地使用多个CPU,因此通常您需要启动多个worker进程,每个worker进程都不同,以便利用所有CPU。

但是,在容器中运行时,通常会处在可以通过运行更多容器来扩大规模的分布式环境中。Heroku,AWS Elastic Beanstalk和Kubernetes:它们全部都隐藏了硬件,并希望通过拆分多个容器来利用多个CPU。

因此,可能只需要一个worker就可以启动Gunicorn。但是,这些系统中的许多系统还包括心跳机制,该机制通过向服务器发送周期性的查询来检查服务器是否处于活动状态。

如果您只有一个worker,并且在处理慢查询的时候遇到了问题,则心跳查询将超时。 届时,负载平衡器将确定容器已卡住,并停止向其发送查询。在某些环境中,它也可能会重新启动。(感谢杰里米·瑟古德(Jeremy Thurgood)向我介绍了这个问题。)

解决方案:启动至少两个worker进程,并可能还使用gthread工作线程后端启动多个线程。 这样,每个worker进程都可以处理多个查询,只要花一些时间等待(例如,返回数据库查询)即可。这样可确保容器获得最大的CPU利用率(不缩放时),并减少了无法响应心跳查询的机会。

$ gunicorn --workers=2 --threads=4 --worker-class=gthread ...

为了在使用Gunicorn时提高性能,我们必须牢记3种并发方式。

第一种并发方式(worker进程,又名UNIX进程)

每个工作程序都是一个加载Python应用程序的UNIX进程。工作人员之间没有共享内存。

建议的worker数量为:(2*CPU)+1。

对于双核(2 CPU)计算机,建议workers值为5 。

gunicorn --workers=5 main:app
第二种并发方式(worker进程 + 线程)

Gunicorn还允许每个worker都有多个线程。在这种情况下,每个worker进程会加载一次Python应用程序,并且同一worker进程产生的每个线程都共享相同的内存空间。
要将线程与Gunicorn一起使用,请使用该threads设置。每次使用时threads,worker类都设置为gthread:

gunicorn --workers=5 --threads=2 main:app

在使用worker进程+线程时,建议的最大并发请求数仍为(2*CPU)+1。
因此,如果我们使用的是四核(4 CPU)计算机,并且要使用worker进程和线程的混合,则可以使用3个worker进程和3个线程,以获取9个最大的并发请求。

gunicorn --workers=3 --threads=3 main:app
第三种并发方式(“伪线程”)

有一些Python库,例如gevent和Asyncio,它们通过使用用协程实现的“伪线程”在Python中启用并发。
Gunicorn通过设置它们的相应工作程序类(worker-class),允许使用这些异步Python库。
在这里,这些设置适用于我们要使用gevent以下命令运行的单核计算机:

gunicorn --worker-class=gevent --worker-connections=1000 --workers=3 main:app

worker-connections是gevent worker类的特定设置。

workers=(2CPU)+1仍然建议使用,因为我们只有1个核心,我们将使用3个工作进程。
在这种情况下,最大并发请求数为3000(3个worker进程
每个worker进程1000个连接)

正确输出日志

容器调度程序通常期望日志在stdout/stderr上输出,因此您应该配置Gunicorn来做到这一点:

$ gunicorn --log-file=- ...

如果您的nginx在Gunicorn前面,而想使用它的日志,则可以不修改。

nginx并非总是必要的

说到nginx,您并不总是需要在Gunicorn前面使用nginx或其他代理。许多容器部署系统已经内置了HTTP负载平衡器/反向代理,在这种情况下,无论如何Gunicorn都不会直接暴露给HTTP客户端。

在容器中运行应用程序的特殊性

在容器中运行应用程序与在计算机或VM中运行有一点不同:您具有不同级别的控制(通常无法从正在运行的容器内部安装文件系统),不同的缩放模型以及通常不同的网络配置。

不要只是复制您的旧配置,请确保对其进行适当的自定义以在容器中运行。

ref: https://pythonspeed.com/articles/gunicorn-in-docker/
ref: https://medium.com/building-the-system/gunicorn-3-means-of-concurrency-efbb547674b7

在Docker容器中正确配置Gunicorn相关推荐

  1. 性能监控之 JMX 监控 Docker 容器中的 Java 应用

    文章目录 一.前言 二.遇到的问题 1.问题现象 2.问题分析 三.解决方案 四.总结 一.前言 今天在配置 docker 和 JMX 监控的时候,看到有一个细节和非容器环境中的 JMX 配置不太一样 ...

  2. 排行前1000的docker容器中,20%存在root帐户配置错误

    在Docker Hub门户中"最受欢迎的Docker容器"排名前1000的Docker容器中约有20%存在帐户错误配置的缺陷,在某些情况下,这些缺陷可能会使用户系统受到远程网络攻击 ...

  3. 容器安装java_在docker容器中安装Java(从宿主机向docker容器中拷贝文件)

    操作系统 [root@Optimus /]# uname -a Linux Optimus 2.6.32-504.el6.x86_64 #1 SMP Wed Oct 15 04:27:16 UTC 2 ...

  4. 查看docker内部路径_web应用在Docker容器中部署(Windows)

    前言 容器化是软件开发的一种方法,通过该方法可将应用程序或服务.其依赖项及其配置(抽象化为部署清单文件)一起打包为容器映像. 容器化应用程序可以作为一个单元进行测试,并可以作为容器映像实例部署到主机操 ...

  5. vs附加其它计算机应用到进程,如何将VS代码附加到在docker容器中运行的节点进程...

    我试图将Visual Studio代码调试程序附加到在Docker容器中运行的node.js应用程序. 我启动应用程序,如: node --debug-brk app.js 我在docker-comp ...

  6. 如何在Docker容器中挂载主机目录

    本文翻译自:How to mount a host directory in a Docker container I am trying to mount a host directory into ...

  7. 如何在Docker容器中运行GUI程序

    如何在Docker容器中运行GUI程序 各位,今天我们将学习如何在Docker之中运行GUI程序.我们可以轻易地在Docker容器中运行大多数GUI程序且不出错.Docker是一个开源项目,提供了一个 ...

  8. Docker容器中的Linux机器快速设置国内源

    Docker容器中的Linux机器快速设置国内源 在Docker容器中启动了服务后,当我们进入容器内,经常很多命令无法使用,比如最基本的vim,可能都没有安装,因为容器内只安装应用服务,导致无法编辑配 ...

  9. 在docker容器中操作es,并给es7.6添加用户鉴权设置密码

    1.docker启动命令:docker-compose up -d 加上 -d 表示后台运行,只是docker-compose up则是在控制台运行,会不停的打印日志. 2.从容器中拷贝文件到宿主机: ...

最新文章

  1. php java 单点登录_php实现多站点共用session实现单点登录的方法详解
  2. 刘卫国python实验答案_MATLAB(刘卫国)部分实验答案
  3. ue4vr插件_UE4 含源码插件合集【转载】
  4. cocos2d-x 中LUA和平台之间的函数调用理解
  5. ubuntu java apt-get_ubuntu apt-get 安装jdk7
  6. 【工具】损坏视频文件修复MP4/MOV格式
  7. python怎么画名字_python 画中国地图怎么把省份名字加上-
  8. 从自建服务器到选择阿里云我们都应该慎重决定
  9. 使用sqlyog连接阿里云rds数据库
  10. [PMZL]第1卷-误入天庭-01
  11. 非接触式CPU卡的外部认证和内部认证过程
  12. 山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(三)
  13. pe下找不到ssd硬盘_进入pe后找不到固态硬盘怎么解决
  14. 28 岁的我,一事无成
  15. 连续信号、离散信号、模拟信号与数字信号区别
  16. vue为什么需要nodejs 的环境
  17. sticky INTENT
  18. python 计算一年内的所有周的具体日期
  19. 微信小程序实现生成二维码功能并下载到本地
  20. 高效可控行事8种思维模型

热门文章

  1. 食品生产许可证办理时间及所需材料介绍
  2. 开发框架图介绍(*)
  3. windows无法更新
  4. 极光推送集成厂商通道指南
  5. 企业数字化转型:信息化与数字化
  6. 网页中插入flv播放器
  7. 一键查杀linux挖矿脚本,这几个linux命令或许帮您查杀挖矿病毒
  8. 如何学习数据分析?数据分析平台来帮你
  9. 论文阅读笔记---Recent development in CNC machining of freeform surfaces: A state-of-the-art review
  10. 《口袋妖怪》大战:通过数据分析,一次性揭示最强王者,谁能成为最后的胜者?