1. 程式人生 > >Redis事務、持久化、主從複製、哨兵、JRedis和JRedis Pool(摘抄)

Redis事務、持久化、主從複製、哨兵、JRedis和JRedis Pool(摘抄)

事務是指一系列操作步驟,這一系列的操作步驟,要麼完全執行,要麼完全地不執行
Redis中的事務是一組命令的集合,至少是兩個或兩個以上的命令,redis事務保證這些命令被執行時中間不會被任何操作打斷
(1)multi標記一個事務的開始,事務內的多條命令會按照先後順序被放入一個佇列中,返回值總是ok
(2)exec執行所有事務內的命令,返回事務內的所有執行語句內容,事務被打斷返回nil,如果其中一條事務語法錯誤,則無法執行事務(任意一條),會完全放棄該事務內的任意命令。
另一個錯誤是語法沒有錯誤,但執行出錯,不報錯的事務會執行成功,執行錯誤的命令報錯(因為沒有回滾機制)
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
(3)discard取消事務,放棄執行事務塊的所有命令,返回值綜述ok
在這裡插入圖片描述


(4)watch監視該值的改變
redis的watch機制:使用watch監視一個或多個key,跟蹤key的value修改情況,如果有key的value值在事務Exec執行之前被修改了,整個事務被取消。Exec返回提示資訊,表示事務已經失敗。
監視後,發現age的值已經被改動,所以放棄當前的事務。注意,redis同一時間只操作一個key
在這裡插入圖片描述
這事實上就是樂觀鎖的實現機制
(4)持久化,即儲存將資料儲存到一個不會丟失的地方,如果把資料放到記憶體中,非常容易丟失,所以放在記憶體中的資料不是持久化,而放到磁碟就算一種持久化,Redis提供兩種機制對資料進行持久化儲存,便於發生故障後能迅速回複數據(AOF和RDB)

=================================
Redis Database(RDB)指定的時間間隔將記憶體中的資料寫到磁碟,資料恢復時將快照檔案讀到記憶體中。

RDB儲存了某個時間點的全部資料集,儲存在一個二進位制檔案中,只有一個檔案,預設是dump.rdb。RDB技術非常適合做備份,可以儲存最近一個小時,一天,一個月的全部資料。儲存資料是在單獨的程序中寫檔案,不影響redis的正常使用。RDB回覆資料時比其它AOP速度更快

RDB方式的資料持久化,僅需在redis.conf檔案中配置即可,預設配置是啟用的。在配置檔案redis.conf中搜索SNAPSHOTTING,查詢在註釋開始和結束之間的關於RDB的配置說明。配SNAPSHOTTING地方有三處。

①配置執行RDB生成快照檔案的時間策略,對Redis進行設定,讓它在“N秒內資料集至少有M個key改動”這一條件被滿足時,自動儲存一次資料集。

配置格式:save seconds change
save 900 1
save 300 10
save 60 100000
這三個策略是可以同時觸發的

②dbfilename:設定RDB的檔名,預設檔名為dump.rdb

③dir:指定RDB檔案的儲存位置,預設是當前目錄

RDB的缺點就是,其會丟失資料,一旦沒有滿足觸發策略容易發生資料丟失

=================================
Append-only File(AOF),Redis每次接收到一條改變資料的命令時,它將把該命令寫到一個AOF檔案中(只記錄命令,是一個文字檔案,可以修改),當Redis重新啟動時,它通過執行AOF檔案中的所有命令來恢復資料。

AOF方式的資料持久化,在redis.conf檔案中配置即可:
①appendonly:預設是no,改成yes,即開啟aof持久化
②appendfilename:指定AOF檔名,預設檔名為appendonly.aof
③dir:指定RDB和AOF檔案存放的目錄,預設是
④appendfsync:配置向aof檔案寫命令資料的策略:
no:不主動進行同步操作,而是完全交給作業系統來做(即每30秒一次),比較快但不是很安全
always:每次執行寫入都會執行同步,慢但是安全
everysec:每秒執行一次同步操作,慢一些但是比較安全
⑤auto-aof-rewrite-min-size:允許重寫的最小AOF檔案大小,預設是64M。當aof檔案大於64M時,開始整理aof檔案,去掉無用的操作命令,縮小aof檔案。
(5)redis伺服器的主從複製
為了避免單點故障,我們需要將資料複製多份部署在多臺不同的伺服器上,即使有一臺伺服器出現故障,其他伺服器依然可以繼續提供服務。
這就要求當一臺伺服器上的資料更新後,自動將更新的資料同步到其它伺服器上,那該怎麼實現?Redis主從複製
在這裡插入圖片描述
主master負責資料的修改操作,從redis全部負責資料的讀操作。讀寫分離可以降低伺服器壓力。

通過啟動多個redis-server可以模擬主從複製結構。

Redis主從複製實現(master/salve)
方式1:修改配置檔案,啟動時,伺服器讀取配置檔案,並自動稱為指定伺服器的從伺服器,從而構成主從複製關係

新建三個redis的配置檔案

如果redis啟動,先停止
作為Master的redis埠是6380
作為Slaver的redis埠分別是6382,6384
從原有的redis.conf拷貝三份,分別命名為redis6380.conf,redis6382.conf,redis6384.conf。
複製這幾個就是為了在一臺機子上啟動多個redis server
在這裡插入圖片描述
編輯Master配置檔案
redis6380.conf在空檔案中加入如下內容:
include /usr/local/redis-3.2.9/redis.conf
包含原來的配置檔案的內容,將redis.conf加入到當前配置檔案
daemonize yes
表示redis是後臺啟動
port 6380
當前redis的埠號
pidfile /var/run/redis_6380.pid
linux執行程式的唯一標識,需要一個位置儲存唯一的表示路徑
logfile 6380.log
設定日誌檔案位置
dbfilename dump6380.rdb
rdb儲存的位置

編輯Slave配置檔案
redis6382.conf和redis6384.conf在空檔案中加入如下內容:
include /usr/local/redis-3.2.9/redis.conf
daemonize yes
port 6382
pidfile /var/run/redis_6382.pid
logfile 6382.log
dbfilename dump6382.rdb
slaveof 127.0.0.1 6380
設定主master地址

===================================
./redis-cli -p 6380
Master伺服器的客戶端
info replication
顯示伺服器的關係資訊
在這裡插入圖片描述
同樣,連線到6382,顯示的是up
在這裡插入圖片描述
在主伺服器上新增key和val,主從都會顯示。從伺服器只能讀不能寫。

當Master服務出現故障,需要手動將slave中的一個提升為master,剩下的slave掛至新的master上

命令:
①:slaveof no one
將一臺slave伺服器提升為Master
②:slaveof 127.0.0.1 6381

方式二:./redis-server --slaveof master-ip master-port在啟動redis時指定當前服務成為某個主redis服務的從Slave

(6)哨兵系統
可自動化的處理故障

  • 監控:Sentinel不斷的檢查主服務和從服務是否按照預期正常工作
  • 提醒:被監控的redis出現問題時,Sentinel會通知管理員或其它應用程式
  • 自動故障轉移:監控的主redis不能正常工作,Sentinel會開始進行故障遷移操作。就是將從伺服器提升為主伺服器,其它伺服器掛到新主伺服器之上。
  • 在這裡插入圖片描述
  • 每個哨兵(Sentinel)獨立執行,可以進行通訊,並交換監控的結果。哨兵通過心跳機制來檢查主從伺服器是否正常。哨兵的個數必須是奇數,從而投票覺得當前主伺服器是否執行正常。

安裝完redis,哨兵就已經存在,redis-sentinel。我們在一臺機子上模擬三個哨兵系統,複製三份sentinel.conf檔案:
在這裡插入圖片描述
Sentinel系統預設port是26379。三個配置port分別設定為26380,26382,26384。三個檔案分別命名:

  • sentinel26380.conf
  • sentinel26382.conf
  • sentinel26384.conf
    三個sentinel配置檔案修改:
    1、修改port 26380 port 26382 port 26384
    2、修改sentinel monitor mymaster 127.0.0.1 6380 2
    格式:sentinel monitor name masterIp masterPort Quorum投票數
    在這裡插入圖片描述
    修改之後執行哨兵系統
    在這裡插入圖片描述
    一旦主redis關閉,會自動轉化主redis
    在這裡插入圖片描述
    此外,如果新啟動了一個伺服器並且配置哨兵,會自動新增到從伺服器之中
    (7)安全設定
    訪問redis預設是沒有密碼的。要設定redis訪問密碼,修改redis.conf中requirepass 密碼。因為redis速度很快,所以在一臺比較好的 伺服器下,一個外部使用者可以1s進行150k次密碼嘗試,需要指定非常非常強大的密碼來防止暴力破解。

開啟訪問密碼設定
修改redis.conf,找到requirepass
只要改了配置檔案就重新載入
在這裡插入圖片描述
兩種密碼的使用方式:
在這裡插入圖片描述
在這裡插入圖片描述

其次,redis可以繫結ip,修改redis.conf檔案,把#bind 127.0.0.1前面的註釋#號去掉,然後把127.0.0.1改成允許訪問你的redis伺服器的ip地址,表示只允許該ip進行訪問。多個ip使用空格分隔
在這裡插入圖片描述

最後,修改redis的埠是很重要的,使用預設埠非常危險,redis.conf中修改port6379,將其修改為自己指定的埠,埠1024以內是保留給作業系統,使用者可以使用1024-65535
在這裡插入圖片描述
(8)Jedis操作Redis
在這裡插入圖片描述
Jedis有執行緒不安全的問題,一般跟commons-pool(執行緒池)一起使用。

package com.fty;	
import redis.clients.jedis.Jedis;
import java.util.List;
public class RedisString {
    public static void main(String[] args) {	
        /**
         * 1、修改redis.conf,啟動redis需要指定redis.conf的位置
         * 2、關閉linux防火牆,或者讓redis的埠號通過防火牆 systemctl statsu firewalld
         */

        //建立Jredis物件,指定連線的redis伺服器的ip埠
        Jedis jedis = new Jedis("127.0.0.1", 6379);

//        jedis.auth("密碼");

        //呼叫Jedis物件的方法操作Redis資料
        jedis.set("break", "豆漿和油條");

        //獲取key的值
        String value = jedis.get("break");
        System.out.println(value);

        //mset一次建立多個key-value
        jedis.mset("lunch","紅燒肉蓋飯", "dinner", "牛排");

        //獲取多個key對應的值mget
        List<String> values = jedis.mget("break", "lunch", "dinner");
        for(String val : values) {
            System.out.println(val);
        }
    }
}

使用Jedis Pool

package com.fty;	
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;	
public class RedisUtils {	
    private static JedisPool pool;

    //建立JedisPool物件
    public static JedisPool open(String ip, int port) {
        if(pool == null) {
            //建立JedisPool
            //建立JedisPoolConfig,給config設定連線池的引數,使用config物件去建立JedisPool
            JedisPoolConfig config = new JedisPoolConfig();

            //給config設定連線池的引數
            config.setMaxTotal(10);//設定最大的執行緒數,一個執行緒就是一個Jedis物件
            config.setMaxIdle(2);//設定最大空閒數
            config.setTestOnBorrow(true);//設定檢查項為true,標識執行緒池中獲取的物件一定是經過檢查可用的

            /**
             * poolConfig 配置器
             * host:redis所在的ip
             * port:redis的埠
             * timeout:連線redis的超時事件
             * password:redis訪問密碼
             */
            pool = new JedisPool(config, "localhost", 6379, 6000, "密碼");//建立Pool物件
        }
        return pool;
    }
    //關閉pool物件
    public static void close() {
        if(pool != null) {
            pool.close();
        }
    }

    public static void main(String[] args) {
        //從JedisPool中獲取JedisPool物件
        JedisPool pool = null;
        Jedis jedis = null;
        try {
            pool = open("localhost", 6379);
            jedis = pool.getResource();

            /**
             * 拿到Jedis後就能進行set 和 get
             */
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //關閉Jedis物件,從Pool中獲取的Jedis放回到Pool,共其它請求使用
            if(jedis != null) {
                jedis.close();//放回池中
            }
        }
    }
}