1. 程式人生 > >Redis原理介紹

Redis原理介紹

Redis是一個基於key-value的快取記憶體系統,類似於memcached,但是支援更復雜的資料結構ListSetSortedSet,並且有持久化的功能。

由於近期工作很多地方都用到了它,所以花了不少時間來閱讀文章、編碼實驗,瞭解一下Redis都能做些什麼,能有什麼樣的效能表現。

首先遇到的第一個問題就是,Redis究竟是什麼?

這個問題看似可笑,其實不然,我很贊同Timyang的觀點,架構者對Redis的理解不同、定位也不同,決定了Redis在整個系統結構中會扮演什麼樣的角色。我總結一下,主流有3種理解:

1、key valuestore.是一個以

key-value形式儲存的資料庫,定位直指MySQL,用來作為唯一的儲存系統。

2、memory cache.是一個把資料儲存在記憶體中的快取記憶體,用來在應用和資料庫間提供緩衝,替代memcached

3、data structrueserver.把它支援對複雜資料結構的高速操作作為賣點,提供某些特殊業務場景的計算和展現需求。比如排行榜應用,Top 10之類的。

目前更多的人還是把它定位為一個memcached的升級版,提供更多的資料結構操作,仍然是一個cache

傳統的memcached在類似於SNS社群這樣的業務場景下,有一些弊端。比如儲存好友關係,不得不使用特殊字元分隔的長字串來儲存。在好友關係沒有上限的業務需求下,操作效能低下,達不到快取系統應有的效能水平。而且從資料庫中的關係型結構對映到

cache中的長字串形式,很明顯也是架構中很蹩腳的一個環節。

Redis提供的ListSetSorted Set就可以很好的業務模型對映到相應的資料結構上,契合度很高。按我的理解,關係資料庫理論幾乎可以照搬到Redis的應用中來。

Redis官方教程中的仿Twitter案例就是一個非常好的入手點。用Set結構來儲存followerfollowing,用List結構來儲存每個人的所有post,再加上一些普通的key-value來儲存使用者基本資訊,很直觀和清晰。

我再來舉一個好友關係的業務場景來描述一下我的理解,標準關係型資料庫結構是怎麼和Redis儲存結構實現一一對映的。

資料庫中有

3張表:

1、使用者表有兩列:id、暱稱

2、好友關係表有列:使用者id、好友id、好友所屬分組id、好友備註、新增好友時間

3、分組表:分組id、分組名稱、所屬使用者id

增加、刪除一個好友,就是在好友關係表裡insertdelete一條記錄。

獲取某使用者的所有好友分組,及分組內的好友數:

select g.gid, g.gname, count(f.fuid)
from groups g left join friends f
on g.gid=f.gid
where g.uid=#uid#
group by g.gid, g.gname
獲取某使用者某分組下的好友列表:

select f.fuid, u.nickname, f.remark, f.time
from friends f left join users u
on f.fuid=u.id
where f.uid=#uid# and f.gid=#gid#
order by f.time
limit #start#, #count#
再來看看Redis如何實現類似的業務場景。

使用者暱稱:uid:xxxxx:nickname,以String結構儲存,相當於user

分組名稱:gid:yyyyy:gname,以String結構儲存

使用者所有分組:uid:xxxxx:groups,以Set結構儲存gid的集合

分組下好友:gid:yyyyy:friends,以Set結構儲存,儲存fuid的集合

好友:uid:xxxxx:fuid:zzzzz:giduid:xxxxx:fuid:zzzzz:remarkuid:xxxxx:fuid:zzzzz:time各自使用String結構儲存,相當於friends表的每個欄位

新增一個好友需要把uid:xxxxx:fuid:zzzzz:giduid:xxxxx:fuid:zzzzz:remarkuid:xxxxx:fuid:zzzzz:time這三個欄位set好,再sadd gid:yyyyy:friends zzzzz,把好友加到這個組的集合內

獲取某使用者的所有好友分組,及分組內的好友數,需要用smembers獲取uid:xxxxx:groups集合中的gid,再用這些gid來分別scardgid:yyyyy:friends獲取該分組下有多少好友。

獲取使用者123456在分組1001下的好友列表:

sort gid:1001:friends
by uid:123456:fuid:*:time
limit 0 10
get #
get uid:*:nickname
get uid:123456:fuid:*:remark
get uid:123456:fuid:*:time

很有意思是不是,很像sql語句,key中的*符號是個佔位符,可以被sort出的結果替換,進而get到動態key裡面的value

我們可以總結一下,傳統的關係型資料庫,處理一對多的問題,需要把外來鍵放在多的一端,因為RDBMS理論中沒有集合這個直接概念。而使用Redis,我們可以很直覺的在一的一端來管理一對多的關係,使用Set

這只是使用上的區別,而理論上,RDBMS的理論完全可以套用在Redis上,所有用關係型資料庫理論可以描述的結構,用Redis的資料結構,都可以實現。

最關鍵的是,如果使用MySQL,當資料規模非常大時,上面兩個查詢操作都需要藉助表關聯技術,而大表間的join在大型系統中是需要極力避免的操作。相反Redis的每個操作都會侷限在一個較小的資料集範圍內,而且key-value的儲存形式,定位key只是一個複雜度為O(1)的操作。在very huge的資料量下,Redis效能效果非常優異,這就是NoSQL的優勢所在!