作者介紹 索寧,擅長(zhǎng)Python開(kāi)發(fā)、MySQL、前端等眾多技術(shù)領(lǐng)域,曾負(fù)責(zé)眾多企業(yè)安全架構(gòu)解決方案,涉獵行業(yè)有媒體、出版社、航空運(yùn)輸、醫(yī)療、軍隊(duì)、政府、教育等。 本文主題:
一、Memcached 1、簡(jiǎn)介、安裝、使用 Memcached 是一個(gè)高性能的分布式內(nèi)存對(duì)象緩存系統(tǒng),用于動(dòng)態(tài) Web 應(yīng)用以減輕數(shù)據(jù)庫(kù)負(fù)載壓力。它通過(guò)在內(nèi)存中緩存數(shù)據(jù)和對(duì)象來(lái)減少讀取數(shù)據(jù)庫(kù)的次數(shù),從而提高動(dòng)態(tài)、數(shù)據(jù)庫(kù)驅(qū)動(dòng)網(wǎng)站的速度。Memcached 基于一個(gè)存儲(chǔ)鍵/值對(duì)的 hashmap。其守護(hù)進(jìn)程(daemon )是用 C寫的,但是客戶端可以用任何語(yǔ)言來(lái)編寫,并通過(guò) memcached 協(xié)議與守護(hù)進(jìn)程通信。 全球好貨,蘇寧易購(gòu)一站購(gòu)齊
廣告
Memcached內(nèi)存管理機(jī)制: Menceched 通過(guò)預(yù)分配指定的內(nèi)存空間來(lái)存取數(shù)據(jù),所有的數(shù)據(jù)都保存在 memcached 內(nèi)置的內(nèi)存中。 利用 Slab Allocation 機(jī)制來(lái)分配和管理內(nèi)存。按照預(yù)先規(guī)定的大小,將分配的內(nèi)存分割成特定長(zhǎng)度的內(nèi)存塊,再把尺寸相同的內(nèi)存塊分成組,這些內(nèi)存塊不會(huì)釋放,可以重復(fù)利用。 當(dāng)存入的數(shù)據(jù)占滿內(nèi)存空間時(shí),Memcached 使用 LRU 算法自動(dòng)刪除不是用的緩存數(shù)據(jù),即重用過(guò)期數(shù)據(jù)的內(nèi)存空間。Memcached 是為緩存系統(tǒng)設(shè)計(jì)的,因此沒(méi)有考慮數(shù)據(jù)的容災(zāi)問(wèn)題,和機(jī)器的內(nèi)存一樣,重啟機(jī)器將會(huì)丟失,如果希望服務(wù)重啟數(shù)據(jù)依然能保留,那么就需要 sina 網(wǎng)開(kāi)發(fā)的 Memcachedb 持久性內(nèi)存緩沖系統(tǒng),當(dāng)然還有常見(jiàn)的 NoSQL 服務(wù)如 Redis。 默認(rèn)監(jiān)聽(tīng)端口:11211 Memcached安裝
Memcached啟動(dòng) memcached -d -m 10 -u root -l 218.97.240.118 -p 12000 -c 256 -P /tmp/memcached.pid 參數(shù)說(shuō)明: -d 是啟動(dòng)一個(gè)守護(hù)進(jìn)程 -m 是分配給Memcache使用的內(nèi)存數(shù)量,單位是MB -u 是運(yùn)行Memcache的用戶 -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文件 Memcached命令 存儲(chǔ)命令: set/add/replace/append/prepend/cas 獲取命令: get/gets 其他命令: delete/stats.. Memcached管理
# memadmin php 工具管理(memcadmin-1.0.12.tar.gz) 1、安裝memadmin php工具。 2、 登陸memadmin php。 web方式訪問(wèn):http://IP地址/memadmin/ 默認(rèn)用戶名密碼都為admin。 2、Python 操作 Memcached 1)安裝 API 及 基本操作 python 操作 Memcached 使用 Python-memcached 模塊 下載安裝:https://pypi./pypi/python-memcached import memcache mc = memcache.Client(['192.168.1.5:12000'], debug=True) mc.set('foo', 'bar') ret = mc.get('foo') print ret 2)天生支持集群 python-memcached 模塊原生支持集群操作,其原理本質(zhì)是在內(nèi)存維護(hù)一個(gè)主機(jī)列表,數(shù)字為權(quán)重,為3即出現(xiàn)3次,相對(duì)應(yīng)的幾率大 mc = memcache.Client([ ('192.168.1.5:12000', 3), # 數(shù)字為權(quán)重 ('192.168.1.9:12000', 1), ], debug=True) # 那么在內(nèi)存中主機(jī)列表為: # host_list = ['192.168.1.5','192.168.1.5','192.168.1.5','192.168.1.9',] 那么問(wèn)題來(lái)了,集群情況下如何選擇服務(wù)器存儲(chǔ)呢? 如果要?jiǎng)?chuàng)建設(shè)置一個(gè)鍵值對(duì)(如:k1 = 'v1'),那么它的執(zhí)行流程如下:
獲取值的話也一樣
3)add 添加一個(gè)鍵值對(duì),如果 key 已經(jīng)存在,重復(fù)添加執(zhí)行 add 則拋出異常 import memcache mc = memcache.Client(['192.168.1.5:12000'], debug=True) mc.add('k1', 'v1') # mc.add('k1', 'v2') # 報(bào)錯(cuò),對(duì)已經(jīng)存在的key重復(fù)添加,失?。。?! 4)replace replace 修改某個(gè) key 的值,如果 key 不存在,則異常 import memcache mc = memcache.Client(['192.168.1.5:12000'], debug=True) # 如果memcache中存在kkkk,則替換成功,否則一場(chǎng) mc.replace('kkkk','999') 5) set和 set_multi set 設(shè)置一個(gè)鍵值對(duì),如果 key 不存在,則創(chuàng)建 set_multi 設(shè)置多個(gè)鍵值對(duì),如果 key 不存在,則創(chuàng)建 import memcache mc = memcache.Client(['192.168.1.5:12000'], debug=True) mc.set('name', 'nick') mc.set_multi({'name': 'nick', 'age': '18'}) 6) delete和 delete_multi delete 刪除指定的一個(gè)鍵值對(duì) delete_multi 刪除指定的多個(gè)鍵值對(duì) import memcache mc = memcache.Client(['192.168.1.5:12000'], debug=True) mc..delete('name', 'nick') mc.delete_multi({'name': 'nick', 'age': '18'}) 7) get和 get_multi get 獲取一個(gè)鍵值對(duì) get_multi 獲取多個(gè)鍵值對(duì) import memcache mc = memcache.Client(['192.168.1.5:12000'], debug=True) val = mc.get('name') item_dict = mc.get_multi(['name', 'age',]) 8)append和 prepend append 修改指定key的值,在該值 后面 追加內(nèi)容 prepend 修改指定key的值,在該值 前面 插入內(nèi)容 import memcache mc = memcache.Client(['192.168.1.5:12000'], debug=True) # 原始值: k1 = 'v1' mc.append('k1', 'after') # k1 = 'v1after' mc.prepend('k1', 'before') # k1 = 'beforev1after' 9) decr和 incr incr 自增,將 Memcached 中的某個(gè)值增加 N ( N 默認(rèn)為1 ) decr 自減,將 Memcached 中的某個(gè)值減少 N ( N 默認(rèn)為1 ) mport memcache mc = memcache.Client(['192.168.1.5:12000'], debug=True) mc.set('k1', '666') mc.incr('k1') # k1 = 667 mc.incr('k1', 10) # k1 = 677 mc.decr('k1') # k1 = 676 mc.decr('k1', 10) # k1 = 666 10) gets和 cas 這兩個(gè)方法就是傳說(shuō)中的鎖 。為了避免臟數(shù)據(jù)的產(chǎn)生而生: import memcache mc = memcache.Client(['192.168.1.5:12000'], debug=True, cache_cas=True) v = mc.gets('product_count') # 如果有人在gets之后和cas之前修改了product_count,那下面的設(shè)置將會(huì)執(zhí)行失敗,剖出異常 mc.cas('product_count', '899') 本質(zhì):每次執(zhí)行 gets 時(shí),就從 memcache 中獲取一個(gè)自增的數(shù)字,通過(guò) cas 去修改 gets 到的值時(shí),會(huì)攜帶之前獲取的自增值和 memcache 中的自增值進(jìn)行比較,如果相等,則可以提交,如果不相等,那表示在 gets 和 cas 執(zhí)行之間,又有其他人執(zhí)行了 gets(獲取了緩沖的指定值),如此一來(lái)有可能出現(xiàn)非正常的數(shù)據(jù),則不允許修改,并報(bào)錯(cuò)。 二、Redis 1、簡(jiǎn)介、安裝、使用、實(shí)例 Remote Dictionary Server(Redis)是一個(gè)基于 key-value 鍵值對(duì)的持久化數(shù)據(jù)庫(kù)存儲(chǔ)系統(tǒng)。Redis 和 Memcached 緩存服務(wù)很像,但它支持存儲(chǔ)的 value 類型相對(duì)更多,包括 string (字符串)、list (鏈表)、set (集合)、zset (sorted set --有序集合)和 hash(哈希類型)。這些數(shù)據(jù)類型都支持 push/pop、add/remove 及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎(chǔ)上,Redis 支持各種不同方式的排序。與Memcached 一樣,為了保證效率,數(shù)據(jù)都是緩存在內(nèi)存中。區(qū)別的是 Redis 會(huì)周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實(shí)現(xiàn)了 master-slave (主從)同步。 Redis 的出現(xiàn),再一定程度上彌補(bǔ)了 Memcached 這類 key-value 內(nèi)存換乘服務(wù)的不足,在部分場(chǎng)合可以對(duì)關(guān)系數(shù)據(jù)庫(kù)起到很好的補(bǔ)充作用。Redis 提供了 Python,Ruby,Erlang,PHP 客戶端,使用方便。 官方文檔: http://www.Redis.io/documentation http://www.Redis.cn/ Redis安裝和使用實(shí)例
至于 Redis 的負(fù)載均衡,方案有很多: LVS、keepalived、Twemproxy 有時(shí)間再補(bǔ)上吧...
Redis持久化方式有兩種: (1)RDB:對(duì)內(nèi)存中數(shù)據(jù)庫(kù)狀態(tài)進(jìn)行快照; (2)AOF:把每條寫命令都寫入文件,類似mysql的binlog日志 RDB。 將Redis在內(nèi)存中的數(shù)據(jù)庫(kù)狀態(tài)保存到磁盤里面,RDB文件是一個(gè)經(jīng)過(guò)壓縮的二進(jìn)制文件,通過(guò)該文件可以還原生成RDB文件時(shí)的數(shù)據(jù)庫(kù)狀態(tài)。 RDB的生成方式: (1)執(zhí)行命令手動(dòng)生成
(2)通過(guò)配置自動(dòng)生成
例如: save 900 1 save 300 10 save 60 10000 那么只要滿足以下三個(gè)條件中的任意一個(gè),BGSAVE命令就會(huì)被執(zhí)行:
AOF AOF持久化是通過(guò)保存Redis服務(wù)器所執(zhí)行的寫命令來(lái)記錄數(shù)據(jù)庫(kù)狀態(tài)的。 AOF文件刷新的方式,有三種: (1)appendfsync always - 每提交一個(gè)修改命令都調(diào)用fsync刷新到AOF文件,非常非常慢,但也非常安全; (2)appendfsync everysec - 每秒鐘都調(diào)用fsync刷新到AOF文件,很快,但可能會(huì)丟失一秒以內(nèi)的數(shù)據(jù); (3)appendfsync no - 依靠OS進(jìn)行刷新,Redis不主動(dòng)刷新AOF,這樣最快,但安全性就差。 默認(rèn)并推薦每秒刷新,這樣在速度和安全上都做到了兼顧。 數(shù)據(jù)恢復(fù) RDB方式: RDB文件的載入工作是在服務(wù)器啟動(dòng)時(shí)自動(dòng)執(zhí)行的,沒(méi)有專門用于載入RDB文件的命令,只要Redis服務(wù)器在啟動(dòng)時(shí)檢測(cè)到RDB文件存在,它就會(huì)自動(dòng)載入RDB文件,服務(wù)器在載入RDB文件期間,會(huì)一直處于阻塞狀態(tài),直到載入工作完成為止。 AOF方式 服務(wù)器在啟動(dòng)時(shí),通過(guò)載入和執(zhí)行AOF文件中保存的命令來(lái)還原服務(wù)器關(guān)閉之前的數(shù)據(jù)庫(kù)狀態(tài),具體過(guò)程: (1)載入AOF文件 (2)創(chuàng)建模擬客戶端 (3)從AOF文件中讀取一條命令 (4)使用模擬客戶端執(zhí)行命令 (5)循環(huán)讀取并執(zhí)行命令,直到全部完成 如果同時(shí)啟用了RDB和AOF方式,AOF優(yōu)先,啟動(dòng)時(shí)只加載AOF文件恢復(fù)數(shù)據(jù)。 2、Python 操作 Redis python安裝 Redis 模塊: $ sudo pip install Redis or $ sudo easy_install Redis or $ sudo python setup.py install 詳見(jiàn): https://github.com/WoLpH/Redis-py https://pypi./pypi/Redis https://Redislabs.com/python-Redis API的使用 1)操作模式 redis-py 提供兩個(gè)類 Redis 和 StrictRedis 用于實(shí)現(xiàn) Redis 的操作命令,StrictRedis 用于實(shí)現(xiàn)大部分官方的命令,并使用官方的語(yǔ)法和命令,Redis 是 StrictRedis 的子類,用于向后兼容舊版本的 redis-py。 import redis r =redis.redis(host='192.168.1.5', port=6379) r.set('foo', 'Bar') print r.get('foo') 2)連接池 redis-py 使用 connection pool 來(lái)管理對(duì)一個(gè) Redis server 的所有連接,避免每次建立、釋放連接帶來(lái)的額外開(kāi)銷。默認(rèn)每個(gè) Redis 實(shí)例都會(huì)維護(hù)著一個(gè)自己的連接池。也可以覆蓋直接建立一個(gè)連接池,然后作為參數(shù) Redis,這樣就可以實(shí)現(xiàn)多個(gè) Redis 實(shí)例共享一個(gè)連接池資源。實(shí)現(xiàn)客戶端分片或有連接如何管理更細(xì)的顆??刂?。 pool = redis.ConnectionPool(host='192.168.1.5', port=6379) r = redis.redis(connection_pool=pool) r.set('foo', 'Bar') print r.get('foo') 3)操作 分為五種數(shù)據(jù)類型,見(jiàn)下圖: ①String 操作,String 在內(nèi)存中格式是一個(gè) name 對(duì)應(yīng)一個(gè) value 來(lái)存儲(chǔ) ②Hash 操作,Redis 中 Hash 在內(nèi)存中的存儲(chǔ)格式類似字典。 ③List操作,Redis 中的 List 在在內(nèi)存中按照一個(gè) name 對(duì)應(yīng)一個(gè) List 來(lái)存儲(chǔ),像變量對(duì)應(yīng)一個(gè)列表。 ④Set 操作,Set 集合就是不允許重復(fù)的列表。 ⑤有序集合,在集合的基礎(chǔ)上,為每個(gè)元素排序;元素的排序需要根據(jù)另外一個(gè)值來(lái)進(jìn)行比較,所以對(duì)于有序集合,每一個(gè)元素有兩個(gè)值:值和分?jǐn)?shù),分?jǐn)?shù)是專門來(lái)做排序的。 4)管道 默認(rèn)情況下,Redis-py 每次在執(zhí)行請(qǐng)求時(shí)都會(huì)創(chuàng)建和斷開(kāi)一次連接操作(連接池申請(qǐng)連接,歸還連接池),如果想要在一次請(qǐng)求中執(zhí)行多個(gè)命令,則可以使用 pipline 實(shí)現(xiàn)一次請(qǐng)求執(zhí)行多個(gè)命令,并且默認(rèn)情況下 pipline 是原子性操作。 見(jiàn)以下實(shí)例: import redis pool = redis.ConnectionPool(host='10.211.55.4', port=6379) r = redis.redis(connection_pool=pool) # pipe = r.pipeline(transaction=False) pipe = r.pipeline(transaction=True) r.set('name', 'nick') r.set('age', '18') pipe.execute() 5) 發(fā)布和訂閱 發(fā)布者:服務(wù)器 訂閱者:Dashboad 和數(shù)據(jù)處理 發(fā)布訂閱的 Demo 如下:
訂閱者: 發(fā)布者: 三、RabbitMQ 1、簡(jiǎn)介、安裝、使用 RabbitMQ 是一個(gè)在 AMQP 基礎(chǔ)上完成的,可復(fù)用的企業(yè)消息系統(tǒng)。他遵循 Mozilla Public License 開(kāi)源協(xié)議。 MQ 全稱為 Message Queue, 消息隊(duì)列(MQ)是一種應(yīng)用程序?qū)?yīng)用程序的通信方式。應(yīng)用程序通過(guò)讀寫出入隊(duì)列的消息(針對(duì)應(yīng)用程序的數(shù)據(jù))來(lái)通信,而無(wú)需專用連接來(lái)鏈接它們。消息傳遞指的是程序之間通過(guò)在消息中發(fā)送數(shù)據(jù)進(jìn)行通信,而不是通過(guò)直接調(diào)用彼此來(lái)通信,直接調(diào)用通常是用于諸如遠(yuǎn)程過(guò)程調(diào)用的技術(shù)。排隊(duì)指的是應(yīng)用程序通過(guò) 隊(duì)列來(lái)通信。隊(duì)列的使用除去了接收和發(fā)送應(yīng)用程序同時(shí)執(zhí)行的要求。 流程上生產(chǎn)者把消息放到隊(duì)列中去, 然后消費(fèi)者從隊(duì)列中取出消息。
RabbitMQ安裝 2、使用API操作RabbitMQ 基于隊(duì)列 Queue 實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型:
RabbitMQ 實(shí)現(xiàn) 1、acknowledgment 消息不丟失 no-ack = False,如果消費(fèi)者由于某些情況宕了(its channel is closed, connection is closed, or TCP connection is lost),那 RabbitMQ 會(huì)重新將該任務(wù)放入隊(duì)列中。 在實(shí)際應(yīng)用中,可能會(huì)發(fā)生消費(fèi)者收到Queue中的消息,但沒(méi)有處理完成就宕機(jī)(或出現(xiàn)其他意外)的情況,這種情況下就可能會(huì)導(dǎo)致消息丟失。為了避免這種情況發(fā)生,我們可以要求消費(fèi)者在消費(fèi)完消息后發(fā)送一個(gè)回執(zhí)給RabbitMQ,RabbitMQ收到消息回執(zhí)(Message acknowledgment)后才將該消息從Queue中移除;如果RabbitMQ沒(méi)有收到回執(zhí)并檢測(cè)到消費(fèi)者的RabbitMQ連接斷開(kāi),則RabbitMQ會(huì)將該消息發(fā)送給其他消費(fèi)者(如果存在多個(gè)消費(fèi)者)進(jìn)行處理。這里不存在timeout概念,一個(gè)消費(fèi)者處理消息時(shí)間再長(zhǎng)也不會(huì)導(dǎo)致該消息被發(fā)送給其他消費(fèi)者,除非它的RabbitMQ連接斷開(kāi)。 這里會(huì)產(chǎn)生另外一個(gè)問(wèn)題,如果我們的開(kāi)發(fā)人員在處理完業(yè)務(wù)邏輯后,忘記發(fā)送回執(zhí)給RabbitMQ,這將會(huì)導(dǎo)致嚴(yán)重的bug——Queue中堆積的消息會(huì)越來(lái)越多;消費(fèi)者重啟后會(huì)重復(fù)消費(fèi)這些消息并重復(fù)執(zhí)行業(yè)務(wù)邏輯…… 消費(fèi)者 2、durable 消息不丟失 如果我們希望即使在RabbitMQ服務(wù)重啟的情況下,也不會(huì)丟失消息,我們可以將Queue與Message都設(shè)置為可持久化的(durable),這樣可以保證絕大部分情況下我們的RabbitMQ消息不會(huì)丟失。但依然解決不了小概率丟失事件的發(fā)生(比如RabbitMQ服務(wù)器已經(jīng)接收到生產(chǎn)者的消息,但還沒(méi)來(lái)得及持久化該消息時(shí)RabbitMQ服務(wù)器就斷電了),如果我們需要對(duì)這種小概率事件也要管理起來(lái),那么我們要用到事務(wù)。由于這里僅為RabbitMQ的簡(jiǎn)單介紹,所以這里將不講解RabbitMQ相關(guān)的事務(wù)。 需要改兩處地方: 生產(chǎn)者 消費(fèi)者 3、消息獲取順序 默認(rèn)情況下,消費(fèi)者拿消息隊(duì)列里的數(shù)據(jù)是按平均分配,例如:消費(fèi)者1 拿隊(duì)列中 奇數(shù) 序列的任務(wù),消費(fèi)者2 拿隊(duì)列中 偶數(shù) 序列的任務(wù)。 channel.basic_qos(prefetch_count=1) 表示誰(shuí)來(lái)誰(shuí)取,不再按照奇偶數(shù)排列,這個(gè)性能較高的機(jī)器拿的任務(wù)就多。 消費(fèi)者 4、發(fā)布訂閱 發(fā)布訂閱和簡(jiǎn)單的消息隊(duì)列區(qū)別在于,發(fā)布訂閱者會(huì)將消息發(fā)送給所有的訂閱者,而消息隊(duì)列中的數(shù)據(jù)被消費(fèi)一次便消失。所以,RabbitMQ 實(shí)現(xiàn)發(fā)布訂閱時(shí),會(huì)為每一個(gè)訂閱者創(chuàng)建一個(gè)隊(duì)列,而發(fā)布者發(fā)布消息的時(shí)候,會(huì)將消息放置在所有相關(guān)的隊(duì)列中。 exchange type = fanout 發(fā)布者 訂閱者 5、關(guān)鍵字發(fā)送 第4步實(shí)例中,發(fā)送消息必須明確指定某個(gè)隊(duì)列并向其中發(fā)送消息,當(dāng)然,RabbitMQ 還支持根據(jù)關(guān)鍵字發(fā)送(隊(duì)列綁定關(guān)鍵字),發(fā)送者將消息發(fā)送到 exchange,exchange 根據(jù)關(guān)鍵字 判定應(yīng)該將數(shù)據(jù)發(fā)送至指定隊(duì)列。 exchange type = direct 消費(fèi)者 生產(chǎn)者 6、模糊匹配 exchange type = topic 在 topic 類型下,可以讓隊(duì)列綁定幾個(gè)模糊的關(guān)鍵字,之后發(fā)送者將數(shù)據(jù)發(fā)送到 exchange,exchange 將傳入”路由值“和 ”關(guān)鍵字“進(jìn)行匹配,匹配成功,則將數(shù)據(jù)發(fā)送到指定隊(duì)列。 匹配基本規(guī)則及示例:
發(fā)送者路由值 隊(duì)列中 www.suoning.python www.* -- 不匹配 www.suoning.python www.# -- 匹配 消費(fèi)者 生產(chǎn)者 提示:點(diǎn)擊底部【閱讀原文】可獲取原文代碼,趕緊收藏吧。 相關(guān)專題:
精選專題(官網(wǎng):dbaplus.cn) ◆近期熱文 ◆ 從SQL改寫到SQL重寫,什么樣的SQL才是好SQL?與MySQL傳統(tǒng)復(fù)制相比,GTID有哪些獨(dú)特的復(fù)制姿勢(shì)?當(dāng)當(dāng)網(wǎng)資深DBA:DB運(yùn)維四大現(xiàn)代化的實(shí)現(xiàn)寫給DBA,也寫給想從事數(shù)據(jù)庫(kù)工作的你平均提速20倍!Oracle 12c In-Memory最佳實(shí)踐 ◆MVP專欄 ◆ 楊志洪丨楊建榮丨鄒德裕丨韓鋒丨歐陽(yáng)辰 網(wǎng)易丨騰訊云丨百度丨朱祥磊丨盧鈞軼 |
|
來(lái)自: waitingnothing > 《網(wǎng)關(guān)》