我使用celery以及docker部署遇到的问题
首先我本机测试时没有问题的,但是在线上docker中,任务一直显示 “Sending due task”。超时的任务是 django orm update 操作,本地不会出现这样的问题。
1. 是不是共用了redis db而不知情?
可能是别人也用这个 redis db 作为 broker,然后比人的任务很多并且排在了我的前面,而我又设置了超时时间
CELERYD_TASK_SOFT_TIME_LIMIT = 20
。于是我将 redis db 改为 61,重启后报错:
invalid DB index
于是搜索 `redis max db number in centos`,在 Maximum number of DB in Redis 找到了答案。 redis 默认只有 16 个 db,但是不限制你设置 db 的数目大小,要记得 redis.conf 设置后要重启才能生效。同时,一个回答者认为 redis 不鼓励设置很多个 db。
(since Redis has a very small memory footprint when is has no data,
~1MB).
我不是运维,于是我将 BROKER 的 redis db 设置为 13。等待结果中。。。。。。(嗯!有这个 db。)
(PS:
我们是使用 docker 部署的,但是改变一个环境变量就需要重新 build 镜像,所以调试一次花的时间很长。我一般直接进入 docker 中,更改代码然后重启 supervisor,但是环境变量以及自定义的 supervisor 命令就没办法,只能重新 build 了。)
celery 队列
celery 有队列的功能,那么我是否能够定义一个自己的专有队列,然后让我的 worker 执行自定义队列中的任务呢?这样就不需要挑别人未使用的 redis db 了。
根据 http://docs.celeryproject.org/en/latest/userguide/routing.html#basics 以及 http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html 我将我的任务放在队列中,然后提示
ImproperlyConfigured:
Cannot mix new setting names with old setting names, please
rename the following settings to use the old format:
task_routes -> CELERY_ROUTES
我将 task_routes 改成 CELERY_ROUTES 就可以了。但是在 http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html 中,就是写的 task_routes,可能 celery 有两种配置命令规范。搜索了一下,确实如此:
New lowercase settings
Version 4.0 introduced new lower case settings and setting organization.The major difference between previous versions, apart from the lower case names, are the renaming of some prefixes, like celerybeat_ to beat_, celeryd_ to worker_, and most of the top level celery_ settings have been moved into a new task_ prefix.
Celery will still be able to read old configuration files, so there’s no rush in moving to the new settings format.
我设置了一个自己的队列,然后 worker 只执行这个队列,但还是会出现 `SoftTimeLimitExceeded`。
多个 docker 重复执行 celery 任务
我使用 docker 部署,然后一次会创建三个容器,一个用来作为备份(只有确定版本稳定了才更新这个容器,否则这个容器一直不变),另外两个用于生产。我现在使用 celery 执行定时任务,在每个整点向微信服务器申请新的 access_token。到了整点,三个容器同时向微信服务器申请 token,然后就会暂时被微信服务器封掉 ip,因为请求的太频繁了。
之前我是使用 celery 加上 python timedelta(minutes=60),但发现每次重启容器的时候任务都会进行,于是就改成了在整点执行任务。
那我现在应该怎么处理呢?
我可以每次重启容器后,进入两个容器中,把 celery_worker 关闭,只留下一个容器执行 celery,可以是可以,但是手动操作太麻烦了。不知道你们是怎样解决这类问题的呢?
睡了一觉,早上想到:这个问题可以转变成:
两个除了启动时间不一样,其他如代码、环境变量等等都一样的程序,如何保证相同的 celery 任务不同时执行。我这里的任务还有一个隐藏条件:只要在一定时间范围内执行了就可以了,执行时间点不一定要扣的很死,比如一定在零点零分执行。
那我就把celery相同任务的执行时间错开。 我可以用随机数作为任务执行的分钟数,这个随机数是启动时生成的,于是任务就被错开了。然后每次任务执行时设置一个 redis key,然后任务执行前看看这个 redis key 是否不为空,避免重复执行。实践了一下是没有问题的,发生3个里面两个在同一份中的概率是,排列组合计算,忘了。
序列化 - Serializers
从 celery==3.1.23 升级到 celery==4.0.2,并删除 django-celery==3.1.17,因为 4.0+ 版本已经支持 Django 了。
遇到了序列化的问题,kombu.exceptions.EncodeError: <function get_file_info at 0x1115c7bf8> is not JSON serializable
函数不能序列化为 json,我就很纳闷,为什么 celery==3.1.23 就可以呢?为了确认是这个问题,我还重新安装 celery==3.1.23,然后就不会报错。我直接搜索 `kombu.exceptions.EncodeError not JSON serializable` 没有找到答案,搜索 `celery not JSON serializable` 也没有找到答案。没办法的情况下,只能更改 celery tasks 定义了。将之前使用函数作为参数的任务改一下。但是,最后遇到问题,有 Django 的 queryset 作为任务,那这样还要将对应querset的参数传入 celery task,我感觉做不了了。于是问同事,刚开始他也没思路,后来我强调 celery==3.1.23 可以序列化而 celery==4.0.2 会报错,他突然想起,说:“celery==4.0.2 默认使用 JSON 作为 serializer ,而 celery==3.1.23 默认使用 pickle”。经过搜索后,将 serializer 改为 pickle,在 celeryconfig.py 中增加如下配置:
CELERY_TASK_SERIALIZER = 'pickle' CELERY_RESULT_SERIALIZER = 'pickle' CELERY_ACCEPT_CONTENT = ['pickle', 'json']
然后就可以了。
还有celery依赖包的问题,比如 kombu 之类的,不能放进 requirements.txt 中如果你不是单独需要的话。因为,当更换 celery 版本的时候,还要手动更换 kombu 这些celery依赖包的版本。所以,在 pip freeze 后也需要做出选择,不把包的依赖包放进去。
反思一下,存在以下问题:
- 升级celery前没有评估好各个引用方法能否改写,之前也确实没有想到会遇到这样的问题;
- 搜索技巧的问题。直接按照报错信息“kombu.exceptions.EncodeError: <function get_file_info at 0x1115c7bf8> is not JSON serializable”去搜索,没有找到答案。如果改用 "differences between celery3 and celery serializers",我就能发现这个:http://docs.celeryproject.org/en/latest/whatsnew-4.0.html,然后页面内搜索 `serializer`,就能发现有一个标题写的很清楚“Json is now the default serializer”
- 问人要提早问,不要不好意思。之前是问的太多了,现在是问的太少了。有些问题可能要花很多时间去找答案,但他人可能了解相关的知识,只要你提问足够具体。
- 升级之前没有了解新的变化。我想的是不用依赖 django-celery 以及版本更高的话文档会更及时。
能否动态增加 celery 任务?如何给定时任务增加参数?
celery 是命令行启动的,那么能否在启动后动态增加呢? 参考:http://stackoverflow.com/questions/11449661/how-to-pragmatically-schedule-celery-task-with-dynamic-inputs。一种是通过函数,函数能够接受参数或者生成参数;而是celery中可以配置定时任务的参数,那如果有很多,就要生成这些代码?celery配置不能使用循环?
“定时任务增加参数”,是否与在一个任务中做完所有参数的工作相同?
附:
celery 序列化器的不同?为什么要将 JSON 作为默认序列化器?
我使用celery以及docker部署遇到的问题的更多相关文章
- 我使用 Docker 部署 Celery 遇到的问题
问题1 - Sending due task 本机测试时没有问题的,但是在线上 docker 中,任务一直显示 "Sending due task".超时的任务是 Django O ...
- ASP.NET Core开发-Docker部署运行
ASP.NET Core开发Docker部署,.NET Core支持Docker 部署运行.我们将ASP.NET Core 部署在Docker 上运行. 大家可能都见识过Docker ,今天我们就详细 ...
- Docker部署Hadoop集群
Docker部署Hadoop集群 2016-09-27 杜亦舒 前几天写了文章"Hadoop 集群搭建"之后,一个朋友留言说希望介绍下如何使用Docker部署,这个建议很好,Doc ...
- 程序开发使用docker部署
我们公司自己研发了一套 grand-line 系统,使用 docker 来部署项目. 我是第一批小白鼠,一开始网络差,build 一次要半个小时,连接进入 web shell 也很慢,部署一个微信项目 ...
- Docker部署SDN环境
2014-12-03 by muzi Docker image = Java class Docker container = Java object 前言 5月份的时候,当我还是一个大学生的时候,有 ...
- 在生产环境使用Docker部署应用
导读 Docker现在越来越流行,但是真正在生产环境部署Docker还是个比较新的概念,还没有一个标准的流程.作者是ROR的程序员,作者结合平时的部署经验,联系Docker的特点,向大家分享了其在生产 ...
- Docker 使用指南 (六)—— 使用 Docker 部署 Django 容器栈
版权声明:本文由田飞雨原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/98 来源:腾云阁 https://www.qclou ...
- NET Core Docker部署
NET Core Docker部署 前言 在前面文章中,介绍了 ASP.NET Core在 macOS,Linux 上基于Nginx和Jexus的发布和部署,本篇文章主要是如何在Docker容器中运行 ...
- Docker部署Elasticsearch集群
http://blog.sina.com.cn/s/blog_8ea8e9d50102wwik.html Docker部署Elasticsearch集群 参考文档: https://hub.docke ...
随机推荐
- stringstream操纵string小总结
1 split字符串 之前在用C#写代码的时候,用过split函数,可以把一个字符串根据某个分隔符分成若干个字符串数组.在用C++操纵字符串的时候,我一直使用很笨的遍历的方法.为此,我问候过很多次C+ ...
- nav布局 在线演示 DIVCSS5
<!doctype html> nav布局 在线演示 DIVCSS5 传统 div ul li布局导航条效果 网站首页 HTML教程 HTML入门 HTML5教程 CSS教程 CSS入门 ...
- 每日Scrum(1)
今天又正式开始了第二个冲刺周期,计划七天,主要需要改进的地方包括UI界面,还有一些细节的把握. 今天出现的主要问题有:在讨论UI界面风格的时候,小组内部意见不统一,对UI界面的创作流程不熟悉,以及难度 ...
- ADDM Reports bug:Significant virtual memory paging was detected on the host operating system
查看ADDM(数据库版本为ORACLE 10.2.0.5.0)报告时,发现其中有个结论非常不靠谱:Significant virtual memory paging was detected on t ...
- ADO.Net(四)——扩展属性和配置文件应用
一.扩展属性 处理:有外键关系时将代号化信息处理成原始文字,让用户可看懂的(粗略解释) 利用扩展属性 如:Info表中的民族列显示的是民族代号处理成Nation表中的民族名称 需要在Info类里面扩展 ...
- oracle DB_LINK
1.先创建远程数据库服务名(注意,如果服务器既有oracle服务端又有客户端,需要在服务端的tnsnames.ora中配置服务名,否则会报如下错误): SQL> select count(*) ...
- InnoDB源码分析--缓冲池(三)
转载请附原文链接:http://www.cnblogs.com/wingsless/p/5582063.html 昨天写到了InnoDB缓冲池的预读:<InnoDB源码分析--缓冲池(二)> ...
- text-transform设置单词首字母大写
text-transform 一.语法 text-transform 主要用于设置文本的大小写. text-transform有5个值,分别如下: none. 默认值. capitalize. 文 ...
- mysql密码相关
Windows中修改密码在不同场景下,有以下几种方案: 方法1:用SET PASSWORD命令,具体更新密码步骤如下: c:>mysql -u root mysql>set passw ...
- URL tailing slash
Without tailing slash request header GET /snippets HTTP/1.1 User-Agent: Fiddler Host: 192.168.128.13 ...