億級流量架構|day11-Redis高級

1.Spring整合哨兵

1.1 入門案例

/jt-manage/src/test/java/com/jt/redis/TestSentinel.java

public class TestSentinel {

	@Test
	public void testSentinel(){
		//IP:端口
		Set<String>   sentinels = new HashSet<>();
		sentinels.add("192.168.126.166:26379");
		JedisSentinelPool pool = 
				new JedisSentinelPool("mymaster", sentinels);
		//new JedisSentinelPool(masterName, sentinels, poolConfig)
		Jedis jedis = pool.getResource();
		jedis.set("shaobing","哨兵測試");
		System.out.println("獲取數據:"+jedis.get("shaobing"));
		pool.returnResource(jedis);
	}
}

1.2 編輯pro文件

/jt-manage/src/main/resources/property/redis.properties

redis.maxTotal=1000
redis.sentinel=192.168.126.166:26379
redis.mastername=mymaster

1.3編輯配置文件

/jt-manage/src/main/resources/spring/applicationContext-redis.xml

<bean id="sentinelPool" class="redis.clients.jedis.JedisSentinelPool">
	<constructor-arg name="masterName" value="${redis.mastername}"/>
	<constructor-arg name="sentinels">
		<set>
			<value>${redis.sentinel}</value>
		</set>
	</constructor-arg>
	<constructor-arg name="poolConfig" ref="poolConfig"/>
</bean>

<!--定義池對象  -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
	<property name="maxTotal" value="${redis.maxTotal}"/>
</bean>

1.4 定義工具類

/jt-common/src/main/java/com/jt/common/service/RedisService.java

@Service
public class RedisService {
	
	//引入哨兵的配置
	@Autowired(required=false)
	private JedisSentinelPool sentinelPool;
	
	public void set(String key,String value){
		Jedis jedis = sentinelPool.getResource();
		jedis.set(key, value);
		sentinelPool.returnResource(jedis);
	}
	
	public void set(String key,String value,int seconds){
		Jedis jedis = sentinelPool.getResource();
		jedis.setex(key, seconds, value);
		sentinelPool.returnResource(jedis);
	}
	
	public String get(String key){
		Jedis jedis = sentinelPool.getResource();
		String result = jedis.get(key);
		sentinelPool.returnResource(jedis);
		return result;
	}
}

2.Redis集羣

2.1 問題說明

1.分片作用

  • 動態實現內存擴充
  • 將數據分散保存

2.哨兵作用

  • 實現redis高可用(ha)

2.2 Redis集羣實現

說明:採用redis集羣配置,在集羣內部實現通信和選舉,同時實現分片的擴容和高可用。

2.3 腦裂

說明:因爲選舉機制投票平票而導致出現多臺主機的現象稱之爲腦裂。

解決方案:讓節點個數增加(保證超過半數即可)。

3.集羣搭建步驟

3.1 劃分集羣規模

規模:3主6從
端口:7000-7008共9臺

3.2 搭建步驟

1.複製redis.conf文件

切換到redis根目錄

cd /usr/local/src/redis-3.2.8/

創建cluster/7000文件夾

mkdir -p cluster/7000

複製redis.conf到7000目錄下

cp redis.conf cluster/7000

2.關閉aof,使用rdb模式

打開復製出來的redis.conf文件

cd cluster
vim 7000/redis.conf

關閉aof,此時rdb模式生效 第593行
在這裏插入圖片描述

3.取消ip綁定
在這裏插入圖片描述

4.關閉保護模式
在這裏插入圖片描述

5.修改端口號
在這裏插入圖片描述

6.開啓後臺啓動
在這裏插入圖片描述

7.修改pid位置 150行
在這裏插入圖片描述

8.修改持久化文件路徑
在這裏插入圖片描述

9.修改內存策略
在這裏插入圖片描述

10.開啓集羣
在這裏插入圖片描述

11.開啓集羣配置
在這裏插入圖片描述

12.修改集羣推選時間
在這裏插入圖片描述

修改完成退出vim

3.3 複製出7001~7008文件夾

使用 cp -r 7000 700x 命令複製出剩餘的8個文件夾

[root@localhost cluster]# cp -r 7000 7002
[root@localhost cluster]# cp -r 7000 7003
[root@localhost cluster]# cp -r 7000 7004
[root@localhost cluster]# cp -r 7000 7005
[root@localhost cluster]# cp -r 7000 7006
[root@localhost cluster]# cp -r 7000 7007
[root@localhost cluster]# cp -r 7000 7008

3.4 修改多個文件端口

打開redis.conf文件

vim 7001/redis.conf

在vim中,使用替換命令,將配置文件中多處7000修改爲指定端口

:%s/7000/7001/g

重複上面的操作,依次完成7002到7008的端口修改

3.5 編輯redis批量啓動腳本

使用vim新建start.sh腳本

vim start.sh

編輯start.sh內容,並保存
在這裏插入圖片描述

啓動 start.sh

./start.sh

3.6 通過ruby創建redis集羣

說明:使用ruby管理集羣
在這裏插入圖片描述

在這裏插入圖片描述

創建redis集羣,在redis根目錄下運行

./src/redis-trib.rb create --replicas 2 192.168.126.166:7000 192.168.126.166:7001 192.168.126.166:7002 192.168.126.166:7003 192.168.126.166:7004 192.168.126.166:7005 192.168.126.166:7006 192.168.126.166:7007 192.168.126.166:7008

集羣劃分
在這裏插入圖片描述

輸入yes
在這裏插入圖片描述

在這裏插入圖片描述

3.7 集羣測試

說明:將redis主機關閉後,檢測高可用是否能實現,並且當主機重啓後,能否實現自動掛載。
在這裏插入圖片描述

3.8 集羣崩潰條件

最少需要宕機超過一半的機器,才能導致集羣崩潰。
在這裏插入圖片描述

4.Spring中工廠模式

4.1 工廠模式作用

核心思想:實例化對象

需求:
1.多例對象的創建。
2。有些對象,例如接口/抽象類等不能直接實例化,接口需要通過代理創建實例,抽象類需要子類創建實例。
3.需要對對象進行二次封裝。

4.2 靜態工廠

說明:靜態工廠中必須要有靜態方法。

調用方式:類名.靜態方法名

Spring配置方式:
/jt-manage/src/main/resources/spring/factory.xml

<!--配置靜態工廠  -->
<bean id="calendarA" class="com.jt.manage.factory.StaticFactory" factory-method="getInstance"/>

工廠模式編輯:

/jt-manage/src/main/java/com/jt/manage/factory/StaticFactory.java

public class StaticFactory {
	
	public static Calendar getInstance(){
		
		return Calendar.getInstance();
	}
}

4.3 實例工廠

說明:實例工廠要求必須先創建工廠對象,然後通過工廠方法調用獲取對象。

配置文件:

/jt-manage/src/main/resources/spring/factory.xml

<!--實例化工廠  -->
<bean id="instanceFactory" class="com.jt.manage.factory.InstanceFactory"/>
<bean id="calendarB" factory-bean="instanceFactory" factory-method="getInstance"/>

工廠定義:

/jt-manage/src/main/java/com/jt/manage/factory/InstanceFactory.java

public class InstanceFactory {
	
	public Calendar getInstance(){
		
		return Calendar.getInstance();
	}
}

4.4 Spring工廠

說明:該模式由Spring內部調用,不需要做多餘的配置,但是需要實現特定的接口FactoryBean

/jt-manage/src/main/java/com/jt/manage/factory/SpringFactory.java

public class SpringFactory implements FactoryBean<Calendar>{

	@Override
	public Calendar getObject() throws Exception {
		
		return Calendar.getInstance();
	}

	@Override
	public Class<?> getObjectType() {
		
		return Calendar.class;
	}

	@Override
	public boolean isSingleton() {
		
		return false;
	}
}

配置文件定義:

/jt-manage/src/main/resources/spring/factory.xml

<!--配置spring工廠  -->
<bean id="calendarC" class="com.jt.manage.factory.SpringFactory"/>

工具類測試:

/jt-manage/src/test/java/com/jt/factory/TestFactory.java

@Test
public void testFactory(){
	//1.實例化Spring容器
	ApplicationContext context = 
			new ClassPathXmlApplicationContext("spring/factory.xml");
	Calendar calendarA = (Calendar) context.getBean("calendarA");
	System.out.println(calendarA.getTime());
	
	Calendar calendarB = (Calendar) context.getBean("calendarB");
	System.out.println(calendarB.getTime());
	
	Calendar calendarC = (Calendar) context.getBean("calendarB");
	System.out.println(calendarC.getTime());
}

5.Spring整合集羣

5.1 入門案例

@Test
public void testCluster(){
	Set<HostAndPort> nodes = new HashSet<>();
	nodes.add(new HostAndPort("192.168.126.166",7000));
	nodes.add(new HostAndPort("192.168.126.166",7001));
	nodes.add(new HostAndPort("192.168.126.166",7002));
	nodes.add(new HostAndPort("192.168.126.166",7003));
	nodes.add(new HostAndPort("192.168.126.166",7004));
	nodes.add(new HostAndPort("192.168.126.166",7005));
	nodes.add(new HostAndPort("192.168.126.166",7006));
	nodes.add(new HostAndPort("192.168.126.166",7007));
	nodes.add(new HostAndPort("192.168.126.166",7008));
	JedisCluster jedisCluster = new JedisCluster(nodes);
	jedisCluster.set("aa", "小提莫哪裏逃");
	System.out.println(jedisCluster.get("aa"));
}

5.2 編輯pro配置文件

/jt-manage/src/main/resources/property/redis.properties

#最小空閒數
redis.minIdle=100
#最大空閒數
redis.maxIdle=300
#最大連接數
redis.maxTotal=1000
#客戶端超時時間單位是毫秒 
redis.timeout=5000
#最大建立連接等待時間  
redis.maxWait=1000
#是否在從池中取出連接前進行檢驗,如果檢驗失敗,則從池中去除連接並嘗試取出另一個
redis.testOnBorrow=true

#redis cluster
redis.cluster0=192.168.126.166:7000
redis.cluster1=192.168.126.166:7001
redis.cluster2=192.168.126.166:7002
redis.cluster3=192.168.126.166:7003
redis.cluster4=192.168.126.166:7004
redis.cluster5=192.168.126.166:7005
redis.cluster6=192.168.126.166:7006
redis.cluster7=192.168.126.166:7007
redis.cluster8=192.168.126.166:7008

5.3 修改Spring配置文件

/jt-manage/src/main/resources/spring/applicationContext-redis.xml

<!-- jedis 配置-->  
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >  
    <!--最大空閒數-->  
    <property name="maxIdle" value="${redis.maxIdle}" />  
    <!--最大建立連接等待時間-->  
    <property name="maxWaitMillis" value="${redis.maxWait}" />  
    <!--是否在從池中取出連接前進行檢驗,如果檢驗失敗,則從池中去除連接並嘗試取出另一個-->  
    <property name="testOnBorrow" value="${redis.testOnBorrow}" />  
    <property name="maxTotal" value="${redis.maxTotal}" />  
    <property name="minIdle" value="${redis.minIdle}" />  
</bean>

 <!--通過工廠模式獲取數據  -->
<bean id="jedisCluster" class="com.jt.common.factory.JedisClusterFactory">
	<!--引入配置文件源文件  -->
	<property name="propertySource">
		<value>classpath:/property/redis.properties</value>
	</property>
	<!--引入池配置文件  -->
	<property name="poolConfig" ref="poolConfig"/>
	<!--添加配置前綴-->
	<property name="redisNodePrefix" value="redis.cluster"/>
</bean>

5.4 編輯工廠模式

/jt-common/src/main/java/com/jt/common/factory/JedisClusterFactory.java

public class JedisClusterFactory implements FactoryBean<JedisCluster>{
	
	//引入pro配置文件
	private Resource propertySource;
	private JedisPoolConfig poolConfig;
	private String redisNodePrefix;
	
	//獲取Set集合信息
	public Set<HostAndPort> getNodes(){
		Set<HostAndPort> nodes = new HashSet<>();
		
		//操作pro對象
		Properties pro = new Properties();
		try {
			pro.load(propertySource.getInputStream());
			
			//遍歷獲取nodes節點數據
			for (Object key : pro.keySet()) {
				//將key變爲String類型 目的判斷字符串方便
				String strKey = (String) key;
				
				//判斷哪個是redis節點數據
				if(strKey.startsWith(redisNodePrefix)){
					//IP:端口
					String value = pro.getProperty(strKey);
					String[] args = value.split(":");
					HostAndPort hostAndPort = 
					new HostAndPort(args[0],Integer.parseInt(args[1]));
					nodes.add(hostAndPort);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return nodes;
	}
	
	@Override
	public JedisCluster getObject() throws Exception {
		
		Set<HostAndPort> nodes = getNodes();
		
		return new JedisCluster(nodes, poolConfig);
	}

	@Override
	public Class<?> getObjectType() {
		
		return JedisCluster.class;
	}

	@Override
	public boolean isSingleton() {
		
		return false;
	}

	public Resource getPropertySource() {
		return propertySource;
	}

	public void setPropertySource(Resource propertySource) {
		this.propertySource = propertySource;
	}

	public JedisPoolConfig getPoolConfig() {
		return poolConfig;
	}

	public void setPoolConfig(JedisPoolConfig poolConfig) {
		this.poolConfig = poolConfig;
	}

	public String getRedisNodePrefix() {
		return redisNodePrefix;
	}

	public void setRedisNodePrefix(String redisNodePrefix) {
		this.redisNodePrefix = redisNodePrefix;
	}	
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章