首页 > 代码库 > day13 memcache,redis,myqlachemy
day13 memcache,redis,myqlachemy
memcache
memcache简介
Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。
Memcached是以LiveJournal旗下Danga Interactive公司的Brad Fitzpatric为首开发的一款软件。现在已成为mixi、hatena、Facebook、Vox、LiveJournal等众多服务中提高Web应用扩展性的重要因素。
Memcached是一种基于内存的key-value存储,用来存储小块的任意数据(字符串、对象)。这些数据可以是数据库调用、API调用或者是页面渲染的结果。
Memcached简洁而强大。它的简洁设计便于快速开发,减轻开发难度,解决了大数据量缓存的很多问题。它的API兼容大部分流行的开发语言。
本质上,它是一个简洁的key-value存储系统。通过socket连接和发送命令
一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。
特征
协议简单
基于libevent的事件处理
内置内存存储方式
memcached不互相通信的分布式
memcached安装
参考安装链接地址:http://www.runoob.com/memcached/window-install-memcached.html
当前安装方法:
[root@centos6 ~]# yum install memcached -y [root@centos6 ~]# memcached -d -m 10 -u root -l 172.1.1.7 -p 11211 –P /tmp/memcached.pid #启动
参数说明:
-
d 是启动一个守护进程
-
m 是分配给Memcache使用的内存数量,单位是MB
-
u 是运行Memcache的用户
-
l 是监听的服务器IP地址
-
p 是设置Memcache监听的端口,最好是
1024
以上的端口
-
c 选项是最大运行的并发连接数,默认是
1024
,按照你服务器的负载量来设定
-
P 是设置保存Memcache的pid文件
python操作memcached:
- 安装API:
python操作Memcached使用Python-memcached模块 下载安装:https://pypi.python.org/pypi/python-memcached
- python操作memcached
#!/usr/bin/env python # -*- coding:utf-8 -*- import memcache memc=memcache.Client([‘172.1.1.7:11211‘],debug=True) #连接远程mencache memc.set(‘key1‘,‘value1‘) #写入键值对 rec=memc.get(‘key1‘) #按照key读取参数 print(rec)
- 连接memcached集群
memc=memcache.Client([(‘172.1.1.6:11211’,1),(‘172.1.1.2:11211’,2)],debug=True)
权重的计算:
python-memcached模块原生支持集群操作,其原理是在内存维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比;
如果用户根据如果要在内存中创建一个键值对(如:k1 = "v1"),那么要执行一下步骤:
- 根据算法将 k1 转换成一个数字
- 将数字和主机列表长度求余数,得到一个值 N( 0 <= N < 列表长度 )
- 在主机列表中根据 第2步得到的值为索引获取主机,例如:host_list[N]
- 连接 将第3步中获取的主机,将 k1 = "v1" 放置在该服务器的内存中
- add操作
#!/usr/bin/env python # -*- coding:utf-8 -*- import memcache #添加一条键值对,如果已经存在的 key,重复执行add操作异常 memc = memcache.Client([‘172.1.1.7:11211‘],debug=True) #连接memcache服务端 memc.add(‘k1‘,‘v1‘) #添加参数 # memc.add(‘k1‘,‘v2‘)
- replace操作
#!/usr/bin/env python # -*- coding:utf-8 -*- import memcache #replace 修改某个key的值,如果key不存在,则异常 memc=memcache.Client([‘172.1.1.7:11211‘],debug=True) memc.replace(‘k1‘,‘vvvv‘) kk=memc.get(‘k1‘) print(kk)
- set&set_multi
- set 设置一个键值对,如果key不存在,则创建,
- 如果key存在,可以修改 set_multi 设置多个键值对,如果key不存在,则创建,如果key存在,可以修改
#!/usr/bin/env python # -*- coding:utf-8 -*- import memcache memc=memcache.Client([‘172.1.1.7:11211‘],debug=True) #memc.set(‘s1‘,‘t1‘) memc.set_multi({‘s2‘:‘k2‘,‘s3‘:‘k3‘}) #千万要记住此处是引号
- delete&delete_multi
- delete 在Memcached中删除指定的一个键值对
- delete_multi 在Memcached中删除指定的多个键值对
#!/usr/bin/env python # -*- coding:utf-8 -*- import memcache memc = memcache.Client([‘172.1.1.7:11211‘],debug=True) #memc.delete(‘s1‘)
memc.delete_multi([‘s2‘,‘s3‘])
- get&get_multi
- get 获取一个键值对
- get_multi 获取多个或者一个键值对
#!/usr/bin/env python # -*- coding:utf-8 -*- import memcache memc=memcache.Client([‘172.1.1.7:11211‘],debug=True) val1 = memc.get(‘s1‘) #取的值不存在就为None print(val1) val2 = memc.get_multi([‘s1‘,‘s2‘,‘s3‘]) print(val2)
- append&prepend
- append 修改指定key的值,在该值 后面 追加内容
prepend 修改指定key的值,在该值 前面 插入内容
- append 修改指定key的值,在该值 后面 追加内容
#!/usr/bin/env python # -*- coding:utf-8 -*- import memcache memc = memcache.Client([‘172.1.1.7:11211‘],debug=True) memc.append(‘s7‘,‘after‘) memc.prepend(‘s7‘,‘before‘) t=memc.get(‘s7‘) print(t)
decr&incr
- incr 自增,将Memcached中的某一个值增加 N ( N默认为1 )
decr 自减,将Memcached中的某一个值减少 N ( N默认为1 )
#!/usr/bin/env python # -*- coding:utf-8 -*- import memcache memc=memcache.Client([‘172.1.1.7:11211‘],debug=True) memc.set(‘k1‘,‘789‘) t1=memc.incr(‘k1‘) print(t1) t2=memc.decr(‘k1‘) print(t2)
- 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 memc=memcache.Client([‘172.1.1.7:11211‘],debug=True) v=memc.gets(‘product_count‘) memc.cas(‘product_count‘,‘211‘) #再次修改则会出错 print(v) memc.cas(‘product_count‘,‘122‘) #设定值
本质上每次执行gets时,会从memcache中获取一个自增的数字,通过cas去修改gets的值时,会携带之前获取的自增值和memcache中的自增值进行比较,如果相等,则可以提交,如果不想等,那表示在gets和cas执行之间,又有其他人执行了gets(获取了缓冲的指定值), 如此一来有可能出现非正常数据,则不允许修改。
redis
- 简介:
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
- redis的安装
[root@centos6 opt]# tar xf redis-3.0.3.tar.gz [root@centos6 opt]# mv redis-3.0.3 redis [root@centos6 opt]# cd redis [root@centos6 redis]# make && make install
[root@centos6 redis]# /opt/redis/src/redis-server /opt/redis/redis.conf & #启动服务
- 客户端操作
[root@centos6 ~]# /opt/redis/src/redis-cli #客户端连接 127.0.0.1:6379> set ‘foo‘ ‘bar‘ #设定键值对 OK 127.0.0.1:6379> get ‘foo‘ #按照key取出值 "bar"
- python操作redis
- 连接方式
- 连接池
- 操作
- String 操作
- Hash 操作
- List 操作
- Set 操作
- Sort Set 操作
- 管道
- 发布订阅
redis-py 的API的使用可以分类为:
连接方式
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) #创建连接 red.set(‘foo‘,‘bar‘) #存入键值对 print(red.get(‘foo‘)) #按照key取出值
连接池
redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.ConnectionPool(host=‘172.1.1.7‘,port=6379) #创建连接池 poo=redis.Redis(connection_pool=red) #创建连接 poo.set(‘hello‘,‘nimei‘) print(poo.get(‘hello‘))
操作
set(name, value, ex=None, px=None, nx=False, xx=False)
在Redis中设置值,默认,不存在则创建,存在则修改
参数:
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有name不存在时,当前set操作才执行
xx,如果设置为True,则只有name存在时,当前set操作才执行
- setnx:设置值,只有name不存在时,执行设置操作(添加)
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red = redis.Redis(host=‘172.1.1.7‘,port=6379) r=red.setnx(‘kk‘,‘vv‘) #setnx设置值,只有name不存在时,执行设置操作(添加) print(red.get(‘kk‘)) #打印key对应的值
- setex:设置超时时间(超时时间过后,key value失效)
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis import time red = redis.Redis(host=‘172.1.1.7‘,port=6379) red.setex(‘kk1‘,‘vv1‘,2) #设置有效时长为2 print(red.get(‘kk1‘)) time.sleep(3) #3秒超时 print(red.get(‘kk1‘)) #返回值为空
- mset&mget:批量设置值
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k6‘,‘v7‘) #单个设值 red.mset(k1=‘v1‘,k2=‘v2‘,k3=‘v3‘) #第一种方法设值 red.mset({‘k4‘:‘v4‘,‘k5‘:‘v5‘}) #第二种方法 print(red.mget(‘k1‘,‘k2‘)) #多个取值 print(red.get(‘k3‘)) #单个取值
- getset:设置新值并获取原来的值
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red = redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k1‘,‘vvv‘) print(red.getset(‘k1‘,‘afternew‘)) #设置新值,返回旧值 print(red.get(‘k1‘)) #此时是新值
- getrange:获取子序列
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k1‘,‘我爱北京天安门‘) tt=red.getrange(‘k1‘,0,3) print(red.getrange(‘k1‘,0,3)) #汉子的话是每三个字节算一个汉子
- setrange(name, offset, value):修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k1‘,‘我爱北京天安门‘) print(red.setrange(‘k1‘,3,‘hah‘))
- setbit(name, offset, value):对name对应值的二进制表示的位进行操作
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k1‘,‘vava‘) red.setbit(‘k1‘,7,1) #将第七位设置成一 print(red.get(‘k1‘))
source = "哈哈哈" for i in source: num=ord(i) print(bin(num).replace(‘b‘,‘‘)) #打印二进制格式字符串
- getbit(name, offset):获取name对应的值的二进制表示中的某位的值 (0或1)
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k1‘,‘abc‘) print(red.getbit(‘k1‘,2))
- bitcount(key, start=None, end=None):获取name对应的值的二进制表示中 1 的个数
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k1‘,‘abc‘) print(red.bitcount(‘k1‘,0,8))
- bitop(operation, dest, *keys):获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
- 参数:
- operation:AND,OR,NOT,XOR
- dest:new data
- src:source data
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k1‘,‘abc‘) print(red.bitop(‘AND‘,‘kk‘,‘k1‘))
- strlen(name):返回name对应值的字节长度(一个汉字3个字节)
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k1‘,‘abc‘) print(red.strlen(‘k1‘))
- incr(self, name, amount=1):自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis red=redis.Redis(host=‘172.1.1.7‘,port=6379) red.set(‘k1‘,‘12345‘) #确保value是整数 print(red.incr(‘k1‘,amount=1))
day13 memcache,redis,myqlachemy