基本介紹html
Redis是一種key-value存儲形式的非關係型數據庫,也是一個強大的內存型存儲系統,可是它比傳統的Memcached 更靈活,支持更多的數據類型,同時也能夠持久化。據官方數據表示Redis讀的速度是110000次/s,寫的速度是81000次/s 。並且Redis支持數據持久化,衆多數據結構存儲,master-slave模式數據備份等多種功能。java
支持的數據類型web
先經過一張圖瞭解下Redis內部內存管理中是如何描述這些不一樣數據類型的:redis
首先Redis內部使用一個redisObject對象來表示全部的key和value,redisObject最主要的信息如上圖所示:type表明一個value對象具體是何種數據類型,encoding是不一樣數據類型在redis內部的存儲方式,好比:type=string表明value存儲的是一個普通字符串,那麼對應的encoding能夠是raw或者是int,若是是int則表明實際redis內部是按數值型類存儲和表示這個字符串的,固然前提是這個字符串自己能夠用數值表示,好比:"123" "456"這樣的字符串。sql
這裏須要特殊說明一下vm字段,只有打開了Redis的虛擬內存功能,此字段纔會真正的分配內存,該功能默認是關閉狀態的。經過上圖咱們能夠發現Redis使用redisObject來表示全部的key/value數據是比較浪費內存的,固然這些內存管理成本的付出主要也是爲了給Redis不一樣數據類型提供一個統一的管理接口,實際做者也提供了多種方法幫助咱們儘可能節省內存使用。數據庫
Stringapi
String數據結構是簡單的key-value類型,value其實不只是String,也能夠是數字。緩存
經常使用命令:get、set、incr、decr、mget等。ruby
應用場景:String是最經常使用的一種數據類型,普通的key/ value 存儲均可以歸爲此類,便可以徹底實現目前 Memcached 的功能,而且效率更高。還能夠享受Redis的定時持久化,操做日誌及 Replication等功能。除了提供與 Memcached 同樣的get、set、incr、decr 等操做外,Redis還提供了下面一些操做:數據結構
Hash
在Memcached中,咱們常常將一些結構化的信息打包成hashmap,在客戶端序列化後存儲爲一個字符串的值,好比用戶的暱稱、年齡、性別、積分等,這時候在須要修改其中某一項時,一般須要將全部值取出反序列化後,修改某一項的值,再序列化存儲回去。這樣不只增大了開銷,也不適用於一些可能併發操做的場合(好比兩個併發的操做都須要修改積分)。而Redis的Hash結構可使你像在數據庫中Update一個屬性同樣只修改某一項屬性值。
經常使用命令:hget,hset,hgetall 等。
應用場景:
咱們簡單舉個實例來描述下Hash的應用場景,好比咱們要存儲一個用戶信息對象數據,包含如下信息:
用戶ID爲查找的key,存儲的value用戶對象包含姓名,年齡,生日等信息,若是用普通的key/value結構來存儲,主要有如下2種存儲方式:
第一種方式將用戶ID做爲查找key,把其餘信息封裝成一個對象以序列化的方式存儲,這種方式的缺點是,增長了序列化/反序列化的開銷,而且在須要修改其中一項信息時,須要把整個對象取回,而且修改操做須要對併發進行保護,引入CAS等複雜問題。
第二種方法是這個用戶信息對象有多少成員就存成多少個key-value對兒,用用戶ID+對應屬性的名稱做爲惟一標識來取得對應屬性的值,雖然省去了序列化開銷和併發問題,可是用戶ID爲重複存儲,若是存在大量這樣的數據,內存浪費仍是很是可觀的。
那麼Redis提供的Hash很好的解決了這個問題,Redis的Hash實際是內部存儲的Value爲一個HashMap,並提供了直接存取這個Map成員的接口,以下圖:
也就是說,Key仍然是用戶ID, value是一個Map,這個Map的key是成員的屬性名,value是屬性值,這樣對數據的修改和存取均可以直接經過其內部Map的Key(Redis裏稱內部Map的key爲field), 也就是經過 key(用戶ID) + field(屬性標籤) 就能夠操做對應屬性數據了,既不須要重複存儲數據,也不會帶來序列化和併發修改控制的問題。很好的解決了問題。
這裏同時須要注意,Redis提供了接口(hgetall)能夠直接取到所有的屬性數據,可是若是內部Map的成員不少,那麼涉及到遍歷整個內部Map的操做,因爲Redis單線程模型的緣故,這個遍歷操做可能會比較耗時,而另其它客戶端的請求徹底不響應,這點須要格外注意。
List
經常使用方法:
Lists 就是鏈表,略有數據結構知識的人都應該能理解其結構。使用Lists結構,咱們能夠輕鬆地實現最新消息排行等功能。Lists的另外一個應用就是消息隊列,能夠利用Lists的PUSH操做,將任務存在Lists中,而後工做線程再用POP操做將任務取出進行執行。Redis還提供了操做Lists中某一段的api,你能夠直接查詢,刪除Lists中某一段的元素。
Redis的list是每一個子元素都是String類型的雙向鏈表,能夠經過push和pop操做從列表的頭部或者尾部添加或者刪除元素,這樣List便可以做爲棧,也能夠做爲隊列。
Sets 就是一個集合,集合的概念就是一堆不重複值的組合。利用Redis提供的Sets數據結構,能夠存儲一些集合性的數據。
Set是集合,是String類型的無序集合,set是經過hashtable實現的,概念和數學中個的集合基本相似,能夠交集,並集,差集等等,set中的元素是沒有順序的。
經常使用方法:
和Sets相比,Sorted Sets增長了一個權重參數score,使得集合中的元素可以按score進行有序排列,好比一個存儲全班同窗成績的Sorted Sets,其集合value能夠是同窗的學號,而score就能夠是其考試得分,這樣在數據插入集合的時候,就已經進行了自然的排序。能夠用Sorted Sets來作帶權重的隊列,好比普通消息的score爲1,重要消息的score爲2,而後工做線程能夠選擇按score的倒序來獲取工做任務。讓重要的任務優先執行。
經常使用方法:
pub/sub
發佈訂閱,相似於消息隊列mq。能夠選擇對某個Key進行訂閱,一旦這個key發佈了一些消息,則全部訂閱了這個Key的對象就能夠收到這個消息。主要能夠用在實時消息系統上,例如聊天之類的。
Transactions
NoSQL不支持事務,可是經過提供了打包執行的功能,即這個包裏面的全部命令必需要一塊兒執行,此外還能夠鎖定某個Key,在打包執行命令時若是檢測到這個Key發生了變化,則直接回滾。
持久化方案
redis默認開啓的RDB持久化方式,可是若是開始了AOF方式,那麼在系統重啓時優先衝AOF文件中回覆數據
數據淘汰策略
長期將Redis做爲緩存使用,不免會遇到內存空間存儲瓶頸,當Redis內存超出物理內存限制時,內存數據就會與磁盤產生頻繁交換,使Redis性能急劇降低。此時如何淘汰無用數據釋放空間,存儲新數據就變得尤其重要了。對此,Redis在生產環境中,採用配置參數maxmemory 的方式來限制內存大小。當實際存儲內存超出maxmemory 參數值時會執行配置的淘汰策略。Redis 肯定驅逐某個鍵值對後,會刪除這個數據,並將這個數據變動消息發佈到本地(AOF 持久化)和從機(主從鏈接)。可是咱們要注意redis的刪除策略和淘汰策略是有區別的。
優缺點
優勢:
缺點:
redis和memcached的區別
使用注意點
使用場景
String
適用場景:適合最簡單的k-v存儲,相似於memcached的存儲結構,短信驗證碼,配置信息等,就用這種類型來存儲。
案例:1.微博數,粉絲數,
hash
適用場景:通常key爲ID或者惟一標示,value對應的就是詳情了。如商品詳情,我的信息詳情,新聞詳情等。
案例:1.存儲部分變動數據,如用戶信息等
List
適用場景:由於list是有序的,比較適合存儲一些有序且數據相對固定的數據。如省市區表、字典表等。由於list是有序的,適合根據寫入的時間來排序,如:最新的***,消息隊列等
案例:
1.在Redis中咱們的最新微博ID使用了常駐緩存,這是一直更新的。可是咱們作了限制不能超過5000個ID,所以咱們的獲取ID函數會一直詢問Redis。只有在start/count參數超出了這個範圍的時候,才須要去訪問數據庫。咱們的系統不會像傳統方式那樣「刷新」緩存,Redis實例中的信息永遠是一致的。SQL數據庫(或是硬盤上的其餘類型數據庫)只是在用戶須要獲取「很遠」的數據時纔會被觸發,而主頁或第一個評論頁是不會麻煩到硬盤上的數據庫了。
取最新N個數據的操做: 記錄前N個最新登錄的用戶Id列表,超出的範圍能夠從數據庫中得到。 //把當前登陸人添加到鏈表裏 ret = r.lpush("login:last_login_times", uid) //保持鏈表只有N位 ret = redis.ltrim("login:last_login_times", 0, N-1) //得到前N個最新登錄的用戶Id列表 last_login_list = r.lrange("login:last_login_times", 0, N-1)
Sets
適用場景:能夠簡單的理解爲ID-List的模式,如微博中一我的有哪些好友,set最牛的地方在於,能夠對兩個set提供交集、並集、差集操做。例如:查找兩我的共同的好友等。
案例:
1.在微博應用中,能夠將一個用戶全部的關注人存在一個集合中,將其全部粉絲存在一個集合。Redis還爲集合提供了求交集、並集、差集等操做,能夠很是方便的實現如共同關注、共同喜愛、二度好友等功能,對上面的全部集合操做,你還可使用不一樣的命令選擇將結果返回給客戶端仍是存集到一個新的集合中。
交集,並集,差集:(Set) //book表存儲book名稱 set book:1:name 」The Ruby Programming Language」 set book:2:name 」Ruby on rail」 set book:3:name 」Programming Erlang」 //tag表使用集合來存儲數據,由於集合擅長求交集、並集 sadd tag:ruby 1 sadd tag:ruby 2 sadd tag:web 2 sadd tag:erlang 3 //即屬於ruby又屬於web的書? inter_list = redis.sinter("tag.web", "tag:ruby") //即屬於ruby,但不屬於web的書? inter_list = redis.sdiff("tag.ruby", "tag:web") //屬於ruby和屬於web的書的合集? inter_list = redis.sunion("tag.ruby", "tag:web") 獲取某段時間全部數據去重值,這個使用Redis的set數據結構最合適了,只須要不斷地將數據往set中扔就好了,set意爲集合,因此會自動排重。
Sorts sets
適用場景:是set的加強版本,增長了一個score參數,自動會根據score的值進行排序。比較適合相似於top 10等不根據插入的時間來排序的數據。
案例:排行榜應用,取TOP N操做
使用: //將登陸次數和用戶統一存儲在一個sorted set裏 zadd login:login_times 5 1 zadd login:login_times 1 2 zadd login:login_times 2 3 ZADD key score member //當用戶登陸時,對該用戶的登陸次數自增1 ret = r.zincrby("login:login_times", 1, uid) //那麼如何得到登陸次數最多的用戶呢,逆序排列取得排名前N的用戶 ret = r.zrevrange("login:login_times", 0, N-1) ZREVRANGE key start stop [WITHSCORES]
Redis集羣
學習連接