读书笔记之《Redis开发与运维》—— 一
前言
????讀書(shū)筆記系列主要記錄自己看的書(shū)籍中的知識(shí)點(diǎn),算是一個(gè)歸納整理吧。Redis在我們的日常開(kāi)發(fā)中可以說(shuō)是很常用了,《Redis開(kāi)發(fā)與運(yùn)維》這本書(shū)講解了Redis開(kāi)發(fā)和運(yùn)維的方方面面,很系統(tǒng)、全面,關(guān)鍵是實(shí)用。特來(lái)擼擼它,記錄一番。全書(shū)分為14章,下面將記錄個(gè)人認(rèn)為每章中重要的知識(shí)點(diǎn)。
一、Redis初識(shí)
????Redis是一種基于鍵值對(duì)(key-value)的NoSQL數(shù)據(jù)庫(kù),Redis中的值可以是由string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、Bitmaps(位圖)、HyperLogLog、GEO(地理信息定位)等多種數(shù)據(jù)結(jié)構(gòu)和算法構(gòu)成,可以滿足很多的應(yīng)用場(chǎng)景。因?yàn)镽edis會(huì)將所有數(shù)據(jù)都放在內(nèi)存里,所以它的讀寫(xiě)性能非常好。Redis還可以將內(nèi)存的數(shù)據(jù)利用快照和日志的形式保存到硬盤(pán)上,這樣發(fā)生斷電或者機(jī)器故障,內(nèi)存中的數(shù)據(jù)就不會(huì)丟失。當(dāng)然Redis還提供了其他很多附加功能。
1、Redis特性
(1)速度快
Redis的所有數(shù)據(jù)都是放在內(nèi)存里的,這是速度快的最主要原因;
Redis是用C語(yǔ)言實(shí)現(xiàn)的,“距離”操作系統(tǒng)更近,執(zhí)行速度相對(duì)會(huì)更快;
Redis采用單線程架構(gòu),預(yù)防了多線程可能產(chǎn)生的競(jìng)爭(zhēng)問(wèn)題;
(2)基于鍵值對(duì)的數(shù)據(jù)結(jié)構(gòu)
Redis中的值不僅可以是字符串,還可以是具體的數(shù)據(jù)結(jié)構(gòu),方面在不同應(yīng)用場(chǎng)景的開(kāi)發(fā)。Redis主要提供五種數(shù)據(jù)結(jié)構(gòu):字符串、哈希、列表、集合、有序列表,并且在字符串的基礎(chǔ)上演變出來(lái)了位圖(Bitmaps)和HyperLogLog倆種“數(shù)據(jù)結(jié)構(gòu)”。Redis3.2版本加入了GEO(地理信息定位)的功能。
(3)豐富的功能
除了5種數(shù)據(jù)結(jié)構(gòu),還有其他額外的許多功能:
鍵過(guò)期功能,用來(lái)實(shí)現(xiàn)緩存;
發(fā)布訂閱功能,用來(lái)實(shí)現(xiàn)消息系統(tǒng);
Lua腳本功能,利用Lua腳本創(chuàng)造出新的Redis命令;
簡(jiǎn)單的事務(wù)功能,在一定程度上保證事務(wù)特性;
流水線(Pipeline)功能,客戶端能將一批命令一次性傳到Redis,減少網(wǎng)絡(luò)開(kāi)銷(xiāo)。
(4)簡(jiǎn)單穩(wěn)定
代碼少,單線程,服務(wù)端、客戶端處理簡(jiǎn)單,redis不依賴操作系統(tǒng)中的類庫(kù),自己實(shí)現(xiàn)了事件處理的相關(guān)功能。
(5)客戶端語(yǔ)言多
redis提供了簡(jiǎn)單的TCP通信協(xié)議,很多編程語(yǔ)言可以很方便的接入到redis。
(6)持久化
redis提供了兩種持久化方式:RDB和AOF。可以用這兩種策略將內(nèi)存的數(shù)據(jù)保存在硬盤(pán)中,保證了數(shù)據(jù)的可持久性。
(7)主從復(fù)制
redis提供了復(fù)制功能,實(shí)現(xiàn)了多個(gè)相同數(shù)據(jù)的redis副本,復(fù)制功能是分布式redis的基礎(chǔ)。
(8)高可用和分布式
redis提供了高可用實(shí)現(xiàn)Redis Sentinel(哨兵),能夠保證redis節(jié)點(diǎn)的故障發(fā)現(xiàn)和故障自動(dòng)轉(zhuǎn)移。并且3.0版本提供了分布式實(shí)現(xiàn)Redis Cluster(集群),
這是redis真正的分布式實(shí)現(xiàn),提供了高可用、讀寫(xiě)和容量的擴(kuò)展性。
2、Redis使用場(chǎng)景
緩存、排行榜系統(tǒng)、計(jì)數(shù)器應(yīng)用(redis天然支持計(jì)數(shù)功能,且計(jì)數(shù)性能很好)、社交網(wǎng)絡(luò)(粉絲、共同喜好、推送等,社交網(wǎng)站的訪問(wèn)量比較大,傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)不太適合保存這種類型的數(shù)據(jù),可用redis實(shí)現(xiàn))、消息隊(duì)列系統(tǒng)(消息隊(duì)列具有業(yè)務(wù)解耦、非實(shí)時(shí)業(yè)務(wù)削峰等特性,redis可以滿足一般的消息隊(duì)列功能,不過(guò)一般項(xiàng)目中還是使用專業(yè)的消息隊(duì)列,更加強(qiáng)大)。
redis也有不適合它解決的問(wèn)題場(chǎng)景,站在數(shù)據(jù)規(guī)模和數(shù)據(jù)冷熱角度來(lái)分析的話:數(shù)據(jù)規(guī)模角度,數(shù)據(jù)可分為大規(guī)模數(shù)據(jù)和小規(guī)模數(shù)據(jù),redis的數(shù)據(jù)是放在內(nèi)存里的,如果數(shù)據(jù)規(guī)模非常大,不適合使用redis存儲(chǔ);站在數(shù)據(jù)冷熱角度,數(shù)據(jù)分為熱數(shù)據(jù)和冷數(shù)據(jù),熱數(shù)據(jù)是指需要頻繁操作的數(shù)據(jù),如果將冷數(shù)據(jù)放在redis中,浪費(fèi)內(nèi)存。
二、API的理解和使用
1、全局命令
(1)查看所有鍵:keys *
(2)鍵總數(shù):dbsize
注意:dbsize命令在計(jì)算總數(shù)時(shí)候不會(huì)遍歷所有鍵,而是直接獲取redis內(nèi)部的鍵總數(shù)變量,時(shí)間復(fù)雜度O(1);而keys命令會(huì)遍歷所有鍵,時(shí)間復(fù)雜度O(n),如果redis保存了大量鍵時(shí),線上環(huán)境禁止使用。
(3)檢查鍵是否存在(鍵存在返回1,不存在返回0):exists key
(4)刪除鍵(返回的結(jié)果是成功刪除的個(gè)數(shù),刪除一個(gè)不存在的鍵,返回0):del key [key …]
注意:del key表示刪除一個(gè),del key1 key2 key3表示刪除3個(gè)
(5)鍵過(guò)期:expire key seconds
注意:redis支持對(duì)鍵添加過(guò)期時(shí)間,超過(guò)過(guò)期時(shí)間后,會(huì)自動(dòng)刪除鍵;ttl key 命令會(huì)返回鍵的剩余過(guò)期時(shí)間,返回值>=0表示鍵的剩余過(guò)期時(shí)間,返回值-1表示鍵沒(méi)有設(shè)置過(guò)期時(shí)間,返回值-2表示鍵不存在。
(6)鍵的數(shù)據(jù)結(jié)構(gòu)類型:type key
注意:如果鍵是字符串類型,返回string,如果鍵是列表類型,返回list,其他幾種類似。如果鍵不存在,返回none。
2、數(shù)據(jù)結(jié)構(gòu)的內(nèi)部編碼
每種數(shù)據(jù)結(jié)構(gòu)都有自己底層的內(nèi)部編碼實(shí)現(xiàn),而且是多種實(shí)現(xiàn),redis會(huì)在合適的場(chǎng)景選擇合適的內(nèi)部編碼。比如zset包含skiplist和ziplist兩種內(nèi)部編碼。這樣設(shè)計(jì)的好處是:可以改進(jìn)內(nèi)部編碼,而對(duì)外的數(shù)據(jù)結(jié)構(gòu)和命令沒(méi)有影響;多種內(nèi)部編碼實(shí)現(xiàn)可以在不同場(chǎng)景下發(fā)揮各自的優(yōu)勢(shì),比如ziplist比較節(jié)省內(nèi)存,但是在列表元素比較多的情況下,性能會(huì)有所下降,這個(gè)時(shí)候redis會(huì)根據(jù)配置選項(xiàng)將列表類型的內(nèi)部實(shí)現(xiàn)轉(zhuǎn)換為linkedlist。
3、單線程架構(gòu)
redis使用單線程架構(gòu)和I/O多路復(fù)用模型來(lái)實(shí)現(xiàn)高性能的內(nèi)存數(shù)據(jù)庫(kù)服務(wù)。一條命令從客戶端達(dá)到服務(wù)端不會(huì)立刻執(zhí)行,所有命令都會(huì)進(jìn)入到一個(gè)隊(duì)列中,然后逐個(gè)被執(zhí)行。不會(huì)有兩條命令被同時(shí)執(zhí)行。redis使用了I/O多路復(fù)用技術(shù)來(lái)解決I/O的問(wèn)題。
redis使用單線程模式那么快的原因:純內(nèi)存訪問(wèn),這個(gè)最重要;非阻塞I/O,redis使用epoll作為I/O多路復(fù)用技術(shù)的實(shí)現(xiàn),并且redis加上自身的事件處理模型將epoll中的連接、讀寫(xiě)、關(guān)閉都轉(zhuǎn)換為事件,不在網(wǎng)絡(luò)I/O上浪費(fèi)過(guò)多的時(shí)間;單線程避免了線程切換和競(jìng)爭(zhēng)產(chǎn)生的消耗。
注意:單線程會(huì)有一個(gè)問(wèn)題,對(duì)于每個(gè)命令的執(zhí)行時(shí)間是有要求的,如果執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)造成其他命令的阻塞,對(duì)于redis來(lái)說(shuō)是致命的,所以redis是面向快速執(zhí)行場(chǎng)景的數(shù)據(jù)庫(kù)。
4、字符串
(1)設(shè)置值:set key value [ex seconds] [px milliseconds] [nx|xx]
注意:nx 鍵必須不存在,才可以設(shè)置成功,用于添加; xx 鍵必須存在,才可以設(shè)置成功,用于更新
(2)獲取值:get key
批量設(shè)置值:mset key value [key value …]
批量獲取值:mget key [key …]
注意:批量操作可以減少網(wǎng)絡(luò)時(shí)間(n次網(wǎng)絡(luò)時(shí)間+n次命令時(shí)間 —> 1次網(wǎng)絡(luò)時(shí)間+n次命令時(shí)間),但是每次批量操作所發(fā)送的命令不是無(wú)節(jié)制的,如果數(shù)量過(guò)多可能造成redis阻塞或者網(wǎng)絡(luò)阻塞。
(3)計(jì)數(shù):incr key
incr命令用于對(duì)值做自增操作,如果值不是整數(shù),返回錯(cuò)誤;如果值是整數(shù),返回自增后的結(jié)果;如果鍵不存在,按照值為0自增,返回結(jié)果1。
很多存儲(chǔ)系統(tǒng)和編程語(yǔ)言內(nèi)部使用CAS機(jī)制實(shí)現(xiàn)計(jì)數(shù)功能,會(huì)有一定的CPU開(kāi)銷(xiāo),但redis中不存在這個(gè)問(wèn)題,因?yàn)閞edis單線程架構(gòu),任何命令到了redis服務(wù)端都要順序執(zhí)行。
(4)內(nèi)部編碼(redis會(huì)根據(jù)當(dāng)前值的類型和長(zhǎng)度決定使用哪種內(nèi)部編碼實(shí)現(xiàn))
int(8個(gè)字節(jié)的長(zhǎng)整形) embstr(小于等于39個(gè)字節(jié)的字符串) raw(大于39個(gè)字節(jié)的字符串)
(5)典型應(yīng)用場(chǎng)景
緩存功能、計(jì)數(shù)、共享session、限速
5、哈希
(1)設(shè)置值
hset key field value
(2)獲取值
hget key field
(3)批量設(shè)置或獲取field-value
hmget key field [field …]
hmset key field value [field value …]
(4)內(nèi)部編碼(ziplist、hashtable)
當(dāng)哈希類型的field個(gè)數(shù)小于512,并且所有的value小于64字節(jié),使用ziplist作為哈希的內(nèi)部實(shí)現(xiàn),否則使用hashtable。512和64是默認(rèn)的,可以配置。
(5)應(yīng)用場(chǎng)景
比如:用戶信息
6、列表
列表是用來(lái)存儲(chǔ)多個(gè)有序的字符串,可以對(duì)列表兩端插入和彈出。列表類型有兩個(gè)特點(diǎn):(1)列表中的元素是有序的;(2)列表中的元素可以是重復(fù)的。
(1)從右端插入、從左端插入
rpush key value [value …] lpush key value [value …]
lrange 0 -1 表示從左到右獲取列表的所有元素
(2)內(nèi)部編碼(ziplist、linkedlist、quicklist)
當(dāng)列表的元素個(gè)數(shù)小于512個(gè),并且列表的每個(gè)元素值都小于64字節(jié),redis會(huì)選用ziplist來(lái)作為列表的內(nèi)部實(shí)現(xiàn),否則選用linkedlist。Redis3.2版本提供了quicklist內(nèi)部編碼,它是以一個(gè)ziplist為節(jié)點(diǎn)的linkedlist,結(jié)合了ziplist和linkedlist兩者的優(yōu)勢(shì)。
(3)使用場(chǎng)景
例如:消息隊(duì)列、文章列表
7、集合
集合中不允許有重復(fù)元素,并且集合中的元素是無(wú)序的。
(1)添加元素
sadd key elements [elements …]
(2)刪除元素
srem key elements [elements …]
(3)內(nèi)部編碼(intset、hashtable)
當(dāng)集合中的元素都是整數(shù)且元素個(gè)數(shù)小于512(默認(rèn)值,可配置),redis選用intset作為集合內(nèi)部實(shí)現(xiàn),否則選用hashtable。
(4)使用場(chǎng)景
標(biāo)簽、社交等,比如一個(gè)用戶對(duì)可樂(lè)、體育感興趣,另一個(gè)用戶對(duì)歷史、新聞感興趣,這些興趣點(diǎn)就是標(biāo)簽。
8、有序集合
不能有重復(fù)成員,元素可以排序,每個(gè)元素設(shè)置一個(gè)分?jǐn)?shù)(score)作為排序的依據(jù)。有序集合的元素不能重復(fù),但是分?jǐn)?shù)可以重復(fù)。
(1)添加成員
zadd key score member [score member …]
(2)內(nèi)部編碼(ziplist、skiplist)
當(dāng)有序集合的元素個(gè)數(shù)小于128個(gè),并且每個(gè)元素的值都小于64字節(jié),Redis使用ziplist作為有序集合的內(nèi)部實(shí)現(xiàn)。否則使用skiplist。
(3)使用場(chǎng)景
排行榜系統(tǒng)
9、健管理
(1)單個(gè)健管理
返回鍵類型、鍵重命名、鍵過(guò)期、遷移鍵等。
注意:遷移鍵有三種方式:move、dump+restore、migrate。move命令用于redis內(nèi)部進(jìn)行數(shù)據(jù)遷移,從一個(gè)數(shù)據(jù)庫(kù)遷移到另一個(gè)數(shù)據(jù)庫(kù),不建議生產(chǎn)環(huán)境使用redis多數(shù)據(jù)庫(kù)功能;dump+restore可以實(shí)現(xiàn)在不同redis實(shí)例之間進(jìn)行數(shù)據(jù)遷移,分為dump和restore兩步,其中在源redis上dump會(huì)將鍵值序列化,采用RDB格式,在目標(biāo)redis上,restore會(huì)將上面序列化的值復(fù)原;migrate命令用于redis實(shí)例之間進(jìn)行數(shù)據(jù)遷移,實(shí)際上migrate是將dump、restore、del三個(gè)命令進(jìn)行了整合。migrate命令的數(shù)據(jù)傳輸直接在源redis和目標(biāo)redis上完成。
move命令作用于redis實(shí)例內(nèi)部,是原子性的,不支持多個(gè)鍵;dump+restore作用于redis實(shí)例之間,不是原子性,不支持多個(gè)鍵;migrate作用于redis實(shí)例之間,是原子性的,支持多個(gè)鍵。
(2)遍歷鍵(keys和scan)
keys會(huì)全量遍歷所有鍵,可能造成redis阻塞。scan可以想象成只掃描字典中的一部分鍵,直到將字典中的所有鍵遍歷完畢。scan可以有效解決
keys命令可能產(chǎn)生的阻塞問(wèn)題,但是scan的過(guò)程中,如果有鍵的變化(增加、刪除、修改),就可能新鍵沒(méi)有遍歷到或者遍歷了重復(fù)的健。所以scan不能保證完整的遍歷出來(lái)所有的健。
(3)數(shù)據(jù)庫(kù)管理
select dbIndex 切換數(shù)據(jù)庫(kù)
flushdb/flushall 清除數(shù)據(jù)庫(kù),flushdb只清除當(dāng)前數(shù)據(jù)庫(kù),flushall清除所有數(shù)據(jù)庫(kù)。
總結(jié)
以上是生活随笔為你收集整理的读书笔记之《Redis开发与运维》—— 一的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。