RabbitMQ

前言

什么是MQ?

MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消 息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。

什么是RabbitMQ?

RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议

RabbitMQ是一个消息代理:它接受和转发消息。 您可以将其视为顺丰快递:当您将要发布的消息快件给到顺丰快递手上,您可以确定顺丰以及快递小哥最终会将邮件发送给您的收件人。 在这个类比中,RabbitMQ是一个顺丰快递、快递小哥、丰巢。

RabbitMQ和顺丰之间的主要区别在于它不处理实体货物信件,而是接受,存储和转发二进制数据——消息。

RabbitMQ和一般的消息传递使用了一些术语:

  • 生产(Producing)就是发送(消息)。 发送消息的程序就所谓的生产者(producer )

  • 队列(queue )是RabbitMQ中的邮箱的名称。 虽然消息流经RabbitMQ和您的应用程序,但它们只能存储在队列中。 队列只受主机的内存和磁盘限制的约束,它本质上是一个大的消息缓冲区。 许多生产者可以发送到一个队列的消息,并且许多消费者可以尝试从一个队列接收数据。 这就是我们代表队列的方式:

  • 消费(Consuming )与接受(receiving)有类似的意义。 消费者(consumer )是一个主要等待接收消息的程序:

请注意,生产者,消费者和代理不必驻留在同一主机上; 实际上在大多数应用中他们没有。 应用程序也可以是生产者和消费者。

RabbitMQ安装

  1. 安装配置epel
  2. $ rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
  3. 安装erlang
  4. $ yum -y install erlang
  5. 安装RabbitMQ
  6. $ yum -y install rabbitmq-server

注意:service rabbitmq-server start/stop

安装API

  1. pip install pika
  2. or
  3. easy_install pika
  4. or
  5. 源码
  6. https://pypi.python.org/pypi/pika

使用API操作RabbitMQ

回顾基于Queue实现生产者消费者模型

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import Queue
  4. import threading
  5. message = Queue.Queue(10)
  6. def producer(i):
  7. while True:
  8. message.put(i)
  9. def consumer(i):
  10. while True:
  11. msg = message.get()
  12. for i in range(12):
  13. t = threading.Thread(target=producer, args=(i,))
  14. t.start()
  15. for i in range(10):
  16. t = threading.Thread(target=consumer, args=(i,))
  17. t.start()

对于RabbitMQ来说,生产和消费不再针对内存里的一个Queue对象,而是某台服务器上的RabbitMQ Server实现的消息队列

生产者:

  1. #!/usr/bin/env python
  2. import pika
  3. # ######################### 生产者 #########################
  4. connection = pika.BlockingConnection(pika.ConnectionParameters(
  5. host='localhost'))
  6. channel = connection.channel()
  7. channel.queue_declare(queue='hello')
  8. channel.basic_publish(exchange='',
  9. routing_key='hello',
  10. body='Hello World!')
  11. print(" [x] Sent 'Hello World!'")
  12. connection.close()

消费者:

  1. #!/usr/bin/env python
  2. import pika
  3. # ########################## 消费者 ##########################
  4. connection = pika.BlockingConnection(pika.ConnectionParameters(
  5. host='localhost'))
  6. channel = connection.channel()
  7. channel.queue_declare(queue='hello')
  8. def callback(ch, method, properties, body):
  9. print(" [x] Received %r" % body)
  10. channel.basic_consume(callback,
  11. queue='hello',
  12. no_ack=True)
  13. print(' [*] Waiting for messages. To exit press CTRL+C')
  14. channel.start_consuming()

1、acknowledgment 消息不丢失

no-ack = False,如果消费者遇到情况(its channel is closed, connection is closed, or TCP connection is lost)挂掉了,那么,RabbitMQ会重新将该任务添加到队列中。

  1. import pika
  2. connection = pika.BlockingConnection(pika.ConnectionParameters(
  3. host='10.211.55.4'))
  4. channel = connection.channel()
  5. channel.queue_declare(queue='hello')
  6. def callback(ch, method, properties, body):
  7. print(" [x] Received %r" % body)
  8. import time
  9. time.sleep(10)
  10. print 'ok'
  11. ch.basic_ack(delivery_tag = method.delivery_tag)
  12. channel.basic_consume(callback,
  13. queue='hello',
  14. no_ack=False)
  15. print(' [*] Waiting for messages. To exit press CTRL+C')
  16. channel.start_consuming()

2、durable 消息不丢失

生产者:

  1. #!/usr/bin/env python
  2. import pika
  3. connection = pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.4'))
  4. channel = connection.channel()
  5. # make message persistent
  6. channel.queue_declare(queue='hello', durable=True)
  7. channel.basic_publish(exchange='',
  8. routing_key='hello',
  9. body='Hello World!',
  10. properties=pika.BasicProperties(
  11. delivery_mode=2, # make message persistent
  12. ))
  13. print(" [x] Sent 'Hello World!'")
  14. connection.close()

消费者:

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import pika
  4. connection = pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.4'))
  5. channel = connection.channel()
  6. # make message persistent
  7. channel.queue_declare(queue='hello', durable=True)
  8. def callback(ch, method, properties, body):
  9. print(" [x] Received %r" % body)
  10. import time
  11. time.sleep(10)
  12. print 'ok'
  13. ch.basic_ack(delivery_tag = method.delivery_tag)
  14. channel.basic_consume(callback,
  15. queue='hello',
  16. no_ack=False)
  17. print(' [*] Waiting for messages. To exit press CTRL+C')
  18. channel.start_consuming()

3、消息获取顺序

默认消息队列里的数据是按照顺序被消费者拿走,例如:消费者1 去队列中获取 奇数 序列的任务,消费者1去队列中获取 偶数 序列的任务。

channel.basic_qos(prefetch_count=1) 表示谁来谁取,不再按照奇偶数排列

消费者:

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import pika
  4. connection = pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.4'))
  5. channel = connection.channel()
  6. # make message persistent
  7. channel.queue_declare(queue='hello')
  8. def callback(ch, method, properties, body):
  9. print(" [x] Received %r" % body)
  10. import time
  11. time.sleep(10)
  12. print 'ok'
  13. ch.basic_ack(delivery_tag = method.delivery_tag)
  14. channel.basic_qos(prefetch_count=1)
  15. channel.basic_consume(callback,
  16. queue='hello',
  17. no_ack=False)
  18. print(' [*] Waiting for messages. To exit press CTRL+C')
  19. channel.start_consuming()

4、发布订阅

发布订阅和简单的消息队列区别在于,发布订阅会将消息发送给所有的订阅者,而消息队列中的数据被消费一次便消失。所以,RabbitMQ实现发布和订阅时,会为每一个订阅者创建一个队列,而发布者发布消息时,会将消息放置在所有相关队列中。

exchange type = fanout

  1. #!/usr/bin/env python
  2. import pika
  3. import sys
  4. connection = pika.BlockingConnection(pika.ConnectionParameters(
  5. host='localhost'))
  6. channel = connection.channel()
  7. channel.exchange_declare(exchange='logs',
  8. type='fanout')
  9. message = ' '.join(sys.argv[1:]) or "info: Hello World!"
  10. channel.basic_publish(exchange='logs',
  11. routing_key='',
  12. body=message)
  13. print(" [x] Sent %r" % message)
  14. connection.close()
  1. #!/usr/bin/env python
  2. import pika
  3. connection = pika.BlockingConnection(pika.ConnectionParameters(
  4. host='localhost'))
  5. channel = connection.channel()
  6. channel.exchange_declare(exchange='logs',
  7. type='fanout')
  8. result = channel.queue_declare(exclusive=True)
  9. queue_name = result.method.queue
  10. channel.queue_bind(exchange='logs',
  11. queue=queue_name)
  12. print(' [*] Waiting for logs. To exit press CTRL+C')
  13. def callback(ch, method, properties, body):
  14. print(" [x] %r" % body)
  15. channel.basic_consume(callback,
  16. queue=queue_name,
  17. no_ack=True)
  18. channel.start_consuming()

5、关键字发送

exchange type = direct

之前事例,发送消息时明确指定某个队列并向其中发送消息,RabbitMQ还支持根据关键字发送,即:队列绑定关键字,发送者将数据根据关键字发送到消息exchange,exchange根据 关键字 判定应该将数据发送至指定队列。

  1. #!/usr/bin/env python
  2. import pika
  3. import sys
  4. connection = pika.BlockingConnection(pika.ConnectionParameters(
  5. host='localhost'))
  6. channel = connection.channel()
  7. channel.exchange_declare(exchange='direct_logs',
  8. type='direct')
  9. result = channel.queue_declare(exclusive=True)
  10. queue_name = result.method.queue
  11. severities = sys.argv[1:]
  12. if not severities:
  13. sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
  14. sys.exit(1)
  15. for severity in severities:
  16. channel.queue_bind(exchange='direct_logs',
  17. queue=queue_name,
  18. routing_key=severity)
  19. print(' [*] Waiting for logs. To exit press CTRL+C')
  20. def callback(ch, method, properties, body):
  21. print(" [x] %r:%r" % (method.routing_key, body))
  22. channel.basic_consume(callback,
  23. queue=queue_name,
  24. no_ack=True)
  25. channel.start_consuming()
  1. #!/usr/bin/env python
  2. import pika
  3. import sys
  4. connection = pika.BlockingConnection(pika.ConnectionParameters(
  5. host='localhost'))
  6. channel = connection.channel()
  7. channel.exchange_declare(exchange='direct_logs',
  8. type='direct')
  9. severity = sys.argv[1] if len(sys.argv) > 1 else 'info'
  10. message = ' '.join(sys.argv[2:]) or 'Hello World!'
  11. channel.basic_publish(exchange='direct_logs',
  12. routing_key=severity,
  13. body=message)
  14. print(" [x] Sent %r:%r" % (severity, message))
  15. connection.close()

6、模糊匹配

exchange type = topic

在topic类型下,可以让队列绑定几个模糊的关键字,之后发送者将数据发送到exchange,exchange将传入”路由值“和 ”关键字“进行匹配,匹配成功,则将数据发送到指定队列。

  • # 表示可以匹配 0 个 或 多个 单词
  • * 表示只能匹配 一个 单词
  1. 发送者路由值 队列中
  2. old.boy.python old.* -- 不匹配
  3. old.boy.python old.# -- 匹配
  1. #!/usr/bin/env python
  2. import pika
  3. import sys
  4. connection = pika.BlockingConnection(pika.ConnectionParameters(
  5. host='localhost'))
  6. channel = connection.channel()
  7. channel.exchange_declare(exchange='topic_logs',
  8. type='topic')
  9. result = channel.queue_declare(exclusive=True)
  10. queue_name = result.method.queue
  11. binding_keys = sys.argv[1:]
  12. if not binding_keys:
  13. sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0])
  14. sys.exit(1)
  15. for binding_key in binding_keys:
  16. channel.queue_bind(exchange='topic_logs',
  17. queue=queue_name,
  18. routing_key=binding_key)
  19. print(' [*] Waiting for logs. To exit press CTRL+C')
  20. def callback(ch, method, properties, body):
  21. print(" [x] %r:%r" % (method.routing_key, body))
  22. channel.basic_consume(callback,
  23. queue=queue_name,
  24. no_ack=True)
  25. channel.start_consuming()
  1. #!/usr/bin/env python
  2. import pika
  3. import sys
  4. connection = pika.BlockingConnection(pika.ConnectionParameters(
  5. host='localhost'))
  6. channel = connection.channel()
  7. channel.exchange_declare(exchange='topic_logs',
  8. type='topic')
  9. routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info'
  10. message = ' '.join(sys.argv[2:]) or 'Hello World!'
  11. channel.basic_publish(exchange='topic_logs',
  12. routing_key=routing_key,
  13. body=message)
  14. print(" [x] Sent %r:%r" % (routing_key, message))
  15. connection.close()

注意:

  1. sudo rabbitmqctl add_user wupeiqi 123
  2. # 设置用户为administrator角色
  3. sudo rabbitmqctl set_user_tags wupeiqi administrator
  4. # 设置权限
  5. sudo rabbitmqctl set_permissions -p "/" root ".*" ".*" ".*"
  6. # 然后重启rabbiMQ服务
  7. sudo /etc/init.d/rabbitmq-server restart
  8. # 然后可以使用刚才的用户远程连接rabbitmq server了。
  9. ------------------------------
  10. credentials = pika.PlainCredentials("wupeiqi","123")
  11. connection = pika.BlockingConnection(pika.ConnectionParameters('192.168.14.47',credentials=credentials))
  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import pika
  4. from pika.adapters.blocking_connection import BlockingChannel
  5. credentials = pika.PlainCredentials("root", "123")
  6. conn = pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.20', credentials=credentials))
  7. # 超时时间
  8. conn.add_timeout(5, lambda: channel.stop_consuming())
  9. channel = conn.channel()
  10. channel.queue_declare(queue='hello')
  11. def callback(ch, method, properties, body):
  12. print(" [x] Received %r" % body)
  13. channel.stop_consuming()
  14. channel.basic_consume(callback,
  15. queue='hello',
  16. no_ack=True)
  17. print(' [*] Waiting for messages. To exit press CTRL+C')
  18. channel.start_consuming()

python与RabbitMQ的更多相关文章

  1. Python操作RabbitMQ

    RabbitMQ介绍 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现的产品,RabbitMQ是一个消息代理,从“生产者”接收消息并传递消 ...

  2. 用 Python、 RabbitMQ 和 Nameko 实现微服务

    用 Python. RabbitMQ 和 Nameko 实现微服务 原创 07-17 17:57 首页 Linux中国 "微服务是一股新浪潮" - 现如今,将项目拆分成多个独立的. ...

  3. python之RabbitMQ

    一.安装RabbitMQ 1. 安装erlang 1 2 3 4 tar xf otp_src_18.3.tar.gz cd otp_src_18.3 ./configure --prefix=/ma ...

  4. Python之路【第九篇】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

    Python之路[第九篇]:Python操作 RabbitMQ.Redis.Memcache.SQLAlchemy   Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用 ...

  5. python - 操作RabbitMQ

    python - 操作RabbitMQ     介绍 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议.MQ全称为Mess ...

  6. 文成小盆友python-num12 Redis发布与订阅补充,python操作rabbitMQ

    本篇主要内容: redis发布与订阅补充 python操作rabbitMQ 一,redis 发布与订阅补充 如下一个简单的监控模型,通过这个模式所有的收听者都能收听到一份数据. 用代码来实现一个red ...

  7. Python之路第十二天,高级(4)-Python操作rabbitMQ

    rabbitMQ RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议. MQ全称为Message Queue, 消息队列(M ...

  8. Python与RabbitMQ交互

    RabbitMQ 消息队列 成熟的中间件RabbitMQ.ZeroMQ.ActiveMQ等等 RabbitMQ使用erlang语言开发,使用RabbitMQ前要安装erlang语言 RabbitMQ允 ...

  9. python中RabbitMQ的使用(安装和简单教程)

    1,简介 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现的产品,RabbitMQ是一个消息代理,从"生产者"接收消息 ...

  10. Python之RabbitMQ的使用

    今天总结一下Python关于Rabbitmq的使用 RabbitMQ官网说明,其实也是一种队列,那和前面说的线程queue和进程queue有什么区别呢? 线程queue只能在同一个进程下进行数据交互 ...

随机推荐

  1. Day044--javascript, ECMAScript

    一. javascript JavaScript基础分为三个部分: ECMAScript:JavaScript的语法标准.包括变量.表达式.运算符.函数.if语句.for语句等. DOM:操作网页上的 ...

  2. NLP相关问题中文本数据特征表达初探

    1. NLP问题简介 0x1:NLP问题都包括哪些内涵 人们对真实世界的感知被成为感知世界,而人们用语言表达出自己的感知视为文本数据.那么反过来,NLP,或者更精确地表达为文本挖掘,则是从文本数据出发 ...

  3. kubernetes云平台管理实战: 服务发现和负载均衡(五)

    一.rc控制器常用命令 1.rc控制器信息查看 [root@k8s-master ~]# kubectl get replicationcontroller NAME DESIRED CURRENT ...

  4. Makefile 使用总结(转)

    Makefile 使用总结  转自 https://www.cnblogs.com/wang_yb/p/3990952.html 1. Makefile 简介 Makefile 是和 make 命令一 ...

  5. oldboy s21day06

    #!/usr/bin/env python# -*- coding:utf-8 -*- # 1.列举你了解的字典中的功能(字典独有).'''dic.keys() 获取所有keydic.values() ...

  6. Navier-Stokes equations (Lectured by Luis Caffarelli)

    百万美元问题: http://www.claymath.org/millennium-problems/navier%E2%80%93stokes-equation Official Problem ...

  7. About the Importance of Aim in Life

    Have an aim in life, or your energies will all be wasted.   ---R. Peters 人生应该树立目标,否则你的精力会白白浪费. ---彼得 ...

  8. API.day01

    第1部分 JDK API 1.1 API(Application Programming Interface,应用接口程序):已经封装好可以直接调用的功能(Java中以类的形式封装) 经常使用的JDK ...

  9. webpack学习笔记——项目引入zepto及tap事件失效的解决

    先要npm下来zepto:npm install zepto 然后npm下来exports-loader和script-loader 配置如下: JavaScript // webpack.confi ...

  10. php 默认保几位小数,末尾为0去掉

    计算保留几位小数,末位为0舍去 // 计算 默认保留1位小数 protected function getSprintf($value,$count,$digit = 1) { $num = 0; i ...