一屁桑、Redis是什么?
Redis是一個(gè)開源(BSD許可)的栏赴,內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng)蘑斧,它可以用作數(shù)據(jù)庫、緩存和消息中間件须眷。
二竖瘾、Redis 能用來做什么?
1花颗、緩存:毫無疑問這是Redis當(dāng)今最為人熟知的使用場(chǎng)景捕传。再提升服務(wù)器性能方面非常有效;
2捎稚、排行榜:如果使用傳統(tǒng)的關(guān)系型數(shù)據(jù)庫來做這個(gè)事兒乐横,非常的麻煩,而利用Redis的SortSet數(shù)據(jù)結(jié)構(gòu)能夠非常方便搞定今野;
3葡公、計(jì)算器/限速器:利用Redis中原子性的自增操作,我們可以統(tǒng)計(jì)類似用戶點(diǎn)贊數(shù)条霜、用戶訪問數(shù)等催什,這類操作如果用MySQL,頻繁的讀寫會(huì)帶來相當(dāng)大的壓力宰睡;限速器比較典型的使用場(chǎng)景是限制某個(gè)用戶訪問某個(gè)API的頻率蒲凶,常用的有搶購時(shí)气筋,防止用戶瘋狂點(diǎn)擊帶來不必要的壓力;注:限速器也是對(duì)請(qǐng)求限流的一種實(shí)現(xiàn)方式旋圆。
4宠默、好友關(guān)系:利用集合的一些命令,比如求交集灵巧、并集搀矫、差集等】桃蓿可以方便搞定一些共同好友瓤球、共同愛好之類的功能;
5敏弃、簡(jiǎn)單消息隊(duì)列卦羡,除了Redis自身的發(fā)布/訂閱模式,我們也可以利用List來實(shí)現(xiàn)一個(gè)隊(duì)列機(jī)制麦到,比如:到貨通知绿饵、郵件發(fā)送之類的需求,不需要高可靠隅要,但是會(huì)帶來非常大的DB壓力蝴罪,完全可以用List來完成異步解耦;
6步清、Session共享,默認(rèn)Session是保存在服務(wù)器的文件中虏肾,即當(dāng)前服務(wù)器廓啊,如果是集群服務(wù),同一個(gè)用戶過來可能落在不同機(jī)器上封豪,這就會(huì)導(dǎo)致用戶頻繁登陸谴轮;采用Redis保存Session后,無論用戶落在那臺(tái)機(jī)器上都能夠獲取到對(duì)應(yīng)的Session信息吹埠。
三第步、Redis不能做什么?
Redis感覺能干的事情特別多缘琅,但它不是萬能的粘都,合適的地方用它事半功倍。如果濫用可能導(dǎo)致系統(tǒng)的不穩(wěn)定刷袍、成本增高等問題翩隧。比如,用Redis去保存用戶的基本信息呻纹,雖然它能夠支持持久化堆生,但是它的持久化方案并不能保證數(shù)據(jù)絕對(duì)的落地专缠,并且還可能帶來Redis性能下降,因?yàn)槌志没^頻繁會(huì)增大Redis服務(wù)的壓力淑仆。
簡(jiǎn)單總結(jié)就是數(shù)據(jù)量太大涝婉、數(shù)據(jù)訪問頻率非常低的業(yè)務(wù)都不適合使用Redis。數(shù)據(jù)太大會(huì)增加成本蔗怠,訪問頻率太低嘁圈,保存在內(nèi)存中純屬浪費(fèi)資源。
四蟀淮、Redis為什么能做這些最住?
上面說了Redis的一些使用場(chǎng)景,那么這些場(chǎng)景的解決方案也有很多其它選擇怠惶,比如緩存可以用Memcache涨缚,Session共享還能用MySql來實(shí)現(xiàn),消息隊(duì)列可以用RabbitMQ策治,我們?yōu)槭裁匆欢ㄒ肦edis呢脓魏?
1、那是因?yàn)镽edis執(zhí)行速度快:
- 速度快通惫,完全基于內(nèi)存茂翔;
- 使用C語言實(shí)現(xiàn),網(wǎng)絡(luò)層使用epoll解決高并發(fā)問題履腋;
- 單線程模型避免了不必要的上下文切換及競(jìng)爭(zhēng)條件珊燎;
注意:?jiǎn)尉€程僅僅是說在網(wǎng)絡(luò)請(qǐng)求這一模塊上用一個(gè)請(qǐng)求處理客戶端的請(qǐng)求,像持久化它就會(huì)重開一個(gè)線程/進(jìn)程去進(jìn)行處理
2遵湖、豐富的數(shù)據(jù)類型:Redis有8種數(shù)據(jù)類型悔政,每一種數(shù)據(jù)類型提供了非常豐富的操作命令,可以滿足絕大部分需求延旧,如果有特殊需求還能自己通過 lua 腳本自己創(chuàng)建新的命令(具備原子性)谋国;
3、除了提供的豐富的數(shù)據(jù)類型迁沫,Redis還提供了像慢查詢分析芦瘾、性能測(cè)試、Pipeline集畅、事務(wù)近弟、Lua自定義命令、Bitmaps牡整、HyperLogLog藐吮、發(fā)布/訂閱、Geo等個(gè)性化功能。
4谣辞、Redis的代碼開源在GitHub迫摔,它的編譯安裝也是非常的簡(jiǎn)單,沒有任何的系統(tǒng)依賴泥从;有非尘湔迹活躍的社區(qū),各種客戶端的語言支持也是非常完善躯嫉。另外它還支持事務(wù)纱烘、持久化、主從復(fù)制讓高可用祈餐、分布式成為可能擂啥。
四、Redis特性
1帆阳、速度快:數(shù)據(jù)存放在內(nèi)存中哺壶;單線程模式,避免了線程上下文切換及多線程競(jìng)爭(zhēng)訪問蜒谤;c語言實(shí)現(xiàn)山宾,更容易接近系統(tǒng)api;采用epoll非阻塞IO资锰,不在網(wǎng)絡(luò)上浪費(fèi)時(shí)間;
2阶祭、支持多種數(shù)據(jù)類型:支持8種數(shù)據(jù)類型:String绷杜、Hash胖翰、List、Set培他、 SortSet、Bitmaps遗座、HyperLogLog途蒋、GEO猛遍;
3、功能豐富:豐富的API,如可設(shè)置鍵過期懊烤,存在即設(shè)置(這可以用來解決分布式鎖問題)梯醒,基于發(fā)布訂閱可實(shí)現(xiàn)簡(jiǎn)單的消息隊(duì)列,通過Lua創(chuàng)建新命令腌紧,具有原子性茸习,管道(pipeline)功能,解決網(wǎng)絡(luò)開銷壁肋;
4号胚、服務(wù)器簡(jiǎn)單:開源代碼優(yōu)雅,容易閱讀源碼浸遗,采用單線程模型猫胁,避免并發(fā)問題,redis自己實(shí)現(xiàn)了多路復(fù)用跛锌;
5弃秆、客戶端語言版本多:如Java、Php察净、Go
6驾茴、支持多種持久化方式:RDB和AOP
7、支持集群部署:支持主從復(fù)制氢卡,高可用集群锈至,內(nèi)部集群方式與Memcache做集群實(shí)現(xiàn)不一樣的機(jī)制。
五译秦、Redis有什么特點(diǎn)峡捡?
Redis是一個(gè)Key-Value類型的內(nèi)存數(shù)據(jù)庫,和memcached有點(diǎn)像筑悴,整個(gè)數(shù)據(jù)庫都是在內(nèi)存當(dāng)中進(jìn)行加載操作们拙,定期通過異步操作把數(shù)據(jù)庫數(shù)據(jù)flush到硬盤上進(jìn)行保存。Redis的性能很高阁吝,可以處理超過10萬次/秒的讀寫操作砚婆,是目前已知性能最快的Key-Value DB。
除了性能外突勇,Redis還支持保存多種數(shù)據(jù)結(jié)構(gòu)装盯,此外單個(gè)value的最大限制是1GB,比memcached的1MB高太多了甲馋,因此Redis可以用來實(shí)現(xiàn)很多有用的功能埂奈,比方說用他的List來做FIFO雙向鏈表,實(shí)現(xiàn)一個(gè)輕量級(jí)的高性 能消息隊(duì)列服務(wù)定躏,用他的Set可以做高性能的tag系統(tǒng)等等账磺。另外Redis也可以對(duì)存入的Key-Value設(shè)置expire時(shí)間芹敌,因此也可以被當(dāng)作一 個(gè)功能加強(qiáng)版的memcached來用。
當(dāng)然垮抗,Redis也有缺陷氏捞,那就是是數(shù)據(jù)庫容量受到物理內(nèi)存的限制,不能用作海量數(shù)據(jù)的高性能讀寫借宵,因此Redis比較適合那些局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上幌衣。
六、使用Redis有哪些好處壤玫?
1豁护、速度快,因?yàn)閿?shù)據(jù)存在內(nèi)存中欲间,類似于HashMap楚里,HashMap的優(yōu)勢(shì)就是查找和操作的時(shí)間復(fù)雜度都是O(1)
2、支持豐富數(shù)據(jù)類型猎贴,支持string班缎,list,set她渴,sorted set达址,hash
3、支持事務(wù)趁耗,操作都是原子性沉唠,所謂的原子性就是對(duì)數(shù)據(jù)的更改要么全部執(zhí)行,要么全部不執(zhí)行
4苛败、豐富的特性:可用于緩存满葛,消息,按key設(shè)置過期時(shí)間罢屈,過期后將會(huì)自動(dòng)刪除
七嘀韧、Redis常見性能問題和解決方案
- Master寫內(nèi)存快照,save命令調(diào)度rdbSave函數(shù)缠捌,會(huì)阻塞主線程的工作锄贷,當(dāng)快照比較大時(shí)對(duì)性能影響是非常大的,會(huì)間斷性暫停服務(wù)曼月,所以Master最好不要寫內(nèi)存快照肃叶。
- Master AOF持久化,如果不重寫AOF文件十嘿,這個(gè)持久化方式對(duì)性能的影響是最小的,但是AOF文件會(huì)不斷增大岳锁,AOF文件過大會(huì)影響Master重啟的恢復(fù)速度绩衷。Master最好不要做任何持久化工作,包括內(nèi)存快照和AOF日志文件,特別是不要啟用內(nèi)存快照做持久化,如果數(shù)據(jù)比較關(guān)鍵咳燕,某個(gè)Slave開啟AOF備份數(shù)據(jù)勿决,策略為每秒同步一次。
- Master調(diào)用BGREWRITEAOF重寫AOF文件招盲,AOF在重寫的時(shí)候會(huì)占大量的CPU和內(nèi)存資源低缩,導(dǎo)致服務(wù)load過高,出現(xiàn)短暫服務(wù)暫筒芑酰現(xiàn)象咆繁。
- Redis主從復(fù)制的性能問題,為了主從復(fù)制的速度和連接的穩(wěn)定性顶籽,Slave和Master最好在同一個(gè)局域網(wǎng)內(nèi)
八玩般、MySQL里有2000w數(shù)據(jù),Redis中只存20w的數(shù)據(jù)礼饱,如何保證Redis中的數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù)
相關(guān)知識(shí):Redis 內(nèi)存數(shù)據(jù)集大小上升到一定大小的時(shí)候坏为,就會(huì)施行數(shù)據(jù)淘汰策略(回收策略)。Redis 提供 6種數(shù)據(jù)淘汰策略:
- volatile-lru:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰
- volatile-ttl:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過期的數(shù)據(jù)淘汰
- volatile-random:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰
- allkeys-lru:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰
- allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰
- no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù)
九镊绪、為什么Redis需要把所有數(shù)據(jù)放到內(nèi)存中?
Redis為了達(dá)到最快的讀寫速度將數(shù)據(jù)都讀到內(nèi)存中匀伏,并通過異步的方式將數(shù)據(jù)寫入磁盤。所以redis具有快速和數(shù)據(jù)持久化的特征蝴韭。如果不將數(shù)據(jù)放在內(nèi)存中够颠,磁盤I/O速度為嚴(yán)重影響redis的性能。在內(nèi)存越來越便宜的今天万皿,redis將會(huì)越來越受歡迎摧找。如果設(shè)置了最大使用的內(nèi)存,則數(shù)據(jù)已有記錄數(shù)達(dá)到內(nèi)存限值后不能繼續(xù)插入新值牢硅。
十蹬耘、Redis是單進(jìn)程單線程的
Redis利用隊(duì)列技術(shù)將并發(fā)訪問變?yōu)榇性L問,消除了傳統(tǒng)數(shù)據(jù)庫串行控制的開銷减余。
十一综苔、Redis的并發(fā)競(jìng)爭(zhēng)問題如何解決?
Redis為單進(jìn)程單線程模式,采用隊(duì)列模式將并發(fā)訪問變?yōu)榇性L問位岔。Redis本身沒有鎖的概念如筛,Redis對(duì)于多個(gè)客戶端連接并不存在競(jìng)爭(zhēng),但是在Jedis客戶端對(duì)Redis進(jìn)行并發(fā)訪問時(shí)會(huì)發(fā)生連接超時(shí)抒抬、數(shù)據(jù)轉(zhuǎn)換錯(cuò)誤杨刨、阻塞、客戶端關(guān)閉連接等問題擦剑,這些問題均是由于客戶端連接混亂造成妖胀。對(duì)此有2種解決方法:
- 客戶端角度芥颈,為保證每個(gè)客戶端間正常有序與Redis進(jìn)行通信,對(duì)連接進(jìn)行池化赚抡,同時(shí)對(duì)客戶端讀寫Redis操作采用內(nèi)部鎖synchronized爬坑。
- 服務(wù)器角度,利用setnx實(shí)現(xiàn)鎖涂臣。注:對(duì)于第一種盾计,需要應(yīng)用程序自己處理資源的同步,可以使用的方法比較通俗赁遗,可以使用synchronized也可以使用lock署辉;第二種需要用到Redis的setnx命令,但是需要注意一些問題吼和。
十二涨薪、Redis事務(wù)的了解CAS(check-and-set 操作實(shí)現(xiàn)樂觀鎖 )?
和眾多其它數(shù)據(jù)庫一樣,Redis作為NoSQL數(shù)據(jù)庫也同樣提供了事務(wù)機(jī)制炫乓。在Redis中刚夺,MULTI/EXEC/DISCARD/WATCH這四個(gè)命令是我們實(shí)現(xiàn)事務(wù)的基石。Redis中事務(wù)的實(shí)現(xiàn)特征:
在事務(wù)中的所有命令都將會(huì)被串行化的順序執(zhí)行末捣,事務(wù)執(zhí)行期間侠姑,Redis不會(huì)再為其它客戶端的請(qǐng)求提供任何服務(wù),從而保證了事物中的所有命令被原子的執(zhí)行箩做。
和關(guān)系型數(shù)據(jù)庫中的事務(wù)相比莽红,在Redis事務(wù)中如果有某一條命令執(zhí)行失敗,其后的命令仍然會(huì)被繼續(xù)執(zhí)行邦邦。
我們可以通過MULTI命令開啟一個(gè)事務(wù)安吁,有關(guān)系型數(shù)據(jù)庫開發(fā)經(jīng)驗(yàn)的人可以將其理解為"BEGIN TRANSACTION"語句。在該語句之后執(zhí)行的命令都將被視為事務(wù)之內(nèi)的操作燃辖,最后我們可以通過執(zhí)行EXEC/DISCARD命令來提交/回滾該事務(wù)內(nèi)的所有操作鬼店。這兩個(gè)Redis命令可被視為等同于關(guān)系型數(shù)據(jù)庫中的COMMIT/ROLLBACK語句。
在事務(wù)開啟之前黔龟,如果客戶端與服務(wù)器之間出現(xiàn)通訊故障并導(dǎo)致網(wǎng)絡(luò)斷開妇智,其后所有待執(zhí)行的語句都將不會(huì)被服務(wù)器執(zhí)行。然而如果網(wǎng)絡(luò)中斷事件是發(fā)生在客戶端執(zhí)行EXEC命令之后氏身,那么該事務(wù)中的所有命令都會(huì)被服務(wù)器執(zhí)行巍棱。
當(dāng)使用Append-Only模式時(shí),Redis會(huì)通過調(diào)用系統(tǒng)函數(shù)write將該事務(wù)內(nèi)的所有寫操作在本次調(diào)用中全部寫入磁盤蛋欣。然而如果在寫入的過程中出現(xiàn)系統(tǒng)崩潰航徙,如電源故障導(dǎo)致的宕機(jī),那么此時(shí)也許只有部分?jǐn)?shù)據(jù)被寫入到磁盤陷虎,而另外一部分?jǐn)?shù)據(jù)卻已經(jīng)丟失捉偏。
Redis服務(wù)器會(huì)在重新啟動(dòng)時(shí)執(zhí)行一系列必要的一致性檢測(cè)倒得,一旦發(fā)現(xiàn)類似問題,就會(huì)立即退出并給出相應(yīng)的錯(cuò)誤提示夭禽。此時(shí),我們就要充分利用Redis工具包中提供的redis-check-aof工具谊路,該工具可以幫助我們定位到數(shù)據(jù)不一致的錯(cuò)誤讹躯,并將已經(jīng)寫入的部分?jǐn)?shù)據(jù)進(jìn)行回滾。修復(fù)之后我們就可以再次重新啟動(dòng)Redis服務(wù)器了缠劝。
十三潮梯、WATCH命令和基于CAS的樂觀鎖
在Redis的事務(wù)中,WATCH命令可用于提供CAS(check-and-set)功能惨恭。假設(shè)我們通過WATCH命令在事務(wù)執(zhí)行之前監(jiān)控了多個(gè)Keys秉馏,倘若在WATCH之后有任何Key的值發(fā)生了變化,EXEC命令執(zhí)行的事務(wù)都將被放棄脱羡,同時(shí)返回Null multi-bulk應(yīng)答以通知調(diào)用者事務(wù)執(zhí)行失敗萝究。
十四、Redis持久化的幾種方式
1锉罐、快照(snapshots)
缺省情況情況下帆竹,Redis把數(shù)據(jù)快照存放在磁盤上的二進(jìn)制文件中,文件名為dump.rdb脓规。你可以配置Redis的持久化策略栽连,例如數(shù)據(jù)集中每N秒鐘有超過M次更新,就將數(shù)據(jù)寫入磁盤侨舆;或者你可以手工調(diào)用命令SAVE或BGSAVE秒紧。
工作原理:
- Redis forks.
- 子進(jìn)程開始將數(shù)據(jù)寫到臨時(shí)RDB文件中。
- 當(dāng)子進(jìn)程完成寫RDB文件挨下,用新文件替換老文件熔恢。
- 這種方式可以使Redis使用copy-on-write技術(shù)。
2复颈、AOF
快照模式并不十分健壯绩聘,當(dāng)系統(tǒng)停止,或者無意中Redis被kill掉耗啦,最后寫入Redis的數(shù)據(jù)就會(huì)丟失凿菩。這對(duì)某些應(yīng)用也許不是大問題,但對(duì)于要求高可靠性的應(yīng)用來說帜讲,Redis就不是一個(gè)合適的選擇衅谷。Append-only文件模式是另一種選擇。你可以在配置文件中打開AOF模式似将。
3获黔、虛擬內(nèi)存方式
當(dāng)你的key很小而value很大時(shí),使用VM的效果會(huì)比較好.因?yàn)檫@樣節(jié)約的內(nèi)存比較大蚀苛。當(dāng)你的key不小時(shí),可以考慮使用一些非常方法將很大的key變成很大的value,比如你可以考慮將key,value組合成一個(gè)新的value。vm-max-threads這個(gè)參數(shù),可以設(shè)置訪問swap文件的線程數(shù),設(shè)置最好不要超過機(jī)器的核數(shù),如果設(shè)置為0,那么所有對(duì)swap文件的操作都是串行的.可能會(huì)造成比較長時(shí)間的延遲,但是對(duì)數(shù)據(jù)完整性有很好的保證玷氏。如果數(shù)據(jù)量很大堵未,可以考慮分布式或者其他數(shù)據(jù)庫。
十五盏触、Redis的緩存失效策略和主鍵失效機(jī)制
作為緩存系統(tǒng)都要定期清理無效數(shù)據(jù)渗蟹,就需要一個(gè)主鍵失效和淘汰策略。在Redis當(dāng)中赞辩,有生存期的key被稱為volatile雌芽。在創(chuàng)建緩存時(shí),要為給定的key設(shè)置生存期辨嗽,當(dāng)key過期的時(shí)候(生存期為0)世落,它可能會(huì)被刪除。
可以對(duì)一個(gè)已經(jīng)帶有生存時(shí)間的 key 執(zhí)行EXPIRE命令糟需,新指定的生存時(shí)間會(huì)取代舊的生存時(shí)間屉佳。過期時(shí)間的精度已經(jīng)被控制在1ms之內(nèi),主鍵失效的時(shí)間復(fù)雜度是O(1)篮灼,EXPIRE和TTL命令搭配使用忘古,TTL可以查看key的當(dāng)前生存時(shí)間。設(shè)置成功返回 1诅诱;當(dāng) key 不存在或者不能為 key 設(shè)置生存時(shí)間時(shí)髓堪,返回 0 。
redis 提供 6種數(shù)據(jù)淘汰策略:
- volatile-lru:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰
- volatile-ttl:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過期的數(shù)據(jù)淘汰
- volatile-random:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰
- allkeys-lru:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰
- allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰
- no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù)
注意這里的6種機(jī)制娘荡,volatile和allkeys規(guī)定了是對(duì)已設(shè)置過期時(shí)間的數(shù)據(jù)集淘汰數(shù)據(jù)還是從全部數(shù)據(jù)集淘汰數(shù)據(jù)干旁,后面的lru、ttl以及random是三種不同的淘汰策略炮沐,再加上一種no-enviction永不回收的策略争群。
使用策略規(guī)則:
1、如果數(shù)據(jù)呈現(xiàn)冪律分布大年,也就是一部分?jǐn)?shù)據(jù)訪問頻率高换薄,一部分?jǐn)?shù)據(jù)訪問頻率低,則使用allkeys-lru
2翔试、如果數(shù)據(jù)呈現(xiàn)平等分布肝箱,也就是所有的數(shù)據(jù)訪問頻率都相同灵奖,則使用allkeys-random
三種數(shù)據(jù)淘汰策略:
ttl和random比較容易理解,實(shí)現(xiàn)也會(huì)比較簡(jiǎn)單。主要是Lru最近最少使用淘汰策略怀泊,設(shè)計(jì)上會(huì)對(duì)key 按失效時(shí)間排序,然后取最先失效的key進(jìn)行淘汰。
十六、Redis分布式鎖正確的實(shí)現(xiàn)方法
資料來源
W3Cschool redis面試題匯總