您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)如何解析Redis中的集群主從復(fù)制原理,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
本篇文章帶大家深入理解下Redis集群主從復(fù)制原理,希望對(duì)大家有所幫助!
1、實(shí)現(xiàn)更高性能:高并發(fā)應(yīng)用,單機(jī)性能會(huì)有影響,需要更多redis服務(wù)器分擔(dān)壓力,實(shí)現(xiàn)負(fù)載均衡
2、實(shí)現(xiàn)高可用:如果單機(jī),防止宕機(jī)/硬件故障
3、實(shí)現(xiàn)可擴(kuò)展:?jiǎn)螜C(jī)內(nèi)存和硬件有限制,實(shí)現(xiàn)橫向擴(kuò)展
冗余或者分片存儲(chǔ)實(shí)現(xiàn)如上特性。
和Kafka,Mysql,Rocketmq一樣,redis支持集群部署,集群節(jié)點(diǎn)有master和slave之分,主節(jié)點(diǎn)是master,從節(jié)點(diǎn)是slave(最新叫副本replica).slave會(huì)通過(guò)復(fù)制機(jī)制,從master同步最新的數(shù)據(jù)。Redis提供了非常方便的命令開(kāi)啟主從復(fù)制?!鞠嚓P(guān)推薦:Redis視頻教程】
如何配置開(kāi)啟主從復(fù)制?
以本機(jī)搭建偽集群為例,6379端口是從節(jié)點(diǎn),6378作為主節(jié)點(diǎn)。
1、從節(jié)點(diǎn)redis.conf配置 replicaof masterip masterport 從節(jié)點(diǎn)啟動(dòng)后,自動(dòng)連接到master節(jié)點(diǎn),開(kāi)始同步數(shù)據(jù).
源碼說(shuō)明:
//每1s執(zhí)行這個(gè)方法 void replicationCron(void) { ... //檢查是否需要連接到master 如果是REPL_STATE_CONNECT狀態(tài),必須連接到master //#define REPL_STATE_CONNECT 1 Must connect to master if (server.repl_state == REPL_STATE_CONNECT) { serverLog(LL_NOTICE,"Connecting to MASTER %s:%d", server.masterhost, server.masterport); //和master創(chuàng)建連接 if (connectWithMaster() == C_OK) { serverLog(LL_NOTICE,"MASTER <-> REPLICA sync started"); } } //發(fā)送ping命令給slave if ((replication_cron_loops % server.repl_ping_slave_period) == 0 && listLength(server.slaves)) { /* Note that we don't send the PING if the clients are paused during * a Redis Cluster manual failover: the PING we send will otherwise * alter the replication offsets of master and slave, and will no longer * match the one stored into 'mf_master_offset' state. */ int manual_failover_in_progress = server.cluster_enabled && server.cluster->mf_end && clientsArePaused(); if (!manual_failover_in_progress) { ping_argv[0] = createStringObject("PING",4); replicationFeedSlaves(server.slaves, server.slaveseldb, ping_argv, 1); decrRefCount(ping_argv[0]); } } //發(fā)送換行符到所有slave,告訴slave等待接收rdb文件 listRewind(server.slaves,&li); while((ln = listNext(&li))) { client *slave = ln->value; int is_presync = (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START || (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_END && server.rdb_child_type != RDB_CHILD_TYPE_SOCKET)); if (is_presync) { if (write(slave->fd, "\n", 1) == -1) { /* Don't worry about socket errors, it's just a ping. */ } } } ... }
3、全量復(fù)制流程-支持無(wú)盤(pán)復(fù)制或者rdb持久化復(fù)制
當(dāng)slave連接到master后,使用psync(以前是sync命令,它不允許部分重新同步,所以現(xiàn)在改用PSYNC)命令初始化復(fù)制,將主節(jié)點(diǎn)replication id和處理過(guò)最大offset發(fā)送到master。
master節(jié)點(diǎn)擁有如下兩個(gè)屬性,一個(gè)replication id(標(biāo)志實(shí)例),一個(gè)offset(標(biāo)志寫(xiě)入從節(jié)點(diǎn)的stream)
Replication ID, offset
如果主節(jié)點(diǎn)緩沖區(qū)中沒(méi)有足夠的積壓工作,或者如果復(fù)制副本引用的是不再已知的歷史記錄(復(fù)制ID),則會(huì)發(fā)生完全重新同步
源碼說(shuō)明:
//沒(méi)有在rdb進(jìn)程,沒(méi)有aof重寫(xiě)進(jìn)程 if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) { time_t idle, max_idle = 0; int slaves_waiting = 0; int mincapa = -1; listNode *ln; listIter li; listRewind(server.slaves,&li); while((ln = listNext(&li))) { client *slave = ln->value; //判斷slave是否是等待bgsave狀態(tài) if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START) { //多久沒(méi)有發(fā)送心跳或查詢數(shù)據(jù)了 空閑時(shí)間間隔 idle = server.unixtime - slave->lastinteraction; if (idle > max_idle) max_idle = idle; slaves_waiting++; mincapa = (mincapa == -1) ? slave->slave_capa : (mincapa & slave->slave_capa); } } if (slaves_waiting && (!server.repl_diskless_sync || max_idle > server.repl_diskless_sync_delay)) { /* Start the BGSAVE. The called function may start a * BGSAVE with socket target or disk target depending on the * configuration and slaves capabilities. */ //bgsave rdb生成 startBgsaveForReplication(mincapa); } }
復(fù)制過(guò)程中,slave狀態(tài)轉(zhuǎn)換流程。
每次實(shí)例作為主實(shí)例從頭開(kāi)始重新啟動(dòng),或者將復(fù)制副本提升為主實(shí)例,都會(huì)為此實(shí)例生成一個(gè)新的復(fù)制ID。如果兩個(gè)replica的復(fù)制id相同,則他們可能在不同的時(shí)間,有相同的數(shù)據(jù),對(duì)于保存最新數(shù)據(jù)集的給定歷史記錄(復(fù)制ID),偏移量作為一個(gè)邏輯時(shí)間來(lái)理解。需要通過(guò)Replication ID, offset兩個(gè)數(shù)據(jù)來(lái)判斷。用來(lái)判斷從節(jié)點(diǎn)同步數(shù)據(jù)到哪了。
1、slave本身有數(shù)據(jù),會(huì)怎么樣?
slave先刪除自身的數(shù)據(jù),再用rdb文件加載。
2、生成rdb文件的過(guò)程中,客戶端寫(xiě)命令怎么處理?
保存到內(nèi)存緩存中,rdb發(fā)送完成后發(fā)送到slave。
3、Redis復(fù)制如何處理key過(guò)期的?
1、副本不會(huì)使key過(guò)期,而是等待主機(jī)使key過(guò)期。當(dāng)主機(jī)使key過(guò)期(或由于LRU而將其逐出)時(shí),它將合成一個(gè)DEL命令,該命令將傳輸?shù)剿懈北尽?/p>
2、但是,由于主機(jī)驅(qū)動(dòng)的expire,有時(shí)副本可能仍然具有邏輯上已過(guò)期的內(nèi)存密鑰,因?yàn)橹鞣?wù)器無(wú)法及時(shí)提供DEL命令。為了處理這個(gè)問(wèn)題,副本使用它的邏輯時(shí)鐘來(lái)報(bào)告一個(gè)key不存在,只用于不違反數(shù)據(jù)集一致性的讀取操作(因?yàn)閬?lái)自主服務(wù)器的新命令將到達(dá))
3、在Lua腳本執(zhí)行期間,不執(zhí)行密鑰過(guò)期。當(dāng)Lua腳本運(yùn)行時(shí),從概念上講,主節(jié)點(diǎn)中的時(shí)間是凍結(jié)的,因此給定的鍵在腳本運(yùn)行的所有時(shí)間內(nèi)都將存在或不存在。這可以防止key在腳本中間過(guò)期,并且需要key才能以保證在數(shù)據(jù)集中具有相同效果的方式將相同的腳本發(fā)送到副本。
一旦復(fù)制副本升級(jí)為主副本,它將開(kāi)始獨(dú)立地使key過(guò)期,并且不需要舊主副本的任何幫助。
1、解決了數(shù)據(jù)備份的問(wèn)題,但是rdb文件大,傳輸大文件,恢復(fù)時(shí)間也長(zhǎng)
2、如果master異常,需要手工將replica選舉為master
3、1主多從,1主1從的情況下,還是存在單點(diǎn)問(wèn)題
4、Redis版本2.8.18后支持無(wú)盤(pán)復(fù)制,性能更高。
1、默認(rèn)用異步復(fù)制,通過(guò)異步確認(rèn)同步的命令數(shù)量
2、1個(gè)master可以有多個(gè)副本
3、副本也可以有自己的副本,從redis4.0開(kāi)始,副本都會(huì)從主節(jié)點(diǎn)接收完全相同的復(fù)制流
4、復(fù)制既可以用于可擴(kuò)展性,也可以用于只讀查詢的多個(gè)副本
關(guān)于如何解析Redis中的集群主從復(fù)制原理就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。