Java-分布式框架-redis-2

一话浇、Redis持久化

RDB快照(snapshot)

在默認(rèn)情況下, Redis 將內(nèi)存數(shù)據(jù)庫快照保存在名字為 dump.rdb 的二進(jìn)制文件中筷转。你可以對 Redis 進(jìn)行設(shè)置蔚万, 讓它在“ N 秒內(nèi)數(shù)據(jù)集至少有 M 個改動”這一條件被滿足時, 自動保存一次數(shù)據(jù)集徽曲。比如說零截, 以下設(shè)置會讓 Redis 在滿足“ 60 秒內(nèi)有至少有 1000 個鍵被改動”這一條件時, 自動保存一次數(shù)據(jù)集:
// save 60 1000
關(guān)閉RDB只需要將所有的save保存策略注釋掉即可秃臣。

還可以手動執(zhí)行命令生成RDB快照涧衙,進(jìn)入redis客戶端執(zhí)行命令save或bgsave可以生成dump.rdb文件,每次命令執(zhí)行都會將所有redis內(nèi)存快照到一個新的rdb文件里奥此,并覆蓋原有rdb快照文件弧哎。save是同步命令,bgsave是異步命令稚虎,bgsave會從redis主進(jìn)程fork(fork()是linux函數(shù))出一個子進(jìn)程專門用來生成rdb快照文件撤嫩。

image.png

注意:如果設(shè)置鏡像保存策略為save 60 1000,若時間55秒蠢终,操作次數(shù)999次的時候redis宕機(jī)了序攘,那么這999次操作會丟失鸭限。

AOF(append-only file)

快照功能并不是非常耐久(durable): 如果 Redis 因?yàn)槟承┰蚨斐晒收贤C(jī), 那么服務(wù)器將丟失最近寫入两踏、且仍未保存到快照中的那些數(shù)據(jù)败京。從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化梦染,將修改的每一條指令記錄進(jìn)文件appendonly.aof中你可以通過修改配置文件來打開 AOF 功能:

  • appendonly yes

從現(xiàn)在開始赡麦, 每當(dāng) Redis 執(zhí)行一個改變數(shù)據(jù)集的命令時(比如 SET), 這個命令就會被追加到 AOF 文件的末尾帕识。這樣的話泛粹, 當(dāng) Redis 重新啟動時, 程序就可以通過重新執(zhí)行 AOF 文件中的命令來達(dá)到重建數(shù)據(jù)集的目的肮疗。你可以配置 Redis 多久才將數(shù)據(jù) fsync 到磁盤一次晶姊。有三個選項(xiàng):

  • appendfsync always:每次有新命令追加到 AOF 文件時就執(zhí)行一次 fsync ,非常慢伪货,也非常安全们衙。
  • appendfsync everysec:每秒 fsync 一次,足夠快(和使用 RDB 持久化差不多)碱呼,并且在故障時只會丟失 1 秒鐘的數(shù)據(jù)蒙挑。
  • appendfsync no:從不 fsync ,將數(shù)據(jù)交給操作系統(tǒng)來處理愚臀。更快忆蚀,也更不安全的選擇。推薦(并且也是默認(rèn))的措施為每秒 fsync 一次姑裂, 這種 fsync 策略可以兼顧速度和安全性馋袜。
AOF重寫

AOF文件里可能有太多沒用指令,所以AOF會定期根據(jù)內(nèi)存的最新數(shù)據(jù)生成aof文件例如舶斧,執(zhí)行了如下幾條命令:

127.0.0.1:6379> incr readcount
(integer) 1
127.0.0.1:6379> incr readcount
(integer) 2
127.0.0.1:6379> incr readcount
(integer) 3
127.0.0.1:6379> incr readcount
(integer) 4
127.0.0.1:6379> incr readcount
(integer) 5

重寫后AOF文件里變成一條命令欣鳖,而不是5條

*3
$3
SET
$9
readcount
$1
5

如下兩個配置可以控制AOF自動重寫頻率

  • auto-aof-rewrite-min-size 64mb

aof文件至少要達(dá)到64M才會自動重寫,文件太小恢復(fù)速度本來就很快捧毛,重寫的意義不大

  • auto-aof-rewrite-percentage 100

aof文件自上一次重寫后文件大小增長了100%則再次觸發(fā)重寫當(dāng)然AOF還可以手動重寫观堂,進(jìn)入redis客戶端執(zhí)行命令bgrewriteaof重寫AOF注意让网,AOF重寫redis會fork出一個子進(jìn)程去做呀忧,不會對redis正常命令處理有太多影響

命令 RDB AOF
啟動優(yōu)先級
體積
恢復(fù)速度
數(shù)據(jù)安全性 容易丟數(shù) 據(jù)根據(jù)策略決定

注意1:redis啟動時如果既有rdb文件又有aof文件則優(yōu)先選擇aof文件恢復(fù)數(shù)據(jù),因?yàn)閍of一般來說數(shù)據(jù)更全一點(diǎn)溃睹。

注意2:redis數(shù)據(jù)庫的定位并不是作為持久層數(shù)據(jù)庫而账,而是一個內(nèi)存數(shù)據(jù)庫,是用來抗并發(fā)的因篇。

Redis 4.0 混合持久化

重啟 Redis 時泞辐,我們很少使用 RDB來恢復(fù)內(nèi)存狀態(tài)笔横,因?yàn)闀G失大量數(shù)據(jù)。我們通常使用 AOF 日志重放咐吼,但是重放 AOF 日志性能相對 RDB來說要慢很多吹缔,這樣在 Redis 實(shí)例很大的情況下,啟動需要花費(fèi)很長的時間锯茄。 Redis 4.0 為了解決這個問題厢塘,帶來了一個新的持久化選項(xiàng)——混合持久化。通過如下配置可以開啟混合持久化:

  • aof-use-rdb-preamble yes

如果開啟了混合持久化肌幽,AOF在重寫時晚碾,不再是單純將內(nèi)存數(shù)據(jù)轉(zhuǎn)換為RESP命令寫入AOF文件,而是將重寫這一刻之前的內(nèi)存做RDB快照處理喂急,并且將RDB快照內(nèi)容和增量的AOF修改內(nèi)存數(shù)據(jù)的命令存在一起格嘁,都寫入新的AOF文件溃斋,新的文件一開始不叫appendonly.aof臣疑,等到重寫完新的AOF文件才會進(jìn)行改名夏块,原子的覆蓋原有的AOF文件侵状,完成新舊兩個AOF文件的替換蚯嫌。于是在 Redis 重啟的時候缨硝,可以先加載 RDB 的內(nèi)容助隧,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放恳蹲,因此重啟效率大幅得到提升步氏。

混合持久化AOF文件結(jié)構(gòu)


image.png

Redis主從架構(gòu)

Redis主從工作原理
  1. slave連接master成功响禽,發(fā)送psync同步命令給master。
  2. master接收到同步命令荚醒,執(zhí)行bgsave后臺生成最新rdb快照數(shù)據(jù)文件芋类,注意這期間master還會接收到新的寫命令,master會把這些指令緩存起來界阁。
  3. master發(fā)送rdb數(shù)據(jù)文件給slave侯繁。
  4. master發(fā)送期間緩存起來的寫指令。
  5. slave清除原來的rdb數(shù)據(jù)文件泡躯。
  6. 合成接收到的rdb快照數(shù)據(jù)文件與新的寫指令贮竟,并加載到內(nèi)存中。
  7. master通過socket長連接持續(xù)把寫指令發(fā)送給從節(jié)點(diǎn)较剃,保證主從命令數(shù)據(jù)一致性咕别。

主從復(fù)制(全量復(fù)制)流程圖:

image.png

注意:repl_back_buffer容器中專門存儲最近的寫命令,但容量有限,默認(rèn)為1MB.

主從之間的連接可能會因?yàn)榫W(wǎng)絡(luò)不穩(wěn)定等原因會造成連接暫時中斷與重連,不可能每次重連發(fā)現(xiàn)主從數(shù)據(jù)不一致就采用全量復(fù)制,redis也給我們提供了部分復(fù)制的功能.

  1. slave連接中斷.
  2. 期間repl_back_buffer容器存儲最近的寫命令.
  3. slave重連master成功.
  4. slave發(fā)送psync(offerset)同步指令給master.
  5. master收到同步指令,判斷offerset是否在repl_back_buffer容器的寫指令的范圍內(nèi),若在,同步offerset后面的指令;若不在,全量同步.
  6. master通過socket長連接持續(xù)把寫指令發(fā)送給從節(jié)點(diǎn),保證主從命令數(shù)據(jù)一致性写穴。

主從復(fù)制(部分復(fù)制)流程圖:

image.png

redis主從架構(gòu)搭建惰拱,配置從節(jié)點(diǎn)步驟
1. 復(fù)制一份redis.conf文件
2. 將相關(guān)配置修改為如下值:
port 6380
pidfile /var/run/redis_6380.pid
logfile "6380.log"
dir /usr/local/redis‐5.0.3/data/6380
3. 配置主從復(fù)制
replicaof 192.168.0.60 6379 # 從本機(jī)6379的redis實(shí)例復(fù)制數(shù)據(jù)
replica‐read‐only yes
4. 啟動從節(jié)點(diǎn)
redis‐server redis.conf
5. 連接從節(jié)點(diǎn)
redis‐cli ‐p 6380
6. 測試在6379實(shí)例上寫數(shù)據(jù),6380實(shí)例是否能及時同步新修改數(shù)據(jù)
7. 可以自己再配置一個6381的從節(jié)點(diǎn)
單機(jī)使用
  • 添加依賴
<dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
</dependency>
public class JedisSingleTest {
    public static void main(String[] args) throws IOException {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(20);
        jedisPoolConfig.setMaxIdle(10);
        jedisPoolConfig.setMinIdle(5);
        // timeout啊送,這里既是連接超時又是讀寫超時偿短,從Jedis 2.8開始有區(qū)分connectionTimeout和soTimeout的構(gòu)造函數(shù)
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.0.60", 6379, 3000, null);

        Jedis jedis = null;
        try {
            //從redis連接池里拿出一個連接執(zhí)行命令
            jedis = jedisPool.getResource();
            //******* jedis普通操作示例 ********
            System.out.println(jedis.set("name", "value"));
            System.out.println(jedis.get("name"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //注意這里不是關(guān)閉連接欣孤,在JedisPool模式下,Jedis會被歸還給資源池昔逗。
            if (jedis != null)
                jedis.close();
        }
    }
}

Redis哨兵高可用架構(gòu)

sentinel哨兵是特殊的redis服務(wù)降传,不提供讀寫服務(wù),主要用來監(jiān)控redis實(shí)例節(jié)點(diǎn)勾怒。哨兵架構(gòu)下client端第一次從哨兵找出redis的主節(jié)點(diǎn)搬瑰,后續(xù)就直接訪問redis的主節(jié)點(diǎn),不會每次都通過sentinel代理訪問redis的主節(jié)點(diǎn)控硼,當(dāng)redis的主節(jié)點(diǎn)發(fā)生變化泽论,哨兵會第一時間感知到,并且將新的redis主節(jié)點(diǎn)通知給client端(這里面redis的client端一般都實(shí)現(xiàn)了訂閱功能卡乾,訂閱sentinel發(fā)布的節(jié)點(diǎn)變動消息)


image.png
redis哨兵架構(gòu)搭建步驟:
1翼悴、復(fù)制一份sentinel.conf文件
cp sentinel.conf sentinel‐26379.conf
2、將相關(guān)配置修改為如下值:
port 26379
daemonize yes
pidfile "/var/run/redis‐sentinel‐26379.pid"
logfile "26379.log"
dir "/usr/local/redis‐5.0.3/data"
// sentinel monitor <master‐name> <ip> <redis‐port> <quorum>
// quorum是一個數(shù)字幔妨,指明當(dāng)有多少個sentinel認(rèn)為一個master失效時(值一般為:sentinel總數(shù)/2 +1)鹦赎,master才算真正失效
sentinel monitor mymaster 192.168.0.60 6379 2
3、啟動sentinel哨兵實(shí)例
src/redis‐sentinel sentinel‐26379.conf
4误堡、查看sentinel的info信息
src/redis‐cli ‐p 26379
127.0.0.1:26379>info
可以看到Sentinel的info里已經(jīng)識別出了redis的主從
5古话、可以自己再配置兩個sentinel,端口26380和26381锁施,注意上述配置文件里的對應(yīng)數(shù)字都要修改
哨兵使用
public class JedisSentinelTest {
    public static void main(String[] args) throws IOException {

        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(20);
        config.setMaxIdle(10);
        config.setMinIdle(5);

        String masterName = "mymaster";
        Set<String> sentinels = new HashSet<String>();
        sentinels.add(new HostAndPort("192.168.0.60",26379).toString());
        sentinels.add(new HostAndPort("192.168.0.60",26380).toString());
        sentinels.add(new HostAndPort("192.168.0.60",26381).toString());
        //JedisSentinelPool其實(shí)本質(zhì)跟JedisPool類似陪踩,都是與redis主節(jié)點(diǎn)建立的連接池
        //JedisSentinelPool并不是說與sentinel建立的連接池,而是通過sentinel發(fā)現(xiàn)redis主節(jié)點(diǎn)并與其建立連接
        JedisSentinelPool jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, config, 3000, null);
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            System.out.println(jedis.set("sentinel666", "666"));
            System.out.println(jedis.get("sentinel666"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //注意這里不是關(guān)閉連接悉抵,在JedisPool模式下肩狂,Jedis會被歸還給資源池。
            if (jedis != null)
                jedis.close();
        }
    }
}
SpringBoot下哨兵使用
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
//線程池
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
spring:
  redis:
    database: 0
    timeout: 3000
    lettuce:
      pool:
        max-idle: 50
        min-idle: 10
        max-active: 100
        max-wait: 1000
     sentinel:    #哨兵模式
       master: mymaster #主服務(wù)器所在集群名稱
       nodes: 192.168.0.60:26379,192.168.0.60:26380,192.168.0.60:26381
@Autowired
private StringRedisTemplate stringRedisTemplate;

@RequestMapping("/test_sentinel")
public void testSentinel() throws InterruptedException {
    int i = 1;
    while (true){
        try {
            stringRedisTemplate.opsForValue().set("name"+i, i+""); //jedis.set(key,value);
            System.out.println("設(shè)置key:"+ "name" + i);
            i++;
            Thread.sleep(1000);
        }catch (Exception e){
            logger.error("錯誤:", e);
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末姥饰,一起剝皮案震驚了整個濱河市傻谁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌列粪,老刑警劉巖审磁,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異岂座,居然都是意外死亡态蒂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進(jìn)店門掺逼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吃媒,“玉大人,你說我怎么就攤上這事吕喘∽改牵” “怎么了?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵氯质,是天一觀的道長募舟。 經(jīng)常有香客問我,道長闻察,這世上最難降的妖魔是什么拱礁? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮辕漂,結(jié)果婚禮上呢灶,老公的妹妹穿的比我還像新娘。我一直安慰自己钉嘹,他們只是感情好鸯乃,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著跋涣,像睡著了一般缨睡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陈辱,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天奖年,我揣著相機(jī)與錄音,去河邊找鬼沛贪。 笑死陋守,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的利赋。 我是一名探鬼主播嗅义,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼隐砸!你這毒婦竟也來了之碗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤季希,失蹤者是張志新(化名)和其女友劉穎褪那,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體式塌,經(jīng)...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡博敬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了峰尝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片偏窝。...
    茶點(diǎn)故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出祭往,到底是詐尸還是另有隱情伦意,我是刑警寧澤,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布硼补,位于F島的核電站驮肉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏已骇。R本人自食惡果不足惜离钝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望褪储。 院中可真熱鬧卵渴,春花似錦、人聲如沸鲤竹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宛裕。三九已至瑟啃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間揩尸,已是汗流浹背蛹屿。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岩榆,地道東北人错负。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像勇边,于是被迫代替她去往敵國和親犹撒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評論 2 350

推薦閱讀更多精彩內(nèi)容