利用rabbit_mq队列消息实现对一组主机进行命令下发
目的:
利用rabbit_mq队列消息实现对一组主机进行命令下发
server:
#!/usr/bin/env python3.5
# -*- coding:utf8 -*-
import os,sys
BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASEDIR)
import pika
from conf import setting
def rabbit(cmd):
try:
group,action = cmd.split(" ",1)
connection = pika.BlockingConnection(pika.ConnectionParameters(
host=setting.HOST["host"],port=setting.HOST["port"]))
channel = connection.channel() channel.exchange_declare(
exchange=group,
type="fanout"
)
channel.basic_publish(exchange=group,
routing_key='',
body=action,
)
print("对主机组[{}],下发命令[{}]执行".format(group,action))
connection.close()
except Exception as e:
print("输入错误:{}".format(e))
print("""
命令输入格式为:
[group] [command] : 组名 命令 log shutdown -t
""")
def run():
while True:
user_cmd = input("请输入要执行的命令:").strip()
if user_cmd:
rabbit(user_cmd)
else:
print("""
命令输入格式为:
[group] [command] : 组名 命令 log shutdown -t
""")
client:
#!/usr/bin/env python3.5
# -*- coding:utf8 -*-
import pika
import os,sys
BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASEDIR)
from conf import setting
def run():
connection = pika.BlockingConnection(pika.ConnectionParameters(
host=setting.HOST["host"],port=setting.HOST["port"]))
channel = connection.channel()
channel.exchange_declare(exchange="NB",type="fanout")
result = channel.queue_declare(exclusive=True) # 不指定queue名字,rabbit会随机分配一个名字,exclusive =True
# 会在使用此queue的消费者断开后,自动将queue删除
queue_name = result.method.queue
channel.queue_bind(exchange='NB',queue=queue_name)
print(' [*] Waiting for NB. To exit press CTRL+C')
def execute_cmd(ch, method, properties, body):
cmd = str(body.decode())
os.system(cmd)
channel.basic_consume(execute_cmd,queue=queue_name,no_ack=True)
channel.start_consuming()
RabbitMq 介绍:
交换机(exchange):
1. 接收消息,转发消息到绑定的队列。四种类型:direct, topic, headers and fanout
direct:转发消息到routigKey指定的队列
topic:按规则转发消息(最灵活)
headers:(这个还没有接触到)
fanout:转发消息到所有绑定队列
2. 如果没有队列绑定在交换机上,则发送到该交换机上的消息会丢失。
3. 一个交换机可以绑定多个队列,一个队列可以被多个交换机绑定。
4. topic类型交换器通过模式匹配分析消息的routing-key属性。它将routing-key和binding-key的字符串切分成单词。这些单词之间用点隔开。它同样也会识别两个通配符:#匹配0个或者多个单词,*匹配一个单词。例如,binding key:*.stock.#匹配routing key:usd.stcok和eur.stock.db,但是不匹配stock.nana。
还有一些其他的交换器类型,如header、failover、system等,现在在当前的RabbitMQ版本中均未实现。
5. 因为交换器是命名实体,声明一个已经存在的交换器,但是试图赋予不同类型是会导致错误。客户端需要删除这个已经存在的交换器,然后重新声明并且赋予新的类型。
6. 交换器的属性:
- 持久性:如果启用,交换器将会在server重启前都有效。
- 自动删除:如果启用,那么交换器将会在其绑定的队列都被删除掉之后自动删除掉自身。
- 惰性:如果没有声明交换器,那么在执行到使用的时候会导致异常,并不会主动声明。
队列(queue):
1. 队列是RabbitMQ内部对象,存储消息。相同属性的queue可以重复定义。
2. 临时队列。channel.queueDeclare(),有时不需要指定队列的名字,并希望断开连接时删除队列。
3. 队列的属性:
- 持久性:如果启用,队列将会在server重启前都有效。
- 自动删除:如果启用,那么队列将会在所有的消费者停止使用之后自动删除掉自身。
- 惰性:如果没有声明队列,那么在执行到使用的时候会导致异常,并不会主动声明。
- 排他性:如果启用,队列只能被声明它的消费者使用。
这些性质可以用来创建例如排他和自删除的transient或者私有队列。这种队列将会在所有链接到它的客户端断开连接之后被自动删除掉。它们只是短暂地连接到server,但是可以用于实现例如RPC或者在AMQ上的对等通信。4. RPC的使用是这样的:RPC客户端声明一个回复队列,唯一命名(例如用UUID),并且是自删除和排他的。然后它发送请求给一些交换器,在消息的reply-to字段中包含了之前声明的回复队列的名字。RPC服务器将会回答这些请求,使用消息的reply-to作为routing key(默认绑定器会绑定所有的队列到默认交换器,名称为“amp.交换器类型名”)发送到默认交换器。注意这仅仅是惯例而已,可以根据和RPC服务器的约定,它可以解释消息的任何属性(甚至数据体)来决定回复给谁。
消息传递:
消息在队列中保存,以轮询的方式将消息发送给监听消息队列的消费者,可以动态的增加消费者以提高消息的处理能力。
2. 为了实现负载均衡,可以在消费者端通知RabbitMQ,一个消息处理完之后才会接受下一个消息。
channel.basic_qos(prefetch_count=1)
注意:要防止如果所有的消费者都在处理中,则队列中的消息会累积的情况。
3. 消息有14个属性,最常用的几种:
deliveryMode:持久化属性
contentType:编码
replyTo:指定一个回调队列
correlationId:消息id
4. 消息生产者可以选择是否在消息被发送到交换器并且还未投递到队列(没有绑定器存在)和/或没有消费者能够立即处理的时候得到通知。通过设置消息的mandatory和/或immediate属性为真,这些投递保障机制的能力得到了强化。
5. 此外,一个生产者可以设置消息的persistent属性为真。这样一来,server将会尝试将这些消息存储在一个稳定的位置,直到server崩溃。当然,这些消息肯定不会被投递到非持久的队列中。
高可用性(HA):
消息ACK,通知RabbitMQ消息已被处理,可以从内存删除。如果消费者因宕机或链接失败等原因没有发送ACK(不同于ActiveMQ,在RabbitMQ里,消息没有过期的概念),则RabbitMQ会将消息重新发送给其他监听在队列的下一个消费者。
channel.basicConsume(queuename, noAck=false, consumer);
2. 消息和队列的持久化。定义队列时可以指定队列的持久化属性(问:持久化队列如何删除?)
channel.queueDeclare(queuename, durable=true, false, false, null);
发送消息时可以指定消息持久化属性:
channel.basicPublish(exchangeName, routingKey,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes());
这样,即使RabbitMQ服务器重启,也不会丢失队列和消息。
3. publisher confirms
4. master/slave机制,配合Mirrored Queue,这种情况下,publisher会正常发送消息和接收消息的confirm,但对于subscriber来说,需要接收Consumer Cancellation Notifications来得到主节点失败的通知,然后re-consume from the queue,此时要求client有处理重复消息的能力。注意:如果queue在一个新加入的节点上增加了一个slave,此时slave上没有此前queue的信息(目前还没有同步机制)。
(通过命令行或管理插件可以查看哪个slave是同步的:
rabbitmqctl list_queues name slave_pids synchronised_slave_pids)
当一个slave重新加入mirrored-queue时,如果queue是durable的,则会被清空。
集群(cluster):
1. 不支持跨网段(如需支持,需要shovel或federation插件)
2. 可以随意的动态增加或减少、启动或停止节点,允许节点故障
3. 集群分为RAM节点和DISK节点,一个集群最好至少有一个DISK节点保存集群的状态。
4. 集群的配置可以通过命令行,也可以通过配置文件,命令行优先。
利用rabbit_mq队列消息实现对一组主机进行命令下发的更多相关文章
- 利用System V消息队列实现回射客户/服务器
一.介绍 在学习UNIX网络编程 卷1时,我们当时可以利用Socket套接字来实现回射客户/服务器程序,但是Socket编程是存在一些不足的,例如: 1. 服务器必须启动之时,客户端才能连上服务端,并 ...
- Spring和ActiveMQ集成实现队列消息以及PUB/SUB模型
前言:本文是基于Spring和ActiveMQ的一个示例文章,包括了Point-To-Point的异步队列消息和PUB/SUB(发布/订阅)模型,只是做了比较简单的实现,无任何业务方面的东西,作为一个 ...
- Flume 读取JMS 消息队列消息,并将消息写入HDFS
利用Apache Flume 读取JMS 消息队列消息.并将消息写入HDFS,flume agent配置例如以下: flume-agent.conf #name the components on ...
- Android中利用Handler实现消息的分发机制(三)
在第二篇文章<Android中利用Handler实现消息的分发机制(一)>中,我们讲到主线程的Looper是Android系统在启动App的时候,已经帮我们创建好了,而假设在子线程中须要去 ...
- Flume 读取RabbitMq消息队列消息,并将消息写入kafka
首先是关于flume的基础介绍 组件名称 功能介绍 Agent代理 使用JVM 运行Flume.每台机器运行一个agent,但是可以在一个agent中包含多个sources和sinks. Client ...
- 【转】Skynet之消息队列 - 消息的存储与分发
Skynet之消息队列 - 消息的存储与分发 http://www.outsky.org/code/skynet-message-queue.html Sep 8, 2014 按我的理解,消息队列是S ...
- ActiveMQ队列消息过期时间设置和自动清除解决方案
版本 apache-activemq-5.15.3 1.消息过期设置 参数详情 1)message过期则客户端不能接收 2)ttlCeiling:表示过期时间上限(程序写的过期时间不能超过此时间,超过 ...
- Java并发编程原理与实战三十六:阻塞队列&消息队列
一.阻塞队列 1.阻塞队列BlockingQueue ---->可以理解成生产者消费者的模式---->消费者要等待到生产者生产出来产品.---->而非阻塞队列ConcurrentLi ...
- 【python】-- RabbitMQ 队列消息持久化、消息公平分发
RabbitMQ 队列消息持久化 假如消息队列test里面还有消息等待消费者(consumers)去接收,但是这个时候服务器端宕机了,这个时候消息是否还在? 1.队列消息非持久化 服务端(produc ...
随机推荐
- 简单的mvc之三:灵活的路由(上)
在上一篇关于管线的随笔中已经提及了管线,通过对管线的分析,我们可以得到下面几个结论:路由系统由URLRoutingModule模块实现,它订阅了PostResolvRequestCache事件:路由系 ...
- download youtube video
using youtube-dl to download youtube video: (1) sudo apt-get install youtube-dl (2) run.sh #!/bin/ba ...
- GetWindowRect和GetClientRect的区别详解
一:关于坐标 MFC中绘图时经常涉及到坐标计算,GetWindowRect和GetClientRect这两个函数,是获取逻辑坐标系中窗口或控件(其实也是窗口)大小和坐标的常用函数了,有什么不一样的? ...
- Supervisor 管理后台守护进程
Supervisor 管理后台守护进程 参考原文如下: http://codinn.com/people/brant/notes/110948/ 做了一些注释 +++++++++++引用开始+++++ ...
- ERROR 1130: Host xxx is not allowed to connect to this MySQL server
在使用MySQL-Front连接mysql的时候发生的这个错误 ERROR 1130: Host xxx is not allowed to connect to this MySQL server ...
- DEV 打印gridcontrl
private void PrintPreview(DevExpress.XtraPrinting.IPrintable gridControlPrint) { ...
- 内存错误:CRT detected that the application wrote to memory after end of heap buffer
今天调试测试代码时,发现在用完了new出来的内存buf后,在执行delete时报错了,具体信息为: HEAP_CORRUPTION_DETECTED: after Normal block(#908) ...
- 理解git分支-远程分支
远程分支 远程引用是对远程仓库的引用(指针),包括分支.标签等等. 你可以通过 git ls-remote (remote)来显式地获得远程引用的完整列表,或者通过 git remote show ( ...
- TCP报文中的SYN,FIN,ACK,PSH,RST,URG
TCP的三次握手是怎么进行的:发送端发送一个SYN=1,ACK=0标志的数据包给接收端,请求进行连接,这是第一次握手:接收端收到请求并且允许连接的话,就会发送一个SYN=1,ACK=1标志的数据包给发 ...
- Perception(1.2)
4.1.2 Definition of Coordinate Systems The global coordinate system is described by its origin lying ...