redis(Remote Dictionary Server)是一個(gè)由Salvatore Sanfilippo寫(xiě)的key-value存儲(chǔ)系統(tǒng),屬于nosql的一種。Redis是一個(gè)開(kāi)源的使用ANSI C語(yǔ)言編寫(xiě)、遵守BSD協(xié)議、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫(kù),并提供多種語(yǔ)言的API。它通常被稱為數(shù)據(jù)結(jié)構(gòu)服務(wù)器,因?yàn)橹担╲alue)可以是 字符串(String),哈希(Map),列表(list),集合(sets)和 有序集合(sorted sets)等類型。
String:字符串類型是redis中的最基本的類型
Hash:hash類型存儲(chǔ)的數(shù)據(jù)分為三個(gè)部分,鍵key、字段field、值value
結(jié)構(gòu)類似于:{stu:{name laowang age 20 sex man}}
List:類似于python中的列表,其中存儲(chǔ)的值是可以重復(fù)出現(xiàn)的。
0、lrange:返回存儲(chǔ)在 key 的list里指定范圍內(nèi)的元素。 start 和 end 偏移量都是基于0的下標(biāo),即list的第一個(gè)元素下標(biāo)是0(list的表頭),第二個(gè)元素下標(biāo)是1。偏移量也可以是負(fù)數(shù),表示偏移量是從list尾部開(kāi)始計(jì)數(shù)。 例如, -1 表示列表的最后一個(gè)元素,-2 是倒數(shù)第二個(gè),以此類推。
1、lpush和rpush
lpush:將所有指定的值插入到存于 key 的列表的頭部。如果 key 不存在,那么會(huì)創(chuàng)建一個(gè)空的列表然后再進(jìn)行 push 操作。 當(dāng) key 保存的不是一個(gè)列表,那么會(huì)返回一個(gè)錯(cuò)誤。
rpush:向存于 key 的列表的尾部插入所有指定的值。如果 key 不存在,那么會(huì)創(chuàng)建一個(gè)空的列表然后再進(jìn)行 push 操作。 當(dāng) key 保存的不是一個(gè)列表,那么會(huì)返回一個(gè)錯(cuò)誤。
2、lpop和rpop
lpop:移除并返回可以對(duì)應(yīng)的list的第一個(gè)元素。當(dāng)key不存在時(shí)返回nil
rpop:移除并返回key對(duì)應(yīng)的列表的最后一個(gè)元素。當(dāng)key不存在時(shí)返回nil
3、blpop:阻塞式列表的彈出原語(yǔ)。 它是命令 LPOP 的阻塞版本,這是因?yàn)楫?dāng)給定列表內(nèi)沒(méi)有任何元素可供彈出的時(shí)候, 連接將被 BLPOP 命令阻塞。 當(dāng)給定多個(gè) key 參數(shù)時(shí),按參數(shù) key 的先后順序依次檢查各個(gè)列表,彈出第一個(gè)非空列表的頭元素。
4、brpop:BRPOP 和 BLPOP 基本是完全一樣的,除了它們一個(gè)是從尾部彈出元素,而另一個(gè)是從頭部彈出元素。
5、lindex:返回元素的索引 index 在key對(duì)應(yīng)的list中存儲(chǔ)的具體內(nèi)容。 下標(biāo)是從0開(kāi)始索引的,所以 0 是表示第一個(gè)元素, 1 表示第二個(gè)元素,并以此類推。 負(fù)數(shù)索引用于指定從列表尾部開(kāi)始索引的元素。在這種方法下,-1 表示最后一個(gè)元素,-2 表示倒數(shù)第二個(gè)元素,并以此往前推。當(dāng) key 位置的值不是一個(gè)列表的時(shí)候,會(huì)返回一個(gè)error。
6、LINSERT key BEFORE|AFTER pivot value:把 value 插入存于 key 的列表中在基準(zhǔn)值 pivot 的前面或后面。當(dāng) key 不存在時(shí),這個(gè)list會(huì)被看作是空l(shuí)ist,任何操作都不會(huì)發(fā)生。當(dāng) key 存在,但保存的不是一個(gè)list的時(shí)候,會(huì)返回error。
7、llen:返回存儲(chǔ)在 key 里的list的長(zhǎng)度。 如果 key 不存在,那么就被看作是空l(shuí)ist,并且返回長(zhǎng)度為 0。 當(dāng)存儲(chǔ)在 key 里的值不是一個(gè)list的話,會(huì)返回error。
8、lpushx和rpushx:只有當(dāng) key 已經(jīng)存在并且存著一個(gè) list 的時(shí)候,在這個(gè) key 下面的 list 的頭部或尾部插入 value。 與 LPUSH 相反,當(dāng) key 不存在的時(shí)候不會(huì)進(jìn)行任何操作。
9、lrem:從存于 key 的列表里移除前 count 次出現(xiàn)的值為 value 的元素。 這個(gè) count 參數(shù)通過(guò)下面幾種方式影響這個(gè)操作:
count > 0: 從頭往尾移除值為 value 的元素。
count < 0: 從尾往頭移除值為 value 的元素。
count = 0: 移除所有值為 value 的元素。
10、LSET key index value:設(shè)置 index 位置的list元素的值為 value。當(dāng)index超出范圍時(shí)會(huì)返回一個(gè)error。
11、LTRIM key start stop:只保留key對(duì)應(yīng)的list中從start到stop的元素,其余元素全部剪切掉。
Set:類似于python中的set集合,存儲(chǔ)的的數(shù)據(jù)不可重復(fù)出現(xiàn),但不保證順序
0、smembers:返回key集合的所有元素。
1、sadd:添加一個(gè)或多個(gè)指定的member元素到集合的 key中.指定的一個(gè)或者多個(gè)元素member 如果已經(jīng)在集合key中存在則忽略.如果集合key 不存在,則新建集合key,并添加member元素到集合key中.如果key 的類型不是集合則返回錯(cuò)誤.
2、scard:集合的基數(shù)(元素的數(shù)量),如果key不存在,則返回 0.
3、sdiff:返回一個(gè)集合與給定集合的差集元素。注意這里是有順序的,比如sdiff myset2 myset3 ,會(huì)返回在myset2中有,而myset3中沒(méi)有的元素,sdiff myset3 myset2 則會(huì)返回myset3中有而myset2中沒(méi)有的元素,交換順序得到的結(jié)果是不一樣的。
4、sdiffstore destination key1 key2 ....:與sdiff類似,不同之處在于會(huì)將key1和key2的差集結(jié)果放在destination中,如果destination已經(jīng)存在, 則將其覆蓋重寫(xiě)。
5、sinter:返回指定所有的集合的成員的交集.。
6、sinterstore destination key [key ...]:與sinter類似,不同之處在于會(huì)將key1和key2的交集結(jié)果放在destination中,如果destination已經(jīng)存在, 則將其覆蓋重寫(xiě)。
7、sismember:返回成員 member 是否是存儲(chǔ)的集合 key的成員。
8、smove source destination member:將member從source集合移動(dòng)到destination集合中.。如果source 集合不存在或者不包含指定的元素,這smove命令不執(zhí)行任何操作并且返回0。否則對(duì)象將會(huì)從source集合中移除,并添加到destination集合中去,如果destination集合已經(jīng)存在該元素,則smove命令僅將該元素充source集合中移除.。如果source 和destination不是集合類型,則返回錯(cuò)誤。相當(dāng)于從source中剪切指定元素,再粘貼到destination中,如果destination中已經(jīng)存在了,則只會(huì)保留一個(gè)。
9、srandmember key [count]:隨機(jī)返回key集合中的特定個(gè)數(shù)的元素。
如果count是整數(shù)且小于集合中元素個(gè)數(shù),返回含有 count 個(gè)不同的元素的數(shù)組;
如果count是個(gè)整數(shù)且大于集合中元素的個(gè)數(shù)時(shí),僅返回整個(gè)集合的所有元素;
當(dāng)count是負(fù)數(shù),則會(huì)返回一個(gè)包含count的絕對(duì)值的個(gè)數(shù)元素的數(shù)組,如果count的絕對(duì)值大于元素的個(gè)數(shù),則返回的結(jié)果集里會(huì)出現(xiàn)一個(gè)元素出現(xiàn)多次的情況。
10、srem:在key集合中移除指定的元素. 如果指定的元素不是key集合中的元素則忽略 如果key集合不存在則被視為一個(gè)空的集合,該命令返回0。如果key的類型不是一個(gè)集合,則返回錯(cuò)誤.
11、scan:scan命令是一個(gè)基于游標(biāo)的迭代器。這意味著命令每次被調(diào)用都需要使用上一次這個(gè)調(diào)用返回的游標(biāo)作為該次調(diào)用的游標(biāo)參數(shù),以此來(lái)延續(xù)之前的迭代過(guò)程。當(dāng)scan命令的游標(biāo)參數(shù)被設(shè)置為 0 時(shí), 服務(wù)器將開(kāi)始一次新的迭代, 而當(dāng)服務(wù)器向用戶返回值為 0 的游標(biāo)時(shí), 表示迭代已結(jié)束。
12、sunion:返回給定的多個(gè)集合的并集中的所有成員。
13、sunionstore destination key [key ...]:與sunion類似,不同之處在于會(huì)將key1和key2的并集結(jié)果放在destination中,如果destination已經(jīng)存在, 則將其覆蓋重寫(xiě)。
Sorted Set:在集合的基礎(chǔ)上加入score控制存儲(chǔ)順序
1、zadd:將所有指定成員添加到鍵為key有序集合(sorted set)里面。 添加時(shí)可以指定多個(gè)分?jǐn)?shù)/成員(score/member)對(duì)。?
如果指定添加的成員已經(jīng)是有序集合里面的成員,則會(huì)更新改成員的分?jǐn)?shù)(scrore)并更新到正確的排序位置;
如果key不存在,將會(huì)創(chuàng)建一個(gè)新的有序集合(sorted set)并將分?jǐn)?shù)/成員(score/member)對(duì)添加到有序集合,就像原來(lái)存在一個(gè)空的有序集合一樣;
如果key存在,但是類型不是有序集合,將會(huì)返回一個(gè)錯(cuò)誤應(yīng)答。
分?jǐn)?shù)值是一個(gè)雙精度的浮點(diǎn)型數(shù)字字符串。+inf和-inf都是有效值。
zset的操作跟之前的list,set,string等的操作相似,這里不再具體列舉。
發(fā)布訂閱
Redis 發(fā)布訂閱(pub/sub)是一種消息通信模式:發(fā)送者(pub)發(fā)送消息,訂閱者(sub)接收消息。
Redis 客戶端可以訂閱任意數(shù)量的頻道。
下圖展示了頻道 channel1 , 以及訂閱這個(gè)頻道的三個(gè)客戶端 —— client2 、 client5 和 client1 之間的關(guān)系:
當(dāng)有新消息通過(guò) PUBLISH 命令發(fā)送給頻道 channel1 時(shí), 這個(gè)消息就會(huì)被發(fā)送給訂閱它的三個(gè)客戶端:
主從復(fù)制:
redis中也有類似于mongodb中的主從復(fù)制機(jī)制,一個(gè)master可以擁有多個(gè)slave,一個(gè)slave又可以擁有多個(gè)slave,如此下去,形成了強(qiáng)大的多級(jí)服務(wù)器集群架構(gòu)。比如,將ip為192.168.1.10的機(jī)器作為主服務(wù)器,將ip為192.168.1.11的機(jī)器作為從服務(wù)器
下面模擬一下redis中的主從復(fù)制:
第一步:建立文件環(huán)境:
node1:port 6001? master
node2:port 6002? slave
node3:port 6003? slave
第二步:修改配置文件(數(shù)據(jù)庫(kù)位置,日志文件位置,端口號(hào),從機(jī)要設(shè)置slaveof,如果有安全驗(yàn)證需設(shè)置免密登錄,)
port ****
dir /home/yuxiuxiu/node1/db/
logfile /home/yuxiuxiu/node1/log/redis.log
第三步:實(shí)現(xiàn)哨兵監(jiān)聽(tīng):
redis中沒(méi)有像mongodb中那樣的直接的在集群中檢測(cè)主機(jī)宕機(jī)并自動(dòng)選舉新的主機(jī)的機(jī)制,要想實(shí)現(xiàn)檢測(cè)主機(jī)的運(yùn)行狀態(tài),在主機(jī)宕機(jī)的時(shí)候產(chǎn)生新的主機(jī),需要借助sentinel機(jī)制,它是一種哨兵監(jiān)聽(tīng)機(jī)制,需要我們另外配置文件來(lái)手動(dòng)執(zhí)行,實(shí)際上在現(xiàn)實(shí)工作中,哨兵可能有很多個(gè),當(dāng)一定數(shù)量的哨兵同時(shí)檢測(cè)到直接宕機(jī),才會(huì)采取行動(dòng)產(chǎn)生新的主機(jī),另一方面也防止sentinel哨兵出現(xiàn)宕機(jī)的情況。這里我們?cè)O(shè)置兩個(gè)哨兵來(lái)協(xié)同工作,下面先來(lái)配置一下sentinel文件:
兩個(gè)哨兵的配置文件只需保證端口號(hào)不同。
先運(yùn)行三個(gè)服務(wù)器,再運(yùn)行哨兵:
運(yùn)行三個(gè)服務(wù)器:
sudo redis-server ./node1/redis.conf
sudo redis-server ./node2/redis.conf
sudo redis-server ./node3/redis.conf
再f分別運(yùn)行兩個(gè)哨兵:
sudo redis-server ./sentinel.conf --sentinel
再來(lái)連接三個(gè)客服端,我們看到主機(jī)正常運(yùn)行,可以get和set,兩個(gè)從機(jī)只可以get,不可以set:
我們可以看到兩個(gè)哨兵同時(shí)監(jiān)聽(tīng)了主機(jī)的6001端口:
現(xiàn)在我們把主機(jī)kill掉:
看到哨兵自動(dòng)更換了監(jiān)聽(tīng)對(duì)象,原本不可以進(jìn)行set操作的服務(wù)器,在成為新的主機(jī)之后,可以進(jìn)行set操作,端口號(hào)為6003的從機(jī)依然無(wú)法進(jìn)行set操作:
這里需要說(shuō)明的是,主機(jī)宕機(jī)時(shí),sentinel機(jī)制會(huì)自動(dòng)修改其配置文件,在原來(lái)的主機(jī)修復(fù)之后,原來(lái)的這個(gè)主機(jī)并不會(huì)奪回主機(jī)的地位。
與python交互
當(dāng)我們用Redis和StrictRedis創(chuàng)建連接時(shí),其實(shí)內(nèi)部實(shí)現(xiàn)并沒(méi)有主動(dòng)給我創(chuàng)建一個(gè)連接,我們獲得的連接是連接池提供的連接,這個(gè)連接由連接池管理,所以我們無(wú)需關(guān)注連接是否需要主動(dòng)釋放關(guān)閉的問(wèn)題。另外連接池有自己的關(guān)閉連接的接口,一旦調(diào)用該接口,所有連接都將被關(guān)閉,連接池的操作不需要程序員管理,系統(tǒng)redis模塊自動(dòng)管理好了。
具體函數(shù)參照: