從入門到精通-Redis,圖文並茂、分佈式鎖、主從複製、哨兵機制、Cluster集羣、緩存擊穿、緩存雪崩、持久化方案、緩存淘汰策略 附案例源碼

導讀

  篇幅較長,乾貨十足,閱讀需要花點時間,全部手打出來的字,難免出現錯別字,敬請諒解。珍惜原創,轉載請註明出處,謝謝~!

  學習之前,先附上一張知識腦圖,百度上找噠~~~

NoSql介紹與Redis介紹

什麼是Redis?

  Redis是用C語言開發的一個開源的高性能鍵值對(key-value)內存數據庫

  它提供五種數據類型來存儲值:字符串類型、散列類型、列表類型、集合類型、有序類型

  它是一種NoSql數據庫。

什麼是NoSql?

  • NoSql,即Not-Only Sql(不僅僅是SQL),泛指非關係型的數據庫
  • 什麼是關係型數據庫?數據結構是一種有行有列的數據庫。
  • NoSql數據庫是爲了解決高併發、高可用、高可擴展、大數據存儲問題而產生的數據庫解決方案。
  • NoSql可以作爲關係型數據庫的良好補充,但是不能替代關係型數據庫

NoSql數據庫分類

鍵值(key-value)存儲數據庫

  • 相關產品:Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley Db等
  • 典型應用:內存緩存,主要用於處理大量數據的高訪問負載
  • 數據模型:一系列鍵值對
  • 優勢:快速查詢
  • 劣勢:存儲的數據缺少結構化

列存儲數據庫

  • 相關產品:Cassandra、Hbase、Riak
  • 典型應用:分佈式的文件系統
  • 數據模型:以列簇式存儲,將同一列數據存在一起
  • 優勢:查找速度快,可擴展性強,更容易進行分佈式擴展
  • 劣勢:功能相對侷限

文檔型數據庫

  • 相關產品:CouchDB、MongoDB
  • 典型應用:web應用(與key-value類似,value是結構化的)
  • 數據模型:一系列鍵值對
  • 優勢:數據結構要求不嚴格
  • 劣勢

圖形(Graph)數據庫

  • 相關數據庫:Neo4J、InfoGrid、Infinite、Graph
  • 典型應用:社交網絡
  • 數據模型:圖結構
  • 優勢:利用圖結構先關算法
  • 劣勢:需要對整個圖做計算才能得出結果,不容易做分佈式的集羣方案。

Redis歷史發展

  2008年,意大利的一家創業公司Merzia推出了一款給予MySql的網站實時統計系統LLOOGG,然而沒過多久該公司的創始人Salvatore Sanfilippo便對MySql的性能感到失望,於是他決定親力爲LLOOGG量身定做一個數據庫,並於2009年開發完成,這個數據庫就是Redis

  不過Salvatore Sanfilippo不滿足將RedisLLOOGG這一款產品,而是希望更多的人使用它,於是在同一年Salvatore Sanfilippo將Redis開源發佈

  並開始和Redis的另一名主要的代碼貢獻者Pieter Noordhuis一起繼續Redis開發直到今天

  Salvatore Sanfilippo自己也沒有想到,短短的幾年時間,Redis就擁有了龐大的用戶羣體。Hacker News在2012年發佈一份數據庫的使用請款調查,結果顯示有近12%的公司在使用Redis。國內如新浪微博、街旁網、知乎網、國外如GitHub、Stack、Overflow、Flickr等都是Redis的用戶

  VmWare公司從2010年開始贊助Redis的開發,Salvatore Sanfilippo和Pieter Noordhuis也分別在3月和5月加入VMware全職開發Redis

Redis的應用場景

  • 內存數據庫(登錄信息、購物車信息、用戶瀏覽記錄等)
  • 緩存服務器(商品數據、廣告數據等等)(最多使用)
  • 解決分佈式集羣架構中的Session分離問題(Session共享)
  • 任務隊列。(秒殺、搶購、12306等等)
  • 支持發佈訂閱的消息模式
  • 應用排行榜
  • 網站訪問統計
  • 數據過期處理(可以精確到毫秒)

Redis安裝及配置

  • 官網地址:https://redis.io/
  • 中文官網地址:http://www.redis.cn
  • 下載地址:http://download.redis.io/releases/

Linux環境下安裝Redis

注:將下載後的Redis拖進Linux需要安裝下,VMware Tools,參考鏈接

將下載後的Redis拖進linux

安裝C語言需要的GCC環境

yum install gcc-c++

解壓Redis源碼壓縮包

tar -zxf redis-4.0.11.tar.gz

編譯Redis源碼

make

安裝Redis

make install PREFIX=/user/local/redis

格式:make install PREFIX=安裝目錄

Redis啓動

redis設置密碼

更改redis.conf配置

 

重啓服務

前端啓動

  • 啓動命令:redis-server,直接運行bin/redis-server將以前端模式啓動。

關閉服務

ctrl+c

啓動缺點:客戶端窗口關閉,則redis-server程序結束,不推薦使用

後端啓動(守護進程啓動)

拷貝redis

cp redis.conf /usr/local/redis/bin

格式:cp 拷貝文件夾 拷貝路徑

 修改redis.conf,將daemonize由no改爲yes

vim redis.conf

 執行命令

 ./redis-server redis.conf

格式:啓動服務 指定配置文件

 關閉服務(粗暴方式)

kill -9 42126

格式:kill -9 進程號

 正常關閉

./redis-cli shutdown

修改redis配置文件(解決IP綁定問題)

# bind 127.0.0.1 綁定的IP才能fangwenredis服務器,註釋掉該配置
protected-mode yes 是否開啓保護模式,由yes改爲no

其他命令說明

redis-server :啓動redis服務
redis-cli :進入redis命令客戶端
redis-benchmark: 性能測試的工具
redis-check-aof : aof文件進行檢查的工具
redis-check-dump :  rdb文件進行檢查的工具
redis-sentinel :  啓動哨兵監控服務

Redis客戶端

自帶命令行客戶端

語法

./redis-cli -h 127.0.0.1 -p 6379 

修改redis.conf配置文件(解決ip綁定問題)

#bind 127.0.0.1 綁定的ip才能訪問redis服務器,註釋掉該配置

protected-mode yes 是否開啓保護模式,由yes改爲no

參數說明

  • -h:redis服務器的ip地址
  • -p:redis實例的端口號

默認方式

如果不制定主機和端口號也可以

./redis-cli

默認的主機地址是:127.0.0.1
默認的端口號是:6379

Redis數據類型

官網命令大全網址

http://www.redis.cn/commands.html

  • String(字符類型)
  • Hash(散列類型)
  • List(列表類型)
  • Set(集合類型)
  • SortedSet(有序集合類型,簡稱zset)

注:命令不區分大小寫,而key是區分大小寫的。

String類型

賦值

語法:SET key value

取值

語法:GET key

取值並賦值

語法:GETSET key value

演示

 數值增減

前提條件:

  1. value整數數據時,才能使用以下命令操作數值的增減。
  2. 數值增減都是原子操作。

遞增數字

語法:INCR key

 增加指定的整數

語法:INCRBY key increment

 遞減數值

語法:DECR key

減少指定的整數 

語法:DECRBY key decrement

 僅當不存在時賦值

注:該命令可以實現分佈式鎖的功能,後續講解!!!!

語法:setnx key value

向尾部追加值

注:APPEND命令,向鍵值的末尾追加value如果鍵不存在則該鍵的值設置爲value,即相當於set key value。返回值是追加後字符串的總長度。

 獲取字符串長度

注:strlen命令,返回鍵值的長度,如果鍵不存在則返回0

 語法:STRLEN key

同時設置/獲取多個鍵值

語法:

  1. MSET key value [key value ....]
  2. MGET key [key ....]

 應用場景之自增主鍵

需求:商品編號、訂單號採用INCR命令生成。

設計:key明明要有一定的設計

實現:定義商品編號key:items:id

 Hash類型

  Hash叫散列類型,它提供了字段和字段值的映射。字段值只能是字符串類型,不支持散列類型、集合類型等其他類型。

賦值 

  HSET命令不區分插入更新操作,當執行插入操作時HSET命令返回1,當執行更新操作時返回0

一次只能設置一個字段值

語法:HSET key field value

 一次設置多個字段值

語法:HMSET key field value [field value ...]

 當字段不存在時

類似HSET,區別在於如何字段存在,該命令不執行任何操作

語法:HSETNX key field value

取值

一次只能獲取一個字段值

語法:HGET key field

 一次可以獲取多個字段值

語法:HMGET key field [field ....]

獲取所有字段值

語法:HGETALL key

 刪除字段

可以刪除一個或多個字段,返回值是被刪除的字段個數

語法:HDEL key field [field ...]

 增加數字

語法:HINCRBY key field increment

 判斷字段是否存在

語法:HEXISTS key field

只獲取字段名或字段值

語法:

  1. HKEYS key
  2. HVALS key

 獲取字段數量

語法:HLEN key

 獲取所有字段

作用:獲取hash的所有信息,包括key和value

語法:hgetall key

 應用之存儲商品信息

注意事項:存在哪些對象數據,特別是對象屬性經常發生增刪改操作的數據。

商品信息字段

  【商品id,商品名稱,商品描述,商品庫存,商品好評】

定義商品信息的key

  商品id爲1001的信息在Redis中的key爲:[items.1001]

示例

 List類型

  ArrayList使用數組方式存儲數據,所以根據索引查詢數據速度快,而新增或者刪除元素時需要涉及到位移操作,所以比較慢。

  LinkedList使用雙向鏈表方式存儲數據,每個元素都記錄前後元素的指針,所以插入、刪除數據時只是更改前後元素的指針即可,速度非常快。然後通過下標查詢元素時需要從頭開始索引,所以比較慢,但是如果查詢前幾個元素或後幾個元素速度比較快。

 List介紹

  Redis的列表類型(list)可以存儲一個有序的字符串列表,常用的操作是向列表兩端添加元素,或者獲取列表的某一個片段

  列表類型內部是使用雙向鏈表(double linked list)實現的,所以向列表兩端添加元素的時間複雜度爲0/1,獲取越接近兩端的元素速度就越快。意味着即使是一個有幾千萬個元素的列表,獲取頭部或尾部的10條記錄也是極快的。

向列表兩端添加元素

向列表左邊添加元素

語法:LPUSH key value [value ...]

 向列表右邊添加元素

語法:RPUSH key value [value ....]

 查看列表

語法:LRANGE key start stop

  LRANGE命令是列表類型最常用的命令之一,獲取列表中的某一片段,將返回start、stop之間的所有元素(包括兩端的元素),索引從0開始。索引可以是負數,“-1”代表最後一邊的一個元素

 從列表兩端彈出元素

LPOP命令從列表左邊彈出一個元素,會分兩步完成:

  1. 將列表左邊的元素從列表中移除
  2. 返回被移除的元素值

語法:

  1. LPOP key
  2. RPOP key

獲取列表中元素的個數

語法:LLEN key 

 刪除列表中指定個數的值

  LREM命令會刪除列表中前count個數爲value的元素,返回實際刪除的元素個數。根據count值不同,該命令的執行方式會有所不同。

語法:LREM key count value

  1. 當count>0時,LREM會從列表左邊開始刪除
  2. 當count<0時,LREM會從列表右邊開始刪除
  3. 當count=0時,LREM會刪除所有值爲value的元素

獲取/設置指定索引的元素值

獲取指定索引的元素值

語法:LINDEX key index

設置指定索引的元素值

語法:LSET key index value

向列表中插入元素 

  該命令首先會在列表中從左到右查詢值爲pivot的元素,然後根據第二個參數是BEFORE還是AFTER來決定將value插入到該元素的前面還是後面。

語法:LINSERT key BEFORE|AFTER pivot value

 將元素從一個列表轉移到另一個列表中

語法:RPOPLPUSH source destination

 應用之商品評論列表

需求1:用戶針對某一商品發佈評論,一個商品會被不同的用戶進行評論,存儲商品評論時,要按時間順序排序。

需要2:用戶在前端頁面查詢該商品的評論,需要按照時間順序降序排序。

思路:

  使用list存儲商品評論信息,key是該商品的id,value是商品評論信息商品編號爲1001的商品評論key【items:comment:1001】 

 Set類型

set類型即集合類型,其中的數據時不重複且沒有順序

集合類型和列表類型的對比:

   集合類型的常用操作是向集合中加入或刪除元素、判斷某個元素是否存在等,由於集合類型的Redis內部是使用值爲空散列標實現,所有這些操作的時間複雜度都爲0/1。

  Redis還提供了多個集合之間的交集、並集、差集的運算。

添加/刪除元素

語法:SADD key member [member ...]

語法:SREM key member [member ...]

獲取集合中的所有元素 

語法:SMEMBERS key

 判斷元素是否在集合中

語法:SISMEMBER key member

 集合運算命令

集合的差集運算 A-B

屬於A並且不屬於B的元素構成的集合

 語法:SDIFF key [key ...]

集合的交集運算 A∩B

屬於A且屬於B的元素構成的集合。 

 語法:SINTER key [key ...]

集合的並集運算 A ∪ B

屬於A或者屬於B的元素構成的集合

 

 

 語法:SUNION key [key ...]

獲取集合中的元素個數

語法:SCARD key

從集合中彈出一個元素 

注意:集合是無序的,所有spop命令會從集合中隨機選擇一個元素彈出

語法:SPOP key

 SortedSet類型zset

  在集合類型的基礎上,有序集合爲集合中的每個元素都關聯一個分數,這使得我們不僅可以完成插入、刪除和判斷元素是否存在集合中,還能夠獲得最高或最低的前N個元素、獲取指定分數範圍內的元素等與分蘇有關的操作。

在某些方面有序集合和列表類型有些相似。

  1. 二者都是有序的。
  2. 二者都可以獲得某一範圍的元素

但是二者有着很大的區別:

  1. 列表類型是通過鏈表實現的,後去靠近兩端的數據速度極快,而當元素增多後,訪問中間數據的速度會變慢。
  2. 有序集合類型使用散列實現,所有即使讀取位於中間部分的數據也很快。
  3. 列表中不能簡單的調整某個元素的位置,但是有序集合可以(通過更改分數實現)。
  4. 有序集合要比列表類型更耗內存。

添加元素

  向有序集合中加入一個元素和該元素的分數,如果該元素已經存在則會用新的分數替換原有的分數。返回值是新加入到集合中的元素個數,不不含之前已經存在的元素。

語法:ZADD key score member [score member ...]

獲取排名在某個範圍的元素列表

按照元素分數從小到大的順序返回索引從start到stop之間的所有元素(包含兩端的元素)

語法:ZRANGE key start stop [WITHSCORES]

 如果需要獲取元素的分數的可以在命令尾部加上WITHSCORES參數

 獲取元素的分數

語法:ZSCORE key member

 刪除元素

移除有序集key中的一個或多個成員,不存在的成員將被忽略。

當key存在但不是有序集類型時,返回錯誤。

語法:ZREM key member [member ...]

 獲取指定分數範圍的元素

語法:ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

 增加某個元素的分數

返回值是更改後的分數

語法:ZINCRBY key increment member

 獲取集合中元素的數量

語法:ZCARD key

 獲得指定分數範圍內的元素個數

語法:ZCOUNT key min max

 按照排名範圍刪除元素

語法:ZREMRANGEBYRANK key start stop

 按照分數範圍刪除元素

語法:ZREMRANGEBYSCORE key min max

 獲取元素的排名

從小到大

語法:ZRANK key member

從大到小

語法:ZREVRANK key member

 

 應用之商品銷售排行榜

需求:根據商品銷售對商品進行排序顯示

思路:定義商品銷售排行榜(sorted set集合),key爲items:sellsort,分數爲商品小數量。

寫入商品銷售量:

>商品編號1001的銷量是9,商品編號1002的銷量是10

>商品編號1001銷量家1

>商品銷量前10名

 

 通用命令

keys

語法:keys pattern

del

語法:DEL key

exists

作用:確認一個key是否存在

語法:exists key

expire

  Redis在實際使用過程中更多的用作緩存,然後緩存的數據一般都是需要設置生存時間的,即:到期後數據銷燬。

EXPIRE key seconds             設置key的生存時間(單位:秒)key在多少秒後會自動刪除

TTL key                     查看key生於的生存時間

PERSIST key                清除生存時間 

PEXPIRE key milliseconds    生存時間設置單位爲:毫秒

例子:
192.168.101.3:7002> set test 1        設置test的值爲1
OK
192.168.101.3:7002> get test            獲取test的值
"1"
192.168.101.3:7002> EXPIRE test 5    設置test的生存時間爲5秒
(integer) 1
192.168.101.3:7002> TTL test            查看test的生於生成時間還有1秒刪除
(integer) 1
192.168.101.3:7002> TTL test
(integer) -2
192.168.101.3:7002> get test            獲取test的值,已經刪除
(nil)

rename

作用:重命名key

語法:rename oldkey newkey

type

作用:顯示指定key的數據類型

語法:type key

Redis事務

事務介紹

  • Redis的事務是通過MULTI,EXEC,DISCARD和WATCH這四個命令來完成。
  • Redis的單個命令都是原子性的,所以這裏確保事務性的對象是命令集合
  • Redis將命令集合序列化並確保處於一事務的命令集合連續且不被打斷的執行。
  • Redis不支持回滾的操作。

相關命令

  • MULTI

    注:用於標記事務塊的開始

    Redis會將後續的命令逐個放入隊列中,然後使用EXEC命令原子化地執行這個命令序列。

    語法:MULTI

  • EXEC

    在一個事務中執行所有先前放入隊列的命令,然後恢復正常的連接狀態。

    語法:EXEC

  • DISCARD

    清楚所有先前在一個事務中放入隊列的命令,然後恢復正常的連接狀態。

    語法:DISCARD

  • WATCH

    當某個事務需要按條件執行時,就要使用這個命令將給定的鍵設置爲受監控狀態

    語法:WATCH key [key ....]

    注:該命令可以實現redis的樂觀鎖

  • UNWATCH

    清除所有先前爲一個事務監控的鍵。

    語法:UNWATCH

 

 事務失敗處理

  • Redis語法錯誤(編譯器錯誤)

 

  •  Redis類型錯誤(運行期錯誤)

 

爲什麼redis不支持事務回滾?

  1. 大多數事務失敗是因爲語法錯誤或者類型錯誤,這兩種錯誤,再開發階段都是可以避免的
  2. Redis爲了性能方面就忽略了事務回滾

Redis實現分佈式鎖

鎖的處理

  單應用中使用鎖:單線程多線程

    synchronize、Lock

  分佈式應用中使用鎖:多進程

分佈式鎖的實現方式

  1. 數據庫的樂觀鎖
  2. 給予zookeeper的分佈式鎖
  3. 給予redis的分佈式鎖

分佈式鎖的注意事項

  1. 互斥性:在任意時刻,只有一個客戶端能持有鎖
  2. 同一性:加鎖和解鎖必須是同一個客戶端,客戶端自己不能把別人加的鎖給解了。
  3. 避免死鎖:即使有一個客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保證後續其他客戶端能加鎖。

實現分佈式鎖

獲取鎖

方式一(使用set命令實現)

方式二(使用setnx命令實現)

package com.cyb.redis.utils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class jedisUtils {
    private static String ip = "192.168.31.200";
    private static int port = 6379;
    private static JedisPool pool;
    static {
        pool = new JedisPool(ip, port);
    }
    public static Jedis getJedis() {
        return pool.getResource();
    }
    public static boolean getLock(String lockKey, String requestId, int timeout) {
        //獲取jedis對象,負責和遠程redis服務器進行連接
        Jedis je=getJedis();
        //參數3:NX和XX
        //參數4:EX和PX
        String result = je.set(lockKey, requestId, "NX", "EX", timeout);
        if (result=="ok") {
            return true;
        }
        return false;
    }

    public static synchronized boolean getLock2(String lockKey, String requestId, int timeout) {
        //獲取jedis對象,負責和遠程redis服務器進行連接
        Jedis je=getJedis();
        //參數3:NX和XX
        //參數4:EX和PX
        Long result = je.setnx(lockKey, requestId);
        if (result==1) {
            je.expire(lockKey, timeout); //設置有效期
            return true;
        }
        return false;
    }
}

釋放鎖

package com.cyb.redis.utils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class jedisUtils {
    private static String ip = "192.168.31.200";
    private static int port = 6379;
    private static JedisPool pool;
    static {
        pool = new JedisPool(ip, port);
    }
    public static Jedis getJedis() {
        return pool.getResource();
    }
    /**
     * 釋放分佈式鎖
     * @param lockKey
     * @param requestId
     */
    public static void releaseLock(String lockKey, String requestId) {
        Jedis je=getJedis();
        if (requestId.equals(je.get(lockKey))) {
            je.del(lockKey);
        }
    }
}

Redis持久化方案

導讀

  Redis是一個內存數據庫,爲了保證數據的持久性,它提供了兩種持久化方案。

  1. RDB方式(默認)
  2. AOF方式

RDB方式

  RDB是Redis默認採用的持久化方式。

  RDB方式是通過快照(snapshotting)完成的,當符合一定條件時Redis會自動將內存中的數據進行快照並持久化到硬盤。

RDB觸發條件

  1. 符合自定義配置的快照規則
  2. 執行save或者bgsave命令
  3. 執行flushall命令
  4. 執行主從複製操作

在redis.conf中設置自定義快照規則

1、RDB持久化條件

  格式:save <seconds> <changes>

示例:

  save 900 1:表示15分鐘(900秒)內至少1個鍵更改則進行快照。

  save 300 10:表示5分鐘(300秒)內至少10個鍵被更改則進行快照。

  save 60 10000:表示1分鐘內至少10000個鍵被更改則進行快照。

2、配置dir指定rdb快照文件的位置

# Note that you must specify a directory here, not a file name.
dir ./

3、配置dbfilename指定rdb快照文件的名稱

# The filename where to dump the DB
dbfilename dump.rdb

說明

  1. Redis啓動後會讀取RDB快照文件,將數據從硬盤載入到內存
  2. 根據數據量大小與結構和服務器性能不同,這個時間也不同。通常將記錄1千萬個字符串類型鍵,大小爲1GB的快照文件載入到內存中需要花費20-30秒鐘。

快照的實現原理

快照過程

  1. redis使用fork函數複製一份當前進程副本(子進程)
  2. 父進程繼續接受並處理客戶端發來的命令,而子進程開始將內存中的數據寫入到硬盤臨時文件
  3. 子進程寫入完所有數據後用該臨時文件替換舊的RDB文件,至此,一次快照操作完成。

注意

  1. redis在進行快照的過程中不會修改RDB文件,只有快照結束後纔會將舊的文件替換成新的,也就是說任何時候RDB文件都是完整的。
  2. 這就使得我們可以通過定時備份RDB文件來實現redis數據庫的備份,RDB文件是經過壓縮的二進制文件,佔用的空間會小於內存中的數據,更加利於傳輸。

RDB優缺點

缺點

  使用RDB方式實現持久化,一旦redis異常退出,就會丟失最後一次快照以後更改的所有數據。這個時候我們就需要根據具體的應用場景,通過組合設置自動快照條件的方式將可能發生的數據損失控制在能夠接受範圍。如果數據相對來說比較重要,希望將損失降到最小,則可以使用AOF方式進行持久化

優點

  RDB可以最大化redis的性能:父進程在保存RDB文件時唯一要做的就是fork出一個字進程,然後這個子進程就會處理接下來的所有保存工作,父進程無需執行任何磁盤I/O操作。同時這個也是一個缺點,如果數據集比較大的時候,fork可能比較耗時,造成服務器在一段時間內停止處理客戶端的請求。

AOF方式

介紹

  默認情況下Redis沒有開啓AOF(append only file)方式的持久化

  開啓AOF持久化後每執行一條會更改Redis中的數據命令,Redis就會將該命令寫入硬盤中的AOF文件,這一過程顯示會降低Redis的性能,但大部分下這個影響是能夠接受的,另外使用較快的硬盤可以提高AOF的性能

配置redis.conf

設置appendonly參數爲yes

appendonly yes

AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數設置的

dir ./

默認的文件名是appendonly.aof,可以通過appendfilename參數修改

appendfilename appendonly.aof

AOF重寫原理(優化AOF文件)

  1. Redis可以在AOF文件體積變得過大時,自動地後臺對AOF進行重寫
  2. 重寫後的新AOF文件包含了恢復當前數據集所需的最小命令集合
  3. 整個重寫操作是絕對安全的,因爲Redis在創建新的AOF文件的過程中,會繼續將命令追加到現有的AOF文件裏面,即使重寫過程中發生停機,現有的AOF文件也不會丟失。而一旦新AOF文件創建完畢,Redis就會從舊AOF文件切換到新AOF文件,並開始對新AOF文件進行追加操作。
  4. AOF文件有序地保存了對數據庫執行的所有寫入操作,這些寫入操作以Redis協議的格式保存,因此AOF文件的內容非常容易被人讀懂,對文件進行分析(parse)也很輕鬆。

參數說明

  1. #auto-aof-rewrite-percentage 100:表示當前aof文件大小超過上次aof文件大小的百分之多少的時候會進行重寫。如果之前沒有重寫過,以啓動時aof文件大小爲基準。
  2. #auto-aof-rewrite-min-size 64mb:表示限制允許重寫最小aof文件大小,也就是文件大小小於64mb的時候,不需要進行優化

同步磁盤數據

  Redis每次更改數據的時候,aof機制都會將命令記錄到aof文件,但是實際上由於操作系統的緩存機制數據實時寫入到硬盤,而是進入硬盤緩存再通過硬盤緩存機制去刷新到保存文件中

參數說明

  1. appendfsync always:每次執行寫入都會進行同步,這個是最安全但是效率比較低
  2. appendfsync everysec:每一秒執行
  3. appendfsync no:不主動進行同步操作,由於操作系統去執行,這個是最快但是最不安全的方式

AOF文件損壞以後如何修復

  服務器可能在程序正在對AOF文件進行寫入時停機,如果停機造成AOF文件出錯(corrupt),那麼Redis在重啓時會拒絕載入這個AOF文件,從而確保數據的一致性不會被破壞。

  當發生這種情況時,可以以以下方式來修復出錯的AOF文件:

    1、爲現有的AOF文件創建一個備份。

    2、使用Redis附帶的redis-check-aof程序,對原來的AOF文件進行修復。

    3、重啓Redis服務器,等待服務器字啊如修復後的AOF文件,並進行數據恢復。

如何選擇RDB和AOF

  1. 一般來說,如果對數據的安全性要求非常高的話,應該同時使用兩種持久化功能。
  2. 如果可以承受數分鐘以內的數據丟失,那麼可以只使用RDB持久化。
  3. 有很多用戶都只使用AOF持久化,但並不推薦這種方式:因爲定時生成RDB快照(snapshot)非常便於進行數據庫備份,並且RDB恢復數據集的速度也要比AOF恢復的速度要快
  4. 兩種持久化策略可以同時使用,也可以使用其中一種。如果同時使用的話,那麼Redis啓動時,會優先使用AOF文件來還原數據。

Redis的主從複製

什麼是主從複製

  持久性保證了即使redis服務重啓也不會丟失數據,因爲redis服務重啓後將硬盤上持久化的數據恢復到內存中,但是當redis服務器的硬盤損壞了可能導致數據丟失,不過通過redis的主從複製機制舊可以避免這種單點故障,如下圖:

 

 說明:

  1. 主redis中的數據有兩個副本(replication)即從redis1和從redis2,即使一臺redis服務器宕機其他兩臺redis服務也可以繼續提供服務。
  2. 主redis中的數據和從redis上的數據保持實時同步,當主redis寫入數據時通過主從複製機制會複製到兩個從redis服務上。
  3. 只有一個主redis,可以有多個從redis。
  4. 主從複製不會阻塞master,在同步數據時,master可以繼續處理client請求
  5. 一個redis可以即是主從,如下圖:

 

主從配置

主redis配置

  無需特殊配置

從redis配置

  修改從服務器上的redis.conf文件

# slaveof <masterip> <masterport>
slaveof 192.168.31.200 6379

  上邊的配置說明當前【從服務器】對應的【主服務器】的ip是192.168.31.200,端口是6379.

實現原理

  1. slave第一次或者重連到master發送一個SYNC的命令。
  2. master收到SYNC的時候,會做兩件事
    1. 執行bgsave(rdb的快照文件)
    2. master會把新收到的修改命令存入到緩衝區

缺點:沒有辦法對master進行動態選舉

Redis Sentinel哨兵機制

簡介

  Sentinel(哨兵)進程是用於監控redis集羣中Master主服務器工作的狀態,在Master主服務器發生故障的時候,可以實現Master和Slave服務器的切換,保證系統的高可用,其已經被集成在redis2.6+的版本中,Redis的哨兵模式到2.8版本之後就穩定了下來。

哨兵進程的作用

  1. 監控(Monitoring):哨兵(Sentinel)會不斷地檢查你的Master和Slave是否運作正常。
  2. 提醒(Notification):當被監控的某個Redis節點出現問題時,哨兵(Sentinel)可以通過API向管理員或者其他應用程序發送通知。
  3. 自動故障遷移(Automatic failover):當一個Master不能正常工作時,哨兵(Sentinel)會開始一次自動故障遷移操作。
    1. 它會將失效Master的其中一個Slave升級爲新的Master,並讓失效Master的其他Slave改爲複製新的Master;
    2. 當客戶端視圖連接失效的Master時,集羣也會向客戶端返回新Master的地址,使得集羣可以使用現在的Master替換失效的Master。
    3. Master和Slave服務器切換後,Master的redis.conf、Slave的redis.conf和sentinel.conf的配置文件的內容都會發生相應的改變,即Master主服務器的redis.conf配置文件中會多一行Slave的配置,sentinel.conf的監控目標會隨之調換。

哨兵進程的工作方式

  1. 每個Sentinel(哨兵)進程以每秒鐘一次的頻率向整個集羣中的Master主服務器Slave從服務器以及其他Sentinel(哨兵)進程發送一個PING命令
  2. 如果一個實例(instance)距離最後一次有效回覆PING命令的時間超過down-after-milliseconds選項所指定的值,則這個實例會被Sentinel(哨兵)進程標記爲主觀下線(SDOWN)。
  3. 如果一個Master主服務器被標記爲主觀下線(SDOWN),則正在監視這個Master主服務器的所有Sentinel(哨兵)進程要以每秒一次的頻率確認Master主服務器確實進入主觀下線狀態
  4. 當有足夠數量的Sentinel(哨兵)進程(大於等於配置文件指定的值)在指定的時間範圍內確認Master主服務器進入了主觀下線狀態(SDOWN),則Master主服務器會被標記爲客觀下線(ODOWN)
  5. 在一般情況下,每個Sentinel(哨兵)進程會以每10秒一次的頻率向集羣中的所有Master主服務器、Slave從服務器發送INFO命令。
  6. 當Master主服務器被Sentinel(哨兵)進程標記爲客觀下線(ODOWN)時,Sentinel(哨兵)進程向下線的Master主服務器的所有Slave從服務器發送INFO命令的頻率會從10秒一次改爲每秒一次。
  7. 若沒有足夠數量的Sentinel(哨兵)進程同意Master主服務器下線,Master主服務器的客觀下線狀態就會被移除。若Master主服務器重新向Sentinel(哨兵)進程發送PING命令返回有效回覆,Master主服務器的主觀下線狀態就會被移除。

實現

修改從機的sentinel.conf

sentinel monitor mymaster  192.168.127.129 6379 1

啓動哨兵服務器

./redis-sentinel sentinel.conf

Redis Cluster集羣

redis-cluster架構圖

 

 架構細節

  1. 所有的redis節點彼此互聯(PING-PING機制),內部使用二進制協議優化傳輸速度和帶寬。
  2. 節點的fail是通過集羣中超過半數的節點檢測失效時才生效。
  3. 客戶端與redis節點直連,不需要中間proxy層,客戶端不需要連接集羣所有節點,連接集羣中任何一個可用節點即可。
  4. redis-cluster把所有的物理節點映射到[0-16383]slot上,cluster負責維護node<->slot<->value
    Redis集羣中內置了16384個哈希槽,當需要在Redis集羣中放置一個key-value時,redis先對key使用crc16算法算出一個結果,然後把結果對16384求餘數,這樣每個key都會對應一個編號在0-16384之間的哈希槽,redis會根據節點數量大致均等的將哈希槽映射到不同節點。

 

redis-cluster投票:容錯 

 

  1.  集羣中所有master參與投票,如果半數以上master節點與其中一個master節點通信超過(cluster-node-timeout),認爲該master節點掛掉。
  2. 什麼時候整個集羣不可用(cluster_state:fail)?
    1. 如果集羣任意master掛掉,且當前master沒有slave,則集羣進入fail狀態。也可以理解成集羣的[0-16384]slot映射不完全時進入fail狀態。
    2. 如果集羣超過半數以上master掛掉,無論是否有slave,集羣進入fail狀態。

安裝Ruby環境

導讀

  redis集羣需要使用集羣管理腳本redis-trib.rb,它的執行相應依賴ruby環境。

安裝

安裝ruby

yum install ruby
yum install rubygems

將redis-3.2.9.gen拖近Linux系統

安裝ruby和redis的接口程序redis-3.2.9.gem

gem install redis-3.2.9.gem

複製redis-3.2.9/src/redis-trib.rb 文件到/usr/local/redis目錄

cp redis-3.2.9/src/redis-trib.rb /usr/local/redis/ -r

安裝Redis集羣(RedisCluster)

  Redis集羣最少需要三臺主服務器,三臺從服務器,端口號分別爲7001~7006。

創建7001實例,並編輯redis.conf文件,修改port爲7001。

 

修改redis.conf配置文件,打開Cluster-enable yes 

 

 重複以上2個步驟,完成7002~7006實例的創建,注意端口修改

啓動所有的實例

創建Redis集羣

./redis-trib.rb create --replicas 1 192.168.242.129:7001 192.168.242.129:7002 192.168.242.129:7003 192.168.242.129:7004 192.168.242.129:7005  192.168.242.129:7006
>>> Creating cluster
Connecting to node 192.168.242.129:7001: OK
Connecting to node 192.168.242.129:7002: OK
Connecting to node 192.168.242.129:7003: OK
Connecting to node 192.168.242.129:7004: OK
Connecting to node 192.168.242.129:7005: OK
Connecting to node 192.168.242.129:7006: OK
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.242.129:7001
192.168.242.129:7002
192.168.242.129:7003
Adding replica 192.168.242.129:7004 to 192.168.242.129:7001
Adding replica 192.168.242.129:7005 to 192.168.242.129:7002
Adding replica 192.168.242.129:7006 to 192.168.242.129:7003
M: d8f6a0e3192c905f0aad411946f3ef9305350420 192.168.242.129:7001
   slots:0-5460 (5461 slots) master
M: 7a12bc730ddc939c84a156f276c446c28acf798c 192.168.242.129:7002
   slots:5461-10922 (5462 slots) master
M: 93f73d2424a796657948c660928b71edd3db881f 192.168.242.129:7003
   slots:10923-16383 (5461 slots) master
S: f79802d3da6b58ef6f9f30c903db7b2f79664e61 192.168.242.129:7004
   replicates d8f6a0e3192c905f0aad411946f3ef9305350420
S: 0bc78702413eb88eb6d7982833a6e040c6af05be 192.168.242.129:7005
   replicates 7a12bc730ddc939c84a156f276c446c28acf798c
S: 4170a68ba6b7757e914056e2857bb84c5e10950e 192.168.242.129:7006
   replicates 93f73d2424a796657948c660928b71edd3db881f
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join....
>>> Performing Cluster Check (using node 192.168.242.129:7001)
M: d8f6a0e3192c905f0aad411946f3ef9305350420 192.168.242.129:7001
   slots:0-5460 (5461 slots) master
M: 7a12bc730ddc939c84a156f276c446c28acf798c 192.168.242.129:7002
   slots:5461-10922 (5462 slots) master
M: 93f73d2424a796657948c660928b71edd3db881f 192.168.242.129:7003
   slots:10923-16383 (5461 slots) master
M: f79802d3da6b58ef6f9f30c903db7b2f79664e61 192.168.242.129:7004
   slots: (0 slots) master
   replicates d8f6a0e3192c905f0aad411946f3ef9305350420
M: 0bc78702413eb88eb6d7982833a6e040c6af05be 192.168.242.129:7005
   slots: (0 slots) master
   replicates 7a12bc730ddc939c84a156f276c446c28acf798c
M: 4170a68ba6b7757e914056e2857bb84c5e10950e 192.168.242.129:7006
   slots: (0 slots) master
   replicates 93f73d2424a796657948c660928b71edd3db881f
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost-0723 redis]#

命令客戶端連接集羣

命令:

./redis-cli -h 127.0.0.1 -p 7001 -c


注:-c表示是以redis集羣方式進行連接
./redis-cli -p 7006 -c
127.0.0.1:7006> set key1 123
-> Redirected to slot [9189] located at 127.0.0.1:7002
OK
127.0.0.1:7002>

查看集羣的命令

查看集羣狀態

127.0.0.1:7003> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:3
cluster_stats_messages_sent:926
cluster_stats_messages_received:926

查看集羣中的節點

127.0.0.1:7003> cluster nodes
7a12bc730ddc939c84a156f276c446c28acf798c 127.0.0.1:7002 master - 0 1443601739754 2 connected 5461-10922
93f73d2424a796657948c660928b71edd3db881f 127.0.0.1:7003 myself,master - 0 0 3 connected 10923-16383
d8f6a0e3192c905f0aad411946f3ef9305350420 127.0.0.1:7001 master - 0 1443601741267 1 connected 0-5460
4170a68ba6b7757e914056e2857bb84c5e10950e 127.0.0.1:7006 slave 93f73d2424a796657948c660928b71edd3db881f 0 1443601739250 6 connected
f79802d3da6b58ef6f9f30c903db7b2f79664e61 127.0.0.1:7004 slave d8f6a0e3192c905f0aad411946f3ef9305350420 0 1443601742277 4 connected
0bc78702413eb88eb6d7982833a6e040c6af05be 127.0.0.1:7005 slave 7a12bc730ddc939c84a156f276c446c28acf798c 0 1443601740259 5 connected
127.0.0.1:7003>

維護節點

  集羣創建完成後可以繼續向集羣中添加節點

添加主節點

添加7007節點作爲新節點

命令:./redis-trib.rb add-node 127.0.0.1:7007 127.0.0.1:7001

 

查看集羣節點發現7007已加到集羣中 

 

 hash槽重新分配

  添加完主節點需要對主節點進行hash槽分配,這樣該主節纔可以存儲數據

查看集羣中槽佔用情況

  redis集羣有16384個槽,集羣中的每個節點分配自己槽,通過查看集羣節點可以看到槽佔用情況。

 

 給剛添加的7007節點分配槽

第一步:連上集羣(連接集羣中任意一個可用節點都行)

./redis-trib.rb reshard 192.168.101.3:7001

第二步:輸入要分配的槽數量

 

 輸入500,表示要分配500個槽

第三步:輸入接收槽的節點id

 

輸入:15b809eadae88955e36bcdbb8144f61bbbaf38fb

ps:這裏準備給7007分配槽,通過cluster node查看7007節點id爲:

15b809eadae88955e36bcdbb8144f61bbbaf38fb

第四步:輸入源節點id

 

 輸入:all

第五步:輸入yes開始移動槽到目標節點id

 

 輸入:yes

添加從節點

  添加7008從節點,將7008作爲7007的從節點

命令:

./redis-trib.rb add-node --slave --master-id  主節點id   新節點的ip和端口   舊節點ip和端口

執行如下命令:

./redis-trib.rb add-node --slave --master-id cad9f7413ec6842c971dbcc2c48b4ca959eb5db4  192.168.101.3:7008 192.168.101.3:7001

cad9f7413ec6842c971dbcc2c48b4ca959eb5db4  7007結點的id,可通過cluster nodes查看。

nodes查看

 

注意:如果原來該節點在集羣中的配置信息已經生成到cluster-config-file指定的配置文件中(如果cluster-config-file沒有指定則默認爲nodes.conf),這時可能會報錯 

[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0

解決辦法是刪除生成的配置文件nodes.conf,刪除後再執行./redis-trib.rb add-node指令

查看集羣中的節點,剛添加7008爲7007的從節點

 

 刪除節點

命令:

./redis-trib.rb del-node 127.0.0.1:7005 4b45eb75c8b428fbd77ab979b85080146a9bc017

刪除已經佔用hash槽的節點會失敗,報錯如下

[ERR] Node 127.0.0.1:7005 is not empty! Reshard data away and try again.

需要將該節點佔用的hash槽分配出去

Jedis連接集羣

創建JedisCluster類連接Redis集羣

@Test
public void testJedisCluster() throws Exception {
    //創建一連接,JedisCluster對象,在系統中是單例存在
    Set<HostAndPort> nodes = new HashSet<>();
    nodes.add(new HostAndPort("192.168.242.129", 7001));
    nodes.add(new HostAndPort("192.168.242.129", 7002));
    nodes.add(new HostAndPort("192.168.242.129", 7003));
    nodes.add(new HostAndPort("192.168.242.129", 7004));
    nodes.add(new HostAndPort("192.168.242.129", 7005));
    nodes.add(new HostAndPort("192.168.242.129", 7006));
    JedisCluster cluster = new JedisCluster(nodes);
    //執行JedisCluster對象中的方法,方法和redis一一對應。
    cluster.set("cluster-test", "my jedis cluster test");
    String result = cluster.get("cluster-test");
    System.out.println(result);
    //程序結束時需要關閉JedisCluster對象
    cluster.close();
}

使用Spring

配置applicationContext.xml

<!-- 連接池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <!-- 最大連接數 -->
    <property name="maxTotal" value="30" />
    <!-- 最大空閒連接數 -->
    <property name="maxIdle" value="10" />
    <!-- 每次釋放連接的最大數目 -->
    <property name="numTestsPerEvictionRun" value="1024" />
    <!-- 釋放連接的掃描間隔(毫秒) -->
    <property name="timeBetweenEvictionRunsMillis" value="30000" />
    <!-- 連接最小空閒時間 -->
    <property name="minEvictableIdleTimeMillis" value="1800000" />
    <!-- 連接空閒多久後釋放, 當空閒時間>該值 且 空閒連接>最大空閒連接數 時直接釋放 -->
    <property name="softMinEvictableIdleTimeMillis" value="10000" />
    <!-- 獲取連接時的最大等待毫秒數,小於零:阻塞不確定的時間,默認-1 -->
    <property name="maxWaitMillis" value="1500" />
    <!-- 在獲取連接的時候檢查有效性, 默認false -->
    <property name="testOnBorrow" value="true" />
    <!-- 在空閒時檢查有效性, 默認false -->
    <property name="testWhileIdle" value="true" />
    <!-- 連接耗盡時是否阻塞, false報異常,ture阻塞直到超時, 默認true -->
    <property name="blockWhenExhausted" value="false" />
</bean>
<!-- redis集羣 -->
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
    <constructor-arg index="0">
        <set>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7001"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7002"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7003"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7004"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7005"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7006"></constructor-arg>
            </bean>
        </set>
    </constructor-arg>
    <constructor-arg index="1" ref="jedisPoolConfig"></constructor-arg>
</bean>

測試代碼

private ApplicationContext applicationContext;
    @Before
    public void init() {
        applicationContext = new ClassPathXmlApplicationContext(
                "classpath:applicationContext.xml");
    }

    // redis集羣
    @Test
    public void testJedisCluster() {
        JedisCluster jedisCluster = (JedisCluster) applicationContext
                .getBean("jedisCluster");

        jedisCluster.set("name", "zhangsan");
        String value = jedisCluster.get("name");
        System.out.println(value);
    }

緩存穿透、緩存擊穿、緩存雪崩

緩存數據步驟

  1. 查詢緩存,如果沒有數據,則查詢數據庫
  2. 查詢數據庫,如果數據不爲空,將結果寫入緩存

緩存穿透

什麼叫緩存穿透?

  一般的緩存系統,都是按照key去緩存查詢,如果不存在對應的value,就應該去後端系統查詢。如果key對應的value是一定不存在的,並且對key併發請求量很大,就會對後端系統造成很大的壓力。這就叫做緩存穿透。

如何解決?

  1. 對查詢結果爲空的情況也進行緩存,緩存時間設置短一點,或者該key對應的數據insert了之後清楚緩存
  2. 對一定不存在的key進行過濾。可以把所有的可能存在的key放到一個大的Bitmap中,查詢時通過該Bitmap過濾。(布隆表達式)

緩存雪崩

什麼叫緩存雪崩?

  當緩存服務器重啓或者大量緩存集合中某一個時間段失效,這樣在失效的時候,也會給後端系統帶來很大壓力。

如何解決?

  1. 在緩存失效後,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。
  2. 不同的key,設置不同的過期時間,讓緩存失效的時間點儘量均勻
  3. 做二級緩存,A1爲原始緩存,A3爲拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置爲短期,A2設置爲長期。

緩存擊穿

什麼叫緩存擊穿?

  對於一些設置了過期時間的key,如果這些key可能會在某些時間點被超高併發地訪問,是一種非常“熱點”的數據。這個時候,需要考慮一個問題:“緩存”被擊穿的問題,這個和緩存雪崩的區別在於這裏針對某一key緩存,前者則是很多key。

  緩存在某個時間點過期的時候,恰好在這個時間點對這個key有大量的併發請求過來,這些請求發現緩存過期一般都會從後端DB加載數據並回設到緩存,這個時候大併發的請求可能會瞬間把後端DB壓垮。

如何解決?

  使用redis的setnx互斥鎖先進行判斷,這樣其他線程就處於等待狀態,保證不會有大併發操作去操作數據庫。

if(redis.setnx()==1){

//查數據庫

//加入線程

}

緩存淘汰策略

  • 當 Redis 內存超出物理內存限制時,內存的數據會開始和磁盤產生頻繁的交換 (swap)。交換會讓 Redis 的性能急劇下降,對於訪問量比較頻繁的 Redis 來說,這樣龜速的存取效率基本上等於不可用。
  • 在生產環境中我們是不允許 Redis 出現交換行爲的,爲了限制最大使用內存,Redis 提供了配置參數 maxmemory 來限制內存超出期望大小。
  • 當實際內存超出 maxmemory 時,Redis 提供了幾種可選策略 (maxmemory-policy) 來讓用戶自己決定該如何騰出新的空間以繼續提供讀寫服務。

策略

noeviction:當內存不足以容納新寫入數據時,新寫入操作會報錯。
allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。
allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。
volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key。
volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key。
volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優先移除。

使用

修改redis.conf的maxmemory,設置最大使用內存:

maxmemory 1024000

修改redis.conf的maxmemory-policy,設置redis緩存淘汰機制:

maxmemory-policy noeviction

SpringBoot整合Redis、Mybatis(附源碼)

點我直達

Redis高級項目實戰,分佈式鎖詳講(附源碼)

點我直達

Redis實戰秒殺(附源碼)

點我直達

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