redis原理及應用

redis原理及應用

一、redis來源

二、數據類型

三、主流的應用場景

四、特性

五、補充

                                                                              

                                                                                       一、  redis來源

  作者:Salvatore Sanfilippo (antirez),男,意大利人.

   需求:    一個訪客信息追蹤網站,網站可以通 過 JavaScript 腳本,將訪客的 IP 地 址、所屬國家、閱覽器信息、被訪問頁 面的地址等數據傳送給 LLOOGG. com 。    然後 LLOOGG.com 會將這些瀏覽數 據通過 web 頁面實時地展示給用戶, 並儲存起最新的 5 至 10,000 條瀏覽 記錄以便進行查閱。

      redis解決方案

         每當某個被追蹤的網站新增一條 瀏覽記錄時, 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 的應用服務。

 

二、支持的數據類型

   

                    

       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。

                                                                                    主流的應用場景

 

1、緩存

2、分佈式鎖

3、 消息列隊

4、位圖

        在我們平時開發過程中,會有一些 bool 型數據需要存取,比如用戶一年的簽到記錄,簽了是 1,沒簽是 0,要記錄 365 天。如果使用普通的 key/value,每個用戶要記錄 365 個,當用戶上億的時候,需要的存儲空間是驚人的。 爲了解決這個問題,Redis 提供了位圖數據結構,這樣每天的簽到記錄只佔據一個位,365 天就是 365 個位,46 個字節 (一個稍長一點的字符串) 就可以完全容納下,這就大大節約了存儲空間。

5、HyperLogLog

6、geoHash 附近的人

  1. geoadd 爲成員增加某個地理位置的座標
  2. geodist 獲取兩個成員之間的地理位置的距離,可以設置距離單位 m:米 ,km:千米,ft:英尺 ,mi:英里
  3. geohash 獲取某個地理位置的hash值
  4. geopos 獲取某個成員的地理位置的座標
  5. georadius 根據給定地理位置座標獲取指定範圍內的地理位置集合 
    • WITHCOORD:傳入WITHCOORD參數,則返回結果會帶上匹配位置的經緯度。
    • WITHDIST:傳入WITHDIST參數,則返回結果會帶上匹配位置與給定地理位置的距離。
    • ASC|DESC:默認結果是未排序的,傳入ASC爲從近到遠排序,傳入DESC爲從遠到近排序。
    • WITHHASH:傳入WITHHASH參數,則返回結果會帶上匹配位置的hash值。
    • COUNT count:傳入COUNT參數,可以返回指定數量的結果。
  6. georadiusbymember 根據給定成員獲取指定範圍內的地理位置集合,相對於georadius命令,使用起來比較方便.參數基本一樣

7、排行榜

8、關注點贊

四、特性

       1、快

       2、支持多種數據類型

      3、過期鍵功能

      4、支持持久化

      5、管道
      6、支持主從模式

      7、sentinel高可用
      8、Cluster集羣

       快!!!內存存儲,不受IO到硬盤IO速度限制 速度極快!

                 

       

                採用了非阻塞 I/O 多路複用機制 極大增加訪問速度。

      過期鍵功能

              設置生存時間 EXPIRE 命令和 PEXPIRE 命令。   SETEX 命令  PSETEX 命令

            設置過期時間 EXPIREAT 命令和 PEXPIREAT 命令。

              查看剩餘生存時間 TTL 命令和 PTTL 命令。

             刪除生存時間或過期時間 PERSIST 命令。

             應用:1、自動更新的緩存

                        2、自動刷新的排行榜:在有序集合中,通過給日排行榜設置生存時間,我們可以 讓 Redis 在每個新的一天開始時,自動刪除舊的排行榜。

                  過期刪除機制:

                 redis 會將每個設置了過期時間的 key 放入到一個獨立的字典中,以後會定時遍歷這個字典來刪除到期的 key。除了定時遍歷之外,它還會使用惰性策略來刪除過期的 key,所謂惰性策略就是在客戶端訪問這個 key 的時候,redis 對 key 的過期時間進行檢查,如果過期了就立即刪除。定時刪除是集中處理,惰性刪除是零散處理。

          定時掃描:

              Redis 默認會每秒進行十次過期掃描,過期掃描不會遍歷過期字典中所有的 key,而是採用了一種簡單的貪心策略。

             1、從過期字典中隨機 20 個 key;

            2、 刪除這 20 個 key 中已經過期的 key;

            3、 如果過期的 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),告訴客戶端,哪個節點纔是負責處理這條命令的,之後客戶端需要根據錯誤中包含的地址和端口號重新向正確的 節點發送命令請求。

 

         集羣搭建:

                       1、創建多個節點

                        2、爲每個節點指派槽,並將多個節點連接起來,組成一個集羣

                        3、當集羣數據庫的 16384 個槽都有節點在處理時,集羣進入上線狀態。

 

                                                        五、補充

      1、應用場景不同,配置不同。

              緩存:關閉aof化,rdb持久化視情況而定 ,開啓最大內存設置(否則爲物理內存)

              數據庫:開啓 aof ,開啓rdb 關閉最大內存設置

 

        

 

 

 

 

    

                      

 

      

    

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章