场景1:
在网站A业务中有个操作 是 要在网站B中新建一台服务器跑业务。A中执行B中的接口创建服务器 中间需要的时间很长。A如果一直等着B返回结果会超时。B 执行命令 很耗资源,而且不能执行太多的并发。 这这种需求下 我们想到的就是 传说中的 “消息列队“ 来解决这种分布式事务。
场景2:
你可能想对100台服务器执行一条批量处理命令,可能会花很长时间,但是你可能不想让你的程序等着结果返回,而是给你返回一个任务ID,过一段时间只要拿着这个任务ID就可以拿到任务执行结果。
场景3:
你想做一个定时任务,比如每天检测一下你们所有客户的资料,如果发现今天是某个客户的生日,就给他发个短信祝福。
1 Celery介绍
Celery是一个基于python开发的分布式异步消息的任务队列
Celery优点:
- 简单。
- 高可用。当任务执行失败或者执行过程中发生中断,Celery会自动尝试重新执行任务
- 快速。一个单进程的celery每分钟可处理上百万个任务
- 灵活。几乎celery的每个组件都可以被扩展和自定制。
Celery分为3个部分
(1)worker部分负责任务的处理,即工作进程(我的理解工作进程就是你写的python代码,当然还包括python调用系统工具功能)
(2)broker部分负责任务消息的分发以及任务结果的存储,这部分任务主要由中间数据存储系统完成,比如消息队列服务器RabbitMQ、redis。作为一个消息中间件。
(3)Celery主类,进行任务最开始的指派与执行控制,他可以是单独的python脚本,也可以和其他程序结合,应用到django或者flask等web框架里面以及你能想到的任何应用
celery的模块架构
工作原理
Celery Flower
Flower是基于Celery web的监控和管理
celery的运用比较简单:
1.安装celery
2 创建一个celery application 用来定义你的任务列表
3.编写需要异步执行的任务函数,并用celery实例的task修饰器修饰
4.调用异步任务时, 用函数名.delay(参数)形式调用为异步调用。 函数名(参数)方式为同步调用。
5.执行celery监听服务
2 安装celery
source ~/python3.6_env/bin/activate
(python3.6_env) $ pip install celery==4.1.0
(python3.6_env) $ pip install redis
安装celery flower
(python3.6_env) $ pip install flower
安装django-celery
(python3.6_env) $pip install django-celery
我们总在说c10k的问题, 也做了不少优化, 然后优化总是不够的。
其中的一个瓶颈就是一些耗时的操作(网络请求/文件操作–含耗时的数据库操作)。
如果我们不关心他们的返回值,则可以将其做成异步任务,保证执行成功即可。
3 Celery使用案例
案例1 任务调度执行:
(1)创建一个celery application 用来定义你的任务列表
编译一个tasks.py 文件
#!/usr/bin/env python
# encoding: utf-8
from celery import Celery
from time import sleep
# broker="redis://redis:6379/1" 列队数据库存放点
# backend="redis://redis:6379/2" 任务执行完成后数据库存放点
//创建一个celery application 用来定义你的任务列表
app=Celery("tasks", broker="redis://127.0.0.1:6379/1",
backend="redis://127.0.0.1:6379/2")
@app.task
def add(x,y):
return x + y
@app.task
def mult(x,y):
sleep(10)
return x * y
@app.task
def getname(name):
return name
@app.task
def sendmail(user_email):
func(user_email)
return True
(2)启动Celery Worker来开始监听并执行任务
celery -A tasks worker --loglevel=info
(3)服务使用方调用任务
再打开一个终端, 进行命令行模式,调用任务
add.delay(6, 5)
<AsyncResult: a324e552-90db-4e12-8b97-1539471c4bb2>
观察服务端变化
案例2. Celery实现定时器
from celery import Celery
from celery.schedules import crontab
app = Celery('tasks', broker='redis://localhost:6379/0')
#@app.on_after_configure.connect
@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
# Calls test('hello') every 10 seconds.
sender.add_periodic_task(10.0, test.s('hello'), name='add every 10')
# Calls test('world') every 30 seconds
sender.add_periodic_task(30.0, test.s('world'), expires=10)
# Executes every Monday morning at 7:30 a.m.
sender.add_periodic_task(crontab(hour=7, minute=30, day_of_week=1), test.s('Happy Mondays!'),)
@app.task
def test(arg):
print(arg)
开启两个终端
(1)一个终端启动worker
celery worker -A tasks -l INFO
(2)另一个终端启动调度器 beat (组件 beat,它用于对任务进行调度)
celery beat -A tasks -l INFO
为了快速部署并启动服务,我们可以写一个Celery管理脚本程序
celery管理脚本
#!/bin/bash
#############################################################
#celery flower web ui controller script
# web reference : https://my.oschina.net/u/2306127/blog/420929
############################################################
CELERY_UI_PORT=10055
BROKER="redis://127.0.0.1:6379/1"
#BROKER="redis://172.16.245.100:6379/1"
APP_NAME="worker"
#start the celery ui web server.
start_celery_flower() {
nohup celery flower --broker=$BROKER --port=$CELERY_UI_PORT >./flower.log 2>./flower.log &
#nohup celery flower --broker=$BROKER --port=$CELERY_UI_PORT >/dev/null 2>/dev/null &
#celery flower --broker=$BROKER --port=$CELERY_UI_PORT -A $APP_NAME &
echo "start celery ui server ok with $CELERY_UI_PORT"
}
#start the celery app start
#params:
# -A app name
# -l log level
# -c concurrency num
start_celery_app() {
#celery worker --workdir tasks -A $APP_NAME -l info
nohup celery worker --workdir tasks -A $APP_NAME -l info -c 2 >./app.log 2>.app.log &
#celery worker -A $APP_NAME -l info -c 5
}
test_app(){
python tasks/client.py
}
stop_celery_app(){
killall celery
}
case $1 in
flower)
start_celery_flower
;;
app)
start_celery_app
;;
test)
test_app
;;
stop)
stop_celery_app
;;
help)
echo "./celery_ctl.sh flower | app | test| stop "
;;
*)
echo "./celery_ctl.sh flower | app | test | stop "
exit 2
esac
知识扩展:
NC (netcat)
实现远程拷贝和网络监听服务
Ubuntu自带nc工具
NC应用的场景:
(1)TCP端口扫描
# nc -v -z -w2 127.0.0.1 1-100
Connection to 127.0.0.1 22 port [tcp/ssh] succeeded!
Connection to 127.0.0.1 53 port [tcp/domain] succeeded!
Connection to 127.0.0.1 80 port [tcp/http] succeeded!
...
nc: connect to 127.0.0.1 port 100 (tcp) failed: Connection refused
(2)拷贝文件
从192.168.1.2拷贝文件到192.168.1.3
首先在接收端192.168.1.3上: nc -l 1234 > test.txt //开启接收的文件端口
然后在发送端192.168.1.2上: nc 192.168.1.3 1234 < test.txt //往指定端口上发送文件
(3)简单聊天工具
在192.168.1.2上: nc -l 1234
在192.168.1.3上: nc 192.168.1.2 1234