Memcached
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。
存储方式
保存键值对发生变动的情况:
- 为缓存分配的内存耗尽。这种情况下,memcached使用LRU(最近最少使用)算法从此缓存中删除条目。最近未曾使用的条目会从此缓存中先删除,最旧的最先访问。
- 条目被确定删除, 如程序中删除。
- 条目过期失效
Memcached安装和基本使用
语法
1
|
telnet HOST PORT |
实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
telnet 127.0.0.1 11211 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. set foo 0 0 3 保存命令 bar 数据 STORED 结果 get foo 取得命令 VALUE foo 0 3 数据 bar 数据 END 结束行 quit |
Memcached安装:
#1. 安装服务 # apt-get install memcached -y #2. 修改配置文件 # sed -i 's@(^-l).*@1 172.17.0.1@g' /etc/memcached.conf # PS: 默认memcached监听在127.0.0.1, 如果本机使用的话,此步骤可以略去,建议将memcached监听在私有网段网卡上,并配合相应的安全访问控制,稍后续. #重启服务: # /etc/init.d/memcached restart # 查看启动状态: # ps -ef|grep memcached # 查看端口监听: # ss -tnlp|grep 11211 # 官网地址:https://memcached.org/ # 解压缩: tar xf memcached-1.4.15.tar.gz && cd memcached-1.4.15 # 编译 ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent make && make install
#!/bin/bash # # Init file for memcached # chkconfig: - 86 14 # description: Distributed memory caching daemon # processname: memcached # config: /etc/sysconfig/memcached . /etc/rc.d/init.d/functions ## Default variables PORT="11211" USER="nobody" MAXCONN="1024" CACHESIZE="64" OPTIONS="" RETVAL=0 prog="/usr/local/memcached/bin/memcached" desc="Distributed memory caching" lockfile="/var/lock/subsys/memcached" start() { echo -n $"Starting $desc (memcached): " daemon $prog -d -p $PORT -u $USER -c $MAXCONN -m $CACHESIZE -o "$OPTIONS" RETVAL=$? echo [ $RETVAL -eq 0 ] && touch $lockfile return $RETVAL } stop() { echo -n $"Shutting down $desc (memcached): " killproc $prog RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f $lockfile return $RETVAL } restart() { stop start } reload() { echo -n $"Reloading $desc ($prog): " killproc $prog -HUP RETVAL=$? echo return $RETVAL } case "$1" in start) start ;; stop) stop ;; restart) restart ;; condrestart) [ -e $lockfile ] && restart RETVAL=$? ;; reload) reload ;; status) status $prog RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|condrestart|status}" RETVAL=1 esac exit $RETVAL
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 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 参数说明: -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..
Python操作Memcached
安装API
1
2
|
python操作Memcached使用Python - memcached模块 下载安装:https: / / pypi.python.org / pypi / python - memcached |
1、python操作memcached
# /usr/bin/env python # -*- coding:utf8 -*- # auth rain
import memcache mc = memcache.Client(['127.0.0.1:12000'], debug=True) mc.set('key','values') resutl = mc.get('key') print(resutl) ------------------------------------ values
Ps:debug = True 表示运行出现错误时,现实错误信息,上线后移除该参数。
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"),那么要执行一下步骤:
- 根据算法将 k1 转换成一个数字
- 将数字和主机列表长度求余数,得到一个值 N( 0 <= N < 列表长度 )
- 在主机列表中根据 第2步得到的值为索引获取主机,例如:host_list[N]
- 连接 将第3步中获取的主机,将 k1 = "v1" 放置在该服务器的内存中
代码如下:
mc = memcache.Client([('172.16.30.162:11211',2),('172.16.30.163:11211',1),('172.16.30.164:11211',1)],debug=1) mc.set('key','values') # 设置一个key, 值为values result = mc.get('key') # 获取key值 print(result) --------------------------------------- values
3、add
添加一条键值对,如果已经存在的 key,重复执行add操作异常
import memcache mc = memcache.Client(['127.0.0.1:12000'], debug=True) mc.set('key','values') resutl = mc.get('key') print(resutl) mc.add('k3','v3') a = mc.get('k3') print(a) mc.add('k3','v3') # MemCached: while expecting 'STORED', got unexpected response 'NOT_STORED'
4、replace
replace 修改某个key的值,如果key不存在,则异常
import memcache mc = memcache.Client(['127.0.0.1:12000'], debug=True) mc.set('key','values') resutl = mc.get('key') print(resutl) # values mc.replace('key','values123') result1 = mc.get('key') print(result1) # values123 mc.replace('123','abcd') # MemCached: while expecting 'STORED', got unexpected response 'NOT_STORED'
5、set 和 set_multi
set 设置一个键值对,如果key不存在,则创建,如果key已经存在,则更新key值
set_multi 设置多个键值对,如果key不存在,则创建,如果key已经存在,则更新key值
# /usr/bin/env python # -*- coding:utf8 -*- # auth rain import memcache mc = memcache.Client(['127.0.0.1:12000'], debug=True) mc.set('k1','v1') result2 = mc.get('k1') print(result2) # v1 mc.set_multi({'key':'values', 'key1':'values123'}) resutl = mc.get_multi(['key', 'key1']) print(resutl) # {'key': 'values', 'key1': 'values123'}
6、delete 和 delete_multi
delete 在Memcached中删除指定的一个键值对
delete_multi 在Memcached中删除指定的多个键值对
# /usr/bin/env python # -*- coding:utf8 -*- # auth rain import memcache mc = memcache.Client(['127.0.0.1:12000'], debug=True) mc.set('k1','v1') result2 = mc.get('k1') print(result2) # v1 mc.set_multi({'key':'values', 'key1':'values123'}) resutl = mc.get_multi(['key', 'key1']) print(resutl) # {'key': 'values', 'key1': 'values123'} mc.delete('k1') result3 = mc.get('k1') print(result3) # None mc.delete_multi(['key','key1']) result4 = mc.get_multi(['key','key1']) print(result4) # {} mc.delete_multi(['key','key1']) result5 = mc.get_multi(['key','key1']) print(result5) # MemCached: while expecting 'DELETED', got unexpected response 'NOT_FOUND' # MemCached: while expecting 'DELETED', got unexpected response 'NOT_FOUND'
7、get 和 get_multi
get 获取一个键值对
get_multi 获取多一个键值对
import memcache mc = memcache.Client(['127.0.0.1:12000'], debug=True) mc.set('k1','v1') result2 = mc.get('k1') print(result2) # v1 mc.set_multi({'key':'values', 'key1':'values123'}) resutl = mc.get_multi(['key', 'key1']) print(resutl) # {'key': 'values', 'key1': 'values123'}
8、append 和 prepend
append 修改指定key的值,在该值 后面 追加内容
prepend 修改指定key的值,在该值 前面 插入内容
# /usr/bin/env python # -*- coding:utf8 -*- # auth rain import memcache mc = memcache.Client(['127.0.0.1:12000'], debug=True) mc.set('k1','v1') result2 = mc.get('k1') print(result2) # v1 mc.append('k1','after') result = mc.get('k1') print(result) # v1after mc.prepend('k1', 'before') result1 = mc.get('k1') print(result1) # beforev1after
9、decr 和 incr
incr 自增,将Memcached中的某一个值增加 N ( N默认为1 )
decr 自减,将Memcached中的某一个值减少 N ( N默认为1 )
# /usr/bin/env python # -*- coding:utf8 -*- # auth rain import memcache mc = memcache.Client(['127.0.0.1:12000'], debug=True) mc.set('k1',100) # 先设置原始值为100 result2 = mc.get('k1') print(result2) # 100 mc.incr('k1') #自增1, 结果为101 result = mc.get('k1') print(result) # 101 mc.decr('k1',2) # 自减2,默认为1,可以不写 result1 = mc.get('k1') print(result1) # 99
10、gets 和 cas
gets 获取带有CAS令牌存储的value(数据值) , 如果key 不存在,则返回空
语法:
gets key
多个key使用空格分开:
gets key1 key2 key3 ..
cas (compare-And-Swap) 用于执行一个"检查并设置" 的操作。它仅在当前客户端最后一次取值后,该key对应的值没有被其他客户端修改的情况下,才能够将值写入。检查是通过cas_token参数进行的,这个参数是memcached指定给已经存在的元素的一个唯一的64位的值。
语法:
cas key flags exptime bytes unique_cas_token [noreply]
value
- key:键值 key-value 结构中的 key,用于查找缓存值。
- flags:可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息 。
- exptime:在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)
- bytes:在缓存中存储的字节数
- unique_cas_token通过 gets 命令获取的一个唯一的64位值。
- noreply(可选): 该参数告知服务器不需要返回数据
- value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)
如商城商品剩余个数,假设改值保存在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(获取了缓冲的指 定值), 如此一来有可能出现非正常数据,则不允许修改。
memcached统计命令:
stats
用于返回统计信息,如PID、版本号、连接数等:
root@test2-ubunut:~/.aliyuncli# telnet localhost 11211 Trying ::1... Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. stats STAT pid 9720 STAT uptime 346412 STAT time 1469082312 STAT version 1.4.14 (Ubuntu) STAT libevent 2.0.21-stable STAT pointer_size 64 STAT rusage_user 9.024617 STAT rusage_system 5.018162 STAT curr_connections 7 STAT total_connections 41 STAT connection_structures 8 STAT reserved_fds 20 STAT cmd_get 51 STAT cmd_set 34 STAT cmd_flush 0 STAT cmd_touch 0 STAT get_hits 39 STAT get_misses 12 STAT delete_misses 2 STAT delete_hits 3 STAT incr_misses 0 STAT incr_hits 6 STAT decr_misses 0 STAT decr_hits 5 STAT cas_misses 0 STAT cas_hits 0 STAT cas_badval 0 STAT touch_hits 0 STAT touch_misses 0 STAT auth_cmds 0 STAT auth_errors 0 STAT bytes_read 1431 STAT bytes_written 2535 STAT limit_maxbytes 67108864 STAT accepting_conns 1 STAT listen_disabled_num 0 STAT threads 4 STAT conn_yields 0 STAT hash_power_level 16 STAT hash_bytes 524288 STAT hash_is_expanding 0 STAT expired_unfetched 0 STAT evicted_unfetched 0 STAT bytes 304 STAT curr_items 4 STAT total_items 38 STAT evictions 0 STAT reclaimed 0 END
stats items
用于显示各个slab中item的数目和存储时长(最后一次访问距离到现在的秒数).
语法:
stats items
stats items STAT items:1:number 4 STAT items:1:age 4105 STAT items:1:evicted 0 STAT items:1:evicted_nonzero 0 STAT items:1:evicted_time 0 STAT items:1:outofmemory 0 STAT items:1:tailrepairs 0 STAT items:1:reclaimed 0 STAT items:1:expired_unfetched 0 STAT items:1:evicted_unfetched 0 END
stats slabs
显示各个slab的信息,包括chunk的大小、数目、使用情况等。
语法:
stats slab
stats slabs STAT 1:chunk_size 96 STAT 1:chunks_per_page 10922 STAT 1:total_pages 1 STAT 1:total_chunks 10922 STAT 1:used_chunks 5 STAT 1:free_chunks 10917 STAT 1:free_chunks_end 0 STAT 1:mem_requested 384 STAT 1:get_hits 39 STAT 1:cmd_set 34 STAT 1:delete_hits 3 STAT 1:incr_hits 6 STAT 1:decr_hits 5 STAT 1:cas_hits 0 STAT 1:cas_badval 0 STAT 1:touch_hits 0 STAT active_slabs 1 STAT total_malloced 1048512 END
stats sizes
显示所有item和的大小和个数
返回两列,第一列是item大小,第二列是item的个数
stats sizes
STAT 96 4
END
flush_all
该命令用于清空缓存中的所有 key/value, 提供了一个可选参数 time, 用于在指定的时间后执行清理缓存操作。
语法:
flush_all [time] [noreply]
flush_all
OK