awk配合xargs的一个用法

工作中有时候需要杀类似下面的很多子进程,想单个的杀实在是很困难(尤其是子进程很多时),

有什么好的办法呢?

[root@tesr root]# ps -ef|grep java|grep cn.

root      3994  3993  0 21:14 ?        00:00:00 /usr/j2sdk1.4.0_01/bin/java cn.c

root      3995  3994  0 21:14 ?        00:00:00 /usr/j2sdk1.4.0_01/bin/java cn.c

root      3996  3995  0 21:14 ?        00:00:04 /usr/j2sdk1.4.0_01/bin/java cn.c

root      3997  3995  0 21:14 ?        00:00:00 /usr/j2sdk1.4.0_01/bin/java cn.c

root      3998  3995  0 21:14 ?        00:00:00 /usr/j2sdk1.4.0_01/bin/java cn.c

root      3999  3995  0 21:14 ?        00:00:00 /usr/j2sdk1.4.0_01/bin/java cn.c

root      4000  3995  0 21:14 ?        00:00:00 /usr/j2sdk1.4.0_01/bin/java cn.c

root      4001  3995  0 21:14 ?        00:00:00 /usr/j2sdk1.4.0_01/bin/java cn.c

root      4002  3995  0 21:14 ?        00:00:00 /usr/j2sdk1.4.0_01/bin/java cn.c

root      4004  3995  1 21:14 ?        00:01:56 /usr/j2sdk1.4.0_01/bin/java cn.c

root      4005  3995  0 21:15 ?        00:00:00 /usr/j2sdk1.4.0_01/bin/java cn.c

其实就是要把这些行的第二列变成横向的,再全部写到kill -9 的后面就行了. 我们知道,

Awk就是用来取列的,但是awk取到的结果是分为多列的,

#ps -ef|grep java|grep cn.|awk {‘print $2’}

3994

3995

3996

3997

3998

3999

4000

4001

4002

4004

4005

如何让这些列变成行呢,xargs就可以!

# ps -ef|grep java|grep cn.|awk {‘print $2’}|xargs

3994 3995 3996 3997 3998 3999 4000 4001 4002 4004 4005

说白了,xarge就是把很多行变为一行!

如想删除数量比较多的文件
ls | xargs -n 20 rm -fr
ls当然是输出所有的文件名(用空格分割)
xargs就是将ls的输出,每20个为一组(以空格为分隔符),作为rm -rf的参数
也就是说将所有文件名20个为一组,由rm -rf删除,这样就不会超过命令行的长度了

再杀的话就很简单了!

Kill -9 3994 3995 3996 3997 3998 3999 4000 4001 4002 4004 4005就行了.

写下这点东西才真正的学会awk和xarge ,大家不妨也试试??

更多关于find,xargs请参考http://www.linuxsir.org/main/?q=node/137#3

Linux如何禁用root账户(There were XXXX failed login attempts since the last successful login.)

警告信息
自从有了一台有公网IP的Linux机器,每次登录就会有这样是信息:

There were 4899 failed login attempts since the last successful login.
Last login: Thu Aug 21 15:45:34 2014 from 87.201.230.138
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory

搜搜网络会发现,有好多这样的问题:

其他网友的说法:
你服务器 IP 在那儿,那 SSH 开在 TCP 22 上谁都能连,连上了谁都能输密码,密码错了就在系统里留下一条记录。
要么是被(无差别地)扫到了,要么是有人在盯着你。只说 SSH 登陆这事,如果你关闭密码登陆(或者密码足够健壮),那有个就算有一百万个猴子在试你的密码,你也完全不用担心的。

作为一个不合格的猿人,看到这个信息,就不舒服

关了Root用户
禁用root用户后使用sftp时可能一些目录无法访问

使用root账户登录系统,添加一个普通账户例如test,并为其设置密码
useradd test
passwd test

编辑配置文件/etc/ssh/sshd_config 修改PermitRootLogin 后面的yes 为 no ,并且去掉前面的注释符,同时可以限制失败次数
注意: 这个失败次数是对所有用户都起作用的。

最后重启sshd服务 systemctl restart sshd.service,此时再用root用户登录,如果不能登陆则代表配置成功。如果需要使用root权限,可以使用su/sudo进行切换

Spring Boot2.0 – 基于spring-boot-devtools实现热插拔

一.你需要准备
Spring Boot 2.1.5.RELEASE
java 1.8+
Maven 3.3+
IDEA
二.开发人员工具介绍
Spring Boot包含一组额外的工具,可以使应用程序开发体验更加愉快。该spring-boot-devtools模块可以包含在任何项目中,以提供额外的开发时间功能。要包含devtools支持,请将模块依赖项添加到您的构建中,如如以下Maven和Gradle列表所示:

Maven.

<dependencies>
<dependency>
<groupId> org.springframework.boot </ groupId>
<artifactId> spring-boot-devtools </ artifactId>
<optional> true </ optional>
</ dependency>
</ dependencies>

Gradle.

configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
dependencies {
developmentOnly(“org.springframework.boot:spring-boot-devtools”)
}

三.配置热插拔
下面我们Maven为例,来实现自动部署新代码的功能:

3.1开启idea自动make功能
使用快捷键CTRL + SHIFT + A –> 查找 –> 选中

接下来,我们需要重启IDEA;

3.2 填加maven依赖
<!–热插拔–>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!–表示依赖不会传递–>
<optional>true</optional>
</dependency>

3.3 开启热部署
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!– 如果没有该配置,devtools不会生效 –>
</configuration>
</plugin>
</plugins>
</build>

3.4关闭热部署
配置完热部署后,默认自动开启,如果需要关闭热部署,可以参考如下方式进行关闭:

3.4.1方式一
@SpringBootApplication
public class MilogeniusWebApplication {

public static void main(String[] args) {
//关闭热部署
System.setProperty(“spring.devtools.restart.enabled”,”false”);
SpringApplication.run(MilogeniusWebApplication.class, args);
}

}

3.4.2 方式二
在application.yml配置文件中增加如下配置:

spring:
# 服务模块
devtools:
restart:
# 热部署开关
enabled: false

四.测试
首先我们启动项目,在尝试修改某个类之后,发现项目自动重启;将热部署开关关闭之后,发现修改某个类,项目不会自动重启;

五.总结
在Spring Boot 2.1.5.RELEASE版本测试下,我发现不配置true也能实现自动部署新代码,大家可以尝试一下,不知道是不是最新版本已经优化了;

spring-boot-devtools 实现热部署

1.devtools

spring为开发者提供了一个名为spring-boot-devtools的模块来使Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Spring Boot应用。

2.项目搭建

本文是采用IDEA搭建的Spring Boot应用,通过spring-boot-devtools配置,可以支持修改java文件会自动重启程序,一些资源无需触发重启,例如thymeleaf模板文件就可以实时编辑。默认情况下,更改/META-INF/maven,/META-INF/resources ,/resources ,/static ,/public 或/templates下的资源不会触发重启,而是触发livereload。devtools模块包含一个嵌入的livereload服务器,可以在资源变化时用来触发浏览器刷新。浏览器需要在livereload.com下载安装扩展。 例如Chrome浏览器在应用商店安装livereload插件后,在要自动刷新的页面点击对应的图标,启动应用后更新页面内容或者css等都会触发页面自动刷新。

3.livereload

livereload 通过引入的脚本livereload.js在 livereload 服务和浏览器之间建立了一个 WebSocket 连接。每当监测到文件的变动,livereload 服务就会向浏览器发送一个信号,浏览器收到信号后就刷新页面,实现了实时刷新的效果。每次启动时,需要点击对应的图标,如下图所示。

4.项目代码配置

(1)pom.xml配置文件

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-devtools</artifactId>
   <optional>true</optional>
</dependency>
<plugin>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-maven-plugin</artifactId>
   <configuration>
      <fork>true</fork<!-- 如果没有该配置,devtools不会生效 -->
   </configuration>
</plugin>

(2)yml配置

1
2
3
4
5
6
devtools:
  livereload:
    enabled: true #是否支持livereload
    port: 35729
  restart:
    enabled: true #是否支持热部署

5.IDEA配置

(1)File-Settings-Compiler-Build project automatically

(2)ctrl + shift + alt + /,选择Registry,勾上 Compiler autoMake allow when app running

6.安装livereload插件
下载livereload插件,将其安装到chrome扩展程序中,并选中允许访问文件网址。


7.测试
(1)修改类 应用会重启
(2)修改配置文件 应用会重启
(3)修改静态文件(html、css等),应用不会重启,但是会调用livereload,浏览器会自动刷新,显示最新的修改内容。

Python 并行分布式框架 Celery

生产者消费者模式

在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。

单单抽象出生产者和消费者,还够不上是生产者消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据,如下图所示:

这里写图片描述

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过消息队列(缓冲区)来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给消息队列,消费者不找生产者要数据,而是直接从消息队列里取,消息队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个消息队列就是用来给生产者和消费者解耦的。————->这里又有一个问题,什么叫做解耦?

解耦:假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会白白糟蹋大好时光。缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。

因为太抽象,看过网上的说明之后,通过我的理解,我举了个例子:吃包子。

假如你非常喜欢吃包子(吃起来根本停不下来),今天,你妈妈(生产者)在蒸包子,厨房有张桌子(缓冲区),你妈妈将蒸熟的包子盛在盘子(消息)里,然后放到桌子上,你正在看巴西奥运会,看到蒸熟的包子放在厨房桌子上的盘子里,你就把盘子取走,一边吃包子一边看奥运。在这个过程中,你和你妈妈使用同一个桌子放置盘子和取走盘子,这里桌子就是一个共享对象。生产者添加食物,消费者取走食物。桌子的好处是,你妈妈不用直接把盘子给你,只是负责把包子装在盘子里放到桌子上,如果桌子满了,就不再放了,等待。而且生产者还有其他事情要做,消费者吃包子比较慢,生产者不能一直等消费者吃完包子把盘子放回去再去生产,因为吃包子的人有很多,如果这期间你好朋友来了,和你一起吃包子,生产者不用关注是哪个消费者去桌子上拿盘子,而消费者只去关注桌子上有没有放盘子,如果有,就端过来吃盘子中的包子,没有的话就等待。对应关系如下图:

这里写图片描述

考察了一下,原来当初设计这个模式,主要就是用来处理并发问题的,而Celery就是一个用python写的并行分布式框架。

然后我接着去学习Celery

Celery 是一个强大的 分布式任务队列 的 异步处理框架,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。我们通常使用它来实现异步任务(async task)和定时任务(crontab)。我们需要一个消息队列来下发我们的任务。首先要有一个消息中间件,此处选择rabbitmq (也可选择 redis 或 Amazon Simple Queue Service(SQS)消息队列服务)。推荐 选择 rabbitmq 。使用RabbitMQ是官方特别推荐的方式,因此我也使用它作为我们的broker。它的架构组成如下图:

在这里插入图片描述

通过celery worker 启动的是启动消费者
通过celery beat 是启动任务生产者
python中使用delay生产任务

Celery的定义

Celery(芹菜)是一个简单、灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一个系统的必需工具。

我比较喜欢的一点是:Celery支持使用任务队列的方式在分布的机器、进程、线程上执行任务调度。然后我接着去理解什么是任务队列。

任务队列

任务队列是一种在线程或机器间分发任务的机制。

消息队列

消息队列的输入是工作的一个单元,称为任务,独立的职程(Worker)进程持续监视队列中是否有需要处理的新任务。

Celery 用消息通信,通常使用中间人(Broker)在客户端和职程间斡旋。这个过程从客户端向队列添加消息开始,之后中间人把消息派送给职程,职程对消息进行处理。如下图所示:

这里写图片描述

Celery 系统可包含多个职程和中间人,以此获得高可用性和横向扩展能力。

Celery****的架构

Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成。

消息中间件

Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成,包括,RabbitMQ,Redis,MongoDB等,这里我先去了解RabbitMQ,Redis

linux安装redis参考:https://blog.csdn.net/luanpeng825485697/article/details/81205424

docker 安装redis参考:https://blog.csdn.net/luanpeng825485697/article/details/81209596

docker安装rabbitmq参考:https://blog.csdn.net/luanpeng825485697/article/details/82078416

任务执行单元

Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中

任务结果存储

Task result store用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括Redis,MongoDB,Django ORM,AMQP等,这里我先不去看它是如何存储的,就先选用Redis来存储任务执行结果。

然后我接着去安装Celery,在安装Celery之前,我已经在自己虚拟机上安装好了Python,版本是3.6,

安装celery,版本为4.2.1

sudo apt install python-celery-common

因为涉及到消息中间件,所以我先去选择一个在我工作中要用到的消息中间件(在Celery帮助文档中称呼为中间人<broker>),为了更好的去理解文档中的例子,我安装了两个中间件,一个是RabbitMQ,一个redis。

在这里我就先根据Celery的帮助文档安装和设置RabbitMQ。要使用 Celery,我们需要创建一个 RabbitMQ 用户、一个虚拟主机,并且允许这个用户访问这个虚拟主机。下面是我在个人pc机Ubuntu16.04上的设置:

$ sudo rabbitmqctl add_user forward password

#创建了一个RabbitMQ用户,用户名为forward,密码是password

$ sudo rabbitmqctl add_vhost ubuntu

#创建了一个虚拟主机,主机名为ubuntu

$ sudo rabbitmqctl set_permissions -p ubuntu forward ".*" ".*" ".*"

#允许用户forward访问虚拟主机ubuntu,因为RabbitMQ通过主机名来与节点通信

$ sudo rabbitmq-server

之后我启用RabbitMQ服务器,结果如下,成功运行:

这里写图片描述

之后我安装Redis,它的安装比较简单,如下:

$ sudo pip install redis

然后进行简单的配置,只需要设置 Redis 数据库的位置:

BROKER_URL = 'redis://localhost:6379/0'

URL的格式为:

redis://:password**@hostname**:port/db_number

URL Scheme 后的所有字段都是可选的,并且默认为 localhost 的 6379 端口,使用数据库 0。我的配置是:

redis://:password**@ubuntu**:6379/5

之后安装Celery,我是用标准的Python工具pip安装的,如下:

$ sudo pip install celery

celery 的命令

Global Options:
  -A APP, --app APP
  -b BROKER, --broker BROKER
  --result-backend RESULT_BACKEND
  --loader LOADER
  --config CONFIG
  --workdir WORKDIR
  --no-color, -C
  --quiet, -q

---- -- - - ---- Commands- -------------- --- ------------

+ Main: 
|    celery worker     
|    celery events
|    celery beat
|    celery shell
|    celery multi
|    celery amqp

开始使用 Celery

使用celery包含三个方面:1. 定义任务函数。2. 运行celery服务。3. 客户应用程序的调用。

注意:发送者和消费者职能处理启动前就定义好的任务,不能代码中现场定义。也就是说必须在定义任务后才能启动消费者。

定义

为了测试Celery能否工作,我运行了一个最简单的任务,编写app1.py:

from celery import Celery
# broker设置中间件,backend设置后端存储
app = Celery('app_name',broker='redis://127.0.0.1:6379/5',backend='redis://127.0.0.1:6379/6')

@app.task(name='task_name')       # 被标记的都属于这个app的任务
def add(x,y):
    return x+y

编辑保存退出后,我在当前目录下运行如下命令(记得要先开启redis):

启动一个worker

$ celery  worker -A app1 --loglevel=info

其中celery会根据--app后面的参数作为命令启动目录的相对目录,去找个这个相对目录文件中的app变量,并把所有用@app.task修饰的函数作为任务来记录元数据。所以不同目录的启动命令是不一样的。

#查询文档,了解到该命令中-A参数表示的是Celery APP的名称,这个实例中指的就是app1.py(和文件名一致),后面的app1就是APP的名称,worker是一个执行任务角色,后面的loglevel=info记录日志类型默认是info,这个命令启动了一个worker,用来执行程序中add这个加法任务(task)。

然后看到界面显示结果如下:

 -------------- celery@luanpeng-XPS15R v4.2.1 (windowlicker)
---- **** ----- 
--- * ***  * -- Linux-4.15.0-33-generic-x86_64-with-Ubuntu-16.04-xenial 2018-09-24 19:19:11
-- * - **** --- 
- ** ---------- [config]
- ** ---------- .> app:         tasks:0x7f34ba22dcc0
- ** ---------- .> transport:   redis://127.0.0.1:6379/5
- ** ---------- .> results:     disabled://
- *** --- * --- .> concurrency: 8 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery
                

[tasks]
  . tasks.add

[2018-09-24 19:19:11,186: INFO/MainProcess] Connected to redis://127.0.0.1:6379/5
[2018-09-24 19:19:11,193: INFO/MainProcess] mingle: searching for neighbors
[2018-09-24 19:19:12,212: INFO/MainProcess] mingle: all alone
[2018-09-24 19:19:12,224: INFO/MainProcess] celery@luanpeng-XPS15R ready.

我们可以看到Celery正常工作在名称luanpeng-XPS15R的虚拟主机上,版本为v4.2.1,在下面的[config]中我们可以看到当前APP的名称tasks,运输工具transport就是我们在程序中设置的中间人redis://127.0.0.1:6379/5,result我们没有设置,暂时显示为disabled,然后我们也可以看到worker缺省使用perfork来执行并发,当前并发数显示为1,然后可以看到下面的[queues]就是我们说的队列,当前默认的队列是celery,然后我们看到下面的[tasks]中有一个任务task_name.

生产者

生产者发送消息启动。按照生产者所在目录引入app中的task函数(也会把task的名称获取到)。调用delay函数(apply_async()方法的升级版)时会发起这样一个name的task就可以了。

例如在上层目录发起任务

from app1.app1 import add
result = add.delay(1,2)   # apply_async()方法的升级版
print(result)

 

  • 1
  • 2
  • 3

启动后,消费者开始处理消息

[2018-09-24 20:07:11,496: INFO/MainProcess] Received task: app1.tasks.add[8207c280-0864-4b1e-8792-155de5417406]  
[2018-09-24 20:07:11,501: INFO/ForkPoolWorker-4] Task app1.tasks.add[8207c280-0864-4b1e-8792-155de5417406] succeeded in 0.003930353002942866s: 12

 

  • 1
  • 2

第一行说明worker收到了一个任务:app1.tasks.add,这里我们和之前发送任务返回的AsyncResult对比我们发现,每个task都有一个唯一的ID,第二行说明了这个任务执行succeed,执行结果为12。

查看资料说调用任务后会返回一个AsyncResult实例,可用于检查任务的状态,等待任务完成或获取返回值(如果任务失败,则为异常和回溯)。但这个功能默认是不开启的,需要设置一个 Celery 的结果后端(backend),也就是tasks.py设置的使用redis进行结果存储。

通过这个例子后我对Celery有了初步的了解,然后我在这个例子的基础上去进一步的学习。

因为Celery是用Python编写的,所以为了让代码结构化一些,就像一个应用

在这里插入图片描述

app1/app1_app.py


from celery import Celery
import os,io
# 在app1目录同级目录执行celery -A app1.app1_app worker -l info
app = Celery(main='app1.app1_app',include=['app1.tasks1','app1.tasks2'])  # 创建app,并引入任务定义。main、include参数的值为模块名,所以都是指定命令的相对目录

app.config_from_object('app1.app1_config')   # 通过配置文件进行配置,而着这里是相对目录

# broker设置中间件,backend设置后端存储
# app = Celery('app1.app1_app',broker='redis://127.0.0.1:6379/5',backend='redis://127.0.0.1:6379/6',include=['app1.tasks1','app1.task2'])

if __name__ == "__main__":
    log_path = os.getcwd()+'/log/celery.log'
    if(not os.path.exists(log_path)):
        f = open(log_path, 'w')
        f.close()
    # 在app1目录同级目录执行celery -A app1.app1_app worker -l info
    app = Celery(main='app1_app',include=['tasks1', 'tasks2'])  # 创建app,并引入任务定义。main、include参数的值为模块名,所以都是指定命令的相对目录

    app.config_from_object('app1_config')  # 通过配置文件c进行配置,而着这里是相对目录
    # 使用下面的命令也可以启动celery,不过要该模块的名称,是的相对目录正确
    app.start(argv=['celery', 'worker', '-l', 'info', '-f', 'log/celery.log', "-c", "40"])

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

一定要注意模块的相对目录,和你想要执行命令的目录

#首先创建了一个celery实例app,实例化的过程中,制定了任务名(也就是包名.模块名),Celery的第一个参数是当前模块的名称,我们可以调用config_from_object()来让Celery实例加载配置模块,我的例子中的配置文件起名为app1_config.py,配置文件如下:

BROKER_URL = 'redis://127.0.0.1:6379/5'   # 配置broker  中间件
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/6'   # 配置backend结果存储
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

 

  • 1
  • 2
  • 3
  • 4
  • 5

在配置文件中我们可以对任务的执行等进行管理,比如说我们可能有很多的任务,但是我希望有些优先级比较高的任务先被执行,而不希望先进先出的等待。那么需要引入一个队列的问题. 也就是说在我的broker的消息存储里面有一些队列,他们并行运行,但是worker只从对应 的队列里面取任务。在这里我们希望tasks.py中的某些任务先被执行。task中我设置了两个任务:

所以我通过from celery import group引入group,用来创建并行执行的一组任务。然后这块现需要理解的就是这个@app.task,@符号在python中用作函数修饰符,到这块我又回头去看python的装饰器(在代码运行期间动态增加功能的方式)到底是如何实现的,在这里的作用就是通过task()装饰器在可调用的对象(app)上创建一个任务。

tasks1.py

from app1.app1_app import app

@app.task
def deal1(text):
    print(text)
    return text+"======="

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

tasks2.py


from app1.app1_app import app

@app.task
def deal2(text):
    print(text)
    return text+"+++++++++"

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

队列

了解完装饰器后,我回过头去整理配置的问题,前面提到任务的优先级问题,在这个例子中如果我们想让deal1这个任务优先于deal2任务被执行,我们可以将两个任务放到不同的队列中,由我们决定先执行哪个任务,我们可以在配置文件app1_config.py中增加这样配置:

URL的格式为:

redis://:password@hostname:port/db_number

 

  • 1
from kombu import Exchange,Queue

BROKER_URL = 'redis://127.0.0.1:6379/5'   # 配置broker  中间件
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/6'   # 配置backend结果存储
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

# (当使用Redis作为broker时,Exchange的名字必须和Queue的名字一样)
CELERY_QUEUES = (
                    Queue("default", Exchange("default"), routing_key = "default"),
                    Queue("for_task1", Exchange("for_task1"), routing_key="task_a"),
                    Queue("for_task2", Exchange("for_task2"), routing_key="task_b")
)

# 定义任务的走向,不同的任务发送  进入不同的队列,并为不同的任务设定不同的routing_key
# 若没有指定这个任务route到那个Queue中去执行,此时执行此任务的时候,会route到Celery默认的名字叫做celery的队列中去。
CELERY_ROUTES = {
    'app1.tasks1.deal1': {"queue": "for_task1", "routing_key": "task_a"},
    'app1.tasks2.deal2':{"queue":"for_task2","routing_key":"task_b"}
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

先了解了几个常用的参数的含义:

Exchange:交换机,决定了消息路由规则;

Queue:消息队列;

Channel:进行消息读写的通道;

Bind:绑定了Queue和Exchange,意即为符合什么样路由规则的消息,将会放置入哪一个消息队列

我将deal1这个函数任务放在了一个叫做for_task1的队列里面,将deal2这个函数任务放在了一个叫做for_task2的队列里面,然后我在当前应用目录下执行命令:

celery -A app1.app1_app worker -l info -Q for_task1

 

  • 1

这个worker就只负责处理for_task1这个队列的任务,这是通过在启动worker是使用-Q Queue_Name参数指定的。

我们定义任务调用文件start_task.py



from __future__ import print_function
from app1.app1_app import app


if __name__=="__main__":
    for i in range(10):
        text = 'text'+str(i)
        app.send_task('app1.tasks1.deal1',args=[text])   # 任务的名称必须和Celery注册的任务名称相同
        app.send_task('app1.tasks2.deal2',args=[text])  # 任务的名称必须和Celery注册的任务名称相同
        print('push over %d'%i)

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

执行上述代码文件

python start_task.py

 

  • 1

任务已经被执行,我在worker控制台查看结果(只有app1.appa_app.deal1任务被这个worker执行了):

[2018-09-24 22:26:38,928: INFO/ForkPoolWorker-8] Task app1.tasks1.deal1[b3007993-9bfb-4161-b5b2-4f0f022f2f8b] succeeded in 0.0008255800021288451s: 'text4======='
[2018-09-24 22:26:38,928: INFO/ForkPoolWorker-6] Task app1.tasks1.deal1[df24b991-88fc-4253-86bf-540754c62da9] succeeded in 0.004320767002354842s: 'text3======='
[2018-09-24 22:26:38,929: INFO/MainProcess] Received task: app1.tasks1.deal1[dbdf9ac0-ea27-4455-90d2-e4fe8f3e895e]  
[2018-09-24 22:26:38,930: WARNING/ForkPoolWorker-4] text5
[2018-09-24 22:26:38,931: INFO/ForkPoolWorker-4] Task app1.tasks1.deal1[dbdf9ac0-ea27-4455-90d2-e4fe8f3e895e] succeeded in 0.0006721289973938838s: 'text5======='

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看到worker收到任务,并且执行了任务。

Scheduler ( 定时任务,周期性任务 )

在这里我们还是在交互模式下手动去执行,我们想要crontab的定时生成和执行,我们可以用celery的beat去周期的生成任务和执行任务,在这个例子中我希望每10秒钟产生一个任务,然后去执行这个任务,我可以这样配置(在app1_config.py文件中添加如下内容):

# 设计周期任务
CELERY_TIMEZONE = 'Asia/Shanghai'

from celery.schedules import crontab   # 设置定时任务
from datetime import timedelta
# 每隔30秒执行app1.tasks1.deal函数
CELERYBEAT_SCHEDULE = {
    'deal-every-30-seconds': {
         'task': 'app1.tasks1.deal1',
         'schedule': timedelta(seconds=30),
         'args': ['hello']
    },
    'deal-every-10-seconds': {
         'task': 'app1.tasks2.deal2',
         'schedule': timedelta(seconds=10),
         'args': ['hello']
    },
     # Executes every Monday morning at 7:30 A.M
    'deal-every-monday-morning': {
         'task': 'app1.tasks2.deal2',
         'schedule': crontab(hour=7, minute=30, day_of_week=1),
         'args': ['hello']
    },
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

使用了scheduler,要制定时区:CELERY_TIMEZONE = ‘Asia/Shanghai’,启动celery加上-B的参数。

celery -A app1.app1_app worker -l info -B

 

  • 1

前两个任务为周期任务,第三个任务为定时任务,指定时间点开始执行分发任务,让worker取走执行,可以这样配置:

看完这些基础的东西,我回过头对celery在回顾了一下,用图把它的框架大致画出来,如下图:

这里写图片描述

celery任务调度的配置项

https://docs.celeryproject.org/en/latest/userguide/configuration.html

celery 任务监控

celery flower

在这里插入图片描述

phpstrom 2020年最新注册码(到2023年)

QYYBAC9D3J-eyJsaWNlbnNlSWQiOiJRWVlCQUM5RDNKIiwibGljZW5zZWVOYW1lIjoi6LaF57qnIOeoi+W6j+WRmCIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN1cnJlbnRVc2UiOmZhbHNlLCJwcm9kdWN0cyI6W3siY29kZSI6IklJIiwiZmFsbGJhY2tEYXRlIjoiMjAyMC0wMS0wNCIsInBhaWRVcFRvIjoiMjAyMS0wMS0wMyJ9LHsiY29kZSI6IkFDIiwiZmFsbGJhY2tEYXRlIjoiMjAyMC0wMS0wNCIsInBhaWRVcFRvIjoiMjAyMS0wMS0wMyJ9LHsiY29kZSI6IkRQTiIsImZhbGxiYWNrRGF0ZSI6IjIwMjAtMDEtMDQiLCJwYWlkVXBUbyI6IjIwMjEtMDEtMDMifSx7ImNvZGUiOiJQUyIsImZhbGxiYWNrRGF0ZSI6IjIwMjAtMDEtMDQiLCJwYWlkVXBUbyI6IjIwMjEtMDEtMDMifSx7ImNvZGUiOiJHTyIsImZhbGxiYWNrRGF0ZSI6IjIwMjAtMDEtMDQiLCJwYWlkVXBUbyI6IjIwMjEtMDEtMDMifSx7ImNvZGUiOiJETSIsImZhbGxiYWNrRGF0ZSI6IjIwMjAtMDEtMDQiLCJwYWlkVXBUbyI6IjIwMjEtMDEtMDMifSx7ImNvZGUiOiJDTCIsImZhbGxiYWNrRGF0ZSI6IjIwMjAtMDEtMDQiLCJwYWlkVXBUbyI6IjIwMjEtMDEtMDMifSx7ImNvZGUiOiJSUzAiLCJmYWxsYmFja0RhdGUiOiIyMDIwLTAxLTA0IiwicGFpZFVwVG8iOiIyMDIxLTAxLTAzIn0seyJjb2RlIjoiUkMiLCJmYWxsYmFja0RhdGUiOiIyMDIwLTAxLTA0IiwicGFpZFVwVG8iOiIyMDIxLTAxLTAzIn0seyJjb2RlIjoiUkQiLCJmYWxsYmFja0RhdGUiOiIyMDIwLTAxLTA0IiwicGFpZFVwVG8iOiIyMDIxLTAxLTAzIn0seyJjb2RlIjoiUEMiLCJmYWxsYmFja0RhdGUiOiIyMDIwLTAxLTA0IiwicGFpZFVwVG8iOiIyMDIxLTAxLTAzIn0seyJjb2RlIjoiUk0iLCJmYWxsYmFja0RhdGUiOiIyMDIwLTAxLTA0IiwicGFpZFVwVG8iOiIyMDIxLTAxLTAzIn0seyJjb2RlIjoiV1MiLCJmYWxsYmFja0RhdGUiOiIyMDIwLTAxLTA0IiwicGFpZFVwVG8iOiIyMDIxLTAxLTAzIn0seyJjb2RlIjoiREIiLCJmYWxsYmFja0RhdGUiOiIyMDIwLTAxLTA0IiwicGFpZFVwVG8iOiIyMDIxLTAxLTAzIn0seyJjb2RlIjoiREMiLCJmYWxsYmFja0RhdGUiOiIyMDIwLTAxLTA0IiwicGFpZFVwVG8iOiIyMDIxLTAxLTAzIn0seyJjb2RlIjoiUlNVIiwiZmFsbGJhY2tEYXRlIjoiMjAyMC0wMS0wNCIsInBhaWRVcFRvIjoiMjAyMS0wMS0wMyJ9XSwiaGFzaCI6IjE2MDgwOTA5LzAiLCJncmFjZVBlcmlvZERheXMiOjcsImF1dG9Qcm9sb25nYXRlZCI6ZmFsc2UsImlzQXV0b1Byb2xvbmdhdGVkIjpmYWxzZX0=-I7c5mu4hUCMxcldrwZEJMaT+qkrzrF1bjJi0i5QHcrRxk2LO0jqzUe2fBOUR4L+x+7n6kCwAoBBODm9wXst8dWLXdq179EtjU3rfJENr1wXGgtef//FNow+Id5iRufJ4W+p+3s5959GSFibl35YtbELELuCUH2IbCRly0PUBjitgA0r2y+9jV5YD/dmrd/p4C87MccC74NxtQfRdeUEGx87vnhsqTFH/sP4C2VljSo/F/Ft9JqsSlGfwSKjzU8BreYt1QleosdMnMK7a+fkfxh7n5zg4DskdVlNbfe6jvYgMVE16DMXd6F1Zhwq+lrmewJA2jPToc+H5304rcJfa9w==-MIIElTCCAn2gAwIBAgIBCTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTE4MTEwMTEyMjk0NloXDTIwMTEwMjEyMjk0NlowaDELMAkGA1UEBhMCQ1oxDjAMBgNVBAgMBU51c2xlMQ8wDQYDVQQHDAZQcmFndWUxGTAXBgNVBAoMEEpldEJyYWlucyBzLnIuby4xHTAbBgNVBAMMFHByb2QzeS1mcm9tLTIwMTgxMTAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcQkq+zdxlR2mmRYBPzGbUNdMN6OaXiXzxIWtMEkrJMO/5oUfQJbLLuMSMK0QHFmaI37WShyxZcfRCidwXjot4zmNBKnlyHodDij/78TmVqFl8nOeD5+07B8VEaIu7c3E1N+e1doC6wht4I4+IEmtsPAdoaj5WCQVQbrI8KeT8M9VcBIWX7fD0fhexfg3ZRt0xqwMcXGNp3DdJHiO0rCdU+Itv7EmtnSVq9jBG1usMSFvMowR25mju2JcPFp1+I4ZI+FqgR8gyG8oiNDyNEoAbsR3lOpI7grUYSvkB/xVy/VoklPCK2h0f0GJxFjnye8NT1PAywoyl7RmiAVRE/EKwIDAQABo4GZMIGWMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGEpG9oZGcfLMGNBkY7SgHiMGgTcMEgGA1UdIwRBMD+AFKOetkhnQhI2Qb1t4Lm0oFKLl/GzoRykGjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBggkA0myxg7KDeeEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQAF8uc+YJOHHwOFcPzmbjcxNDuGoOUIP+2h1R75Lecswb7ru2LWWSUMtXVKQzChLNPn/72W0k+oI056tgiwuG7M49LXp4zQVlQnFmWU1wwGvVhq5R63Rpjx1zjGUhcXgayu7+9zMUW596Lbomsg8qVve6euqsrFicYkIIuUu4zYPndJwfe0YkS5nY72SHnNdbPhEnN8wcB2Kz+OIG0lih3yz5EqFhld03bGp222ZQCIghCTVL6QBNadGsiN/lWLl4JdR3lJkZzlpFdiHijoVRdWeSWqM4y0t23c92HXKrgppoSV18XMxrWVdoSM3nuMHwxGhFyde05OdDtLpCv+jlWf5REAHHA201pAU6bJSZINyHDUTB+Beo28rRXSwSh3OUIvYwKNVeoBY+KwOJ7WnuTCUq1meE6GkKc4D/cXmgpOyW/1SmBz3XjVIi/zprZ0zf3qH5mkphtg6ksjKgKjmx1cXfZAAX6wcDBNaCL+Ortep1Dh8xDUbqbBVNBL4jbiL3i3xsfNiyJgaZ5sX7i8tmStEpLbPwvHcByuf59qJhV/bZOl8KqJBETCDJcY6O2aqhTUy+9x93ThKs1GKrRPePrWPluud7ttlgtRveit/pcBrnQcXOl1rHq7ByB8CFAxNotRUYL9IF5n3wJOgkPojMy6jetQA5Ogc8Sm7RG6vg1yow==

第二个

OQT3OJ25XE-eyJsaWNlbnNlSWQiOiJPUVQzT0oyNVhFIiwibGljZW5zZWVOYW1lIjoi5rC45LmF5r+A5rS7IGlkZWEubWVkZW1pbmcuY29tIiwiYXNzaWduZWVOYW1lIjoiIiwiYXNzaWduZWVFbWFpbCI6IiIsImxpY2Vuc2VSZXN0cmljdGlvbiI6IiIsImNoZWNrQ29uY3VycmVudFVzZSI6ZmFsc2UsInByb2R1Y3RzIjpbeyJjb2RlIjoiSUkiLCJwYWlkVXBUbyI6IjIwMjAtMDMtMjQifSx7ImNvZGUiOiJBQyIsInBhaWRVcFRvIjoiMjAyMC0wMy0yNCJ9LHsiY29kZSI6IkRQTiIsInBhaWRVcFRvIjoiMjAyMC0wMy0yNCJ9LHsiY29kZSI6IlBTIiwicGFpZFVwVG8iOiIyMDIwLTAzLTI0In0seyJjb2RlIjoiR08iLCJwYWlkVXBUbyI6IjIwMjAtMDMtMjQifSx7ImNvZGUiOiJETSIsInBhaWRVcFRvIjoiMjAyMC0wMy0yNCJ9LHsiY29kZSI6IkNMIiwicGFpZFVwVG8iOiIyMDIwLTAzLTI0In0seyJjb2RlIjoiUlMwIiwicGFpZFVwVG8iOiIyMDIwLTAzLTI0In0seyJjb2RlIjoiUkMiLCJwYWlkVXBUbyI6IjIwMjAtMDMtMjQifSx7ImNvZGUiOiJSRCIsInBhaWRVcFRvIjoiMjAyMC0wMy0yNCJ9LHsiY29kZSI6IlBDIiwicGFpZFVwVG8iOiIyMDIwLTAzLTI0In0seyJjb2RlIjoiUk0iLCJwYWlkVXBUbyI6IjIwMjAtMDMtMjQifSx7ImNvZGUiOiJXUyIsInBhaWRVcFRvIjoiMjAyMC0wMy0yNCJ9LHsiY29kZSI6IkRCIiwicGFpZFVwVG8iOiIyMDIwLTAzLTI0In0seyJjb2RlIjoiREMiLCJwYWlkVXBUbyI6IjIwMjAtMDMtMjQifSx7ImNvZGUiOiJSU1UiLCJwYWlkVXBUbyI6IjIwMjAtMDMtMjQifV0sImhhc2giOiIxNjg3Njk5NS8wIiwiZ3JhY2VQZXJpb2REYXlzIjo3LCJhdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlLCJpc0F1dG9Qcm9sb25nYXRlZCI6ZmFsc2V9-LXnx/g4ye21mKR0OvGl2ADAi2x3teIZejiqp3MUSWCOnHwCJnH3kwKzBccPJNKNIKP5ZqnKZ7V77rj2NNw++G4QiNyL2XVILj4HR1lUT8j7Nm6I797koHMh7I/zJG6vv3nQJhMyxo1rnO1st8MEnmPmLiAkCoteSni3S3hZphuICFkCJFPkDKX5Tv7J/MgTQTSeUZSbTFRi61WPGmeX8tQ7CKULKTvoGenvwRbL+v9JxtmThrDdyn8GcHyU8RzUeh+qeKpEaP4jjdlfLXTzBmjgs+7cnchy5hU9sEJC/CnhWTFYzQEVJAOYkjO1Q3+f+ljafwnsAL+8V3hCmUFablw==-MIIElTCCAn2gAwIBAgIBCTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTE4MTEwMTEyMjk0NloXDTIwMTEwMjEyMjk0NlowaDELMAkGA1UEBhMCQ1oxDjAMBgNVBAgMBU51c2xlMQ8wDQYDVQQHDAZQcmFndWUxGTAXBgNVBAoMEEpldEJyYWlucyBzLnIuby4xHTAbBgNVBAMMFHByb2QzeS1mcm9tLTIwMTgxMTAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcQkq+zdxlR2mmRYBPzGbUNdMN6OaXiXzxIWtMEkrJMO/5oUfQJbLLuMSMK0QHFmaI37WShyxZcfRCidwXjot4zmNBKnlyHodDij/78TmVqFl8nOeD5+07B8VEaIu7c3E1N+e1doC6wht4I4+IEmtsPAdoaj5WCQVQbrI8KeT8M9VcBIWX7fD0fhexfg3ZRt0xqwMcXGNp3DdJHiO0rCdU+Itv7EmtnSVq9jBG1usMSFvMowR25mju2JcPFp1+I4ZI+FqgR8gyG8oiNDyNEoAbsR3lOpI7grUYSvkB/xVy/VoklPCK2h0f0GJxFjnye8NT1PAywoyl7RmiAVRE/EKwIDAQABo4GZMIGWMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGEpG9oZGcfLMGNBkY7SgHiMGgTcMEgGA1UdIwRBMD+AFKOetkhnQhI2Qb1t4Lm0oFKLl/GzoRykGjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBggkA0myxg7KDeeEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQAF8uc+YJOHHwOFcPzmbjcxNDuGoOUIP+2h1R75Lecswb7ru2LWWSUMtXVKQzChLNPn/72W0k+oI056tgiwuG7M49LXp4zQVlQnFmWU1wwGvVhq5R63Rpjx1zjGUhcXgayu7+9zMUW596Lbomsg8qVve6euqsrFicYkIIuUu4zYPndJwfe0YkS5nY72SHnNdbPhEnN8wcB2Kz+OIG0lih3yz5EqFhld03bGp222ZQCIghCTVL6QBNadGsiN/lWLl4JdR3lJkZzlpFdiHijoVRdWeSWqM4y0t23c92HXKrgppoSV18XMxrWVdoSM3nuMHwxGhFyde05OdDtLpCv+jlWf5REAHHA201pAU6bJSZINyHDUTB+Beo28rRXSwSh3OUIvYwKNVeoBY+KwOJ7WnuTCUq1meE6GkKc4D/cXmgpOyW/1SmBz3XjVIi/zprZ0zf3qH5mkphtg6ksjKgKjmx1cXfZAAX6wcDBNaCL+Ortep1Dh8xDUbqbBVNBL4jbiL3i3xsfNiyJgaZ5sX7i8tmStEpLbPwvHcByuf59qJhV/bZOl8KqJBETCDJcY6O2aqhTUy+9x93ThKs1GKrRPePrWPluud7ttlgtRveit/pcBrnQcXOl1rHq7ByB8CFAxNotRUYL9IF5n3wJOgkPojMy6jetQA5Ogc8Sm7RG6vg1yow==

复制以上即可