设为首页 收藏本站
查看: 650|回复: 0

[经验分享] python16_day11【MQ、Redis、Memcache】

[复制链接]
累计签到:2 天
连续签到:1 天
发表于 2017-7-3 08:44:20 | 显示全部楼层 |阅读模式
一、RabbitMQ
  是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。
  MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消 息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。
  1.RabbitMQ install



安装配置epel源
    $ rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
  
安装erlang
    $ yum -y install erlang
  
安装RabbitMQ
    $ yum -y install rabbitmq-server
  
  注意:service rabbitmq-server start/stop
  2. Python API install  



pip install pika
or
easy_install pika
or
源码
https://pypi.python.org/pypi/pika
  3.基于QUEUE实现生产消费模型



import Queue
import threading

message = Queue.Queue(10)

def producer(i):
     while True:
         message.put(i)

def consumer(i):
     while True:
         msg = message.get()

for i in range(12):
     t = threading.Thread(target=producer, args=(i,))
     t.start()

for i in range(10):
     t = threading.Thread(target=consumer, args=(i,))
     t.start()
  4.基于RabbitMQ
  对于RabbitMQ来说,生产和消费不再针对内存里的一个Queue对象,而是某台服务器上的RabbitMQ Server实现的消息队列。



import pika
  
# ######################### 生产者 #########################
connection = pika.BlockingConnection(pika.ConnectionParameters(
         host='localhost'))
channel = connection.channel()
  
channel.queue_declare(queue='hello')
  
channel.basic_publish(exchange='',
                       routing_key='hello',
                       body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()

  
# ########################## 消费者 ##########################
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
         host='localhost'))
channel = connection.channel()
  
channel.queue_declare(queue='hello')
  
def callback(ch, method, properties, body):
     print(" [x] Received %r" % body)
  
channel.basic_consume(callback,
                       queue='hello',
                       no_ack=True)
  
print('
  • Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()
      5.消费者ack


    DSC0000.gif DSC0001.gif


    import pika
    connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost', port=5672))
    channel = connection.channel()
    channel.queue_declare(queue='hello')

    def callback(ch, method, properties, body):
         print(" [x] Received %r" % body)

    channel.basic_consume(callback, queue='hello', no_ack=False)
    # no_ack: acknowledgment 消息不丢失,MQ判读出现异常,没有消费,没有ack,则把消息放回队列.
    channel.start_consuming()
    消息ack  6.durable消息持久化





    import pika

    connection = pika.BlockingConnection(pika.ConnectionParameters(
             host='127.0.0.1', port=5672))
    channel = connection.channel()

    channel.queue_declare(queue='hello1', durable=True)        # 创建通道, 持久化修改1:durable=True
    channel.basic_publish(exchange='',
                           routing_key='hello',
                           body='Hello World!',
                           properties=pika.BasicProperties(delivery_mode=2)  # 持久化修改2
                           )
    connection.close()
    生产者




    import pika
    connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost', port=5672))
    channel = connection.channel()

    def callback(ch, method, properties, body):
         print(" [x] Received %r" % body)
         import time
         time.sleep(10)
         print('ok')
         ch.basic_ack(delivery_tag=method.delivery_tag)  # 持久化:修改2
    channel.basic_consume(callback,
                           queue='hello',
                           no_ack=False)         # 持久化:修改1
    channel.start_consuming()
    消费者    7.消息获取顺序





    import pika
    connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost', port=5672))
    channel = connection.channel()

    def callback(ch, method, properties, body):
         print(" [x] Received %r" % body)
         import time
         time.sleep(10)
         print('ok')
         ch.basic_ack(delivery_tag=method.delivery_tag)
    channel.basic_qos(prefetch_count=1)         # 默认消息队列里的数据是按照顺序被消费者拿走,
                                                 # 例如:消费者1 去队列中获取 奇数 序列的任务,消费者1去队列中获取 偶数 序列的任务。
                                                 # 表示谁来谁取,不再按照奇偶数排列
    channel.basic_consume(callback,
                           queue='hello',
                           no_ack=False)

    channel.start_consuming()
    消费者  8.发布订阅
      exchange type = fanout





    import pika
    import sys

    connection = pika.BlockingConnection(pika.ConnectionParameters(
             host='localhost'))
    channel = connection.channel()

    channel.exchange_declare(exchange='logs',
                              type='fanout')

    message = ' '.join(sys.argv[1:]) or "info: Hello World!"
    channel.basic_publish(exchange='logs',
                           routing_key='',
                           body=message)
    print(" [x] Sent %r" % message)
    connection.close()
    发布者




    import pika

    connection = pika.BlockingConnection(pika.ConnectionParameters(
             host='localhost'))
    channel = connection.channel()

    channel.exchange_declare(exchange='logs',
                              type='fanout')

    result = channel.queue_declare(exclusive=True)
    queue_name = result.method.queue

    channel.queue_bind(exchange='logs',
                        queue=queue_name)

    print('
  • Waiting for logs. To exit press CTRL+C')

    def callback(ch, method, properties, body):
         print(" [x] %r" % body)

    channel.basic_consume(callback,
                           queue=queue_name,
                           no_ack=True)

    channel.start_consuming()
    订阅者  9.发布订阅(关键字)
      exchange type = direct





    import pika
    import sys

    connection = pika.BlockingConnection(pika.ConnectionParameters(
             host='localhost'))
    channel = connection.channel()

    channel.exchange_declare(exchange='direct_logs',
                              type='direct')

    severity = sys.argv[1] if len(sys.argv) > 1 else 'info'
    message = ' '.join(sys.argv[2:]) or 'Hello World!'
    channel.basic_publish(exchange='direct_logs',
                           routing_key=severity,
                           body=message)
    print(" [x] Sent %r:%r" % (severity, message))
    connection.close()
    发布者




    import pika
    import sys

    connection = pika.BlockingConnection(pika.ConnectionParameters(
             host='localhost'))
    channel = connection.channel()

    channel.exchange_declare(exchange='direct_logs',
                              type='direct')

    result = channel.queue_declare(exclusive=True)
    queue_name = result.method.queue

    severities = sys.argv[1:]
    if not severities:
         sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
         sys.exit(1)

    for severity in severities:
         channel.queue_bind(exchange='direct_logs',
                            queue=queue_name,
                            routing_key=severity)

    print('
  • Waiting for logs. To exit press CTRL+C')

    def callback(ch, method, properties, body):
         print(" [x] %r:%r" % (method.routing_key, body))

    channel.basic_consume(callback,
                           queue=queue_name,
                           no_ack=True)

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


    • # 表示可以匹配 0 个 或 多个 单词
    • *  表示只能匹配 一个 单词



    发送者路由值              队列中
    old.boy.python          old.*  -- 不匹配
    old.boy.python          old.#  -- 匹配




    import pika
    import sys

    connection = pika.BlockingConnection(pika.ConnectionParameters(
             host='localhost'))
    channel = connection.channel()

    channel.exchange_declare(exchange='topic_logs',
                              type='topic')

    routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info'
    message = ' '.join(sys.argv[2:]) or 'Hello World!'
    channel.basic_publish(exchange='topic_logs',
                           routing_key=routing_key,
                           body=message)
    print(" [x] Sent %r:%r" % (routing_key, message))
    connection.close()
    发布者




    import pika
    import sys

    connection = pika.BlockingConnection(pika.ConnectionParameters(
             host='localhost'))
    channel = connection.channel()

    channel.exchange_declare(exchange='topic_logs',
                              type='topic')

    result = channel.queue_declare(exclusive=True)
    queue_name = result.method.queue

    binding_keys = sys.argv[1:]
    if not binding_keys:
         sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0])
         sys.exit(1)

    for binding_key in binding_keys:
         channel.queue_bind(exchange='topic_logs',
                            queue=queue_name,
                            routing_key=binding_key)

    print('
  • Waiting for logs. To exit press CTRL+C')

    def callback(ch, method, properties, body):
         print(" [x] %r:%r" % (method.routing_key, body))

    channel.basic_consume(callback,
                           queue=queue_name,
                           no_ack=True)

    channel.start_consuming()
    订阅者二、Memcached
      1.安装API
      pip3 install python-memcached
      2.基本使用



    import memcache

    mc = memcache.Client(['10.211.55.4:12000'], debug=True)
    mc.set("foo", "bar")
    ret = mc.get('foo')
    print ret

      3.支持集群


    • 根据算法将 k1 转换成一个数字
    • 将数字和主机列表长度求余数,得到一个值 N( 0 <= N < 列表长度 )
    • 在主机列表中根据 第2步得到的值为索引获取主机,例如:host_list[N]
    • 连接 将第3步中获取的主机,将 k1 = "v1" 放置在该服务器的内存中



    mc = memcache.Client([('1.1.1.1:12000', 1), ('1.1.1.2:12000', 2), ('1.1.1.3:12000', 1)], debug=True)

    mc.set('k1', 'v1')

      4.add命令
      添加一条键值对,如果已经存在的 key,重复执行add操作异常



    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import memcache

    mc = memcache.Client(['10.211.55.4:12000'], debug=True)
    mc.add('k1', 'v1')
    # mc.add('k1', 'v2') # 报错,对已经存在的key重复添加,失败!!!

      5.replace命令
      replace 修改某个key的值,如果key不存在,则异常



    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import memcache

    mc = memcache.Client(['10.211.55.4:12000'], debug=True)
    # 如果memcache中存在kkkk,则替换成功,否则一场
    mc.replace('kkkk','999')

      6.set 和 set_multi
      set            设置一个键值对,如果key不存在,则创建,如果key存在,则修改!
      set_multi   设置多个键值对,如果key不存在,则创建,如果key存在,则修改!



    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import memcache

    mc = memcache.Client(['10.211.55.4:12000'], debug=True)

    mc.set('key0', 'wupeiqi')

    mc.set_multi({'key1': 'val1', 'key2': 'val2'})

      7.delete 和 delete_multi
      delete             在Memcached中删除指定的一个键值对
      delete_multi    在Memcached中删除指定的多个键值对




    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import memcache

    mc = memcache.Client(['10.211.55.4:12000'], debug=True)

    mc.delete('key0')
    mc.delete_multi(['key1', 'key2'])

      8.get 和 get_multi
      get            获取一个键值对
      get_multi   获取多一个键值对




    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import memcache

    mc = memcache.Client(['10.211.55.4:12000'], debug=True)

    val = mc.get('key0')
    item_dict = mc.get_multi(["key1", "key2", "key3"])

      9.append 和 prepend
      append    修改指定key的值,在该值 后面 追加内容
      prepend   修改指定key的值,在该值 前面 插入内容




    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import memcache

    mc = memcache.Client(['10.211.55.4:12000'], debug=True)
    # k1 = "v1"

    mc.append('k1', 'after')
    # k1 = "v1after"

    mc.prepend('k1', 'before')
    # k1 = "beforev1after"

      10.decr 和 incr
      incr  自增,将Memcached中的某一个值增加 N ( N默认为1 )
      decr 自减,将Memcached中的某一个值减少 N ( N默认为1 )



    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import memcache

    mc = memcache.Client(['10.211.55.4:12000'], debug=True)
    mc.set('k1', '777')

    mc.incr('k1')
    # k1 = 778

    mc.incr('k1', 10)
    # k1 = 788

    mc.decr('k1')
    # k1 = 787

    mc.decr('k1', 10)
    # k1 = 777

      11.gets 和 cas
      如商城商品剩余个数,假设改值保存在memcache中,product_count = 900
        A用户刷新页面从memcache中读取到product_count = 900
      B用户刷新页面从memcache中读取到product_count = 900

      如果A、B用户均购买商品
      A用户修改商品剩余个数 product_count=899
      B用户修改商品剩余个数 product_count=899
      如此一来缓存内的数据便不在正确,两个用户购买商品后,商品剩余还是 899
      如果使用python的set和get来操作以上过程,那么程序就会如上述所示情况!
      如果想要避免此情况的发生,只要使用 gets 和 cas 即可,如:



    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import memcache
    mc = memcache.Client(['10.211.55.4:12000'], debug=True, cache_cas=True)

    v = mc.gets('product_count')
    # ...
    # 如果有人在gets之后和cas之前修改了product_count,那么,下面的设置将会执行失败,剖出异常,从而避免非正常数据的产生
    mc.cas('product_count', "899")

      Ps:本质上每次执行gets时,会从memcache中获取一个自增的数字,通过cas去修改gets的值时,会携带之前获取的自增值和memcache中的自增值进行比较,如果相等,则可以提交,如果不想等,那表示在gets和cas执行之间,又有其他人执行了gets(获取了缓冲的指定值), 如此一来有可能出现非正常数据,则不允许修改。
    三、Redis
      1.安装API
      pip3 install redis
      2.功能介绍


    • 连接方式
    • 连接池
    • 操作

      • String 操作
      • Hash 操作
      • List 操作
      • Set 操作
      • Sort Set 操作


    • 管道
    • 发布订阅
      3.基本操作



    import redis

    r = redis.Redis(host='10.211.55.4', port=6379)
    r.set('foo', 'Bar')
    print r.get('foo')

      4.连接池
      redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。



    import redis

    pool = redis.ConnectionPool(host='10.211.55.4', port=6379)

    r = redis.Redis(connection_pool=pool)
    r.set('foo', 'Bar')
    print r.get('foo')

      5.操作
      参考:http://www.cnblogs.com/wupeiqi/articles/5132791.html

  • 运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
    2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
    3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
    4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
    5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
    6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
    7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
    8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

    所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-390586-1-1.html 上篇帖子: 缓存,队列(Redis,RabbitMQ) 下篇帖子: FAIL : SSHException: Incompatible ssh peer (no acceptable kex algorithm)问题解决及更新p
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    扫码加入运维网微信交流群X

    扫码加入运维网微信交流群

    扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

    扫描微信二维码查看详情

    客服E-mail:kefu@iyunv.com 客服QQ:1061981298


    QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


    提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


    本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



    合作伙伴: 青云cloud

    快速回复 返回顶部 返回列表