Java中高级核心知识全面解析(3),美团Java面试算法题
特別是當出現(xiàn)?斷線重復(fù)制?的情況是時,為了讓從服務(wù)器補足斷線時確實的那一小部分數(shù)據(jù),卻要執(zhí)行一次如此耗資源的?SYNC?命令,顯然是不合理的。
③、PSYNC 命令的引入
所以在?Redis 2.8?中引入了?PSYNC?命令來代替?SYNC?,它具有兩種模式:
部分復(fù)制的原理主要是靠主從節(jié)點分別維護一個?復(fù)制偏移量,有了這個偏移量之后斷線重連之后一比較,之后就可以僅僅把從服務(wù)器斷線之后確實的這部分數(shù)據(jù)給補回來了。
3.Redis Sentinel 哨兵
上圖展示了一個典型的哨兵架構(gòu)圖,它由兩部分組成,哨兵節(jié)點和數(shù)據(jù)節(jié)點:
- 哨兵節(jié)點: 哨兵系統(tǒng)由一個或多個哨兵節(jié)點組成,哨兵節(jié)點是特殊的 Redis 節(jié)點,不存儲數(shù)據(jù);
- 數(shù)據(jù)節(jié)點: 主節(jié)點和從節(jié)點都是數(shù)據(jù)節(jié)點;
在復(fù)制的基礎(chǔ)上,哨兵實現(xiàn)了 自動化的故障恢復(fù) 功能,下方是官方對于哨兵功能的描述:
- 監(jiān)控(Monitoring): 哨兵會不斷地檢查主節(jié)點和從節(jié)點是否運作正常。
- 自動故障轉(zhuǎn)移(Automatic failover): 當?主節(jié)點?不能正常工作時,哨兵會開始?自動故障轉(zhuǎn)移操作,它會將失效主節(jié)點的其中一個?從節(jié)點升級為新的主節(jié)點,并讓其他從節(jié)點改為復(fù)制新的主節(jié)點。
- 配置提供者(Configuration provider): 客戶端在初始化時,通過連接哨兵來獲得當前 Redis服務(wù)的主節(jié)點地址。
- 通知(Notification): 哨兵可以將故障轉(zhuǎn)移的結(jié)果發(fā)送給客戶端。
其中,監(jiān)控和自動故障轉(zhuǎn)移功能,使得哨兵可以及時發(fā)現(xiàn)主節(jié)點故障并完成轉(zhuǎn)移。而配置提供者和通知功能,則需要在與客戶端的交互中才能體現(xiàn)。
1)快速體驗
①、第一步:創(chuàng)建主從節(jié)點配置文件并啟動
正確安裝好 Redis 之后,我們?nèi)サ?Redis 的安裝目錄 (mac 默認在?/usr/local/?),找到?redis.conf文件復(fù)制三份分別命名為?redis-master.conf / redis-slave1.conf / redis-slave2.conf?,分別作為1?個主節(jié)點和2?個從節(jié)點的配置文件 (下圖演示了我本機的?redis.conf?文件的位置)
打開可以看到這個?.conf?后綴的文件里面有很多說明的內(nèi)容,全部刪除然后分別改成下面的樣子:
#redis-master.conf port 6379 daemonize yes logfile "6379.log" dbfilename "dump-6379.rdb" #redis-slave1.conf port 6380 daemonize yes logfile "6380.log" dbfilename "dump-6380.rdb" slaveof 127.0.0.1 6379 #redis-slave2.conf port 6381 daemonize yes logfile "6381.log" dbfilename "dump-6381.rdb" slaveof 127.0.0.1 6379然后我們可以執(zhí)行?redis-server <config file path>?來根據(jù)配置文件啟動不同的 Redis 實例,依次啟動主從節(jié)點:
redis-server /usr/local/redis-5.0.3/redis-master.conf redis-server /usr/local/redis-5.0.3/redis-slave1.conf redis-server /usr/local/redis-5.0.3/redis-slave2.conf節(jié)點啟動后,我們執(zhí)行?redis-cli?默認連接到我們端口為?6379?的主節(jié)點執(zhí)行?info Replication?檢查一下主從狀態(tài)是否正常:(可以看到下方正確地顯示了兩個從節(jié)點)
②、第二步:創(chuàng)建哨兵節(jié)點配置文件并啟動
按照上面同樣的方法,我們給哨兵節(jié)點也創(chuàng)建三個配置文件。(哨兵節(jié)點本質(zhì)上是特殊的 Redis 節(jié)點,所以配置幾乎沒什么差別,只是在端口上做區(qū)分就好)
# redis-sentinel-1.conf port 26379 daemonize yes logfile "26379.log" sentinel monitor mymaster 127.0.0.1 6379 2 # redis-sentinel-2.conf port 26380 daemonize yes logfile "26380.log" sentinel monitor mymaster 127.0.0.1 6379 2 # redis-sentinel-3.conf port 26381 daemonize yes logfile "26381.log" sentinel monitor mymaster 127.0.0.1 6379 2其中,?sentinel monitor mymaster 127.0.0.1 6379 2?配置的含義是:該哨兵節(jié)點監(jiān)控?127.0.0.1:6379?這個主節(jié)點,該主節(jié)點的名稱是?mymaster?,最后的?2?的含義與主節(jié)點的故障判定有關(guān):至少需要?2?個哨兵節(jié)點同意,才能判定主節(jié)點故障并進行故障轉(zhuǎn)移。
執(zhí)行下方命令將哨兵節(jié)點啟動起來:
redis-server /usr/local/redis-5.0.3/redis-sentinel-1.conf --sentinel redis-server /usr/local/redis-5.0.3/redis-sentinel-2.conf --sentinel redis-server /usr/local/redis-5.0.3/redis-sentinel-3.conf --sentinel使用?redis-cil?工具連接哨兵節(jié)點,并執(zhí)行?info Sentinel?命令來查看是否已經(jīng)在監(jiān)視主節(jié)點了:
# 連接端口為 26379 的 Redis 節(jié)點 ? ~ redis-cli -p 26379 127.0.0.1:26379> info Sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3此時你打開剛才寫好的哨兵配置文件,你還會發(fā)現(xiàn)出現(xiàn)了一些變化:
③、第三步:演示故障轉(zhuǎn)移
首先,我們使用?kill -9?命令來殺掉主節(jié)點,同時?在哨兵節(jié)點中執(zhí)行?info Sentinel?命令來觀察故障節(jié)點的過程:
? ~ ps aux | grep 6379 longtao 74529 0.3 0.0 4346936 2132 ?? Ss 10:30上午 0:03.09 redis-server *:26379 [sentinel] longtao 73541 0.2 0.0 4348072 2292 ?? Ss 10:18上午 0:04.79 redis-server *:6379 longtao 75521 0.0 0.0 4286728 728 s008 S+ 10:39上午 0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git -- exclude-dir=.hg --exclude-dir=.svn 6379 longtao 74836 0.0 0.0 4289844 944 s006 S+ 10:32上午 0:00.01 redis-cli -p 26379 ? ~ kill -9 73541如果?剛殺掉瞬間?在哨兵節(jié)點中執(zhí)行?info?命令來查看,會發(fā)現(xiàn)主節(jié)點還沒有切換過來,因為哨兵發(fā)現(xiàn)主節(jié)點故障并轉(zhuǎn)移需要一段時間:
# 第一時間查看哨兵節(jié)點發(fā)現(xiàn)并未轉(zhuǎn)移,還在 6379 端口 127.0.0.1:26379> info Sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3一段時間之后你再執(zhí)行?info?命令,查看,你就會發(fā)現(xiàn)主節(jié)點已經(jīng)切換成了?6381?端口的從節(jié)點:
# 過一段時間之后在執(zhí)行,發(fā)現(xiàn)已經(jīng)切換了 6381 端口 127.0.0.1:26379> info Sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=127.0.0.1:6381,slaves=2,sentinels=3但同時還可以發(fā)現(xiàn),哨兵節(jié)點認為新的主節(jié)點仍然有兩個從節(jié)點 (上方 slaves=2),這是因為哨兵在將?6381?切換成主節(jié)點的同時,將?6379?節(jié)點置為其從節(jié)點。雖然?6379?從節(jié)點已經(jīng)掛掉,但是由于?哨兵并不會對從節(jié)點進行客觀下線,因此認為該從節(jié)點一直存在。當?6379?節(jié)點重新啟動后,會自動變成6381?節(jié)點的從節(jié)點。
另外,在故障轉(zhuǎn)移的階段,哨兵和主從節(jié)點的配置文件都會被改寫:
- 對于主從節(jié)點: 主要是?slaveof?配置的變化,新的主節(jié)點沒有了?slaveof?配置,其從節(jié)點則slaveof?新的主節(jié)點。
- 對于哨兵節(jié)點: 除了主從節(jié)點信息的變化,紀元(epoch) (記錄當前集群狀態(tài)的參數(shù)) 也會變化,紀元相關(guān)的參數(shù)都 +1 了。
2)客戶端訪問哨兵系統(tǒng)代碼演示
上面我們在?快速體驗?中主要感受到了服務(wù)端自己對于當前主從節(jié)點的自動化治理,下面我們以 Java 代碼為例,來演示一下客戶端如何訪問我們的哨兵系統(tǒng):
public static void testSentinel() throws Exception { String masterName = "mymaster"; Set<String> sentinels = new HashSet<>(); sentinels.add("127.0.0.1:26379"); sentinels.add("127.0.0.1:26380"); sentinels.add("127.0.0.1:26381"); // 初始化過程做了很多工作 JedisSentinelPool pool = new JedisSentinelPool(masterName, sentinels); Jedis jedis = pool.getResource(); jedis.set("key1", "value1"); pool.close(); }①、客戶端原理
Jedis 客戶端對哨兵提供了很好的支持。如上述代碼所示,我們只需要向 Jedis 提供哨兵節(jié)點集合和?masterName?,構(gòu)造?JedisSentinelPool?對象,然后便可以像使用普通 Redis 連接池一樣來使用了:通過?pool.getResource()?獲取連接,執(zhí)行具體的命令。
在整個過程中,我們的代碼不需要顯式的指定主節(jié)點的地址,就可以連接到主節(jié)點;代碼中對故障轉(zhuǎn)移沒有任何體現(xiàn),就可以在哨兵完成故障轉(zhuǎn)移后自動的切換主節(jié)點。之所以可以做到這一點,是因為在?JedisSentinelPool?的構(gòu)造器中,進行了相關(guān)的工作;主要包括以下兩點:
3)新的主服務(wù)器是怎樣被挑選出來的?
故障轉(zhuǎn)移操作的第一步?要做的就是在已下線主服務(wù)器屬下的所有從服務(wù)器中,挑選出一個狀態(tài)良好、數(shù)據(jù)完整的從服務(wù)器,然后向這個從服務(wù)器發(fā)送?slaveof no one?命令,將這個從服務(wù)器轉(zhuǎn)換為主服務(wù)器。但是這個從服務(wù)器是怎么樣被挑選出來的呢?
簡單來說 Sentinel 使用以下規(guī)則來選擇新的主服務(wù)器:
4.Redis 集群
上圖 展示了?Redis Cluster?典型的架構(gòu)圖,集群中的每一個 Redis 節(jié)點都?互相兩兩相連,客戶端任意直連?到集群中的?任意一臺,就可以對其他 Redis 節(jié)點進行?讀寫?的操作。
1)基本原理
Redis 集群中內(nèi)置了?16384?個哈希槽。當客戶端連接到 Redis 集群之后,會同時得到一份關(guān)于這個?集群的配置信息,當客戶端具體對某一個?key?值進行操作時,會計算出它的一個 Hash 值,然后把結(jié)果對?16384?求余數(shù),這樣每個key?都會對應(yīng)一個編號在?0-16383?之間的哈希槽,Redis 會根據(jù)節(jié)點數(shù)量?大致均等?的將哈希槽映射到不同的節(jié)點。
再結(jié)合集群的配置信息就能夠知道這個?key?值應(yīng)該存儲在哪一個具體的 Redis 節(jié)點中,如果不屬于自己管,那么就會使用一個特殊的?MOVED?命令來進行一個跳轉(zhuǎn),告訴客戶端去連接這個節(jié)點以獲取數(shù)據(jù):
GET x -MOVED 3999 127.0.0.1:6381MOVED?指令第一個參數(shù)?3999?是?key?對應(yīng)的槽位編號,后面是目標節(jié)點地址,?MOVED?命令前面有一個減號,表示這是一個錯誤的消息。客戶端在收到?MOVED?指令后,就立即糾正本地的?槽位映射表,那么下一次再訪問?key?時就能夠到正確的地方去獲取了。
2)集群的主要作用
3)快速體驗
①、第一步:創(chuàng)建集群節(jié)點配置文件
首先我們找一個地方創(chuàng)建一個名為?redis-cluster?的目錄:
mkdir -p ~/Desktop/redis-cluster然后按照上面的方法,創(chuàng)建六個配置文件,分別命名為:redis_7000.conf?/?redis_7001.conf?…?redis_7005.conf,然后根據(jù)不同的端口號修改對應(yīng)的端口值就好了:
# 后臺執(zhí)行 daemonize yes # 端口號 port 7000 # 為每一個集群節(jié)點指定一個 pid_file pidfile ~/Desktop/redis-cluster/redis_7000.pid # 啟動集群模式 cluster-enabled yes # 每一個集群節(jié)點都有一個配置文件,這個文件是不能手動編輯的。確保每一個集群節(jié)點的配置文件不通 cluster-config-file nodes-7000.conf # 集群節(jié)點的超時時間,單位:ms,超時后集群會認為該節(jié)點失敗 cluster-node-timeout 5000 # 最后將 appendonly 改成 yes(AOF 持久化) appendonly yes記得把對應(yīng)上述配置文件中根端口對應(yīng)的配置都修改掉 (port/ pidfile/ cluster-config-file)。
②、第二步:分別啟動 6 個 Redis 實例
redis-server ~/Desktop/redis-cluster/redis_7000.conf redis-server ~/Desktop/redis-cluster/redis_7001.conf redis-server ~/Desktop/redis-cluster/redis_7002.conf redis-server ~/Desktop/redis-cluster/redis_7003.conf redis-server ~/Desktop/redis-cluster/redis_7004.conf redis-server ~/Desktop/redis-cluster/redis_7005.conf然后執(zhí)行?ps -ef | grep redis?查看是否啟動成功:
可以看到?6?個 Redis 節(jié)點都以集群的方式成功啟動了,但是現(xiàn)在每個節(jié)點還處于獨立的狀態(tài),也就是說它們每一個都各自成了一個集群,還沒有互相聯(lián)系起來,我們需要手動地把他們之間建立起聯(lián)系。
③、第三步:建立集群
執(zhí)行下列命令:
redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005- 這里稍微解釋一下這個?--replicas 1?的意思是:我們希望為集群中的每個主節(jié)點創(chuàng)建一個從節(jié)點。
觀察控制臺輸出:
看到?[OK]?的信息之后,就表示集群已經(jīng)搭建成功了,可以看到,這里我們正確地創(chuàng)建了三主三從的集群。
④、第四步:驗證集群
我們先使用?redic-cli?任意連接一個節(jié)點:
redis-cli -c -h 127.0.0.1 -p 7000 127.0.0.1:7000>- -c?表示集群模式;-h?指定 ip 地址;?-p?指定端口。
然后隨便 set 一些值觀察控制臺輸入:
127.0.0.1:7000> SET name wmyskxz -> Redirected to slot [5798] located at 127.0.0.1:7001 OK 127.0.0.1:7001>可以看到這里 Redis 自動幫我們進行了Redirected操作跳轉(zhuǎn)到了7001這個實例上。
我們再使用?cluster info?(查看集群信息) 和?cluster nodes?(查看節(jié)點列表) 來分別看看:(任意節(jié)點輸入均可)
127.0.0.1:7001> 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:2 cluster_stats_messages_ping_sent:1365 cluster_stats_messages_pong_sent:1358 cluster_stats_messages_meet_sent:4 cluster_stats_messages_sent:2727 cluster_stats_messages_ping_received:1357 cluster_stats_messages_pong_received:1369 cluster_stats_messages_meet_received:1 cluster_stats_messages_received:2727 127.0.0.1:7001> CLUSTER NODES 56a04742f36c6e84968cae871cd438935081e86f 127.0.0.1:7003@17003 slave 4ec8c022e9d546c9b51deb9d85f6cf867bf73db6 0 1584428884000 4 connected 4ec8c022e9d546c9b51deb9d85f6cf867bf73db6 127.0.0.1:7000@17000 master - 0 1584428884000 1 connected 0-5460 e2539c4398b8258d3f9ffa714bd778da107cb2cd 127.0.0.1:7005@17005 slave a3406db9ae7144d17eb7df5bffe8b70bb5dd06b8 0 1584428885222 6 connected d31cd1f423ab1e1849cac01ae927e4b6950f55d9 127.0.0.1:7004@17004 slave 236cefaa9cdc295bc60a5bd1aed6a7152d4f384d 0 1584428884209 5 connected 236cefaa9cdc295bc60a5bd1aed6a7152d4f384d 127.0.0.1:7001@17001 myself,master - 0 1584428882000 2 connected 5461-10922 a3406db9ae7144d17eb7df5bffe8b70bb5dd06b8 127.0.0.1:7002@17002 master - 0 1584428884000 3 connected 10923-16383 127.0.0.1:7001>5)數(shù)據(jù)分區(qū)方案簡析
最后
給大家送一個小福利
資料附送高清腦圖,高清知識點講解教程,以及一些面試真題及答案解析。送給需要的提升技術(shù)、準備面試跳槽、自身職業(yè)規(guī)劃迷茫的朋友們。
CodeChina開源項目:【一線大廠Java面試題解析+核心總結(jié)學(xué)習(xí)筆記+最新講解視頻】
7.0.0.1:7002@17002 master - 0 1584428884000 3 connected 10923-16383
127.0.0.1:7001>
總結(jié)
以上是生活随笔為你收集整理的Java中高级核心知识全面解析(3),美团Java面试算法题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java怎么销毁session_【Jav
- 下一篇: Optimus双显卡笔记本上用Media