Redis的分片机制+哨兵机制+集群

1.自定义注解,编辑AOP切面:

1.自定义注解:

/**
 * 该注解主要实现查询操作. 
 * 有缓存查询缓存,没缓存查询数据库
 * 操作规范:
 * 	key: 
 * 		1.用户没有赋值
 * 			如果key为"",表示用户使用自动生成的key
 * 			key:包名.类名.方法名.拼接第一个参数
 * 		2.如果用户赋值
 * 			key:使用用户的数据
 *  seconds:
 *  	如果时间不为0,表示用户需要设定超时时间
 */
@Target({ElementType.METHOD}) //对方法生效
@Retention(RetentionPolicy.RUNTIME)
public @interface Cache_Find {
	String key() default "";
	int  seconds() default 0;
}

2.编辑AOP切面:

//切面 = 切入点 + 通知
@Aspect			//标识切面
@Component		//交给spring容器管理
public class CacheAspect {
	
	@Autowired
	private Jedis jedis;
	/**
	 * 利用AOP规则:动态获取注解对象
	 * 步骤:
	 * 	1.根据key查询redis.
	 *  2.没有数据,需要让目标方法执行.查询的结果保存redis
	 *  3.将json串转化为返回值对象 返回.
	 * @param joinPoint
	 * @param cacheFind
	 * @return
	 */
	@SuppressWarnings("unchecked")//除去警告
	@Around("@annotation(cacheFind)")
	public Object around(ProceedingJoinPoint joinPoint,
			Cache_Find cacheFind) {
		Object data = null;
		
		String key = getKey(joinPoint,cacheFind);
		//1.从redis中获取数据
		String result = jedis.get(key);
		//2.判断缓存中是否有数据
		try {
			if(StringUtils.isEmpty(result)) {
				//2.1缓存中没有数据
				data = joinPoint.proceed();//目标方法执行,就是执行下面的findItemCatCache方法
				//2.2将返回值结果,转化为JSON
				String json = ObjectMapperUtil.toJSON(data);//相互之间的转换在下面
				//2.3判断用户是否编辑时间
				//如果有时间,必须设定超时时间.
				if(cacheFind.seconds()>0) {
					int seconds = cacheFind.seconds();
					jedis.setex(key,seconds, json);//ex是用来设计时间的,超出时间redis会自动清除
				}else {
					jedis.set(key,json);
				}
				
				System.out.println("AOP查询数据库!!!!!");
			}else {
				//表示缓存数据不为空,将缓存数据转化为对象
				Class returnClass = getReturnClass(joinPoint);
				data = ObjectMapperUtil.toObject(result,returnClass);
				System.out.println("AOP查询缓存!!!!");
			}
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		
		return data;
	}
	
	/**
	 * 获取目标方法的返回值类型
	 * @param joinPoint
	 * @return
	 */
	private Class getReturnClass(ProceedingJoinPoint joinPoint) {
		
		MethodSignature signature = 
				(MethodSignature) .getSignature();
		return signature.getRetujoinPointrnType();
	}

	/**
	 * 动态获取key
	 * @param joinPoint
	 * @param cacheFind
	 * @return
	 */
	private String getKey(ProceedingJoinPoint joinPoint, Cache_Find cacheFind) {
		String key = cacheFind.key();
		if(StringUtils.isEmpty(key)) {
			//key自动生成 
			String className = 
					joinPoint.getSignature().getDeclaringTypeName();
			String methodName = 
					joinPoint.getSignature().getName();
			if(joinPoint.getArgs().length>0)
				//拼接第一个参数
				key = className+"."+methodName+"::"
					+ joinPoint.getArgs()[0];
			else 
				key = className+"."+methodName;
		}
		
		return key;
	}
}

----------------------------------------------
@Bean//方法的返回值,交给容器管理
public Jedis jedis() {
	return new Jedis(host,port);
}

对象和json直接的相互转换:

public class ObejctMapperUtil {
	//常量对象,可以调用对象的方法 线程是安全的
	private static final ObjectMapper MAPPER = new ObjectMapper();
	public static String toJSON(Object data) {
		String json = null;
		try {
			json=MAPPER.writeValueAsString(data);
		} catch (JsonProcessingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		return json;
	}
	
	/**
	 * 根据JSON转化成对象
	 * 参数:JSON数据,Class
	 * 返回值由用户决定
	 */
	public static <T> T toObject(String json,Class<T> target) {
		T obj = null;
		try {
			obj = MAPPER.readValue(json, target);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		return obj;
	}
}

3.Redis速度提示:

原始访问数据:
在这里插入图片描述
有redis之后的访问数据
在这里插入图片描述

2. Redis中持久化规则:

说明:redis运行时会根据配置文件中的配置指定持久化方式。都会按照特定的规则定期将内存中的数据保存到持久化文件中。

当redis服务器重启时,首先根据配置文件中指定的持久化文件读取其中的数据,之后恢复到内存中,继续为用户提供服务。

1. RDB模式:

1.1特点:

  • RDB模式是redis中默认的持久化策略
  • RDB模式定期持久化(每个多久持久化一次)
    • 风险:可能会数据丢失
  • RDB模式工作的效率高,RDB模式定期做内存数据的快照,持久化文件较小。数据恢复时间短。
  • RDB模式操作是同步的。

2.持久化命令:

  1. save:阻塞式持久化,当redis持久化操作时,不允许用户更新数据。
  2. bgsave:非阻塞式。在后台单独执行持久化,但是不能准确了解什么时候执行完成,类似于GC。
    在这里插入图片描述
    3.持久化策略:

save 900 1 在900秒内如果执行1次更新操作,持久化一次

save 300 10 在300秒内如果执行10次更新操作,持久化一次

save 60 10000 在60秒内如果执行10000次更新操作,持久化一次

save 1 1 效率很低. 基本实现不丢数据.

4. AOF模式:

​ 特点:

  • AOF模式默认条件下是关闭状态,需要手动开启
  • AOF模式可以实现实时持久化(不丢失数据)
  • AOF模式记录用户的操作过程。持久文件大,回复时间长。
  • AOF模式持久化操作是异步进行。

​ AOF配置:(redis.conf文件)
在这里插入图片描述
​ 持久化策略:
在这里插入图片描述
​ always:只要操作redis,就会持久化

​ everyesc:每秒持久化一次

​ no:持久化操作由当前操作系统决定(时钟),一般不用。

5. RDB模式与AOF模式优先级:

  1. 两种持久化方式可以同时存在。
  2. 如果同时进行,以AOF模式为准,AOF模式优先级高。

3.内存优化策略:

redis运行在内存中,如果redis执行大量的set(添加)操作。最终导致内存溢出,为了保证redis正常运行,必须通过某种机制,实现内存的控制。

1. LRU算法:

​ LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

​ (简单理解:长时间没有用到的将会被淘汰)

2. LFU算法:

​ LFU(least frequently used (LFU) page-replacement algorithm)。即最不经常使用页置换算法,要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。但是有些页在开始时使用次数很多,但以后就不再使用,这类页将会长时间留在内存中,因此可以将引用计数寄存器定时右移一位,形成指数衰减的平均使用次数

​ (简单理解:就是使用的次数)

3.Redis(5.0)内存策略:

  • volatile-lru 将设定超时时间的数据采用lru算法删除
  • allkeys-lru 所有数据采用lru算法删除
  • volatile-lfu 将设定超时时间的数据采用lfu算法删除
  • allkeys-lfu 所有数据采用lfu算法删除
  • volatile-random 将设定超时时间的数据随机删除
  • allkeys-random 所有数据随机删除
  • volatile-ttl 将设定超时时间的数据采用TTL方式排序,将马上要过期的数据删除。
  • noeciction(默认策略) 如果内存溢出们不会删除数据只会报错返回。

4. Redis分片机制:

单台redis内存使用有上限,一般不超过1024 M。但是如果业务有特殊要求,单台redis不能提供内存的支持,redis分片机制,实现内存的扩容。

备注:一下几种机制,都是放在单独的文件夹下面,通过修改对应的conf文件来实现的。

1. redis分片搭建:

1.1准备分片文件的目录:

[root@localhost redis]# mkdir shards

1.2复制配置文件:

[root@localhost redis]# cp redis.conf shards/redis-6379.conf
[root@localhost redis]# cp redis.conf shards/redis-6380.conf
[root@localhost redis]# cp redis.conf shards/redis-6381.conf

1.3修改端口号:分别修改为6380/6381

vim redis.conf shards/redis-6379.conf #修改文件

在这里插入图片描述
1.4启动服务:

redis-server -p 端口号 redis-6379.conf

1.5查看已经启动的服务
在这里插入图片描述
1.6代码演示:

/**
	* 实现redis分片测试  6379/6380/6381
	* 使用的类是ShardedJedis
*/
@Test
public void testShards() {
    String host = "192.168.80.134";
    List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
    shards.add(new JedisShardInfo(host, 6379));
    shards.add(new JedisShardInfo(host, 6380));
    shards.add(new JedisShardInfo(host, 6381));
    ShardedJedis  jedis = new ShardedJedis(shards);
    jedis.set("100", "迅哥升本加油");
    System.out.println(jedis.get("100"));
}

1.7 SpringBoot整合:

@Configuration  //标识配置类
@PropertySource("classpath:/properties/redis.properties")//此处的redis.properties需要自己去编写
public class RedisConfig {
	
	@Value("${redis.nodes}")
	private String nodes;
	
	@Bean
	public ShardedJedis shardedJedis() {
		List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
		String[] arrayNodes = nodes.split(",");
		//node={ip:port}
		for (String node : arrayNodes) {
			String host = node.split(":")[0];
			int port = Integer.parseInt(node.split(":")[1]);
			JedisShardInfo info = new JedisShardInfo(host, port);
			shards.add(info);
		}
		return new ShardedJedis(shards);
	}
}	

1.8修改AOP的引用:

//切面 = 切入点 + 通知
@Aspect			//标识切面
@Component		//交给spring容器管理
public class CacheAspect {
	@Autowired(required = false)
	private ShardedJedis jedis;
    //(此处代码同上,就是类型更改了)
    
    
--------------------------------
@Bean
public ShardedJedis shardedJedis() {
    List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
    String[] arrayNodes = nodes.split(",");
    for (String node : arrayNodes) {
        String host = node.split(":")[0];
        int port = Integer.parseInt(node.split(":")[1]);
        JedisShardInfo info = new JedisShardInfo(host, port);
        shards.add(info);
    }
    return new ShardedJedis(shards);
}

2.小结:

  • Redis分片效率是最高的
  • Redis分片主要目的实现内存扩展
  • Redis分片没有实现高可用技术,如果一天Redis宕机。则整个分片不能正常运行。

5. 哨兵机制

原理:

  • 哨兵主要根据IP地址和端口监听主机Master,并且记录当前主机全部的丛机的信息。
  • 哨兵利用PING-PONG机制检查是否存活,如果联系3次主机没有反应,表示主机宕机,。之后由哨兵开始选举
  • 哨兵根据内部的推选,选举新的主机,之后修改其他redis的配置文件,实现新的主从关系。(主要是为了防止出现多主的现象)

1.哨兵主从搭建:

​ 把上面的分片机制的文件,复制到新的文件夹之后,为哨兵机制
在这里插入图片描述
1.2主从挂载:

执行下面的命令,是将6380端口的挂载到6379下面。

slaveof 192.168.80.134:6379

1.3编辑哨兵配置文件:

1.关闭保护模式:
在这里插入图片描述2.开启后台启动
在这里插入图片描述
3.修改哨兵监控

sentinel monitor mymaster 127.0.0.1 6379 1

mymaster: 代表当前主机的变量名称

IP:端口: 当前主机信息

总的台数一般都是设置成奇数。
在这里插入图片描述
4.修改推选时间:
在这里插入图片描述
5.修改哨兵推选失效时间:
在这里插入图片描述
1.4测试:

@Test
public void testSentinel() {
    Set<String> sentinels = new HashSet<>();
    sentinels.add("192.168.80.1348:26379");
    JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels);
    Jedis jedis = pool.getResource();
    jedis.set("测试", "哨兵搭建完成!!!!!");
    System.out.println(jedis.get("测试"));
}

1.5SpringBoot整合:

@Bean
public JedisSentinelPool jedisSentinelPool() {
    Set<String> sentinels = new HashSet<>();
    sentinels.add(nodes);
    return new JedisSentinelPool("mymaster", sentinels);
}

-----------------------------
@Bean//实例化对象是如果方法中添加了参数,首先会先到Spring容器中查找该参数,如果有则直接注入
@Scope("prototype")	//多例对象  用户使用时创建
public Jedis jedis(JedisSentinelPool pool) {
    return pool.getResource();
}

1.6小结:

  • Redis哨兵主要实现了Redis高可用机制,自动的实现故障迁移。
  • Redis哨兵没有实现内容扩容。
  • Redis没有实现高可用。

6.Redis集群:

1.Redis集群的准备:

1.准备文件夹:

Mkdir cluster
#并创建文件夹
mkdir 7000 7001 7002 7003 7004 7005

2复制文件:

将redis根目录下的redis.cong文件复制到cluster/7000,并保存

3.编辑配置文件。

1)注释本地绑定的IP地址:
在这里插入图片描述
2)关闭保护模式:
在这里插入图片描述
3)修改端口号:
在这里插入图片描述
4)启动后台启动:
在这里插入图片描述
5)修改pid文件:
在这里插入图片描述6)修改持久化文件路径:
在这里插入图片描述
7)设定内存优化策略:
在这里插入图片描述
8)关闭AOF模式:
在这里插入图片描述
9)开启集群配置:
在这里插入图片描述10)开启集群配置文件:
在这里插入图片描述
11)修改集群超时时间:
在这里插入图片描述
4.将修改好的文件,复制到不同的文件夹下,然后批量修改。

:%s/7000/7001/g

5.可用通过脚本开启或者关闭
在这里插入图片描述

​ 6.创建集群:

#5.0版本执行 使用C语言内部管理集群
redis-cli --cluster create --cluster-replicas 1 192.168.80.134:7000 192.168.80.134:7001 192.168.80.134:7002 192.168.80.134:7003 192.168.80.134:7004 192.168.80.134:7005

在这里插入图片描述
在这里插入图片描述
2.测试:

@Test
public void testCluster() {
    String host = "192.168.80.134";
    Set<HostAndPort> nodes = new HashSet<>();
    nodes.add(new HostAndPort(host,7000));
    nodes.add(new HostAndPort(host,7001));
    nodes.add(new HostAndPort(host,7002));
    nodes.add(new HostAndPort(host,7003));
    nodes.add(new HostAndPort(host,7004));
    nodes.add(new HostAndPort(host,7005));
    JedisCluster jedisCluster = new JedisCluster(nodes);
    jedisCluster.set("测试", "你好redis集群");
    System.out.println(jedisCluster.get("测试"));
}

3.整合SpringBoot:

@Configuration  //标识配置类
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {
	
	@Value("${redis.nodes}")
	private String nodes; 
	
	@Bean
	public JedisCluster jedisCluster() {
		Set<HostAndPort> setNodes = new HashSet<>(); 
		String[] arrayNode = nodes.split(",");
		//node{IP:PORT}
		for (String node : arrayNode) {
			String host = node.split(":")[0];
			int port = Integer.parseInt(node.split(":")[1]);
			setNodes.add(new HostAndPort(host, port));
		}
		return new JedisCluster(setNodes);
	}
	
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值