python 操作memcached

Memcached

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

memcached作为高速运行的分布式缓存服务器,具有以下的特点。
  · 协议简单
  · 基于libevent的事件处理
  · 内置内存存储方式
  · memcached不互相通信的分布式

存储方式

为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据消失。另外,内容容量达到指定值之后,就基于LRU(Least Recently Used,最近最少使用)算法自动删除不使用的缓存。memcached本身是为缓存而设计的服务器,因此并没有过多考虑数据的永久性问题。

保存键值对发生变动的情况:

  • 为缓存分配的内存耗尽。这种情况下,memcached使用LRU(最近最少使用)算法从此缓存中删除条目。最近未曾使用的条目会从此缓存中先删除,最旧的最先访问。
  • 条目被确定删除, 如程序中删除。
  • 条目过期失效
主要功能:
  服务器参数监控:STATS、SETTINGS、ITEMS、SLABS、SIZES实时刷新
  服务器性能监控:GET、DELETE、INCR、DECR、CAS等常用操作命中率实时监控
  支持数据遍历,方便对存储内容进行监视
  支持条件查询,筛选出满足条件的KEY或VALUE
  数组、JSON等序列化字符反序列显示
  兼容memcache协议的其他服务,如Tokyo Tyrant (遍历功能除外)
  支持服务器连接池,多服务器管理切换方便简洁

Memcached安装和基本使用

Memcached 连接

编辑
我们可以通过 telnet 命令并指定主机ip和端口来连接 Memcached 服务。[3] 

语法

1
telnet HOST PORT
命令中的HOST和PORT为运行 Memcached 服务的 IP 和 端口。

实例

以下实例演示了如何连接到 Memcached 服务并执行简单的 set 和 get 命令。
本实例的 Memcached 服务运行的主机为 127.0.0.1(本机) 、端口为 11211。
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
ubuntu 安装
#!/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
memcached 系统启动脚本
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
View Code

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
View Code

 

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
View Code

stats sizes 

显示所有item和的大小和个数

返回两列,第一列是item大小,第二列是item的个数

stats sizes
STAT 96 4
END

flush_all  

该命令用于清空缓存中的所有 key/value, 提供了一个可选参数 time, 用于在指定的时间后执行清理缓存操作。

语法:

flush_all [time] [noreply]
flush_all
OK

 

posted @ 2016-07-20 17:24  yxy_linux  阅读(329)  评论(0编辑  收藏  举报