Redis介紹及實踐分享

一、Redis是什麼
1)Redis是REmote DIctionary Server的縮寫,是一個key- value存儲系統
2)Redis提供了一些豐富的數據結構,包括Strings,Lists, HashesSets和Ordered Sets以及Hashes。 包括對這些數據結 構的操做支持
3)Redis能夠替代Memcached,而且解決了斷電後數據徹底丟 失的問題
4)Redis官方網站: http://redis.io
    Redis做者Blog: http://antirez.com

二、Redis安裝
Download, extract and compile Redis with:
$ wget http://download.redis.io/releases/redis-3.2.5.tar.gz
$ tar xzf redis-3.2.5.tar.gz
$ cd redis-3.2.5
$ make

The binaries that are now compiled are available in the src directory:Run Redis with:

$ src/redis-server
You can interact with Redis using the built-in client:
$ src/redis-cli
redis> set foo bar
OK
redis> get foo
"bar"

三、Redis優勢
1)性能極高,Redis能支持10萬每秒的讀寫頻率
2)豐富的數據類型及對應的操做
3)Redis的全部操做都是原子性的,同時Redis還支 持對幾個操做合併後的原子性執行,也即支持事
4)豐富的特性,Redis還支持publish/subscribe, key過時等特性

四、Redis性能
如下摘自官方測試描述:
在50個併發的狀況下請求10W次,寫的速度是11W次/s,讀的速 度是8.1w次/s

測試環境:
1)50個併發,請求10W次
2)讀和寫大小爲256bytes的字符串
3)Linux2.6 Xeon X3320 2.5GHz的服務器上
4)經過本機的loopback interface接口上執行

五、Redis數據類型
redis經常使用五種數據類型:string,hash,list,set,sorted set
 
Redis內部使用一個redisObject對象來表示全部的key和value,redisObject最主要的信息如上圖所示:
    type表明一個value對象具體是何種數據類型,encoding是不一樣數據類型在redis內部的存儲方式,好比: type=string表明value存儲的是一個普通字符串,那麼對應的encoding能夠是raw或者是int,若是是int 則表明實際redis內部是按數值型類存儲和表示這個字符串的

Commands 集合: http://redis.io/commands

5.1 String
經常使用命令:
set,get,decr,incr,mget 等

應用場景:
String是最經常使用的一種數據類型,普通的key/value存儲

實現方式:
String在redis內部存儲默認就是一個字符串,被redisObject所引用,當遇到incr, decr等操做時會轉成數值型進行計算,此時redisObject的encoding字段爲int

5.2 Hash
經常使用命令:
hget,hset,hgetall 等

應用場景:
好比,咱們存儲供應商酒店價格的時候能夠採起此結構,用酒店編碼做爲Key, RatePlan+RoomType做爲Filed,價格信息做爲Value

實現方式:
Hash對應Value內部實際就是一個HashMap,實際這裏會有2種不一樣實現,這個Hash 的成員比較少時Redis爲了節省內存會採用相似一維數組的方式來緊湊存儲,而不 會採用真正的HashMap結構,對應的value redisObject的encoding爲zipmap;當成 員數量增大時會自動轉成真正的HashMap,此時encoding爲ht

5.3 List
經常使用命令:
lpush,rpush,lpop,rpop,lrang等

應用場景:
Redis list應用場景很是多,也是Redis最重要的數據結構之一,好比twitter的關注 列表,粉絲列表等均可以用Redis的list結構來實現

實現方式:
Redis list的實現爲一個雙向鏈表,便可以支持反向查找和遍歷,更方便操做,不過 帶來了部分額外的內存開銷,Redis內部的不少實現,包括髮送緩衝隊列等也都是 用的這個數據結構

5.4 Set
經常使用命令:
sadd,spop,smembers,sunion 等

應用場景:
Set對外提供的功能與list相似,當你須要存儲一個列表數據,又不但願出現重複 數據時,set 是一個很好的選擇,而且set提供了判斷某個成員是否在一個set集合 內的接口,這個也是list所不能提供的

實現方式:
Set 的內部實現是一個value永遠爲null的HashMap,實際就是經過計算hash的方 式來快速排除重複的,這也是set能提供判斷一個成員是否在集合內的緣由

5.5 Sorted set
經常使用命令:
zadd,zrange,zrem,zcard等

使用場景:
Sorted set的使用場景與set相似,區別是set不是自動有序的,而sorted set能夠 經過用戶額外提供一個優先級(score)的參數來爲成員排序,而且是插入有序的, 即自動排序.當你須要一個有序的而且不重複的集合列表,那麼能夠選擇sorted  set數據結構

實現方式:
Sorted set的內部使用HashMap和跳躍表(SkipList)來保證數據的存儲和有序, HashMap裏放的是成員到score的映射,而跳躍表裏存放的是全部的成員,排序依據 是HashMap裏存的score,使用跳躍表的結構能夠得到比較高的查找效率

5.6 內存優化
Redis爲不一樣數據類型分別提供了一組參數來控制內存使用,咱們在前面提到過Redis Hash的value內部 是一個HashMap,若是該Map的成員數比較少,則會採用一維數組的方式來緊湊存儲該Map,即省去了大量指 針的內存開銷,這個參數在redis.conf配置文件中下面2項:
    hash-max-zipmap-entries   64
    hash-max-zipmap-value     512

含義是當value這個Map內部不超過多少個成員時會採用線性緊湊格式存儲,默認是64,即value內部有64 個如下的成員就是使用線性緊湊存儲,超過該值自動轉成真正的HashMap
hash-max-zipmap-value 含義是當value這個Map內部的每一個成員值長度不超過多少字節就會採用線性緊 湊存儲來節省空間

以上2個條件任意一個條件超 過設置值都會轉換成真正的HashMap,也就不會再節省內存了,那麼這個值是 不是設置的越大越好呢,答案固然是否認的,HashMap的優點就是查找和操做的時間複雜度都是O(1)的,而 放棄Hash採用一維存儲則是O(n)的時間複雜度,若是成員數量不多,則影響不大,不然會嚴重影響性能,所 以要權衡好這個值的設置,整體上仍是時間成本和空間成本上的權衡

六、Redis發佈/訂閱
Redis的發佈/訂閱(Publish/Subscribe)功能類 似於傳統的消息路由功能,發佈者發佈消息,訂閱 者接收消息,溝通發佈者和訂閱者之間的橋樑是 訂閱的Channel或者Pattern

訂閱者和發佈者之間的關係是鬆耦合的,發佈者 不指定哪一個訂閱者才能接收消息,訂閱者不僅接 收特定發佈者的消息

七、Redis數據過時設置
Redis能夠按key設置過時時間,過時後將被自動 刪除,這個特性讓Redis很適合用來存儲酒店動態 流量和價格信息

用TTL命令能夠獲取某個key值的過時時間,-1表 示不會過時

八、Redis事務支持
Redis目前對事務支持還比較簡單,也即支持一些 簡單的組合型的命令,只能保證一個client發起 的事務中的命令能夠連續的執行,而中間不會插 入其餘client的命令:因爲Redis是單線程來處 理全部client的請求的因此作到這點是很容易

事務的執行過程當中,若是redis意外的掛了,這時 候事務可能只被執行了一半,能夠用redis- check-aof 工具進行修復

九、Redis數據存儲
9.1 數據快照
數據快照的原理是將整個Redis內存中存的全部 數據遍歷一遍後,保存到一個擴展名爲rdb的數據文件 中。經過SAVE命令能夠調用這個過程

9.2 數據快照配置
save 900 1
save 300 10
save 60 10000
以上在redis.conf中的配置指出在多長時間內,有 多少次更新操做,就將數據同步到數據文件,這個 能夠多個條件配合.上面的含義是900秒後有一個 key發生改變就執行save,300秒後有10個key發生 改變執行save,60秒有10000個key發生改變執行 save

十、Redis AOF
10.1 數據快照的缺點是持久化以後若是出現 crash則會丟失一段數據,所以做者增長了另外 一種追加式的操做日誌記錄,叫append only  file,其日誌文件以aof結尾,咱們通常稱爲aof文 件。要開啓aof日誌的記錄,須要在配置文件中進 行以下設置:
appendonly yes

10.2 appendonly配置若是不開啓,可能會在斷電時致使一段 時間內的數據丟失。由於redis自己同步數據文件是按save條 件來同步的,因此有的數據會在一段時間內只存在於內存中
appendfsync no/always/everysec
1)no:表示等操做系統進行數據緩存同步到磁盤
2)always:表示每次更新操做後手動調用fsync() 將數據寫 到磁盤
3)everysec:表示每秒同步一次。通常用everysec

10.3 AOF文件只增不減會致使文件愈來愈大,重寫過程以下
1)Redis經過fork產生子進程
2)子進程將當前全部數據寫入一個臨時文件
3)父子進程是並行執行的,在子進程遍歷並寫臨時文件的時 候,父進程在照常接收請求,處理請求,寫AOF,不過這時他是 把新來的AOF寫在一個緩衝區中
4)子進程寫完臨時文件後就會退出.這時父進程會接收到子 進程退出的消息,他會把本身如今收集在緩衝區中的全部AOF 追加在臨時文件中
5)最後把臨時文件rename一下,更名爲appendonly.aof, 這 時原來的aof文件被覆蓋。整個過程完成

十一、Redis數據恢復
當Redis服務器掛掉時,重啓時將按如下優先級恢復數據到內 存中:
1)若是隻配置了AOF,重啓時加載AOF文件恢復數據
2)若是同時配置了RBD和AOF,啓動時只加載AOF文件恢復數據
3)若是隻配置了RDB,啓動時將加載dump文件恢復數據

十二、Redis主從複製
12.1 Master/Slave配置
Master IP:175.41.209.118
Master Redis Server Port:6379

Slave配置很簡單,只須要在slave服務器的redis.conf加入:
slaveof 175.41.209.118 6379
啓動master和slave,而後寫入數據到master,讀取slave,可 以看到數據被複制到slave了

用途:讀寫分離,數據備份,災難恢復等

12.2 Redis主從複製過程
配置好slave後,slave與master創建鏈接,而後發送sync命令。 不管是第一次鏈接仍是從新鏈接,master都會啓動一個後臺 進程,將數據庫快照保存到文件中,同時master主進程會開始 收集新的寫命令並緩存;後臺進程完成寫文件後,master就 發送文件給slave,slave將文件保存到硬盤上,再加載到內存 中, 接着master就會把緩存的命令轉發給slave,後續master 將收到的寫命令發送給slave;若是master同時收到多個 slave發來的同步鏈接命令,master只會啓動一個進程來寫數 據庫鏡像, 而後發送給全部的slave

12.3 Redis主從複製特色
1)master能夠擁有多個slave
2)多個slave能夠鏈接同一個master外,還能夠鏈接到其餘 slave
3)主從複製不會阻塞master,在同步數據時,master能夠繼續 處理client請求
4)能夠在master禁用數據持久化,註釋掉master配置文件中的 全部save配置,只需在slave上配置數據持久化
5)提升系統的伸縮性

12.4 Redis主從複製速度
          官方提供了一個數據, Slave在21秒即完成了對 Amazon網站 10G key set的複製

1三、Redis客戶端
13.1 Redis的客戶端很是豐富,幾乎全部流行的 語言都有客戶端
客戶端列表:http://redis.io/clients
Java客戶端推薦Jedis: https://github. com/xetorthio/jedis

13.2 Jedis目前Release版本是3.2.5,支持的特性以下,一句話歸納,該有的都有了,不應有的也有了
• Sorting
• Connection handling
• Commands operating on any kind of values
• Commands operating on string values
• Commands operating on hashes
• Commands operating on lists
• Commands operating on sets
• Commands operating on sorted sets
• Transactions
• Pipelining
• Publish/Subscribe
• Persistence control commands
• Remote server control commands
• Connection pooling
• Sharding (MD5, MurmureHash)
• Key-tags for sharding
• Sharding with pipelining

13.3 Jedis使用
添加Maven依賴:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

最簡單的使用方式:
Jedis jedis = new Jedis("localhost");
jedis.set("foo", "bar");
String value = jedis.get("foo");

更多高級用法參考: https://github.com/xetorthio/jedis/wiki

1四、Redis shard
14.1 目前,Redis server沒有提供shard功能,只能 在client端實現
Redis有些客戶端實現了shard,好比Java客戶端 Jedis.

Jedis使用一致性哈希算法實現shard,提供
JedisPool,JedisPoolConfig,JedisSharedInfo, ShardedJedisPool等相關類來使用shared功能

14.2 Jedis shardedJedisPool的建立例子
<bean id="dataJedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxActive" value="200"/>
<property name="maxIdle" value="200"/>
<property name="maxWait" value="1000"/>
<property name="testOnBorrow" value="true"/>
</bean>
<bean id="dataJedisShardInfo" class="redis.clients.jedis.JedisShardInfo">
<constructor-arg index="0" value="${redis.host}"/>
<constructor-arg index="1" value="${redis.port}"/>
<constructor-arg index="2" value="10000"/>
</bean>
<bean id="dataShardedJedisPool" class="redis.clients.jedis.ShardedJedisPool">
<constructor-arg index="0" ref="dataJedisPoolConfig"/>
<constructor-arg index="1">
<list>
<ref bean="dataJedisShardInfo"/>
</list>
</constructor-arg>
</bean>

14.3 Jedis shardedJedisPool的使用
ShardedJedis shardedJedis = shardedJedisPool.getResource();
//xxoo
shardedJedisPool.returnResource(shardedJedis);

1五、Redis cluster
穩定版本的redis(2.4.5)只支持簡單的 master-slave replication: 一個master寫,多 個slave讀。只能經過客戶端一致性哈希本身作 sharding

Redis cluster是下一階段最重要的功能之一,會 有集羣的自動sharding,多節點容錯等:集羣功 將在3.0版本推出

1六、Redis Use In ChoiceHotels
16.1 Choice的Redis Server是一主一從,使用亞馬 遜AWS虛擬機,機器配置以下:
7.5 GB memory
4 EC2 Compute Units (2 virtual cores with 2
EC2 Compute Units each)
64-bit platform
I/O Performance: High

16.2 現狀:天天約更新30萬左右的數據,如今庫裏有400W條紀 錄(400W個Key,使用的是Hash結構存儲),每條數據都設有過 期時間,佔用了2.5G的內存

爲了提升讀寫性能Master關閉了Persistence功能,Slave只 負責同步備份Master的數據,不對外提供服務
另外一種可選方案是用Master提供寫服務,Slave提供讀服務來 實現讀寫分離

16.3 Master開啓Save功能的影響:在dump過程當中,除了磁盤有 大量的IO操做之外,Redis是fork一個子進程來dump數據到硬 盤,原有進程佔用30%+的CPU,dump數據的子進程單獨另外佔 用一個CPU

Master開啓Save對性能的直接影響:TPS大概減小 30%
Choice Master Redis服務器開啓Save功能後的明顯影響是: 機器Load一直居高不下,大量請求超時:關閉Save功能後服 務器壓力銳減,基本無請求超時狀況發生

16.4 Redis開啓AOF日誌功能的影響:對性能有影 響,可是因爲每次追加的數據量小,因此對性能的 影響相對小不少
Choice Master Reids開啓AOF功能後,機器load 微升,對性能無明顯影響

16.5 bgrewriteaof對性能的影響:爲了定時減少 AOF文件的大小,Redis2.4之後增長了自動的 bgrewriteaof的功能,Redis會選擇一個自認爲負 載低的狀況下執行bgrewriteaof,這個重寫AOF文 件的過程是很影響性能的
Choice Master開啓自動bgrewriteaof功能對系 統的明顯影響是:高併發時段有請求超時,機器 load 明顯上升幾倍

16.6 目前較好的方案是:Mater關閉Save功能,關 閉AOF日誌功能,以求達到性能最佳:Slave開啓
Save並開啓AOF日誌功能,並開啓bgrewriteaof 功能,不對外提供服務,這樣Slave的負載整體上 會一直略高於Master負載,但Master性能達到最

16.7 總結:
從目前使用的狀況來看,整體效果仍是比較理想 的, ChoiceHotels的價格存儲使用Redis的Hash 結構也很是適合,HotelCode+Date最爲key, 這樣 的key很容易設置過時,RatePlan+RoomType做爲 Filed, 價格和流量是Value
目前天天從GTA到Choice大約500w個請求,整個 過程80%的請求在500毫秒內返回,基本無超時現 象發生

16.8 Redis Master Info
redis_version:2.4.4
connected_clients:171
connected_slaves:1
used_memory_human:2.37G
used_memory_peak_human:2.46G
aof_enabled:0
expired_keys:1595004
keyspace_hits:2611419705
keyspace_misses:55827727
role:master
aof_current_size:3874203906
aof_base_size:3850549480
db0:keys=4073286,expires=4073286


相關文章
相關標籤/搜索