memcached是什么?
memcached是一个高性能的分布式内存对象缓存系统,用于动态web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于键值对的存储。其守护进程是用C写的,但客户端可以用任何语言来编写。
memcached和memcache的关系
简单来说,可以把memcached看成是memcache的升级版。memcache和memcached分别依赖libmemcache(原生)和libmemcached操作库开发的。而libmemcached操作库使用比较安全,且内存消耗小。
安装memcached服务
使用memcached是由一个服务端和一个客户端进行的。首先我们需要下载开启memcached的服务。
安装memcached
apt-get install memcached
启动memcached
memcached -d -m 64m -p 11211
参数 | 描述 |
---|---|
-d | 启动一个守护进程 |
-m | 分配给memcache使用的内存数量,单位是MB |
-u | 运行memcache的用户 |
-l | 监听的服务器ip地址 |
-p | 设置memcache的监听端口,最好是1024以上的端口 |
-c | 最大运行的并发连接数,默认是1024 |
-P | 设置保存memcache的pid文件 |
使用telnet命令可查看memcache服务是否开启 |
telnet 127.0.0.1 11211
若出现以下情况即为memcache服务开启成功
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
memcached与Python
当memcache服务安装开启后,就可以使用python作为客户端对memcache进行操作
首先安装python-memcached模块
pip install python-memcached
导入memcache模块
>>> import memcache
连接到一台memcache服务器
>>> conn = memcache.Client(['127.0.0.1:11211'])
对memcache的操作
# set方法添加一个键值对,如果已存在,则会覆盖掉
>>> conn.set('key','value')
True
# get方法获取值
>>> conn.get('key')
value
# add方法添加一个不存在的键值对,如果存在,则会返回False
>>> conn.set('key','new')
False
>>> conn.get('key')
value
# replace方法修改值,若key不存在则返回False
>>> conn.replace('key','replace')
True
>>> conn.get('key')
replace
>>> conn.replace('keyk','valuev')
False
# append方法在指定key的值后面追加内容
>>> conn.append('key','end')
True
>>> conn.get('key')
replaceend
# prepend方法在指定key的值前面追加内容
>>> conn.prepend('key','start')
True
>>> conn.get('key')
startreplaceend
# set方法设置超时时间,以秒为单位
>>> conn.set('k','time',1)
True
>>> conn.get('k')
>>>
# set_multi方法批量添加键值对,不存在就创建,存在就覆盖
>>> conn.set_multi({'key1':'value1','key2':'value2'})
[]
# get_multi方法批量获取值
>>> conn.get_multi(['key1','key2'])
{'key1':'value1','key2':'value2'}
# delete方法删除值
>>> conn.delete('key1')
1
# delete_multi方法批量删除值
>>> conn.delete_multi(['key','key2'])
1
# incr方法自增,默认增长量为1
>>> conn.set('k','1')
True
>>> conn.incr('k')
2
>>> conn.incr('k',5)
7
# decr方法自减,默认减少量为1
>>> conn.decr('k')
6
>>> conn.decr('k',5)
1
gets与cas
CAS(Check And Set)是乐观锁的一种算法,即不加锁的算法。
如果不采用CAS,则有如下的情景:
第一步,A取出数据对象X;
第二步,B取出数据对象X;
第三步,B修改数据对象X,并将其放入缓存;
第四步,A修改数据对象X,并将其放入缓存。
我们可以发现,第四步中会产生数据写入冲突。
如果采用CAS协议,则是如下的情景。
第一步,A取出数据对象X,并获取到CAS-ID1;
第二步,B取出数据对象X,并获取到CAS-ID2;
第三步,B修改数据对象X,在写入缓存前,检查CAS-ID与缓存空间中该数据的CAS-I
D是否一致。结果是“一致”,就将修改后的带有CAS-ID2的X写入到缓存。
第四步,A修改数据对象Y,在写入缓存前,检查CAS-ID与缓存空间中该数据的CAS-ID是否一致。结果是“不一致”,则拒绝写入,返回存储失败。
我们可以通过重试,或者其他业务逻辑解决第四步设置失败的问题。
# --s1.py
import memcache
# 连接时设置debug=True以查看错误信息,设置cache_cas=True打开乐观锁
conn = memcache.Client(['127.0.0.1'], debug=True, cache_cas=True)
conn.set('k','9')
# gets获取到值并得到cas码
rs = conn.gets('k')
print(rs)
# 阻塞
input('>>>')
# 检查cas码并设置值
conn.cas('k','cas1')
# --s2.py
import memcache
# 连接时设置debug=True以查看错误信息,设置cache_cas=True打开乐观锁
conn = memcache.Client(['127.0.0.1'], debug=True, cache_cas=True)
conn.set('k','9')
# gets获取到值并得到cas码
rs = conn.gets('k')
print(rs)
# 阻塞
input('>>>')
# 检查cas码并设置值
conn.cas('k','cas2')
多节点数据存储流程
当启动了多个memcached服务,我们存储的数据在哪个节点上呢?
- 先将一个字符串转换为一个数字
- 得出的结果和节点的数量进行除法运算
- 得出的结果肯定在节点数量之间,余数是几,就在那台节点上面存放数据