1. 程式人生 > >複習電商筆記-31-redis哨兵

複習電商筆記-31-redis哨兵

 

商品類目新增快取

1)將結果資料儲存到redis中,注意key的定義,不要太長,不要相同。將java物件序列化成json字串,同時可設定生存時間。

2)檢測快取中是否存在,如果存在就返回。不存在就直接去資料庫進行查詢。(如果有異常,要捕獲處理,不能影響正常業務邏輯)

 

 

修改ItemCatService.java檔案

package com.jt.manage.service;

import java.io.IOException;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jt.common.service.RedisService;
import com.jt.manage.mapper.ItemCatMapper;
import com.jt.manage.pojo.ItemCat;

@Service
public class ItemCatService extends BaseService<ItemCat>{
	@Autowired
	private ItemCatMapper itemCatMapper;
	@Autowired
	private RedisService redisService;
	//引入java物件和json串轉換物件ObjectMapper;全域性唯一
	private static final ObjectMapper MAPPER = new ObjectMapper();
	
	public List<ItemCat> queryByPid(Integer id) throws IOException{
		/*
		 * 商品分類要使用快取步驟:
		 * 1)先判斷快取中是否有資料,如果有資料就讀取,直接返回
		 * 2)如果快取中沒有資料,要繼續執行業務,不能丟擲異常
		 * 3)執行完業務,要多一步動作,要把結果放入快取中string,先把java物件轉換成json串,kv寫入快取中。
		 */
		
	MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		String ITEM_CAT_KEY = "ITEM_CAT_" + id;	//唯一性
		
		//從redis中獲取資料
		String jsonItemCat = redisService.get(ITEM_CAT_KEY);
		if(StringUtils.isNotEmpty(jsonItemCat)){
			JsonNode jsonNode = MAPPER.readTree(jsonItemCat);	//把json串轉換JsonNode
			//利用jackson提供方法,將json串轉成java物件,List<Object>
			List<ItemCat> itemCatList = MAPPER.readValue(jsonNode.traverse(),
                    MAPPER.getTypeFactory().constructCollectionType(List.class, ItemCat.class));
			return itemCatList;
		}else{
			//繼續執行業務,一般都是去資料庫訪問
			List<ItemCat> itemCatList = itemCatMapper.queryByPid(id);
			
			//寫redis,kv(string,string)
			jsonItemCat = MAPPER.writeValueAsString(itemCatList);	//將java物件轉成json串
			redisService.set(ITEM_CAT_KEY, jsonItemCat);
			return itemCatList;
		}
	}

}

 

Redis主從複製

 

 

主從複製

cp redis.conf redis-master.conf		#主節點配置
redis-server redis-master.conf		#啟動主

cp redis.conf redis-slave01.conf		#從1配置,修改埠 6380
redis-server redis-slave01.conf		#啟動從1
redis-cli –p 6380						#登入從1
slaveof 127.0.0.1 6379				#掛接到主

cp redis.conf redis-slave02.conf		#從2配置,修改埠6381
redis-server redis-slave02.conf		#啟動從2
redis-cli –p 6381						#登入從2
slaveof 127.0.0.1 6379				#掛接到主

檢查配置

info					#檢視所有資訊
info Replication		#只檢視Replication片段資訊

檢視結果,確認狀態

127.0.0.1:6379> info Replication
# Replication
role:master			#說明master生效
connected_slaves:2		#master主節點下有兩個從節點
slave0:ip=127.0.0.1,port=6380,state=online,offset=845,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=845,lag=1
master_repl_offset:845
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:844
127.0.0.1:6379>

測試

127.0.0.1:6379>set name tony
127.0.0.1:6380>get name			#讀取到同步的資訊
127.0.0.1:6381>get name
127.0.0.1:6381>set name hellen	#報錯,從上不允許設定資料
(error) READONLY You can't write against a read only slave.

 

Redis哨兵實現HA高可用

哨兵實現實時冗餘備份和容災,但不支援分片。

 

 

哨兵sentinel

Redis Sentinel(哨兵)是一個分散式系統,你可以在一個架構中執行多個 Sentinel 程序(progress), 這些程序使用流言協議(gossip protocols)來接收關於主伺服器是否下線的資訊,並使用投票協議(agreement protocols)來決定是否執行自動故障遷移,以及選擇哪個從伺服器作為新的主伺服器。

Sentinel系統用於管理多個Redis伺服器(instance),該系統執行以下三個任務:

  1. 監控(Monitoring): Sentinel 會不斷地檢查你的主伺服器和從伺服器是否運作正常。
  2. 提醒(Notification): 當被監控的某個 Redis 伺服器出現問題時,Sentinel 可以通過 API 向管理員或者其他應用程式傳送通知。
  3. 自動故障遷移(Automatic failover):當一個主伺服器不能正常工作時, Sentinel 會開始一次自動故障遷移操作,它會將失效主伺服器的其中一個從伺服器升級為新的主伺服器,並讓失效主伺服器的其他從伺服器改為複製新的主伺服器; 當客戶端試圖連線失效的主伺服器時,叢集也會向客戶端返回新主伺服器的地址, 使得叢集可以使用新主伺服器代替失效伺服器。

 

 

哨兵的工作原理

 sentinel以每10秒一次的頻率向master傳送info命令,通過info的回覆來分析master資訊,master的回覆主要包含了兩部分資訊,一部分是master自身的資訊,一部分是master所有的slave(從)的資訊,所以sentinel可以自動發現master的從服務。sentinel從master獲取到的master自身資訊以及master所有的從資訊,將會更新到sentinel的sentinelState中及masters(sentinelRedisInstance結構)中的slaves字典中。

 

 

哨兵sentinel-實現高可用

哨兵sentinel類似zookeeper。它含有監控,監控每個節點的活躍狀態。

上面配置了3個節點,但如果主宕機,整個快取系統就癱瘓,如何實現主宕機,自動從多個從中選舉出一個節點當主呢?redis在3.0版本之後提供了哨兵sentinel。通過哨兵實現高可用。

但一個哨兵也可能宕機,一次啟動兩個哨兵,自身也實現高可用。

cp sentinel.conf sentinel2.conf			#複製哨兵
26379為26380								#修改埠
sentinel monitor mymaster 192.168.163.20 6379 1		#設定訪問名稱
											#最後的數值為選舉時過票數量(坑)
redis-sentinel sentinel.conf				#啟動哨兵
redis-sentinel sentinel2.conf				#啟動哨兵2,形成哨兵的高可用

ps –ef|grep redis    #檢視程序

6010  5709  0 00:38 pts/2    00:00:13 redis-server 127.0.0.1:6379

6012  5710  0 00:38 pts/2    00:00:13 redis-server 127.0.0.1:6380

6014  5721  0 00:38 pts/3    00:00:13 redis-server 127.0.0.1:6381

6018  5927  1 00:39 pts/6    00:00:21 redis-server *:26379 [sentinel]     

6047  6037  1 00:41 pts/7    00:00:19 redis-server *:26380 [sentinel]      

6241  2512  0 01:10 pts/1    00:00:00 grep redis

測試

kill 6010     #可以看到slave的兩個節點開始報連結拒絕錯誤,不一會哨兵將6380切換為主

info          #在6380上info命令,可以看到其role:master

kill 6018     #刪除一個哨兵,在6380上set資料,6381自動同步

 

 

sentinel的坑

 

 

 

 

開放埠或者關閉防火牆

6379,6380,6381

26379,26380

service iptables stop

 

 

 

 

protected-mode

預設情況下,Redis node和sentinel的protected-mode都是yes,在搭建叢集時,若想從遠端連線redis叢集,需要將redis node和sentinel的protected-mode修改為no,若只修改redis node,從遠端連線sentinel後,依然是無法正常使用的,且sentinel的配置檔案中沒有protected-mode配置項,需要手工新增。

 

 

 

 

遠端訪問拒絕

sentinel.conf預設配置

sentinel monitor mymaster 127.0.0.1 6380 1

當redis和sentinel在一臺伺服器上時,必須指定實際的IP地址

sentinel monitor mymaster 192.168.163.30 6380 1

 

 

 

選舉數

sentinel.conf中96行左右的位置

sentinel monitor mymaster 127.0.0.1 6379 2

最後的2代表選舉的個數,這個值非常關鍵。其中的2表示只有在兩個sential程序發現master不可用時才執行failover故障轉移。例如:即使一個master宕機,如果投票個數未超過1個,redis不會觸發failover,不會觸發選舉,而是一直等待master恢復,當master恢復,一切又工作正常。只有當投票數大於等於1時,才認為master才會觸發選舉,自動從眾多的slave中選擇一個節點升級為master,其他自動從節點自動連線次節點。同時會自動修改sentinel.conf檔案

sentinel monitor mymaster 192.168.163.30 6380 1

預設30秒進行切換

 

 

修改從節點的選舉優先順序

redis.conf

slave-priority 100	

這樣當Master掛掉的時候Sentinel會優先選擇slave-priority值較小的作為新的Master。

 

 

sentinel.conf配置詳解

配置語句

說明

daemonize yes

以後臺程序模式執行

port 26379

哨兵的埠號,該埠號預設為26379,不得與任何redis node的埠號重複

logfile " /var/log/redis/sentinel.log "

log檔案所在地

sentinel monitor master1 192.168.163.30 6379 1

(第一次配置時)哨兵對哪個master進行監測,此處的master1為一“別名”可以任意,將來程式訪問時使用,如sentinel-26379。然後哨兵會通過這個別名後的IP知道整個該master內的slave關係。因此你不用在此配置slave是什麼而由哨兵自己去維護這個“連結串列”。

sentinel monitor master1 192.168.163.30 6379 1

最後一個1代表當節點宕機時的觸發選舉的判斷條件,1就代表sentinel認定宕機的個數,必須大於這個個數,選舉才開始發生,預設值為2,很坑。

sentinel down-after-milliseconds master1 1000

如果master在多少秒內無反應哨兵會開始進行master-slave間的切換,使用“選舉”機制

sentinel failover-timeout master1 5000

如果在多少秒內沒有把宕掉的那臺master恢復,那哨兵認為這是一次真正的宕機,而排除該宕掉的master作為節點選取時可用的node然後等待一定的設定值的毫秒數後再來探測該節點是否恢復,如果恢復就把它作為一臺slave加入哨兵監測節點群並在下一次切換時為他分配一個“選取號”。

 

 

 

安全訪問

redis.conf

masterauth "123456"

requirepass "123456"

sentinel.conf

sentinel auth-pass mymaster 123456

否則在每個的redis-cli中執行語句:

CONFIG SET protected-mode no

jedis訪問時

jedis.auth("123456");

 

 

jedis訪問sentinel

@Test
	public void sentinel(){
    	Set<String> sentinels = new HashSet<String>();
    	sentinels.add(new HostAndPort("192.168.163.30",26379).toString());
    	//sentinels.add(new HostAndPort("192.168.163.30",26380).toString());
    	
    	//mymaster是在sentinel.conf中配置的名稱
    	//sentinel monitor mymaster 192.168.163.30 6380 1
    	JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels);
    	System.out.println("當前master:" + pool.getCurrentHostMaster());
    	
    	Jedis jedis = pool.getResource();
		//jedis.auth("123456");

    	System.out.println(jedis.get("num"));
    	pool.returnResource(jedis);   
    	
    	pool.destroy();
    	System.out.println("ok");
	}