The result of tag: (1 results)

在Python中用Memcached作缓存

by LauCyun Dec 21,2017 23:04:13 11,471 views

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


图片来源:互联网

Memcached官网:http://memcached.org

1 安装与运行Memcached

Memcached支持许多平台:Linux、BSD、Mac OS,也可以安装在Windows上。

Linux系统安装Memcached,首先要先安装libevent库。

# Ubuntu/Debia
sudo apt-get install -y libevent libevent-deve
# Redhat/Fedora/Centos
yum install -y libevent libevent-deve

自动安装

Ubuntu/Debian:

sudo apt-get install memcached

Redhat/Fedora/Centos:

yum install memcached

源代码安装

从其官方网站下载Memcached最新版本:

wget -c http://memcached.org/latest  # 下载最新版本
tar -zxvf memcached-1.x.x.tar.gz     # 解压源码
cd memcached-1.x.x                   # 进入目录
./configure                          # 配置
make && make test                    # 编译
sudo make install                    # 安装

运行Memcached

memcached -m 256 -u root -p 11211 -l 127.0.0.1 -c 128 -P /tmp/memcached.pid -d

参数说明:

  • -m:分配给memcached使用的内存数量,单位是MB,默认是64MB;
  • -u:运行memcached的用户;
  • -p:设置memcached监听的端口,最好是1024以上的端口,默认是11211;
  • -l:监听的服务器IP地址,可以有多个地址;
  • -c:选项是最大运行的并发连接数,默认是1024,按照你服务器的负载量来设定;
  • -P:设置保存memcached的pid文件;
  • -d:启动一个守护进程

其他的参数,请通过memcached -h查阅。

可以启动多个守护进程,但是端口不能重复。 设置开机启动的话可以将上行命令增加到/etc/rc.d/rc.local文件中。

再介绍一下,Memcached的命令有:

  • 存储命令:setaddreplaceappendprependcas
  • 查找命令:getgetsdeleteincrdecr
  • 统计命令:statsstats itemsstats slabsstats sizesflush_all

2 Python操作Memcached

网上流传说Python-API中效率最高的是libmc,另外还有python-memcached。不过由于目前需要中效率并没有太高要求,于是选择了使用最多的python-memcached

安装

pip install python-memcached

安装完后,查看一下python-memcached版本:

$ pip list | grep python-memcached
python-memcached (1.59)

先来看一个简单的例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

# 连接
mc = memcache.Client(["127.0.0.1:11211"], debug=True)
# 插入
mc.set("hello", "Hello memcached!")
# 读取
ret = mc.get("hello")
print(ret)

运行后,输出结果:

Hello memcached!

其中debug=True表示运行出现错误时,可以显示错误信息,生产环境中可以不加。

集群

python-memcached模块原生支持集群操作,其原理是在内存中维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比。

主机 权重
127.0.0.11:11211 1
192.168.56.1:11212 2
192.168.0.148:11213 3

那么内存中主机列表为host_list = ["127.0.0.1", "192.168.56.1", "192.168.56.1", "192.168.0.148", "192.168.0.148", "192.168.0.148", ]

用户如果要在内存中创建一个键值对(eg. key1 = "value1"),那么要执行以下步骤:

  • 根据算法将key1转换成一个数字
  • 将数字和主机列表长度求余数,得到一个值N(0 <= N < 长度)
  • 在主机列表中根据第二步得到的值为索引获取主机,例如: host_list[N]
  • 连接将第三步中获取的主机,将key1 = "value1"放置在该服务器的内存中

实现代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

# 集群
mc = memcache.Client([('127.0.0.1:11211', 1), ('192.168.56.1:11212', 2), ('192.168.0.148:11213', 3)])
# 插入
mc.set('key1', 'value1')
print(mc.get("key1"))

"""
  验证
"""
# 127.0.0.1:11211
mc1 = memcache.Client(['127.0.0.1:11211'])
print("host=127.0.0.1:11211, ", "key1=", mc1.get("key1"))
# 192.168.56.1:11212
mc2 = memcache.Client(['192.168.56.1:11212'])
print("host=192.168.56.1:11212, ", "key1=", mc2.get("key1"))
# 192.168.0.148:11213
mc3 = memcache.Client(['192.168.0.148:11213'])
print("host=192.168.0.148:11213, ", "key1=", mc3.get("key1"))

运行结果:

value1
host=127.0.0.1:11211,  key1= None
host=192.168.56.1:11212,  key1= None
host=192.168.0.148:11213,  key1= value1

说明键值对key1 = "value1"存在192.168.0.148:11213中。

add

add用于添加一个键值对,如果已经存在的key,重复执行add操作会出现异常。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(["127.0.0.1:11211"], debug=True)
# set
ret1 = mc.add("key-add", "value")
print(ret1)

ret2 = mc.add("key-add", "value")
print(ret2)

运行结果:

True
MemCached: while expecting 'STORED', got unexpected response 'NOT_STORED'
False

replace

replace用于修改某个key的值,如果key不存在,则出现异常。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(["127.0.0.1:11211"], debug=True)
# add
mc.add("key-replace", "value1")
ret1 = mc.get("key-replace")
print(ret1)
# replace
mc.replace("key-replace", "value2")
ret2 = mc.get("key-replace")
print(ret2)

运行结果:

value1
value2

set 和 set_multi、get 和 get_multi

set用于设置一个键值对,如果key不存在,则创建;如果key存在,则修改。

set_multi用于设置多个键值对,如果key不存在,则创建;如果key存在,则修改。

get获取一个键值对。

get_multi获取多个键值对,keys为一个list

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(["127.0.0.1:11211"], debug=True)
# set
mc.set("key-set", "value1")
ret = mc.get("key-set")
print(ret)
# set multi
dic = {"key-set-1": "value1-1", "key-set-2": "value1-2", "key-set-3": "value1-3"}
mc.set_multi(dic)
print(mc.get_multi(['key-set-1', 'key-set-2', 'key-set-3']))

运行结果:

value1
{"key-set-1": "value1-1", "key-set-2": "value1-2", "key-set-3": "value1-3"}

delete 和 delete_multi

delete用于删除指定的一个键值对。

delete_multi用于删除指定多个键值对,貌似现在不能用。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(['127.0.0.1:11211'], debug=True)
# set
mc.set('key-delete', 'value-delete')
print(mc.get('key-delete'))
# # delete
mc.delete('key-delete')
print(mc.get('key-delete'))

# set_multi
dic = {'key-delete-1': 'value1-delete-1', 'key-delete-2': 'value1-2', 'key-delete-3': 'value1-delete-3'}
mc.set_multi(dic)
print(mc.get_multi(['key-delete-1', 'key-delete-2', 'key-delete-3']))
# delete multi
mc.delete_multi(['key-delete-1', 'key-delete-2', 'key-delete-3'])
print(mc.get_multi(['key-delete-1', 'key-delete-2', 'key-delete-3']))

运行结果:

value-delete
None
{'key-delete-2': 'value1-2', 'key-delete-1': 'value1-delete-1', 'key-delete-3': 'value1-delete-3'}
{}

append 和 prepend

append用于修改已存在key的值后面追加内容。

prepend用于修改已存在key的值前面插入内容。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(['127.0.0.1:11211'], debug=True)
# set
mc.set('key1', 'value')
print(mc.get('key1'))
# append
ret1 = mc.append("key1", "-append")
print(ret1)
print(mc.get('key1'))
# prepend
ret2 = mc.prepend("key1", "prepend-")
print(ret2)
print(mc.get('key1'))

运行结果:

value
True
value-append
True
prepend-value-append

incr 和 decr

incr用于对已存在的key的数字值进行自增操作。

decr用于对已存在的key的数字值进行自减操作。

incrdecr 操作的数据必须是十进制的32位无符号整数。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import memcache

mc = memcache.Client(['127.0.0.1:11211'], debug=True)
# set
mc.set('key1', 10)
print("key1=%s" % mc.get('key1'))
# incr
ret1 = mc.incr("key1", 10)
print(ret1)
print("key1=%s" % mc.get('key1'))
# decr
ret2 = mc.decr("key1", 5)
print(ret2)
print("key1=%s" % mc.get('key1'))

运行结果:

key1=10
20
key1=20
15
key1=15

至于其他的命令就不一一介绍了,想继续了解的话,请阅读http://www.runoob.com/memcached/memcached-tutorial.html

3 参考

...

Tags Read More