Python基础篇【第12篇】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy
Posted on 2016-01-20 23:03 salibra 阅读(128) 评论(0) 收藏 举报1. Memcache
1.1 简介
官网:http://memcached.org/
Github:https://github.com/memcached/memcached
官方定义:Free & open source, high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。
Memcache只支持一种数据格式,就是key:value的格式
1.2 特征
协议简单
它是基于文本行的协议,直接通过telnet在memcached服务器上可进行存取数据操作
基于libevent事件处理
Libevent是一套利用C开发的程序库,它将BSD系统的kqueue,Linux系统的epoll等事件处理功能封装成一个接口,与传统的select相比,提高了性能。
内置的内存管理方式
所有数据都保存在内存中,存取数据比硬盘快,当内存满后,通过LRU算法自动删除不使用的缓存,但没有考虑数据的容灾问题,重启服务,所有数据会丢失。
分布式
各个memcached服务器之间互不通信,各自独立存取数据,不共享任何信息。服务器并不具有分布式功能,分布式部署取决于memcache客户端。
自身不支持持久化
由于自身机制限制,memcache不支持持久化,但是可以利用其他方式将数据读出写入到需要保存的地方,当memcache宕机后重新加入到系统中时,再进行预热,将数据重新写入memcache中。
在 Memcached中可以保存的item数据量是没有限制的,只要内存足够 。
Memcached单进程在32位系统中最大使用内存为2G,若在64位系统则没有限制,这是由于32位系统限制单进程最多可使用2G内存,要使用更多内存,可以分多个端口开启多个Memcached进程 ,
最大30天的数据过期时间,设置为永久的也会在这个时间过期,常量REALTIME_MAXDELTA=60*60*24*30控制
最大键长为250字节,大于该长度无法存储,常量KEY_MAX_LENGTH=250控制
单个item最大数据是1MB,超过1MB数据不予存储,常量POWER_BLOCK=1048576进行控制,它是默认的slab大小
最大同时连接数是200,通过 conn_init()中的freetotal进行控制,最大软连接数是1024,通过settings.maxconns=1024 进行控制
跟空间占用相关的参数:settings.factor=1.25, settings.chunk_size=48, 影响slab的数据占用和步进方式
memcached是一种无阻塞的socket通信方式服务,基于libevent库,由于无阻塞通信,对内存读写速度非常之快。
memcached分服务器端和客户端,可以配置多个服务器端和客户端,应用于分布式的服务非常广泛。
memcached作为小规模的数据分布式平台是十分有效果的。
memcached是键值一一对应,key默认最大不能超过128个字 节,value默认大小是1M,也就是一个slabs,如果要存2M的值(连续的),不能用两个slabs,因为两个slabs不是连续的,无法在内存中 存储,故需要修改slabs的大小,多个key和value进行存储时,即使这个slabs没有利用完,那么也不会存放别的数据。
memcached已经可以支持C/C++、Perl、PHP、Python、Ruby、Java、C#、Postgres、Chicken Scheme、Lua、MySQL和Protocol等语言客户端。
1.3 安装和基本使用
安装memcache
wget http://memcached.org/latest tar -zxvf memcached-1.x.x.tar.gz cd memcached-1.x.x ./configure && make && make test && sudo make install PS:依赖libevent CentOS:yum install libevent-devel Ubuntu:apt-get install libevent-dev
启动memcache
memcached -d -m 10 -u root -l 10.211.55.4 -p 12000 -c 256 -P /tmp/memcached.pid 参数说明: -d 是启动一个守护进程 -m 是分配给Memcache使用的内存数量,单位是MB -u 是运行Memcache的用户 -l 是监听的服务器IP地址 -p 是设置Memcache监听的端口,最好是1024以上的端口 -c 选项是最大运行的并发连接数,默认是1024,按照你服务器的负载量来设定 -P 是设置保存Memcache的pid文件
存储命令
存储命令的格式:
<command name> <key> <flags> <exptime> <bytes>
<data block>
格式参数说明

命令使用教程:http://www.cnblogs.com/jeffwongishandsome/archive/2011/11/06/2238265.html
Python操作memcache常用方法:
2.1 简单操作Python
import memcache #导入python memcache模块 mc = memcache.Client(['10.211.55.4:12000'], debug=True) #创建memcache连接,IP:port 用引号引起来,再用中括号括起来。 #debug=True,设置出错时显示信息,线上环境无需 mc.set("key1", "value1") ret = mc.get('foo') print ret
2.2 memcache模块集群模式支持
Python-memcached模块默认支持memcache的集群操作,其原理是在内存维护一个memcache主机列表,且集群中主机的权重值和主机列表中重复出现的次数成正比。
理解代码如下:
主机 权重 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"),那么要执行一下步骤:
- 根据算法将 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) #用小括号将 ('IP:PORT',weight) 为一个单位 mc.set('k1', 'v1')
#存储时根据上边的算法计算到某台机器写入,取出时同样的算法算出机器,取出数据即可。
2.3 add
添加一条键值对
1.如内存中不存在该键值对,则 添加到内存中
2.如果已经存在的 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重复添加,失败!!!
2.4 replace
replace 修改某个key的值
1.如果key存在,则正常替换
2.如果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')
2.5 set 和 set_multi
set 设置一个键值对,如果key不存在,则创建(相当于add);如果key存在,则修改(相当于replace);
set_multi 设置多个键值对,如果key不存在,则创建(相当于add);如果key存在,则修改(相当于replace);
#!/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'})
#一次性添加多个,格式为字典键值对格式
2.6 delete 和 delete_multi
delete 在Memcached中删除指定的一个键值对
delete_multi 在Memcached中删除指定的多个键值对
由于memcache中数据key都是唯一的,所以删除时只需给出key值即可。
#!/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'])
2.7 get 和 get_multi
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"])
#被get_multi的key用引号引起来,且是列表格式
2.8 append 和 prepend
append 修改指定key的值,在该值 后面 追加内容
prepend 修改指定key的值,在该值 前面 插入内容
注:不是追加key-value键值对,而是直接修改value,追加到value中。
#!/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"
2.9、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,后边的10为步长 mc.decr('k1') # k1 = 787 mc.decr('k1', 10) # k1 = 777
2.10、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 即可
原理说明:本质上每次执行gets修改数据时,会从memcache中获取一个自增的数字cas_id,通过cas去修改gets的值时,会将之前获取的自增值和memcache中的自增值进行比较,如果相等,则可以提交;如果不想等(其它用户进行了cas操作),那表示在gets和cas执行之间,又有其他人执行了gets(获取了缓冲的指定值), 如此一来有可能出现非正常数据,则不允许修改。
#!/usr/bin/env python # -*- coding:utf-8 -*- import memcache,time mc = memcache.Client(['192.168.56.136:11211'], debug=True, cache_cas=True) mc.set('k1','01') ################## v = mc.gets('k1') print "value:",v print mc.cas_ids
####################
mc.cas('k1', "02") v = mc.gets('k1') print "value:",v print mc.cas_ids
结果为:
value: 01 #第一次获取到的value
{'k1': 83} #第一次的内部id
value: 02 #第二次修改后获取道德value
{'k1': 84} #经过一次cas修改后的内部id
浙公网安备 33010602011771号