Python標(biāo)準(zhǔn)庫(kù)系列之Memcache模塊

本系列文章來(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ù)

如圖所示

image.png
# 將字符串轉(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>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谈宛,隨后出現(xiàn)的幾起案子次哈,更是在濱河造成了極大的恐慌,老刑警劉巖吆录,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窑滞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)哀卫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)巨坊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人聊训,你說(shuō)我怎么就攤上這事抱究。” “怎么了带斑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵鼓寺,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我勋磕,道長(zhǎng)妈候,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任挂滓,我火速辦了婚禮苦银,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赶站。我一直安慰自己幔虏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布贝椿。 她就那樣靜靜地躺著想括,像睡著了一般。 火紅的嫁衣襯著肌膚如雪烙博。 梳的紋絲不亂的頭發(fā)上瑟蜈,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音渣窜,去河邊找鬼铺根。 笑死,一個(gè)胖子當(dāng)著我的面吹牛乔宿,可吹牛的內(nèi)容都是我干的位迂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼详瑞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼掂林!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蛤虐,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤党饮,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后驳庭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體刑顺,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氯窍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蹲堂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狼讨。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖柒竞,靈堂內(nèi)的尸體忽然破棺而出政供,到底是詐尸還是另有隱情,我是刑警寧澤朽基,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布布隔,位于F島的核電站,受9級(jí)特大地震影響稼虎,放射性物質(zhì)發(fā)生泄漏衅檀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一霎俩、第九天 我趴在偏房一處隱蔽的房頂上張望哀军。 院中可真熱鬧,春花似錦打却、人聲如沸杉适。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)猿推。三九已至,卻和暖如春腻暮,著一層夾襖步出監(jiān)牢的瞬間彤守,已是汗流浹背毯侦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工哭靖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侈离。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓试幽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親卦碾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铺坞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 一、MemCache簡(jiǎn)介 session MemCache是一個(gè)自由洲胖、源碼開(kāi)放济榨、高性能、分布式的分布式內(nèi)存對(duì)象緩存...
    李偉銘MIng閱讀 3,808評(píng)論 2 13
  • 1绿映、memcache的概念擒滑? Memcache是一個(gè)高性能的分布式的內(nèi)存對(duì)象緩存系統(tǒng)腐晾,通過(guò)在內(nèi)存里維護(hù)一個(gè)統(tǒng)一的巨...
    桖辶殤閱讀 2,235評(píng)論 2 12
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)丐一,斷路器藻糖,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • 根據(jù)情景創(chuàng)造產(chǎn)品
    楓咻閱讀 237評(píng)論 0 0