一文搞懂Redis鍵值對存儲數(shù)據(jù)庫
簡介
Redis(Remote Dictionary Server,遠(yuǎn)程字典服務(wù)器)是一個(gè)開源的、高性能的鍵值對(key-value)存儲系統(tǒng),是跨平臺的非關(guān)系型數(shù)據(jù)庫。
2008年,一款基于MySQL的網(wǎng)站實(shí)時(shí)統(tǒng)計(jì)系統(tǒng)——LLOOGG被正式推出。不久之后,Merzia公司由于不滿于這個(gè)系統(tǒng)的現(xiàn)有性能,于2009年為LLOOGG設(shè)計(jì)了一個(gè)全新的數(shù)據(jù)庫——Redis(第一個(gè)版本)。為了使Redis能夠應(yīng)用到更多地方,其創(chuàng)始人在社區(qū)開源代碼,并與Redis另一名主要的代碼貢獻(xiàn)者共同開發(fā)著Redis。
2010年,VMware公司贊助Redis的開發(fā),開發(fā)人員開始全職開發(fā)Redis。從2013年5月起,Pivotal成為Redis的主要贊助商。
根據(jù)Redis官網(wǎng)的最新介紹,Redis是一個(gè)開源(持有BSD許可)的、基于內(nèi)存處理的數(shù)據(jù)結(jié)構(gòu)存儲,用作數(shù)據(jù)庫存儲、緩存處理、消息代理和流引擎(Streaming Engine)。Redis的功能十分強(qiáng)大,在短短幾年的時(shí)間里,不僅獲得了龐大的用戶群體,還得到了大量程序員和IT公司的支持和推廣。
DB-Engines網(wǎng)站根據(jù)鍵值對存儲數(shù)據(jù)庫管理系統(tǒng)的受歡迎程度對它們進(jìn)行排名,該排名結(jié)果每月更新一次。DB-Engines網(wǎng)站的鍵值對數(shù)據(jù)庫排名如下。
根據(jù)Stack Overflow年度開發(fā)人員的調(diào)查結(jié)果顯示,Redis連續(xù)4年獲得最受歡迎的鍵值對存儲數(shù)據(jù)庫的稱號。Redis是基于ANSI C語言編寫的,并且為開發(fā)者提供了多種語言的API,如C#、C++、GO、Java、PHP、Ruby、JavaScript、Perl、Python等。伴隨著Redis的用戶越來越多,大部分的互聯(lián)網(wǎng)公司都開始使用Redis作為公共緩存。
特點(diǎn)
Redis作為熱門的NoSQL數(shù)據(jù)庫系統(tǒng)之一,提供了多種鍵值數(shù)據(jù)類型以適應(yīng)不同場景下的存儲需求。Redis主要有以下6個(gè)特點(diǎn)。
1. 豐富的數(shù)據(jù)結(jié)構(gòu)
Redis通常被稱為數(shù)據(jù)結(jié)構(gòu)服務(wù)器,因?yàn)樗粌H支持多種類型的數(shù)據(jù)結(jié)構(gòu),如字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合等,而且還可以通過Redis哨兵(Sentinel)和自動分區(qū)(Cluster)實(shí)現(xiàn)高可用性。
2. 內(nèi)存存儲與持久化
Redis數(shù)據(jù)庫的所有數(shù)據(jù)都被加載到內(nèi)存中進(jìn)行操作或處理,由于內(nèi)存的讀寫速度遠(yuǎn)遠(yuǎn)大于硬盤,因此Redis的數(shù)據(jù)讀寫速度及性能也比其他數(shù)據(jù)庫更加優(yōu)秀,它每秒可以讀寫超過10萬個(gè)鍵值。
Redis的數(shù)據(jù)存儲在計(jì)算機(jī)內(nèi)存中,為了能夠持久地使用Redis數(shù)據(jù),防止系統(tǒng)故障造成數(shù)據(jù)丟失,可以將Redis中的數(shù)據(jù)異步寫入磁盤空間中,這個(gè)過程就叫做Redis持久化。Redis提供了兩種不同的持久化方法,一種是快照(RDB,Redis DataBase),另一種是追加文件(AOF,Append Only File)。
3. 支持事務(wù)
Redis的事務(wù)操作可以保證數(shù)據(jù)操作的原子性,即一個(gè)事務(wù)中的所有命令要么全部執(zhí)行,要么全部不執(zhí)行。如果其中任何一個(gè)命令執(zhí)行失敗,整個(gè)事務(wù)將被回滾到之前的狀態(tài)。這種原子性保證了Redis的數(shù)據(jù)操作具有可靠性和一致性。
4. 支持主從復(fù)制
Redis支持主從復(fù)制構(gòu)建集群,支持?jǐn)?shù)據(jù)的備份。為了分擔(dān)讀取數(shù)據(jù)的壓力,Redis不僅支持主從同步,而且也支持一主多從以及多級從結(jié)構(gòu),其中主節(jié)點(diǎn)提供寫操作,從節(jié)點(diǎn)僅提供讀操作。對于“讀多寫少”的狀況,可為主節(jié)點(diǎn)配置多個(gè)從節(jié)點(diǎn),從而提高響應(yīng)效率。
(1) Redis主從同步實(shí)現(xiàn)過程
Redis主從數(shù)據(jù)的同步是異步進(jìn)行的,主從同步存在一個(gè)狀態(tài)差,但不會影響主邏輯,也不會降低Redis的處理性能。
如圖2-2所示,Redis實(shí)現(xiàn)主從同步的過程大致可以分為以下6步。
① 從節(jié)點(diǎn)執(zhí)行slaveof命令;
② 從節(jié)點(diǎn)保存slaveof命令中主節(jié)點(diǎn)的信息,不做其他操作;
③ 從節(jié)點(diǎn)內(nèi)部的定時(shí)任務(wù)發(fā)現(xiàn)有主節(jié)點(diǎn)的信息,開始使用socket連接主節(jié)點(diǎn);
④ 連接成功后,從節(jié)點(diǎn)向主節(jié)點(diǎn)發(fā)送ping命令,請求連接;
⑤ 如果主節(jié)點(diǎn)設(shè)置了權(quán)限,從節(jié)點(diǎn)需要進(jìn)行權(quán)限驗(yàn)證;如果驗(yàn)證失敗,復(fù)制終止;權(quán)限驗(yàn)證通過后,主從節(jié)點(diǎn)進(jìn)行數(shù)據(jù)同步,主節(jié)點(diǎn)將全部數(shù)據(jù)全部發(fā)送至從節(jié)點(diǎn),做一次完整備份;
⑥ 主從節(jié)點(diǎn)完成備份后,主節(jié)點(diǎn)將持續(xù)發(fā)送給從節(jié)點(diǎn)新的數(shù)據(jù)變動命令,從節(jié)點(diǎn)實(shí)時(shí)同步,保證主從數(shù)據(jù)一致性。
(1) Redis數(shù)據(jù)同步的過程
Redis 2.8版本之后,從服務(wù)器對主服務(wù)器的同步操作需要使用psync命令來實(shí)現(xiàn),主從服務(wù)器在執(zhí)行psync命令期間的通信過程如下。
參數(shù)說明:
1) runId:每個(gè)Redis節(jié)點(diǎn)啟動都會生成唯一的uuid,每次Redis重啟后,runId都會發(fā)生變化。
2) offset:主節(jié)點(diǎn)和從節(jié)點(diǎn)各自維護(hù)自己的主從復(fù)制偏移量offset,當(dāng)主節(jié)點(diǎn)有寫入命令時(shí),offset=offset+命令的字節(jié)長度。從節(jié)點(diǎn)在收到主節(jié)點(diǎn)發(fā)送的命令后,也會增加自己的offset,并把自己的offset發(fā)送給主節(jié)點(diǎn)。這樣,主節(jié)點(diǎn)同時(shí)保存自己的offset和從節(jié)點(diǎn)的offset,并通過對比offset來判斷主從節(jié)點(diǎn)數(shù)據(jù)是否一致。
發(fā)送psync命令的目的是讓從服務(wù)器與主服務(wù)器進(jìn)行同步,以確保從服務(wù)器的數(shù)據(jù)與主服務(wù)器的數(shù)據(jù)保持一致。當(dāng)從服務(wù)器發(fā)送psync命令后,主服務(wù)器可能會有以下3種響應(yīng)情況。
1) FULLRESYNC:第一次連接,進(jìn)行全量復(fù)制
2) CONTINUE:進(jìn)行部分復(fù)制
3) ERR:不支持psync命令,進(jìn)行全量復(fù)制
5. 功能豐富
Redis不僅是優(yōu)秀的存儲數(shù)據(jù)庫,還擔(dān)任著其他角色,比如緩存系統(tǒng)、隊(duì)列系統(tǒng)等。
作為緩存系統(tǒng),Redis為每個(gè)鍵設(shè)置生存時(shí)間(Time To Live,TTL),生存時(shí)間到期后鍵會自動被刪除,還可以限定數(shù)據(jù)占用的最大內(nèi)存空間,在數(shù)據(jù)達(dá)到空間限制后按照一定的規(guī)則自動淘汰不需要的鍵。借助Redis出色的性能、豐富的數(shù)據(jù)類型及其特有的持久化,用戶可將Redis應(yīng)用到更加寬廣、豐富的業(yè)務(wù)中去。
Redis是一個(gè)高性能的優(yōu)先級隊(duì)列,它借助列表類型鍵實(shí)現(xiàn)隊(duì)列,支持阻塞時(shí)的讀取操作。除此之外,Redis還支持“發(fā)布/訂閱”的消息模式,可幫助用戶構(gòu)建聊天室系統(tǒng)
6. 簡單穩(wěn)定
Redis使用起來十分便捷,它提供了幾十種編程語言的客戶端庫。用戶可以使用命令操作Redis數(shù)據(jù)庫,實(shí)現(xiàn)讀寫數(shù)據(jù),便于在程序中與Redis的交互。命令語句與Redis的關(guān)系相當(dāng)于SQL語句與MySQL的關(guān)系。
Redis的開發(fā)代碼量僅3萬多行,并且開源,便于用戶通過修改Redis源代碼來適應(yīng)自己的項(xiàng)目需求。同時(shí),對于希望充分發(fā)揮數(shù)據(jù)庫性能的開發(fā)者而言,Redis也具有很大的吸引力。到目前為止,已有近百名開發(fā)者為Redis貢獻(xiàn)了代碼。在良好的開發(fā)氛圍和嚴(yán)謹(jǐn)?shù)陌姹景l(fā)布機(jī)制下,Redis穩(wěn)定版本的性能更具可靠性。
應(yīng)用場景
Redis 數(shù)據(jù)庫主要被大型企業(yè)、初創(chuàng)公司和政府組織用于以下場景:緩存、構(gòu)建隊(duì)列系統(tǒng)、實(shí)時(shí)欺詐檢測、全球用戶會話管理、實(shí)時(shí)庫存管理、AI/ML功能存儲以及索賠處理。
Redis數(shù)據(jù)庫在內(nèi)存中讀寫數(shù)據(jù)的容量受到物理內(nèi)存的限制,不適用海量數(shù)據(jù)的高性能讀寫,再加上它缺少原生的可擴(kuò)展機(jī)制,不具備可擴(kuò)展能力,需要通過客戶端來實(shí)現(xiàn)分布式讀寫,因此Redis適合的場景主要局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上。目前,國內(nèi)的互聯(lián)網(wǎng)企業(yè),如新浪微博和知乎,以及國外互聯(lián)網(wǎng)企業(yè)的產(chǎn)品,如GitHub、Stack Overflow、Flickr和Instagram,這些都是Redis的用戶。
常見用例包括以下6種。
1. 存儲數(shù)據(jù)庫
使用云數(shù)據(jù)庫Redis時(shí),Redis作為持久化數(shù)據(jù)庫,主程序部署在ECS上,所有業(yè)務(wù)數(shù)據(jù)存儲在Redis中。云數(shù)據(jù)庫Redis版支持持久化功能,主備雙機(jī)冗余數(shù)據(jù)存儲,保證了服務(wù)的高可用性。適用場景為游戲網(wǎng)站及應(yīng)用。
2. 緩存
Redis最常見的應(yīng)用場景是作為緩存系統(tǒng)。它使用String類型來將序列化后的對象存儲到內(nèi)存中。
Redis是單線程模型,而Memcached則支持多線程。應(yīng)用在多核服務(wù)器上時(shí),Redis的性能比Memcached要遜色一些。Redis的性能優(yōu)異,通常情況下其性能不會成為服務(wù)的瓶頸。Redis將會很好地代替Memcached,成為熱點(diǎn)數(shù)據(jù)緩存的首選工具。
3. 消息隊(duì)列
Redis支持保存List鏈表和Set集合的數(shù)據(jù)結(jié)構(gòu),且支持對List進(jìn)行各種操作?;贚ist來做FIFO雙向鏈表可實(shí)現(xiàn)一個(gè)輕量級的高性能消息隊(duì)列服務(wù)。常見的應(yīng)用場景有12306網(wǎng)站的排隊(duì)購票業(yè)務(wù)和候補(bǔ)業(yè)務(wù),電商網(wǎng)站的秒殺、搶購等業(yè)務(wù)。
4. 排行榜
Redis使用有序集合和一個(gè)計(jì)算熱度的算法,可以輕松地得到一個(gè)熱度排行榜。常見的應(yīng)用場景有新聞?lì)^條、微博熱搜榜、熱歌榜、游戲排行榜等。
5. 位操作
當(dāng)需要處理上億數(shù)據(jù)量的情況時(shí),可以考慮使用位操作。例如處理幾億用戶的簽到、去重登錄的統(tǒng)計(jì)、查詢用戶的在線狀態(tài)等場景。如果為每個(gè)用戶建立一個(gè)key,那么對于擁有十億用戶的騰訊來說,所需要的內(nèi)存大小將難以想象。使用Redis的位操作命令,如setbit、getbit和bitcount,可以解決上述問題。可以在Redis內(nèi)部構(gòu)建一個(gè)足夠長的數(shù)組,每個(gè)數(shù)組的值為0或1。數(shù)組的下標(biāo)(index)使用數(shù)字表示用戶ID。這樣,可以使用下標(biāo)和元素值來記錄并存儲數(shù)億條記錄。
6. 計(jì)數(shù)器
Redis高效率讀寫的特點(diǎn)可以充分發(fā)揮其計(jì)數(shù)功能。Redis的數(shù)據(jù)結(jié)構(gòu)中,String、hash等支持原子性的遞增操作,適用諸如統(tǒng)計(jì)點(diǎn)擊數(shù)應(yīng)用。因?yàn)镽edis是單線程,所以能夠避免并發(fā)問題,保證不會出錯(cuò),而且其100%毫秒級的性能,非常適用于高并發(fā)的秒殺活動、分布式序列號的生成、網(wǎng)站訪問統(tǒng)計(jì)等場景。
支持的數(shù)據(jù)結(jié)構(gòu)
Redis以鍵值對的形式存儲數(shù)據(jù),而value則支持多種數(shù)據(jù)類型,常見的數(shù)據(jù)結(jié)構(gòu)有String(字符串)、List(列表)、Set(集合)、Hash(散列)和Sorted Sets(有序結(jié)合)。本節(jié)將詳細(xì)講解這5種數(shù)據(jù)結(jié)構(gòu)。
1.String(字符串)
String類型是Redis最基本的數(shù)據(jù)類型,一個(gè)key對應(yīng)一個(gè)value,String類型的value最大能存儲512MB。String的值是二進(jìn)制類型的,具有較高的安全性,其值的數(shù)據(jù)類型可以為文本、圖片、視頻或者序列化的對象。
String數(shù)據(jù)結(jié)構(gòu)多用于實(shí)現(xiàn)計(jì)數(shù)功能,例如掘金文章的點(diǎn)擊數(shù)量、閱讀數(shù)量、視頻觀看量、分布式鎖,也常用于集群環(huán)境下的session共享。
2.List(列表)
Redis列表是簡單的字符串列表,按照插入順序排序,最多可存儲232-1個(gè)元素。對列表進(jìn)行讀寫操作時(shí),只能添加或讀取一個(gè)元素到列表的頭部(左邊)或者尾部(右邊)。
GoodID為列表的鍵名,2022001、2022002、2022003和2022003都是列表中的鍵值。這些值均按照插入順序排列,分別為列表的第1個(gè)字符串元素、第2個(gè)字符串元素、第3個(gè)字符串元素、第4個(gè)字符串元素。另外,List允許出現(xiàn)重復(fù)的值,如該List中的第3個(gè)元素和第4個(gè)字符串元素都為2022003。
List數(shù)據(jù)結(jié)構(gòu)可用于獲取最新的評論列表、最近N天的活躍用戶數(shù)、新聞推薦等。
3.Set(集合)
Set是字符串元素的無序集合。其中,字符串元素是不重復(fù)且無序的,集合最多可存儲232-1個(gè)元素。
Set類型與hash類型的存儲結(jié)構(gòu)相同,僅存儲鍵,不存儲值(nil)。這是因?yàn)镾et的內(nèi)部實(shí)現(xiàn)是一個(gè)value永遠(yuǎn)為null的HashMap。HashMap通過計(jì)算hash的方式來實(shí)現(xiàn)快速排重,這也是set能提供判斷一個(gè)成員是否在集合內(nèi)的原因。Set的value和List的value類似,都是一個(gè)字符串列表,區(qū)別在于Set是無序的,且Set中的元素是唯一的。
利用Redis提供的Set數(shù)據(jù)結(jié)構(gòu)可以存儲大量的數(shù)據(jù),并且高效的內(nèi)部存儲機(jī)制使其在查詢方面具有更高的工作效率。
Set可用于存儲一些集合性的數(shù)據(jù),比如微博應(yīng)用中,把一個(gè)用戶關(guān)注的人放在一個(gè)集合中,用戶的粉絲放到一個(gè)集合中,通過集合的交集、并集、差集等操作,實(shí)現(xiàn)共同關(guān)注,互相關(guān)注、可能認(rèn)識的人等功能。除此之外,Set集合常用于限時(shí)抽獎(jiǎng)活動、共同好友、商品篩選等場景。
4.Hash(散列)
Redis Hash是一個(gè)無序的鍵值(key-value)對集合。Redis本身就是key-value類型,此處的Hash數(shù)據(jù)結(jié)構(gòu)指的是key-value中的value,正是因?yàn)槿绱?,hash特別適合用于存儲對象。
Hash是一個(gè)字符串類型的key和value的映射表,其中存儲鍵的類型必須為字符串類型,值的類型可以是不可重復(fù)的字符串、數(shù)字等。
Hash使用哈希表結(jié)構(gòu)實(shí)現(xiàn)數(shù)據(jù)存儲,一個(gè)存儲空間保存多個(gè)鍵值對數(shù)據(jù),常應(yīng)用于各種商城購物車如淘寶、京東等。
5.Sorted Sets(有序集合)
Sorted Sets是在Set的基礎(chǔ)上,為value中的每個(gè)字符串關(guān)聯(lián)了一個(gè)score(得分)屬性。Sorted Sets通過計(jì)算得分,將字符串進(jìn)行排序,這也是有序集合與散列的主要區(qū)別。
有序集合允許直接操作值,散列則是通過鍵來查找值;有序集合的鍵是唯一的,值是不唯一的,而散列的值則是唯一的。有序集合是按照值的大小進(jìn)行排序的,常用于各種排行榜,如百度新聞榜單、熱搜榜等。