redis原理及應用web
1、redis來源redis
2、數據類型算法
3、主流的應用場景數據庫
4、特性數組
5、補充緩存
1、 redis來源服務器
做者:Salvatore Sanfilippo (antirez),男,意大利人.網絡
需求: 一個訪客信息追蹤網站,網站能夠通 過 JavaScript 腳本,將訪客的 IP 地 址、所屬國家、閱覽器信息、被訪問頁 面的地址等數據傳送給 LLOOGG. com 。 而後 LLOOGG.com 會將這些瀏覽數 據經過 web 頁面實時地展現給用戶, 並儲存起最新的 5 至 10,000 條瀏覽 記錄以便進行查閱。數據結構
redis解決方案app
每當某個被追蹤的網站新增一條 瀏覽記錄時, LLOOGG.com 就會將這條新的瀏覽記錄推入 (push)到與該網站相對應的列表裏面,當列表的 長度超過用戶指定的最大長度時,程序每向 列表推入一條新的記錄,就須要從列表中彈出(pop)一條最舊的記錄。
如今已經被普遍使用:
Twitter 使用 Redis 來儲存用戶時間線(user timeline)。
StackOverflow 使用 Redis 來進行緩存和消息分發。
Pinterest 使用 Redis 來構建關注模型(follow model)和興趣圖譜(interest graph)。
Flickr 使用 Redis 來構建隊列。
Github 使用 Redis 做爲持久化的鍵值對數據庫,並使用 Resque 來實現消息隊列。
新浪微博使用 Redis 來實現計數器、反向索引、排行榜、消息 隊列,並儲存用戶關係。
知乎使用 Redis 來進行計數、緩存、消息分發和任務調度。
掌上醫訊使用redis來進行緩存,分佈式鎖等。
阿里雲、百度雲、Amazon、 RedisLab 等公司都提供了基於 Redis 的應用服務。
2、支持的數據類型
Redis 全部的數據結構都是以惟一的 key 字符串做爲名稱,而後經過這個惟一 key 值來獲取相應的 value 數據。不一樣類型的數據結構的差別就在於 value 的結構不同。
a.字符串
經常使用命令 SET key value [NX|XX] 保存值
SETNX key value 命令僅在鍵 key 不存在的狀況下,才進行設置操做
SETXX key value 命令僅在鍵 key 存在的狀況下,才進行設置操做
APPEND key value
STRLEN key
get key
SETRANGE key index value 根據索引設置值
GETRANGE key start end
字符串結構使用很是普遍,一個常見的用途就是緩存用戶信息。咱們將用戶信息結構體使用 JSON 序列化成字符串,而後將序列化後的 字符串塞進 Redis 來緩存。一樣,取用戶信息會通過一次反序列化的過程。
struct SDS<T> {
T capacity; // 數組容量
T len; // 數組長度
byte flags; // 特殊標識位,
byte[] content; // 數組內內容
}
Redis 的字符串是動態字符串,是能夠修改的字符串,內部結構實現上相似於 Java 的 ArrayList,採用預分配冗餘空間的方式來減小內存的頻繁分配,如圖中所示,內部爲當前字符串實際分配的空間 capacity 通常要高於實際字符串長度 len。當字符串長度小於 1M 時,擴容都是加倍現有的空間,若是超過 1M,擴容時一次只會多擴 1M 的空間。須要注意的是字符串最大長度爲 512M。
存儲二進制數據相關的命令
SETBIT key index value
GETBIT key index
BITCOUNT key [start] [end]
b 列表
Redis 的列表至關於 Java 語言裏面的 LinkedList,注意它是鏈表而不是數組。這意味着 list 的插入和刪除操做很是快
經常使用的命令有 LPUSH key value [value ...]
LPOP key
RPUSH key value [value ...]
RPOP key
LLEN key
LINDEX key index
LRANGE key start stop
LSET key index value
LREM key count value
LTRIM key start stop
阻塞彈出
BLPOP key [key ...] timeout
Redis 的列表結構經常使用來作異步隊列使用。將須要延後處理的任務結構體序列化成字符串塞進 Redis 的列表,另外一個線程從這個列表中輪詢數據進行處理
hash 字典
Redis 的字典至關於 Java 語言裏面的 HashMap,它是無序字典。內部實現結構上同 Java 的 HashMap 也是一致的
經常使用指令:HSET key field value
HGET key field
HEXISTS key field
HDEL key field [field ...]
HLEN key
hash 結構也能夠用來存儲用戶信息,不一樣於字符串一次性須要所有序列化整個對象,hash 能夠對用戶結構中的每一個字段單獨存儲。這樣當咱們須要獲取用戶信息時能夠進行部分獲取。而以整個字符串的形式去保存用戶信息的話就只能一次性所有讀取,這樣就會比較浪費網絡流量...
集合(set)
Redis 的集合至關於 Java 語言裏面的 HashSet,它內部的鍵值對是無序的惟一的。它的內部實現至關於一個特殊的字典,字典中全部的 value 都是一個值NULL
。
用戶能夠速地向集合添加元素,或者從集合裏面 刪除元素,也能夠對多個集合進行集合運算操做,比 如計算並集、交集和差集。
SDIFF key [key ...] 計算全部給定集合的差集,並返回結果。
SDIFF key [key ...] 計算全部給定集合的差集,,並將結果儲存到 destkey 。
SINTER key [key ...] 計算全部給定集合的交集,並返回結果
SINTERSTORE destkey key [key ...] 計算全部給定集合的交集,並將結果儲存到 destkey
SUNION key [key ...] 計算全部給定集合的並集,並返回結果
SUNIONSTORE destkey key [key ...] 計算全部給定集合的並集,並將結果儲存到 destkey
使用集合實現共同關注功能
使用集合能夠實現商品篩選功能
有序集合
有序集合和集合同樣,均可以包含任意數量的、各不相同的元素( element),不一樣於集合的是,有序集 合的每一個元素都關聯着一個浮點數格式的分 值(score),而且有序集合會按照分 值,以從小到大的順序 來排列有序集合中的各個元素。 雖然有序集合中的每一個元素都必 須是各不相同的,但元素的分 值並無這一限制,換句話來講,兩個不 同元素的分值能夠是相同的。
ZADD key score element [[score element] [score element] ...]
ZREM key element [element ...]
ZSCORE key element 返回分值
ZINCRBY key increment element 添加分值 ZINCRBY fruits-price 1.5 西瓜 3.5
ZCARD key 返回有序集合包含的元素數量
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 獲取指定分值範圍內的升序元素
ZCOUNT key min max 計算給定分值範圍內的元素數量
zset 能夠用來存粉絲列表,value 值是粉絲的用戶 ID,score 是關注時間。咱們能夠對粉絲列表按關注時間進行排序
ZUNIONSTORE destkey numkeys key [key ...] 計算多個集合的並集
eg:水果的銷售狀況:
HyperLogLog
需求:記錄網站天天得到的獨立 IP 數量
集合方式:
SADD '2018.9.10::unique::ip' ip 加入IP
SCARD '20148:9:10:unique::ip' 計算獨立IP數量
集合實現的問題
使用字符串來儲存每一個 IPv4 地址最多須要耗費 15 字節(格式爲 'XXX.XXX.XXX.XXX' ,好比 '202.189.128.186')。下表給給出了不一樣用戶量使用內存的數量
隨着集合記錄的 IP 愈來愈多,消耗的內存也會愈來愈多。 另外若是要儲存 IPv6 地址的話,須要的內存還會更多一些。爲了解決此類問題,Redis 提供了 HyperLogLog 數據結構就是用來解決這種統計問題的。
HyperLogLog 提供了兩個指令 pfadd 和 pfcount
pfadd key value 增長對象
pfcount key 獲取計數
HyperLogLog 是不精確的去重計數方案,雖然不精確可是也不是很是不精確,標準偏差是 0.81%,重點是省空間,總共佔用的內存是12k.關於該算法的介紹https://blog.csdn.net/firenet1/article/details/77247649
發明這個算法的牛人,名字叫Philippe Flajolet 。
pfmerge 用於將多個 pf 計數值累加在一塊兒造成一個新的 pf 值。
好比獲取兩個網站的合併起來的獨立ip。
主流的應用場景
一、緩存
二、分佈式鎖
三、 消息列隊
四、位圖
在咱們平時開發過程當中,會有一些 bool 型數據須要存取,好比用戶一年的簽到記錄,簽了是 1,沒簽是 0,要記錄 365 天。若是使用普通的 key/value,每一個用戶要記錄 365 個,當用戶上億的時候,須要的存儲空間是驚人的。 爲了解決這個問題,Redis 提供了位圖數據結構,這樣天天的簽到記錄只佔據一個位,365 天就是 365 個位,46 個字節 (一個稍長一點的字符串) 就能夠徹底容納下,這就大大節約了存儲空間。
五、HyperLogLog
六、geoHash 附近的人
七、排行榜
八、關注點贊
4、特性
一、快
二、支持多種數據類型
三、過時鍵功能
四、支持持久化
五、管道
六、支持主從模式
七、sentinel高可用
八、Cluster集羣
快!!!內存存儲,不受IO到硬盤IO速度限制 速度極快!
採用了非阻塞 I/O 多路複用機制 極大增長訪問速度。
過時鍵功能
設置生存時間 EXPIRE 命令和 PEXPIRE 命令。 SETEX 命令 PSETEX 命令
設置過時時間 EXPIREAT 命令和 PEXPIREAT 命令。
查看剩餘生存時間 TTL 命令和 PTTL 命令。
刪除生存時間或過時時間 PERSIST 命令。
應用:一、自動更新的緩存
二、自動刷新的排行榜:在有序集合中,經過給日排行榜設置生存時間,咱們能夠 讓 Redis 在每一個新的一天開始時,自動刪除舊的排行榜。
過時刪除機制:
redis 會將每一個設置了過時時間的 key 放入到一個獨立的字典中,之後會定時遍歷這個字典來刪除到期的 key。除了定時遍歷以外,它還會使用惰性策略來刪除過時的 key,所謂惰性策略就是在客戶端訪問這個 key 的時候,redis 對 key 的過時時間進行檢查,若是過時了就當即刪除。定時刪除是集中處理,惰性刪除是零散處理。
定時掃描:
Redis 默認會每秒進行十次過時掃描,過時掃描不會遍歷過時字典中全部的 key,而是採用了一種簡單的貪心策略。
一、從過時字典中隨機 20 個 key;
二、 刪除這 20 個 key 中已通過期的 key;
三、 若是過時的 key 比率超過 1/4,那就重複步驟 1;
注意:若是有大批量的 key 過時,要給過時時間設置一個隨機範圍,而不能所有在同一時間過時。不然可能會系統資源不足,形成卡頓。
支持持久化
Redis 的數據所有在內存裏,若是忽然宕機,數據就會所有丟失,所以必須有一種機制來保證 Redis 的數據不會由於故障而丟失,這種機制就是 Redis 的持久化機制。
若是咱們僅僅是將 Redis 用做緩存的話,那麼這種數據丟失帶來的問題並非很是大,咱們只須要重 啓機器,而後再次將數據放到 緩存裏面就能夠了;但若是我 們將 Redis 用做數據庫的話,那麼這種數據 丟失就不能接受了。
Redis 的持久化機制有兩種:
第一種是快照 RDB,全量備份 記錄數據
那麼 Redis 服務器在何時纔會建立 RDB 文件呢?
在 Redis 服務器建立 RDB 文件的狀況中,如下三種是最常 見的:
1. 服務器執行客戶端發送的 SAVE 命令; 手動 阻塞 快
2. 服務器執行客戶端發送的 BGSAVE 命令;手動 不阻塞 慢
3. 使用 save 配置選項設置的自動保存條件被知足,服務器自動執行 BGSAVE 。自動 不阻塞
BGSAVE 命令不會㐀成服務器阻塞的緣由在於:
1. 當 Redis 服務器接收到 BGSAVE 命令的時候,它不會本身來建立 RDB 文件,而是經過 fork() 來生 成一個子進程,而後由子進程負責建立 RDB 文件,而本身則繼續處理客戶端的命令請求;
2. 當子進程建立好 RDB 文件並退出時,它會向父進程(也便是負責處理命令請求的 Redis 服務器)發 送一個信號,告知它 RDB 文件已經建立完畢;
3. 最後 Redis 服務器(父進程)接收子進程建立的 RDB 文件,BGSAVE 執行完畢。
自動BGSAVE的條件
save 900 1
save 300 10
save 60 10000
表示「若是距離上一次建立 RDB 文件已通過去了 900 秒,而且服務器的全部數據庫總共已經發生了 很多於 1 次修改,那麼執行 BGSAVE 命令」。
RDB持久化策略的不足:
因 爲建立 RDB 文件須要將服務器全部數據庫的數據都保存起來, 這是一個很是耗費資源和時間的操做,因此服務器須要隔一段時間才建立一個新的 RDB 文件,也即 是說,建立 RDB 文件的操做不能執行得過於頻繁,不然就會嚴重地影響服務器的性能。 好比說,在 save 配置選項的默認設置下,即便有超過 10000 次修改操做發生,服務器也至少會間隔 一分鐘才建立下一個 RDB 文件: save 900 1 save 300 10 save 60 10000 若是在等待建立下一個 RDB 文件的過程當中,服務器遭遇了意外停機,那麼用 戶將丟失最後一次建立 RDB 文件以後,數據庫發生的全部修改。
第二種是 AOF 日誌 增量備份 記錄指令
AOF 持久化有一個巨大的優點,那就是,用戶能夠根據本身的須要對 AOF 持 久化進行調整,讓 Redis 在遭遇意外停機時不丟失任何數據,或者只丟失一秒鐘數據,這比 RDB 持 久化遭遇意外停機時,丟失的數據要少得多。
配置 相關配置
appendonly yes no#開啓AOF模式
appendfilename "appendonly.aof" #保存數據的AOF文件名稱
appendfsync always everysec no
原理
AOF 持久化保存數據庫數據的方法是:每當有修改數據 庫的命令被執行時,服務器就會將被執行的命 令寫入到 AOF 文件的末尾。下次服務啓動時還原。
AOF重寫-----給文件瘦身
AOF 重寫的觸發
有兩種方法能夠觸發 AOF 重寫:
1. 客戶端向服務器發送 BGREWRITEAOF 命令。
2. 經過設置配置選項來讓服務器自動執行 BGREWRITEAOF 命令,它們分別是:
• auto-aof-rewrite-min-size ,觸發 AOF 重寫所需的最小體積:只有在 AOF 文件的體積 大於等於 size 時,服務器纔會考慮是否須要進行 AOF 重寫。這個選項用於避免對體積太小的 AOF 文件進行重寫。
• auto-aof-rewrite-percentage ,指定觸發重寫所需的 AOF 文件體積百分比:當 AOF 文件的體積大於 auto-aof-rewrite-min-size 指定的體積,而且超過上一次重寫以後的 AOF 文件 體積的 percent% 時,就會觸發 AOF 重寫。(若是服務器剛剛啓動不久,尚未進行過 AOF 重 寫,那麼使用服務器啓動時載入的 AOF 文件的體積來做爲基準值。)將這個值設置爲 0 表示關 閉自動 AOF 重寫。
管道
在通常狀況下, 用戶每執行一個 Redis 命令,客戶端與服務器都須要進行一次通訊:客戶端會將命令 請求發送給服務器,而服務器則會將執行命令所得的結果返回給客戶端。 當程序執行一些複雜的操做時, 客戶端可能須要執行多個命令, 並與服務器進行屢次通訊。
Redis 的流水線功能容許客戶端一次將多個命令請求發送給服務器, 並將被執行的多個命令請求的結 果在一個命令回覆中所有返回 給客戶端, 使用這個功能能夠有效地減小客 戶端在執行多個命令時須要 與服務器進行通訊的次數。
支持主從模式
爲了分擔讀壓力,Redis支持主從複製,Redis的主從結構能夠採用一主多從或者級聯結構,Redis主從複製能夠根據是不是全量分爲全量同步和增量同步。
Redis 的複製(replication)功能容許用戶根據一個 Redis 服務器來建立任意多個該服務器的複製品,其 中被複制的服務器爲主服務器(master),而經過複製建立出來的服務器複製品則爲從服務器(slave)。 主從服務器二者擁有相同的數據庫數據:只要主從服務器之間的網絡鏈接正常,主服務器就會一直將 發生在本身身上的數據更新同步 給從服務器,從而一直保證主從服務器的數據相同。
Redis 提供了兩種方法來爲某個主服務器建立從服務器:
1. 使用 SLAVEOF 命令,好比向一個服務器發送 SLAVEOF 127.0.0.1 6379 ,可讓接收到該命令的服務器變爲 127.0.0.1:6379 的從服務器。 在將一個服務器設置成從服務器以後,能夠經過向它發送 SLAVEOF no one 來讓它變回一個主 服務器(數據庫已有的數據會被保留)。
2. 在啓動服務器時,經過設置 slaveof 配置選項來讓服務器成爲指定 服務器的從服務器。
我配置的服務器分佈:
6376 | 6377 | 6378 | 6379 |
master | slave | slave | slave |
配置而且啓動主節點:
port 6376
daemonize yes
logfile "6376.log"
dbfilename "dump_6376.rdb"
dir "/var/redis/data/"
啓動並重啓從節點
port 6377
daemonize yes
logfile "6377.log"
dbfilename "dump-6377.rdb"
dir "/var/redis/data/"
slaveof 127.0.0.1 6376 // 從屬主節點
查看服務狀態,登錄客戶端,查看主從關係 INFO replication
sentinel高可用
監視主從服務器,並在主服務器下線時自動進行故障轉移.
它負責持續監控主從節點的健康,當主節點掛掉時,自動選擇一個最優的從節點切換爲主節點。客戶端來鏈接集羣時,會首先鏈接 sentinel,經過 sentinel 來查詢主節點的地址,而後再去鏈接主節點進行數據交互。當主節點發生故障時,客戶端會從新向 sentinel 要地址,sentinel 會將最新的主節點地址告訴客戶端。如此應用程序將無需重啓便可自動完成節點切換。好比上圖的主節點掛掉後,集羣將可能自動調整爲下圖所示結構。
部署sentinel集羣
sentinel26379 | sentinel26380 | sentinel26381 |
修改sentinel.conf文件
// Sentinel節點的端口
port 26379
dir /var/redis/data/
logfile "26379.log"
// 當前Sentinel節點監控 127.0.0.1:6379 這個主節點
// 2表明判斷主節點失敗至少須要2個Sentinel節點節點贊成
// mymaster是主節點的別名
sentinel monitor mymaster 127.0.0.1 6376 2
//每一個Sentinel節點都要按期PING命令來判斷Redis數據節點和其他Sentinel節點是否可達,若是超過30000毫秒且沒有回覆,則斷定不可達
sentinel down-after-milliseconds mymaster 30000
//故障轉移超時時間爲180000毫秒
sentinel failover-timeout mymaster 180000
啓動sentinel節點
redis-sentinel sentinel.conf
確認登錄客戶端確認:
redis-cli -h 127.0.0.1 -p 26379 INFO Sentinel
測試
相關指令 sentinel masters
sentinel slaves mymaster
Redis Sentinel
的如下幾個功能。
Sentinel
節點會按期檢測Redis
數據節點和其他Sentinel
節點是否可達。Sentinel
節點會將故障轉移通知給應用方。Redis Sentinel
結構中,客戶端在初始化的時候鏈接的是Sentinel
節點集合,從中獲取主節點信息。
消息丟失
Redis 主從採用異步複製,意味着當主節點掛掉時,從節點可能沒有收到所有的同步消息,這部分未同步的消息就丟失了。若是主從延遲特別大,那麼丟失的數據就可能會特別多。Sentinel 沒法保證消息徹底不丟失,可是也儘量保證消息少丟失。它有兩個選項能夠限制主從延遲過大。
min-slaves-to-write 1
min-slaves-max-lag 10
第一個參數表示主節點必須至少有一個從節點在進行正常複製,否 則就中止對外寫服務,喪失可用性。 何爲正常複製,何爲異常複製?這個就是由第二個參數控制的,它的單位是秒,表示若是 10s 沒有收到從節點的反饋,就意味着從節點同步不正常,要麼網絡斷開了,要麼一直沒有給反饋。
Cluster集羣
------複製特性能夠建立指定服務器的複製品,這些複製品能夠用於擴展系統處理讀請求的能力。
------Redis Sentinel 能夠在複製特性的基礎上,經過監視主從服務器並在主服務器故障時執行自動故
障轉移來保證系統的可用性。
寫能力不足怎麼辦??????
分片技術
集羣使用分片來擴展數據庫的容量,並將命令請求的負載交給不一樣的節點來分擔。
集羣將整個數據庫分爲 16384 個槽(slot),全部鍵都屬於這 16384 個槽的其中一個,計算鍵 key 屬於哪一個槽的公式爲 slot_number = crc16(key) % 16384 ,其中 crc16 爲 16 位的循環冗餘校驗和函數。
集羣中的每一個主節點均可以處理 0 個至 16384 個槽,當 16384 個槽都有某個節點在負責處理時,集羣進入上線狀態,並開始處理客戶端發送的數據命令請求。
好比說,若是咱們有三個主節點 7000 、 7001 和 7002 ,那麼咱們能夠:
- 將槽 0 至 5460 指派給節點 7000 負責處理;
- 將槽 5461 至 10922 指派給節點 7001 負責處理;
- 將槽 10923 至 16383 指派給節點 7002 負責處理;
這樣就能夠將 16384 個槽平均地指派給三個節點負責處理。
請求轉向:
對於一個被指派了槽的主 節點來講,這個主節點只會處理屬於指派給本身的槽的命令請求。若是一個節點接收到了和本身處理的槽無關的命令請求,那麼節點會向客戶端返回一個轉向錯誤(redirection error),告訴客戶端,哪一個節點纔是負責處理這條命令的,以後客戶端須要根據錯誤中包含的地址和端口號從新向正確的 節點發送命令請求。
集羣搭建:
一、建立多個節點
二、爲每一個節點指派槽,並將多個節點鏈接起來,組成一個集羣
三、當集羣數據庫的 16384 個槽都有節點在處理時,集羣進入上線狀態。
5、補充
一、應用場景不一樣,配置不一樣。
緩存:關閉aof化,rdb持久化視狀況而定 ,開啓最大內存設置(不然爲物理內存)
數據庫:開啓 aof ,開啓rdb 關閉最大內存設置