Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

       一、 Memcached

  1. Memcached安装和基本使用
  2. Python操作Memcached
    2.1 set
    2.2 集群操作
    2.3 add
    2.4 replace
    2.5 set 和 set_multi
    2.6 delete 和 delete_multi
    2.7 get 和 get_multi
    2.8 append 和 prepend
    2.9 decr 和 incr  
    2.10 gets 和 cas
二、redis
  1. 安装Redis
  2. 安装Python的redis模块
  3. redis模块介绍
    3.1 操作模式
    3.2 连接池
    3.3 数据操作
    3.3.1 通用操作
    3.3.2 String操作
    3.3.3 Hash操作
    3.3.4 List操作
    3.3.5 Set操作
    3.3.6 有序集合的操作
    3.3.7 管道
    3.3.8 发布订阅
三、rabbitMQ

3.1 RabbitMQ的安装
3.2 rabbitMQ工作机制
3.3 简单的rabbitMQ使用
3.4 发布订阅
3.5 路由/关键字
3.6 主题

四、SQLAlchemy

一、 Memcached

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。

1.1 Memcached安装和基本使用
  • 安装Memcached:

    用wget 去http://memcached.org下载最新源码
    tar -zxvf memcached-x.x.x.tar.gz
    cd memcached-x.x.x
    ./configure && make && make test && sudo make install
    PS:依赖libevent,需要提前安装
    yum install libevent-devel
    apt-get install libevent-dev

  • 启动Memcached

    memcached -d -m 10 -u root -l 10.211.55.4 -p 12000 -c 256 -P /tmp/memcached.pid

    PS:如果你是在本机的虚拟机内测试,请将IP改为0.0.0.0
  • 参数说明:

    -d:启动一个守护进程
    -m:分配给Memcache使用的内存数量,单位是MB
    -u :运行Memcache的用户
    -l :监听的服务器IP地址
    -p:设置Memcache监听的端口,最好是1024以上的端口
    -c :最大运行的并发连接数,默认是1024,按照服务器的负载量来设定
    -P:设置保存Memcache的pid文件

  • Memcached命令

    存储命令: set/add/replace/append/prepend/cas
    获取命令: get/gets
    其他命令: delete/stats..

1.2 Python操作Memcached

安装API

1.2.1 set

set是最基本的操作,传入两个参数,第一个是name,第二个是这个name对应的value。

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

debug = True 表示运行出现错误时,显示错误信息,上线后请移除该参数。

1.2.2 集群操作

python-memcached模块原生支持集群操作,其原理是在内存维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比。

主机 权重
1.1.1.1 1
1.1.1.2 2
1.1.1.3 1

那么在内存中主机列表为:host_list = ["1.1.1.1", "1.1.1.2", "1.1.1.2", "1.1.1.3", ]
用户如果要在内存中创建一个键值对(如:k1 = "v1"),那么要执行以下步骤:

  1. 根据算法将 k1 转换成一个数字
  2. 将数字和主机列表长度求余数,得到一个值 N( 0 <= N < 列表长度 )
  3. 在主机列表中根据 第2步得到的值为索引获取主机,例如:host_list[N]
  4. 连接 将第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')
1.2.3 add

添加一条键值对。如果已经存在该 key,则弹出异常。

mc.add('k1', 'v1')
mc.add('k1', 'v2') # 报错,对已存在的key重复添加!!!
1.2.4 replace

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

mc.replace('kkkk','999')
1.2.5 set 和 set_multi

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

mc.set('key0', 'jack') 
mc.set_multi({
     'key1': 'val1', 'key2': 'val2'})
1.2.6 delete 和 delete_multi

delete: 删除指定的一个键值对
delete_multi: 删除指定的多个键值对

mc.delete('key0')
mc.delete_multi(['key1', 'key2'])
1.2.7 get 和 get_multi

get: 获取一个键值对
get_multi : 获取多一个键值对

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

append : 修改指定key的值,在原来的值后面追加内容
prepend 修改指定key的值,在原来的值前面插入内容

# k1 = "v1" 
mc.append('k1', 'after')
# k1 = "v1after" 
mc.prepend('k1', 'before')
# k1 = "beforev1after"
1.2.9 decr 和 incr  

incr : 自增,将值增加 N ( N默认为1 )
decr :自减,将值减少 N ( N默认为1 )

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
1.2.10 gets 和 cas

使用缓存系统共享数据资源就必然绕不开数据争夺和脏数据的问题。举个例子:
假设商城某件商品的剩余个数保存在memcache中,product_count = 900
A用户刷新页面从memcache中读取到product_count = 900
B用户刷新页面从memcache中读取到product_count = 900

A、B用户均购买商品,并修改product_count的值:

A用户修改后 product_count=899
B用户修改后 product_count=899
如此一来缓存内的数据便不再正确,实际此时product_count应该等于898.
如果使用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")

本质上每次执行gets时,会从memcache中获取一个自增的数字,通过cas去修改gets的值时,会携带之前获取的自增值和memcache中的自增值进行比较,如果相等,则可以提交;如果不相等,那表示在gets和cas执行之间,又有其他人执行了gets,则不允许修改。

二、redis

Redis是什么?先看其官方介绍:

Redis is an open source (BSD licensed), in-memory data structure store, used as database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs and geospatial indexes with radius queries. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.

巴拉巴拉一堆......
Redis是一个驻扎在内存中的数据存储结构,常用于数据库、缓存和消息代理。它采用先进的 key-value 存储方式,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis的官方网站是:http://www.redis.io/

Redis 与其他同类软件相比有三个不同的特点:

  • Redis是完全在内存中保存数据的数据库,使用磁盘只是为了持久性目的;
  • Redis相比许多键值数据存储系统有相对丰富的数据类型;
  • Redis可以将数据复制到任意数量的从服务器中;

Redis有以下方面的优点:

  • 异常快速 : Redis是非常快的,每秒可以执行大约110000设置操作,81000个/每秒的读取操作。
  • 支持丰富的数据类型 : Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型。
    *操作都是原子的 : 所有 Redis 的操作都是原子,从而确保当两个客户同时访问 Redis 服务器得到的是更新后的值(最新值)。
  • MultiUtility工具:Redis是一个多功能实用工具,可以在很多如:缓存,消息传递队列中使用(Redis原生支持发布/订阅)。
2.1 安装Redis

在 Ubuntu 上安装 Redis:

$sudo apt-get update

$sudo apt-get install redis-server

启动 Redis

$redis-server

查看 redis 是否在运行

$redis-cli

这将打开一个 Redis 提示符,如下所示:

redis 127.0.0.1:6379>

输入 PING 命令

redis 127.0.0.1:6379> ping
PONG

显示上面的内容则说明你已经成功地安装了 Redis。
PS:如果你是在本机的虚拟机内运行redis服务,请在/etc/redis.conf内将bind IP改为0.0.0.0

2.2 安装Python的redis模块

有多种方式可以安装redis模块:

sudo pip3 install redis
or
sudo easy_install redis
or
源码安装
详见:https://github.com/WoLpH/redis-py

redis模块的使用可以分类为:

  • 连接方式
  • 连接池
  • 操作
    • String 操作
    • Hash 操作
    • List 操作
    • Set 操作
    • Sort Set 操作
  • 管道
  • 发布订阅
2.3 redis模块介绍
2.3.1 操作模式

redis提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。

#!/usr/bin/env python
# -*- coding:utf-8 -*- 
import redis
 
r = redis.Redis(host='10.211.55.4', port=6379)
r.set('foo', 'Bar')
print(r.get('foo'))

PS:请将10.211.55.4更换成你所在的redis服务器地址

2.3.2 连接池

redis使用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'))
2.3.3 数据操作
2.3.3.1 通用操作
  • delete(*names)
    删除redis中的任意数据类型

  • exists(name)
    检测redis的name是否存在

  • keys(pattern='*')
    根据正则模式获取redis的name

    KEYS * 匹配数据库中所有 key 。
    KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
    KEYS h*llo 匹配 hllo 和 heeeeello 等。
    KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo

  • expire(name ,time)
    为某个name设置超时时间

  • rename(src, dst)
    对redis的name重命名

  • move(name, db))
    将redis的某个值移动到指定的db下

  • randomkey()
    随机获取一个redis的name(不删除)

  • type(name)
    获取name对应值的类型

  • scan(cursor=0, match=None, count=None)
  • scan_iter(match=None, count=None)
    用于增量迭代获取key

2.3.3.2 String操作

redis中的String在内存中按照一个name对应一个value来存储。

  • set(name, value, ex=None, px=None, nx=False, xx=False)
    在Redis中设置值,不存在则创建,存在则修改

    ex,过期时间(秒)
    px,过期时间(毫秒)
    nx,如果设置为True,则只有name不存在时,当前set操作才执行
    xx,如果设置为True,则只有name存在时,岗前set操作才执行

  • setnx(name, value)
    设置值

    只有name不存在时,执行设置操作(添加)

  • setex(name, value, time)
    设置值

    time,过期时间(数字秒 或 timedelta对象)

  • psetex(name, time_ms, value)
    设置值

    time_ms,过期时间(数字毫秒 或 timedelta对象)

  • mset(*args, **kwargs)
    批量设置值

    mset(k1='v1', k2='v2')
    mget({'k1': 'v1', 'k2': 'v2'})

  • get(name)
    获取值
  • mget(keys, *args)
    批量获取

    mget('ylr', 'jack')

    mget(['ylr', 'jack'])

  • getset(name, value)
    设置新值并获取原来的值

  • getrange(key, start, end)
    获取子序列(根据字节获取,非字符)

    key,Redis 中字符串的 name
    start,起始位置(字节)
    end,结束位置(字节)
    如: "张三丰" ,0-3表示 "张"

  • setrange(name, offset, value)
    修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)

    offset,字符串的索引,字节(一个汉字三个字节)
    value,要设置的值

  • setbit(name, offset, value)
    对name对应值的二进制表示的位进行操作

    name,redis的name
    offset,位的索引(将值变换成二进制后再进行索引)
    value,值只能是 1 或 0
    如果在Redis中有一个对应: n1 = "foo",
    那么字符串foo的二进制表示为:01100110 01101111 01101111
    如果执行 setbit('n1', 7, 1),则就会将第7位设置为1,
    那么最终二进制则变成 01100111 01101111 01101111,即:"goo"

  • getbit(name, offset)
    获取name对应值的二进制表示中的指定位的值 (0或1)
  • bitcount(key, start=None, end=None)
    获取name对应的值的二进制表示中 1 的个数

    key,Redis的name
    start,位起始位置
    end,位结束位置

  • bitop(operation, dest, *keys)
    获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值

    operation,AND(并) ,OR(或) ,NOT(非) , XOR(异或)
    dest, 新的Redis的name
    *keys,要查找的Redis的name
    如:
    bitop("AND", 'new_name', 'n1', 'n2', 'n3')
    获取Redis中n1,n2,n3对应的值,然后将所有的值做位运算,然后将结果保存 new_name 对应的值中。

  • strlen(name)
    返回name对应值的字节长度(一个汉字3个字节)
  • incr(name, amount=1)
    自增 name对应的值,当name不存在时,则创建name=amount。

    name,Redis的name
    amount,自增数(必须是整数)
    同incrby

  • incrbyfloat(name, amount=1.0)
    自增 name对应的值,当name不存在时,则创建name=amount。

    name,Redis的name
    amount,自增数(浮点型)

  • decr(name, amount=1)
    自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。

    name,Redis的name
    amount,自减数(整数)

  • append(key, value)
    在name对应的值后面追加内容

    key, redis的name
    value, 要追加的字符串

2.3.3.3 Hash操作

redis中Hash在内存中的存储格式如下图:

  • hset(name, key, value)
    name对应的hash中设置一个键值对(不存在,则创建;否则,修改)

    key,name对应的hash中的key
    value,name对应的hash中的value

  • hsetnx(name, key, value)
    当name对应的hash中不存在当前key时,则创建(相当于添加)

  • hmset(name, mapping)
    在name对应的hash中批量设置键值对

    mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
    r.hmset('xx', {'k1':'v1', 'k2': 'v2'})

  • hget(name,key)
    在name对应的hash中获取根据key获取value

  • hmget(name, keys, *args)

    在name对应的hash中获取多个key的值
    *args,要获取的key列表,如:['k1', 'k2', 'k3']
    keys,要获取的key,如:k1,k2,k3
    r.mget('xx', ['k1', 'k2'])
    print r.hmget('xx', 'k1', 'k2')

  • hgetall(name)
    获取name对应hash的所有键值

  • hlen(name)
    获取name对应的hash中键值对的个数

  • hkeys(name)
    获取name对应的hash中所有的key的值

  • hvals(name)
    获取name对应的hash中所有的value的值

  • hexists(name, key)
    检查name对应的hash是否存在当前传入的key

  • hdel(name,*keys)
    将name对应的hash中指定key的键值对删除

  • hincrby(name, key, amount=1)
    自增name对应的hash中的指定key的值,不存在则创建key=amount

  • hincrbyfloat(name, key, amount=1.0)
    自增name对应的hash中的指定key的值,不存在则创建key=amount

  • hscan(name, cursor=0, match=None, count=None)
    增量式迭代获取,对于大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而防止内存被撑爆。

    cursor,游标(基于游标分批取获取数据)
    match,匹配指定key,默认None 表示所有的key
    count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
    例如:
    第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None)
    第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None)
    ...
    直到返回值cursor的值为0时,表示数据已经通过分片获取完毕

  • hscan_iter(name, match=None, count=None)
    利用yield封装hscan创建生成器,实现分批去redis中获取数据

    match,匹配指定key,默认None 表示所有的key
    count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
    如:
    for item in r.hscan_iter('xx'):
    print item

2.3.3.4 List操作

redis中的List在内存中按照一个name对应一个List来存储。如图:

  • lpush(name,values)
    在name对应的list中添加元素,每个新的元素都添加到列表的最左边

    r.lpush('oo', 11,22,33)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值