本系列文章來(lái)源:<a>https://blog.ansheng.me/article/python-full-stack-way</a>
這個(gè)模塊是一個(gè)Python操作memcached的一個(gè)API接口纳猪。
安裝Memcached
CentOS
yum install memcached
啟動(dòng)memcache:
[root@wangerxiao ~]# memcached -d -m 10 -u root -l 0.0.0.0 -p 11211 -c 256 -P /tmp/memcached.pid
參數(shù)說(shuō)明:
參數(shù) 描述
-d 是啟動(dòng)一個(gè)守護(hù)進(jìn)程
-m 是分配給Memcache使用的內(nèi)存數(shù)量,單位是MB
-u 是運(yùn)行Memcache的用戶(hù)
-l 是監(jiān)聽(tīng)的服務(wù)器IP地址
-p 是設(shè)置Memcache監(jiān)聽(tīng)的端口,最好是1024以上的端口
-c 選項(xiàng)是最大運(yùn)行的并發(fā)連接數(shù)驹暑,默認(rèn)是1024鼠次,按照你服務(wù)器的負(fù)載量來(lái)設(shè)定
-P 是設(shè)置保存Memcache的pid文件
設(shè)置開(kāi)機(jī)自啟:
[root@wangerxiao ~]# chmod +x /etc/rc.d/rc.local
[root@wangerxiao ~]# echo 'memcached -d -m 10 -u root -l 0.0.0.0 -p 11211 -c 256 -P /tmp/memcached.pid' >> /etc/rc.local
關(guān)閉memcached:
[root@wangerxiao ~]# pkill `cat /tmp/memcached.pid`
測(cè)試
先查看11211端口是否啟動(dòng)
[root@wangerxiao ~]# netstat -tlnp | grep "11211"
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 12423/memcached
使用telnet查看啟動(dòng)的11211端口是否可以各拷,可以則測(cè)試OK杭棵。
如果出現(xiàn)以下內(nèi)容就代表啟動(dòng)成功粘驰!
[root@wangerxiao ~]# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Memcache使用
安裝Memcache
[root@wangerxiao ~]# wget https://pypi.python.org/packages/f7/62/14b2448cfb04427366f24104c9da97cf8ea380d7258a3233f066a951a8d8/python-memcached-1.58.tar.gz#md5=23b258105013d14d899828d334e6b044
解壓并安裝
[root@wangerxiao ~]# tar -zxvf python-memcached-1.58.tar.gz
[root@wangerxiao ~]# cd python-memcached-1.58/
[root@wangerxiao python-memcached-1.58]# python setup.py install
進(jìn)入Python解釋器導(dǎo)入模塊,如果導(dǎo)入成功就表示模塊安裝成功皮仁。
[root@wangerxiao ~]# ipython
Python 3.5.2 (default, Aug 25 2016, 14:14:24)
Type "copyright", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: import memcache
體驗(yàn)一下
# 導(dǎo)入memcache模塊
In [4]: import memcache
# 連接到一臺(tái)Memcached服務(wù)器
In [5]: conn = memcache.Client(['127.0.0.1:11211'])
# 設(shè)置一個(gè)值籍琳,如果存在則覆蓋
In [6]: conn.set('k1','v1')
Out[6]: True
# 獲取值的內(nèi)容
In [7]: conn.get('k1')
Out[7]: 'v1'
更多方法
設(shè)置超時(shí)時(shí)間
In [8]: conn.set('k','v',1)
Out[8]: True
#時(shí)間超時(shí),無(wú)法獲取到值
In [9]: conn.get('k')
設(shè)置值魂贬,如果存在就報(bào)錯(cuò)
In [10]: conn.add('k','hello')
Out[10]: True
# False設(shè)置失敗
In [11]: conn.add('k','world')
Out[11]: False
# 原值沒(méi)變
In [12]: conn.get('k')
Out[12]: 'hello'
修改值巩割,不存在則返回False
In [13]: conn.replace('k','helloworld')
# 設(shè)置成功
Out[13]: True
In [14]: conn.get('k')
# 返回修改后的值
Out[14]: 'helloworld'
In [15]: conn.replace('kk')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-2125c72626a0> in <module>()
----> 1 conn.replace('kk')
TypeError: replace() missing 1 required positional argument: 'val'
# 修改一個(gè)不存在的值
In [16]: conn.replace('kk','hello')
Out[16]: False
設(shè)置多個(gè)值裙顽,值不存在則創(chuàng)建付燥,存在則修改
In [17]: conn.get('key1')
In [18]: conn.set_multi({'key1':'value1','key2':'value2'})
Out[18]: []
In [19]: conn.get('key1')
Out[19]: 'value1'
刪除一個(gè)值
In [20]: conn.get('key1')
Out[20]: 'value1'
In [21]: conn.delete('key1')
Out[21]: 1
In [22]: conn.get('key1')
刪除多個(gè)值
In [23]: conn.set_multi({'key3':'value3','key4':'value4'})
Out[23]: []
In [24]: conn.delete_multi(['key3','key4'])
Out[24]: 1
獲取一個(gè)值和獲取多個(gè)值
In [26]: conn.set_multi({'key5':'value5','key6':'value6'})
Out[26]: []
In [27]: conn.get('key5')
Out[27]: 'value5'
In [28]: conn.get_multi(['key5','key6'])
Out[28]: {'key5': 'value5', 'key6': 'value6'}
修改指定key的值,在該值后面追加內(nèi)容
In [29]: conn.append('key5','after')
Out[29]: True
In [30]: conn.get('key5')
Out[30]: 'value5after
修改指定key的值愈犹,在該值 前面 插入內(nèi)容
In [32]: conn.prepend('key5','before')
Out[32]: True
In [33]: conn.get('key5')
Out[33]: 'beforevalue5after'
自增與自減键科,將Memcached中的某一個(gè)值加或減少N(N默認(rèn)為1)
In [34]: conn.set('number',9)
Out[34]: True
In [35]: conn.incr('number')
Out[35]: 10
In [36]: conn.incr('number',10)
Out[36]: 20
In [37]: conn.decr('number')
Out[37]: 19
In [38]: conn.decr('number',10)
Out[38]: 9
比如設(shè)置了這么一個(gè)值:
conn.set('n',10)
現(xiàn)在A用戶(hù)和B用戶(hù)同時(shí)獲取到了這兩個(gè)值,如果有其中的任何一個(gè)用戶(hù)對(duì)這個(gè)值進(jìn)行了修改漩怎,那么另外一個(gè)用戶(hù)在對(duì)這個(gè)值進(jìn)行操作的時(shí)候就會(huì)報(bào)錯(cuò)勋颖。
如果要解決以上的問(wèn)題可以使用gets與cas,測(cè)試代碼如下:
# -- s1.py
# _*_ coding:utf-8 _*_
import memcache
conn1 = memcache.Client(['192.168.56.100:11211'], debug=True, cache_cas=True)
conn1.set('n', 9)
# gets會(huì)獲取到值并且獲取計(jì)數(shù)器
result = conn1.gets('n')
print(result)
# 阻塞
input('>>>')
# 設(shè)置值
conn1.cas('n', 99)
# -- s2
# _*_ coding:utf-8 _*_
import memcache
conn2 = memcache.Client(['192.168.56.100:11211'], debug=True, cache_cas=True)
# gets會(huì)獲取到值并且獲取計(jì)數(shù)器
result = conn2.gets('n')
print(result)
# 阻塞
input('>>>')
# 設(shè)置值
conn2.cas('n', 100)
多節(jié)點(diǎn)的操作
首先在服務(wù)器上面起四個(gè)memcached實(shí)例勋锤,每個(gè)實(shí)例都是一個(gè)單獨(dú)的memcached服務(wù)
[root@wangerxiao ~]# netstat -tlnp | grep "memcache"
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 12423/memcached
tcp 0 0 0.0.0.0:11212 0.0.0.0:* LISTEN 17481/memcached
tcp 0 0 0.0.0.0:11213 0.0.0.0:* LISTEN 17577/memcached
tcp 0 0 0.0.0.0:11214 0.0.0.0:* LISTEN 17808/memcached
# _*_ coding:utf-8 _*_
import memcache
# 連接到多臺(tái)memcached服務(wù)器
conn = memcache.Client(
# IP:端口饭玲,權(quán)重
[('192.168.56.100:11211', 4),
('192.168.56.100:11212', 3),
('192.168.56.100:11213', 1),
('192.168.56.100:11214', 2)]
)
conn.set('k', 'v')
多節(jié)點(diǎn)數(shù)據(jù)存儲(chǔ)流程
1.先將一個(gè)字符串轉(zhuǎn)換為一個(gè)數(shù)字
2.得出的結(jié)果和節(jié)點(diǎn)的數(shù)量進(jìn)行除法運(yùn)算
3.得出的結(jié)果肯定在節(jié)點(diǎn)數(shù)量之間,余數(shù)是幾叁执,就在那臺(tái)節(jié)點(diǎn)上面存放數(shù)據(jù)
如圖所示
# 將字符串轉(zhuǎn)換為數(shù)字模塊
import binascii
# 摘自memcache源碼中的一部分
def cmemcache_hash(key):
return ((((binascii.crc32(key) & 0xffffffff) >> 16) & 0x7fff) or 1)
# result就是返回的數(shù)字
result = cmemcache_hash(bytes('k', encoding='utf-8'))
print(result)
基于Memcached的Session實(shí)例
主程序腳本
# _*_coding:utf-8 _*_
import tornado.ioloop
import tornado.web
import MemcacheToSession
class BaseHandler(tornado.web.RequestHandler):
def initialize(self):
self.session = MemcacheToSession.Session(self)
# pass
class MainHandler(BaseHandler):
def get(self):
Info = self.session.GetAll()
self.render("template/index.html", Data=Info)
def post(self, *args, **kwargs):
# 獲取傳過(guò)來(lái)的值
Key = self.get_argument('key')
Val = self.get_argument('val')
action = self.get_argument('action')
if action == 'set':
# 設(shè)置值
self.session[Key] = Val
elif action == 'del':
del self.session[Key]
# 獲取所有信息
Info = self.session.GetAll()
# 返回給前端渲染
self.render("template/index.html", Data=Info)
settings = {
"tempalte_path": "template",
"cookie_secret": "508CE6152CB93994628D3E99934B83CC",
}
application = tornado.web.Application([
(r'/', MainHandler),
], **settings)
if __name__ == "__main__":
application.listen(9999)
tornado.ioloop.IOLoop.instance().start()
模板文件
<!-- template\index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<form action="/" method="post">
set/del:<input type="text" name="action" value="set"/>
Key: <input type="text" name="key"/>
Val: <input type="text" name="val"/>
<input type="submit" value="設(shè)置"/>
</form>
</body>
</html>
設(shè)置Session的小模塊
# _*_ coding: utf-8 _*_
import memcache
import hashlib
import uuid
import json
# 連接memcached
conn = memcache.Client(
['192.168.56.100:11211']
)
class Session:
CookieID = 'uc'
ExpiresTime = 60 * 20
def __init__(self, handler):
"""
用于創(chuàng)建用戶(hù)session在memcached中的字典
:param handler: 請(qǐng)求頭
"""
self.handler = handler
# 從客戶(hù)端獲取隨機(jī)字符串
SessionID = self.handler.get_secure_cookie(Session.CookieID, None)
# 客戶(hù)端存在并且在服務(wù)端也存在
if SessionID and conn.get(SessionID):
self.SessionID = SessionID
else:
# 獲取隨機(jī)字符串
self.SessionID = self.SessionKey()
# 把隨機(jī)字符串寫(xiě)入memcached,時(shí)間是20分鐘
conn.set(self.SessionID, json.dumps({}), Session.ExpiresTime)
# 每次訪(fǎng)問(wèn)超時(shí)時(shí)間就加20分鐘
conn.set(self.SessionID, conn.get(self.SessionID), Session.ExpiresTime)
# 設(shè)置Cookie
self.handler.set_secure_cookie('uc', self.SessionID)
def SessionKey(self):
"""
:return: 生成隨機(jī)字符串
"""
UUID = str(uuid.uuid1()).replace('-', '')
MD5 = hashlib.md5()
MD5.update(bytes(UUID, encoding='utf-8'))
SessionKey = MD5.hexdigest()
return SessionKey
def __setitem__(self, key, value):
"""
設(shè)置session
:param key: session信息中的key
:param value: 對(duì)應(yīng)的Value
"""
# 獲取session_id
SessionDict = json.loads(conn.get(self.SessionID))
# 設(shè)置字典的key
SessionDict[key] = value
# 重新賦值
conn.set(self.SessionID, json.dumps(SessionDict), Session.ExpiresTime)
def __getitem__(self, item):
"""
:param item: Session信息中對(duì)應(yīng)的Key
:return: 獲取的Session信息
"""
# 獲取SessionID并轉(zhuǎn)換為字典
SessionDict = json.loads(conn.get(self.SessionID))
# 獲取對(duì)應(yīng)的數(shù)據(jù)
ResultData = SessionDict.get(item, None)
return ResultData
def __delitem__(self, key):
"""
:param key: 要?jiǎng)h除的Key
"""
# 獲取SessionID并轉(zhuǎn)換為字典
SessionDict = json.loads(conn.get(self.SessionID))
# 刪除字典的key
del SessionDict[key]
# 重新賦值
conn.set(self.SessionID, json.dumps(SessionDict), Session.ExpiresTime)
def GetAll(self):
# 獲取Session中所有的信息茄厘,僅用于測(cè)試
SessionData = conn.get(self.SessionID)
return SessionData
演示鏈接:<a>https://blog.ansheng.me/article/python-standard-library-memcache#基于memcached的session實(shí)例</a>