Day10:Redis高级

本文详细介绍了Redis的持久化策略,包括RDB和AOF模式,以及AOF模式下开启后的持久化策略。此外,探讨了Redis内存管理和缓存问题,如缓存穿透、击穿和雪崩。接着,讲解了Redis分片技术,以解决单台Redis内存限制,实现动态扩容。最后,讨论了Spring整合Redis分片的方法,以及Redis哨兵系统的原理和配置,以确保高可用性。
摘要由CSDN通过智能技术生成

在这里插入图片描述
在这里插入图片描述

第一部分

一、redis持久化策略

说明:

  • redis作为内存数据库需要保持大量的用户的数据,但是redis中的数据保存到内存中断电,宕机,会导致内存数据丢失,所以为了防止数据丢失采用持久化方式,实现内存数据的备份。

策略:

  • 当redis种内存有数据时,通过自身的策略有2种方式,一种RDB模式/AOF模式。根据各自模式的设定进行数据的持久化。RDB或者AOF都有各自的持久化文件。
  • 当redis重启时,会根据配置文件中制定的持久化文件的名称,加载持久化文件,为了恢复内存数据。

RDB模式:

  • 特点:RDB模式定期将内存中的数据持久化,如果用户允许丢失少量的数据,首选RDB模式。RDB模式定期为内存做快照,该方式的备份速度很快,

备份命令
dump.rdb–>查看加密

  • 说明:执行redis备份命令需要在客户端中执行

    命令:save 手动备份
    命令:bgsave 后台备份

  • 区别:save 会造成线程阻塞,只有当备份操作完成时,才允许直行redis更新操作
    bgsave表示后台运行,不会造成线程阻塞,挑当前不忙的实践做数据备份。

  • 备份方式: 看配合文件 redis.conf

配置文件说明
在这里插入图片描述
在900秒内redis做一个更新操作 备份一次
在300秒内redis做10次更新操作 备份一次
在60秒内,如果redis做一万次更新 备份一次
在这里插入图片描述
持久化文件名称及路径:
在这里插入图片描述

AOF模式:

说明:
AOF可以做到实时数据备份,该模式相当于通过配置文件记录了用户的全部操作过程
特点:
1、可以实时数据备份,安全性更好
2、持久化速度较RDB模式慢
3、AOF持久化文件的体积会很大
4、当数据恢复时,需要消耗很长的时间

RDB快(允许丢数据,快照形式保存,数据恢复快),AOF慢 (数据实时备份,安全性好,持久化文件体积大,数据恢复需要很长时间)

AOF模式持久化策略

1、开启AOF模式

开启AOF以后,RDB模式不生效

在这里插入图片描述
在这里插入图片描述
2、持久化策略
在这里插入图片描述

Redis内存策略:

**说明:**为了保证服务器正常运行,需要为redis设定最大内存空间,但是如果内存一直新增,内存很快就会占满,如果优化内存???

解决方案:采用LRU算法

可以将内存中最近最不常使用的数据清空,保存其他的数据

内存优化手段

1、设定内存空间 建议内存不要超过1G 256-512M 537行
在这里插入图片描述
2、内存策略
在这里插入图片描述
3、策略设定
在这里插入图片描述

※ 缓存使用的问题:

缓存穿透:
条件:访问一个不存在的数据
说明:当访问一个不存在的数据,因为缓存中没有这个key,导致缓存形同虚设,最终访问后台数据库,但是数据中没有该数据所以返回null
隐患:如果有人恶意频繁访问一个不存在的数据,可能会导致数据库服务负载高导致宕机。
总结业务系统访问一个不存在的数据,称之为缓存穿透
防护限定同一IP访问频率 【京东】

缓存击穿:
条件:当缓存key失效/过期/未命中时,高并发访问该key
说明如果给一个key设定了失效时间,当key失效时有一万的并发请求访问这个key,这时缓存失效,所有的请求都会访问后台数据库,称之为缓存击穿。
场景:【微博】热点消息访问量很大,如果该缓存失效则会直接访问后台数据库,导致数据库负载过高

缓存雪崩:
前提:高并发访问,缓存命中较低或者失效时
说明假设缓存都设定了失效时间,在同一时间内缓存大量失效。如果这时用户高并发访问,缓存命中率过低,导致全部的用户访问都会访问后台真实的数据库
场景:在高并发条件下,缓存动态更新时【flushall】

二、Redis分片技术

1、如果将全部数据都保存到一台redis中,如果该服务器损坏,则影响全部的服务
2、使用单台Redis内存设定一般不要超过1G,但是有些业务数据量很大,如果不修改内存则数据无法存储

改进方案:采用Redis分片技术实现
优点:
1、使用redis分片技术可以实现内存数据的动态扩容
2、使用分片每台redis节点中尽可能保存1/n的数据量,防止数据的丢失
3、对于用户而言,整个redis的分片就是一个服务

分片搭建:

1、复制配置文件:将redis.conf文件复制到shards中,启动几个就复制几个,63
79、6380、6381

在这里插入图片描述
2、修改端口号
说明:分别修改6380和6381的配置文件中的端口号

在这里插入图片描述
在这里插入图片描述
3、分别启动,查看redis
在这里插入图片描述
4、测试分片

在这里插入图片描述

在这里插入图片描述
pool.getResource()的类型是ShardedJedis

Hash一致性算法

数据如何保存?
2的32次方
node:IP地址+算法
顺时针寻找
==》
1、将节点的IP+算法确定唯一的哈希值,之后在内存中确定节点的位置
2、当保存数据时,根据key进行hash运算,确定唯一的一个位置【不保证绝对唯一】。
3、根据当前key位置顺时针查找最近的node节点进行挂载。

均衡性

说明:根据redis几点的个数要求尽可能的让数据均匀分片,每个节点中的数据尽可能保证1/n
提升:为了保证均衡性,hash一致性算法引入虚拟节点的概念,为了平衡数据。如果一个节点不够则声称多个节点。

单调性

说明:如果node节点新增,能够动态实现数据的迁移【原本属于nodeC的空间,分给了虚拟NodeB】不需要关心原先存储在C上但是分给虚拟NodeB上的数据,他们仍保存在原有位置,只不过所属位置区域的名称发生了改变

分散性

特点:由于分布式原因,导致用户使用内存时,不能获取全部的内存空间,导致一个key对应多个位置

在这里插入图片描述

负载

说明:从另一个角度考虑分散性
特点:一个位置对应多个key
在这里插入图片描述

如何解决分散性和负载的问题?

在进行架构设计时,要求使用全部的内存空间。

第二部分:Spring整合分片

分片:动态内存扩容,减少内存丢失。

一、编辑Properties文件

redis.host=192.168.126.166
redis.port.a=6379
redis.port.b=6380
redis.port.c=6381
redis.maxTotal=10000

二、编辑config-application-redis.xml

<!-- 实现spring整合分片 -->
	<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxTotal" value="${redis.maxTotal}"/>
	</bean>
	
	<!-- 定义三个redis节点 -->
	<!-- A -->
	<bean id="shardInfoA" class="redis.clients.jedis.JedisShardInfo">
		<constructor-arg name="host"  value="${redis.host}"/>
		<constructor-arg name="port"  value="${redis.port.a}"/>
	</bean>
	
	<!-- B -->
	<bean id="shardInfoB" class="redis.clients.jedis.JedisShardInfo">
		<constructor-arg name="host"  value="${redis.host}"/>
		<constructor-arg name="port"  value="${redis.port.b}"/>

	</bean>
	
	<!-- C -->
	<bean id="shardInfoC" class="redis.clients.jedis.JedisShardInfo">
		<constructor-arg name="host"  value="${redis.host}"/>
		<constructor-arg name="port"  value="${redis.port.c}"/>
	</bean>
	
	<!-- 定义连接池 -->
	<bean id="jedisPool" class="redis.clients.jedis.ShardedJedisPool">
		<constructor-arg name="poolConfig" ref="poolConfig"/>
		<constructor-arg name="shards">
			<list>
				<ref bean="shardInfoA"/>
				<ref bean="shardInfoB"/>
				<ref bean="shardInfoC"/>
			</list>
		</constructor-arg>
	</bean>

三、编辑工具API

在这里插入图片描述

@Service
public class RedisService {

	//有的工程需要,有的工程不需要。设置required=false,有就注入,没有就不注入。
    @Autowired(required = false)
    private ShardedJedisPool shardedJedisPool;

  //传递redis的内容 key和value
    private void set(String key,String value){
    	ShardedJedis jedis = shardedJedisPool.getResource();//获取连接
    	jedis.set(key,value);
    	shardedJedisPool.returnResource(jedis);;//返回连接

    }
    //设定超时时间
    private void set(String key,String value,int seconds){
    	ShardedJedis jedis = shardedJedisPool.getResource();//获取连接
    	jedis.setex(key,seconds,value);
    	shardedJedisPool.returnResource(jedis);//返回连接

    }
    //传递key值
    private String get(String key){
    	ShardedJedis jedis = shardedJedisPool.getResource();//获取连接
    	String result = jedis.get(key);//将获取到的内容存储到字符串中
    	shardedJedisPool.returnResource(jedis);//返回连接
    	return result;
    }
}

四、将项目重新打包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、修改ItemCatServiceImpl

@Service
public class ItemCatServiceImpl implements ItemCatService {

	@Autowired
	private ItemCatMapper itemCatMapper;

	// 注入Redis
	@Autowired
	//private Jedis jedis;//不使用单台jedis 使用分片技术
	private RedisService redisService;

	private static ObjectMapper objectMapper = new ObjectMapper();

	/**
	 * 1.根据parentId查询列表信息 2.将列表数据转化为返回voList集合
	 */
	public List<EasyUITree> findItemCatById(Long parentId) {
		ItemCat itemCat = new ItemCat();
		itemCat.setParentId(parentId);
		List<ItemCat> itemCatList = itemCatMapper.select(itemCat);
		List<EasyUITree> treeList = new ArrayList<>();
		for (ItemCat itemCatTemp : itemCatList) {
			EasyUITree easyUITree = new EasyUITree();
			easyUITree.setId(itemCatTemp.getId());
			easyUITree.setText(itemCatTemp.getName());
			// 如果是父级则应该closed,如果不是父级 open
			String state = itemCatTemp.getIsParent() ? "closed" : "open";
			easyUITree.setState(state);
			treeList.add(easyUITree);
		}
		return treeList;
	}

	// 通过redis缓存实现信息查询
	public List<EasyUITree> findCacheItemCatById(Long parentId) {
		// TODO Auto-generated method stub

		List<EasyUITree> treeList = null;

		// 1 查询缓存数据 要保证key不重复,操作的是item_cat对象 拼接parentId
		String key = "ITEM_CAT_" + parentId;
		String resultJson = redisService.get(key);

		try {

			// 2判断缓存数据是否为空
			if (StringUtils.isEmpty(resultJson)) {
				// 如果缓存内容为空,需要查询数据库中的内容 调用已经写好的方法
				//找到数据后,将数据通过API转化为Json串
				treeList = findItemCatById(parentId);
				String jsonData = objectMapper.writeValueAsString(treeList);
				//将数据库k-v写入缓存中
				redisService.set(key, jsonData);
				
				System.out.println("第一次查询数据库");
			} else {
				// 如果缓存中的数据不为空,则将Json串转化为Java对象,直接return返回
				//将json串转为java对象【list
				//先或得到数组 再转为集合
				
				EasyUITree[] trees = objectMapper.readValue(resultJson, EasyUITree[].class);
				treeList = Arrays.asList(trees);
				System.out.println("查询缓存数据");
			}

		} catch (Exception e) {
			// TODO: handle exception
		}

		return treeList;
	}

}

在这里插入图片描述
在这里插入图片描述

第三部分:Redis哨兵

业务需求

采用redis分片技术可以实现内存扩容,但是如果其中一台机器宕机,则整个redis分片不能正常运行。

实现主从挂载【为redis高可用做准备】

角色划分:6379主 6380/6381从机
在这里插入图片描述
在这里插入图片描述
新建sentinel文件夹,其中有三台redis配置信息
在这里插入图片描述
在这里插入图片描述
检查节点状态

info replication

在这里插入图片描述
打开6380redis服务,将80挂载到79上
在这里插入图片描述
在这里插入图片描述
从机没有写的权限
在这里插入图片描述
切换到主机,可以修改
将6381挂载到6379上
在这里插入图片描述
在这里插入图片描述
查看一下主机状态
在这里插入图片描述

哨兵实现

原理:

1、哨兵监控主机状态,并且获取主机全部信息,包括从机信息。
2、当主机宕机【心跳检测】,三次连接没有响应,则断定主机宕机,哨兵会匆匆集中选举一台从机当主机。同事将另外的从机(旧的主机)修改挂在状态,挂载到新的主机上。
3、当旧的主机修复完成后,充当从机,等待下次选举。

在这里插入图片描述

编辑哨兵配置文件

1、同名配置文件sentinel.conf拷贝到sentinel文件中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2、编辑sentinel.conf配置文件
在这里插入图片描述
3、修改哨兵监听节点信息
在这里插入图片描述
只有一票,写1
在这里插入图片描述
4、修改推选时间10s
在这里插入图片描述
5、修改超时时间20s
在这里插入图片描述
哨兵的启动
在这里插入图片描述
在这里插入图片描述
测试,新建redis连接,关掉主机
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值