redis

.

1.Redis缓存

说明:引入缓存机制可以有效的降低用户访问物理设备的频次,从而提高响应速度.
如何设计缓存
1.缓存数据如何存储? 应该采用什么样的数据结构呢? K-V key的唯一性
2.缓存数据的容量大小 应该动态维护缓存数据,将不需要的数据提前删除. LRU算法/LFU算法/随机算法/TTL算法
3.缓存数据保存到内存中,但是内存的特点断电即擦除. 定期将内存数据持久化(写入磁盘中)
4.单台缓存服务器性能不足,所以一般需要搭建集群(实现高可用).
5.使用C语言开发.

1.1 什么是Redis

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
速度: 读: 11.2万/秒 写:8.6万/秒 50万/秒
list不能当做缓存来用

1.2Redis命令

1.2.1.String类型

set 添加key-value set username admin
get 根据key获取数据 get username
strlen 根据key获取值的长度 strlen key
exists 判断key是否存在 exists name
返回1存在 0不存在
del 删除redis中的key del key
Keys 用于查询符合条件的key keys * 查询redis中全部的key
keys n?me 使用占位符获取数据
keys nam* 获取nam开头的数据
mset 赋值多个key-value mset key1 value1 key2 value2 key3 value3
mget 获取多个key的值 mget key1 key2
append 对某个key的值进行追加 append key value
type 检查某个key的类型 type key
select 切换redis数据库 select 0-15 redis中共有16个数据库
flushdb 清空单个数据库 flushdb
flushall 清空全部数据库 flushall
expire 指定key的生效时间 单位秒 expire key 20 key20秒后失效
pexpire 指定key的失效时间 单位毫秒 pexpire key 2000,key 2000毫秒后失效
ttl 检查key的剩余存活时间 ttl key -2数据不存在 -1该数据永不超时
persist 撤销key的失效时间 persist key

1.2.2.Hash类型

说明:可以用散列类型保存对象和属性值
hset 为对象添加数据 hset key field value
hget 获取对象的属性值 hget key field
hexists 判断对象的属性是否存在 HEXISTS key field.1表示存在 0表示不存在
hsetnx 设置hash的一个字段,只有当这个字段不存在时有效 HSETNX key field value
hstrlen 获取hash中指定key的值的长度 HSTRLEN key field
hvals 获取hash的所有值 HVALS user

1.2.3.List类型

说明:Redis中的List集合是双端循环列表,分别可以从左右两个方向插入数据.
List集合可以当做队列使用,也可以当做栈使用
队列:存入数据的方向和获取数据的方向相反
栈:存入数据的方向和获取数据的方向相同

lpush 从队列的左边入队一个或多个元素 LPUSH key value [value …]
rpush 从队列的右边入队一个或多个元素 RPUSH key value [value …]
lpop 从队列的左端出队一个元素 LPOP key
rpop 从队列的右端出队一个元素 RPOP key
lpushx 当队列存在时从队列的左侧入队一个元素 LPUSHX key value
rpushx 当队列存在时从队列的右侧入队一个元素 RPUSHx key value

1.2.4.Redis事务命令

说明:redis中操作可以添加事务的支持.一项任务可以由多个redis命令完成,如果有一个命令失败导致入库失败时.需要实现事务回滚.
multi 标记一个事务开始 127.0.0.1:6379> MULTI,OK
exec 执行所有multi之后发的命令 127.0.0.1:6379> EXEC.OK
discard 丢弃所有multi之后发的命令

1.2.5 下载Redis

1.上传redis
2.解压redis服务
[root@localhost src]# tar -xvf redis-5.0.4.tar.gz
3.移动文件/修改文件名称
mv redis-5.0.4.tar.gz software
修改解压后redis的名字
mv redis-5.0.4 redis
4安装Redis:是由c语言编写的程序
说明:在Redis根目录中执行如下命令
1).make
2). make install
5.修改redis配置文件
修改redis根目录下的redis.conf文件
1).去除IP绑定
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201209124822675.png
2).修改保护模式
在这里插入图片描述
3).开启后台启动
在这里插入图片描述
6.Redis服务器命令
说明: Redis服务在运行时,必须依赖于配置文件 redis.conf. 操作redis时最好在根目录中操作
1).启动redis
redis-server redis.conf
2).进入redis客户端
redis-cli -p 6379或者 端口号与默认端口号一致时 redis-cli
ctrl + c 退出客户端
3).关闭redis服务器
方式一:命令:kill 线程号
方法二: redis-cli -p 6379 shutdown 或者端口号与默认端口号一致时redis-cli shutdown

2.SpringBoot整合Redis

1.导入jar包
在这里插入图片描述

2.1测试setNx/setEx/set命令

/**
* 需求: 如果数据不存在,则将数据修改
*/
@Test
public void testSetNx(){
Jedis jedis = new Jedis(“192.168.126.129”,6379);
jedis.set(“key1”, “aaa”);
//如果key不存在,则赋值
jedis.setnx(“key1”, “测试方法”);
System.out.println(jedis.get(“key1”));
}

/**
 * 需求: 实现超时时间的设定与赋值操作的原子性.
 * 考点: **为数据设定超时时间时,切记满足原子性要求**.
 *      否则会出现key永远不能删除的现象
 */
@Test
public void testSetEx(){
    Jedis jedis = new Jedis("192.168.126.129",6379);
    /*jedis.set("key2", "bbb");
    jedis.expire("key2", 3);*/
    //???数据超时之后一定会被删除吗???  错的
    jedis.setex("key2", 10, "bbb");
}
/**
 * 需求: 如果数据存在时,才会修改数据,并且为数据添加超时时间10秒(原子性).
 * 参数说明:
 *      NX: 只有数据不存在时,才会赋值.
 *      XX: 只有数据存在时,才会赋值.
 *      EX: 秒
 *      PX: 毫秒
 */
public void testSet(){
    Jedis jedis = new Jedis("192.168.126.129",6379);
   /* if(jedis.exists("key3")){
        jedis.setex("key3",10 ,"ccc");
    }*/
    SetParams setParams = new SetParams();
    setParams.xx().ex(10);
    //将所有的操作采用原子性的方式进行控制
    jedis.set("key3", "ccc", setParams);
}

2.2测试hash

/**
* HASH测试
*/
@Test
public void testHash(){
Jedis jedis = new Jedis(“192.168.126.129”,6379);
jedis.hset(“person”, “id”, “100”);
jedis.hset(“person”, “name”, “tomcat猫”);
System.out.println(jedis.hgetAll(“person”));
}

2.3测试List

**
* Set集合测试
* 1. sadd 新增元素
* 2. SCARD 获取元素数量
* 3. SINTER key1 key2 获取元素的交集
* 4. SMEMBERS set 获取集合元素
* demo自己补一下
* * */
@Test
public void testMulti(){
Jedis jedis = new Jedis(“192.168.126.129”,6379);
//开启事务
Transaction transaction = jedis.multi();
try {
transaction.set(“a”, “a”);
transaction.set(“b”, “b”);
//提交事务
transaction.exec();
}catch (Exception e){
//回滚事务
transaction.discard();
}
}

2.4 测试事务

/**
* Set集合测试
* 1. sadd 新增元素
* 2. SCARD 获取元素数量
* 3. SINTER key1 key2 获取元素的交集
* 4. SMEMBERS set 获取集合元素
* demo自己补一下
* * */
@Test
public void testMulti(){
Jedis jedis = new Jedis(“192.168.126.129”,6379);
//开启事务
Transaction transaction = jedis.multi();
try {
transaction.set(“a”, “a”);
transaction.set(“b”, “b”);
//提交事务
transaction.exec();
}catch (Exception e){
//回滚事务
transaction.discard();
}
}

2.5.1 SpringBoot整合Redis 编辑properties配置文件

在这里插入图片描述

2.5.2 编辑配置类

在这里插入图片描述

2.6 编辑ObjectMapperUtil

说明:业务需求在业务中通常需要将业务对象转化为JSON数据.需要通过工具API进行手动的转化.
从数据库中读取数据到redis是对象转换为json字符串,从缓存到客户端是将字符串转换为对象,
ObjectMapper是Jackson提供的一个对象 writeValueAsString()是将对象转换为字符串 ,readValue将字符串转换为对象
public class ObjectMapperUtil {
private static final ObjectMapper MAPPER = new ObjectMapper();
public static String toJSON(Object target){
try {
return MAPPER.writeValueAsString(target);
} catch (JsonProcessingException e) {
e.printStackTrace();
//将检查异常转化为运行时异常.
throw new RuntimeException(e);
}
}
public static T toObject(String json,Class targetClass){
try {
return MAPPER.readValue(json, targetClass);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}

2.7实现商品分类缓存操作

2.7.1 编辑ItemController
/**
* 业务需求: 实现商品分类树形结构展现
* url地址: http://localhost:8091/item/cat/list
* 参数: id= 父级节点的ID
* 返回值: List
/
@RequestMapping("/list")
public List findItemCatList(Long id){
//暂时只查询一级商品分类信息
long parentId = (id==null?0:id);
//return itemCatService.findItemCatList(parentId);
return itemCatService.findItemCatCache(parentId);
}
2.7.2 编辑ItemService
@Service
public class ItemCatServiceImpl implements ItemCatService{
@Autowired
private ItemCatMapper itemCatMapper;
@Autowired(required = false) //类似于懒加载
private Jedis jedis;
@Override
public ItemCat findItemCatById(Long itemCatId) {
return itemCatMapper.selectById(itemCatId);
}
/
*
* 1.根据parentId 查询子级目录信息
* 2.获取ItemCatList集合,之后将List集合转化为VOList集合
* 3.返回数据
* @param parentId
* @return
/
/
*
* 实现步骤:
* 1.先定义key ITEM_CAT_PARENT::0
* 2.先查询缓存
* 有 true 获取缓存数据之后,将JSON转化为对象 之后返回
* 没有 false 应该查询数据库, 之后将数据保存到redis中. 默认30天超时.
* * @param parentId
* @return
/
@Override
public List findItemCatCache(long parentId) {
Long startTime = System.currentTimeMillis();
List treeList = new ArrayList<>();
//1.定义key
String key = “ITEM_CAT_PARENT::”+parentId;
//2.从缓存中获取对象
if(jedis.exists(key)){
//存在 直接获取缓存数据,之后转化为对象
String json = jedis.get(key);
treeList = ObjectMapperUtil.toObject(json,treeList.getClass());
System.out.println(“查询redis缓存,获取数据”);
long endTime = System.currentTimeMillis();
System.out.println(“耗时:”+(endTime-startTime)+“毫秒”);
}else{
//不存在 应该先查询数据库,之后将数据保存到缓存中.
treeList = findItemCatList(parentId);
String json = ObjectMapperUtil.toJSON(treeList);
jedis.setex(key, 7
246060, json);
System.out.println(“查询数据库获取结果”);
long endTime = System.currentTimeMillis();
System.out.println(“耗时:”+(endTime-startTime)+“毫秒”);
}
return treeList;
}

3.AOP实现Redis缓存

1) AOP作用
利用AOP可以实现对方法(功能)的扩展.实现代码的解耦.
2) 切面组成要素

3.1切面 = 切入点表达式 + 通知方法

3.1.1 切入点表达式
1).bean(bean的ID) 拦截bean的所有的方法 具体的某个类 粗粒度的.
2).within(包名.类名) 扫描某个包下的某个类 com.jt.* 粗粒度的.
3).execution(返回值类型 包名.类名.方法名(参数列表)) 细粒度的
4).@annotation(包名.注解名) 细粒度的
3.1.2 通知方法
说明: 通知相互之间没有顺序可言. 每个通知方法都完成特定的功能,切记AOP的通知方法与目标方法之间的顺序即可.
1).before 目标方法执行前
2).afterReturning 目标方法执行后
3).afterThrowing 目标方法执行抛出异常时执行.
4).after 不管什么情况,最后都要执行的.
上述四大通知类型,一般用来记录程序的运行状态的.(监控机制)JoinPoint
5).around 目标方法执行前后都要执行.ProceedingJoinPoint joinPoint.process();目标方法执行的结果
如果要对程序的运行轨迹产生影响,则首选around

3.2 AOP入门案例

@Aspect //标识我是一个切面
@Component //将对象交给spring容器管理 cacheAOP
public class CacheAOP {
//切面 = 切入点表达式 + 通知方法
//表达式1: bean(itemCatServiceImpl) ItemCatServiceImpl类
//@Pointcut(“bean(itemCatServiceImpl)”)
//@Pointcut("within(com.jt.service.)")
// .
一级包下的类 …* 所有子孙后代的包和类
//返回值类型任意, com.jt.service包下的所有类的add方法参数类型任意类型
//写参数类型时注意类型的大小写
@Pointcut(“execution(* com.jt.service….(…))”)
public void pointcut(){

}
/**
 *
 * joinPoint代表连接点对象,一般适用于前四大通知类型(除around之外的)
 *        客人                         路人
 */
@Before("pointcut()")
public void before(JoinPoint joinPoint){
    //1.获取目标对象
    Object target = joinPoint.getTarget();
    System.out.println(target);
    //2.获取目标对象的路径 包名.类名.方法名
    String className = joinPoint.getSignature().getDeclaringTypeName();
    String methodName = joinPoint.getSignature().getName();
    System.out.println("目标方法的路径:"+(className+"."+methodName));
    //3.获取参数类型
    System.out.println(Arrays.toString(joinPoint.getArgs()));
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint){
    System.out.println("环绕通知执行");
    Object data = null;
    try {
        data = joinPoint.proceed(); //执行目标方法
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    return data;
}

}

3.3 AOP实现redis缓存

3.3.1 需要通过自定义注解的形式动态实现缓存操作.通过注解获取其中的key.超时时间.
在这里插入图片描述
3.3.2 自定义注解的用法
在这里插入图片描述
3.3.3 编辑CacheAOP
@Aspect //标识我是一个切面
@Component //将对象交给spring容器管理 cacheAOP
public class CacheAOP {
@Autowired
private Jedis jedis;
/**
* 实现思路:
* 1.动态获取key 用户自定义的前缀+用户的参数[0,xx]
* 2.判断key是否存在
* 存在: 直接从redis中获取数据 JSON, 需要将json转化为具体对象 按照返回值类型进行转化
* 不存在: 执行目标方法.获得返回值数据. 将返回值结果转化为JSON格式. 之后保存到缓存中.
* @param joinPoint
* @return
*/
@Around("@annotation(cacheFind)")
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind) throws NoSuchMethodException {
Object result = null;
//1.获取key的前缀
String key = cacheFind.key();
//2.获取方法参数
String argString = Arrays.toString(joinPoint.getArgs());
key = key + “::” + argString;
try {
//3.判断缓存中是否有数据
if(jedis.exists(key)){
String json = jedis.get(key);
//5.获取返回值类型
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
result = ObjectMapperUtil.toObject(json,methodSignature.getReturnType());
System.out.println(“AOP查询redis缓存”);
}else{
//表示缓存中没有数据,执行目标方法
result = joinPoint.proceed();
String json = ObjectMapperUtil.toJSON(result);
//4.判断数据中是否有超时时间
if(cacheFind.seconds()>0){
jedis.setex(key,cacheFind.seconds(),json);
}else{
jedis.set(key,json);
}
System.out.println(“AOP执行数据库调用!!!”);
}
} catch (Throwable throwable) {
throwable.printStackTrace();
throw new RuntimeException(throwable);
}
return result;
}

3.3.4想要用缓存,直接在方法上加注解就可以
在这里插入图片描述

4 Redis属性说明

4.1 Redis持久化策略

4.1.1 为什么要持久化

Redis中的记录都保存在内存中,如果内存断电或者服务器宕机,则内存数据直接丢失.业务中不允许发生. 所以需要将数据定期进行维护.

4.1.2 RDB模式

说明: RDB模式是Redis的默认的持久化策略.无需手动的开启.
特点:
1.Redis会定期的执行RDB持久化操作. 缺点**:可能导致内存数据丢失.**
2.RDB记录的是内存数据的快照,并且后续的快照会覆盖之前的快照.每次只保留最新数据.效率更高.
命令:
1).save 命令 要求立即执行持久化操作 save会造成线程的阻塞.
2).bgsave 命令 后台执行持久化操作 后台运行不会造成阻塞. 异步操作, 不能保证立即执行

4.1.3 AOF模式

说明: AOF模式默认条件下是关闭的,需要手动的开启,如果开启了AOF模式则RDB模式将失效.但是如果手动执行save命令,则也会生成RDB文件.
1).开启AOF模式
在这里插入图片描述

特点:
1.AOF模式记录程序的执行的过程.所以可以保证数据不丢失.
2.由于AOF记录程序运行的过程,所以整个持久化文件相对大,所以需要定期维护. 效率低

4.1.4 RDB与AOF模式持久化对比

1).RDB模式
save 900 1 如果在900秒内,执行了一次更新操作则持久化一次
save 300 10
save 60 10000 操作越快 ,持久化的周期越短.
2).AOF模式
appendfsync always 用户执行一次更新操作,则持久化一次 异步操作
appendfsync everysec 每秒操作一次
appendfsync no 不主动操作 一般不用.

4.1.5 关于RDB与AOF总结

策略: 如果数据允许少量丢失,首选RDB模式,
如果数据不允许丢失则首选AOF模式.
企业策略: 又要满足效率,同时满足数据不丢失.
主机: 采用RDB模式
从机: 采用AOF模式

2.1.6面试题
题目: 小丽是公司特别漂亮的妹子,误操作将redis服务器执行了flushAll命令,问你作为项目经理如何处理??
A. 训斥一顿,之后HR开除.
B. 秀一下自己的技术,让小丽崇拜 一起过上了幸福的生活
解决方案: 需要将从库中的AOF文件 进行编辑,删除多余的flushAll命令,之后重启redis即可.

4.2 内存优化策略

4.2.1 为什么需要内存优化
说明: 由于redis在内存中保存数据.如果一直存储,则内存数据必然溢出.所以需要定期维护内存数据的大小.
维护策略: 删除旧的不用的数据,保留新的常用的数据
4.2.2 LRU算法
LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。
计算维度: 时间T
注意事项: LRU算法是迄今为止内存中最好用的数据置换算法.
4.2.3 LFU算法
LFU(least frequently used (LFU) page-replacement algorithm)。即最不经常使用页置换算法,要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。但是有些页在开始时使用次数很多,但以后就不再使用,这类页将会长时间留在内存中,因此可以将引用计数寄存器定时右移一位,形成指数衰减的平均使用次数。
维度: 使用次数
4.2.4 随机算法
4.2.5 TTL算法
根据剩余的存活时间,将马上要超时的数据提前删除.
4.3 配置内存优化策略8种配置
1.volatile-lru 在设定了超时时间的数据中,采用lru算法
2.allkeys-lru 在所有的数据中,采用lru算法
3.volatile-lfu 在设定了超时时间的数据中,采用lfu算法
4.allkeys-lfu 所有数据采用lfu算法
5.volatile-random 设置超时时间数据的随机算法
6.allkeys-random 所有数据的随机
7.volatile-ttl 将设定了超时时间的数据,提前删除.
8.noeviction 默认规则 如果设定noeviction 则不删除数据,直接报错返回.
*

4.4关于Redis常见面试题

业务场景: 高并发环境下.用户长时间对服务器进行操作,可能产生如下的问题.
4.4.1 什么是缓存穿透
说明: 用户高并发环境下访问数据库和缓存中都不存在的数据称之为缓存穿透现象.
解决方案:
1). 禁用IP 限制IP访问.
2). 限流 每秒最多访问3次
3). 布隆过滤器

布隆过滤器
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。
在这里插入图片描述
布隆过滤器优化:
问题:如何解决hash碰撞问题
知识点: 由于hash碰撞问题,可能由多个key有相同的位置,所以得出结论,布隆过滤器认为数据存在,那么数据可能存在.如果布隆过滤器认为数据不存在,则数据一定不在.
如何降低hash碰撞的几率:
答:1.扩容二进制向量位数. 2.增加hash函数的个数
当位数增加/函数适当增加,则可以有效的降低hash碰撞的几率. 默认值 0.03
在这里插入图片描述
4.4.2什么是缓存击穿
说明: **某个(一个)热点数据在缓存中突然失效.**导致大量的用户直接访问数据库.导致并发压力过高造成异常.
解决方案:
1.尽可能将热点数据的超时时间 设定的长一点
2.设定多级缓存 超时时间采用随机算法
.
4.4.3 什么是缓存雪崩
说明: 在缓存服务器中,由于大量的缓存数据失效,导致用户访问的命中率过低.导致直接访问数据库.
问题分析:
1. fluashAll命令可能导致缓存雪崩.
2. 设定超时时间时,应该采用随机算法
3. 采用多级缓存可以有效防止.

5. redis分片机制

说明: 单台redis内存容量是有限的.但是如果有海量的数据要求实现缓存存储,则应该使用多个Redis节点.

5.1Redis分片机制定义

在这里插入图片描述

5.2Redis分片机制配置

5.2.1配置规划
说明: 准备3台redis服务器 分别为 6379/6380/6381
5.2.2 准备3个配置文件
在这里插入图片描述
修改各自端口号 改为6380 6381
5.2.3 启动redis服务器
redis-server 6380.conf
5.2.4 检查redis启动状态
ps -ef |grep redis
5.2.5 Redis分片机制配置
1)说明:根据redis节点个数.拼接字符串
在这里插入图片描述
2)编辑RedisConfig配置类
在这里插入图片描述
3)修改CacheAOP中的注入
在这里插入图片描述

5.3Redis分片机制说明

5.3.1 一致性Hash算法介绍
一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,目的是解决分布式缓存的问题。 [1] 在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动态伸缩等问题 [2] 。
5.3.2 一致性Hash原理说明
常识:
1).对相同的数据hash得到的结果相同
2).常见hash值 8位16进制数 2^32种可能性
在这里插入图片描述5.3.3 平衡性说明
说明: 平衡性是指hash的结果应该平均分配到各个节点,这样从算法上解决了负载均衡问题 .
如果发现数据分布不均匀,则采用虚拟节点的方式,实现数据的平衡. 如果一次平衡不能达到目标则多次生成虚拟节点.但是数据平衡没有办法做到绝对的平均.
在这里插入图片描述
5.3.4 单调性说明
单调性是指在新增或者删减节点时,不影响系统正常运行
如果新增或者删除节点,则尽可能不要改变原有的数据结构.
5.3.5 分散性
分散性是指数据应该分散地存放在分布式集群中的各个节点(节点自己可以有备份),不必每个节点都存储所有的数据
鸡蛋不要放到一个篮子里.

6.Redis哨兵机制

1 )Redis分片机制问题
说明: 如果redis分片中有一个节点宕机,则可能会影响整个服务的运行. redis分片没有实现高可用.

6.1 Redis主从结构搭建

6.1.1 复制配置文件
在这里插入图片描述
准备3台redis
6.1.2主从搭建
进入redis-cli -p 8.69
命令2: slaveof IP PORT 主从挂载命令
检查主从结构状态 命令1: info replication
关于主从结构说明:
主和从都知道 当前的主从的状态, 并且只有主机可以写操作.从机只能读操作.
6.1.3 Redis哨兵机制工作原理
1).当哨兵启动时,首先会监控主机,从主机中获取当前所有的节点的状态,同时哨兵开启心跳检测机制.
2).当主机发生宕机的现象时,由于哨兵有PING-PONG机制 发现主机宕机,则哨兵开始进行选举.
3).当选举成功之后,新的主机当选之后,其他的节点当新主机的从.
在这里插入图片描述6.1.4编辑哨兵配置文件
在这里插入图片描述
1)关闭保护模式
在这里插入图片描述
2).开启后台运行
在这里插入图片描述
3).编辑监控配置
在这里插入图片描述
4).修改选举时间
在这里插入图片描述

6.2 启动哨兵服务

命令: redis-sentinel sentinel.conf
高可用检查:
1).先关闭主机 等待10秒检查是否进行选举.
2).启动6379. 检查是否当选新主机的从.

6.3 SpringBoot整合哨兵机制

6.3.1 编辑pro配置文件
在这里插入图片描述
6.3.2 编辑配置类
在这里插入图片描述
6.3.3 编辑CacheAOP
在这里插入图片描述
6.3.4 关于分片/哨兵总结
1.Redis分片主要的作用实现内存的扩容,缺点:没有实现高可用的效果.
2.Redis哨兵主要的作用实现了redis节点高可用. 缺点:没有实现内存扩容
Redis哨兵机制实质就是引入第三方的监控,但是需要保证第三方的高可用.就必须引入更多的资源.

7.Redis集群(重要)

为什么要搭建集群
通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取。
Redis是一个很好的Cache工具。大型网站应用,热点数据量往往巨大,几十G上百G是很正常的事儿。
由于内存大小的限制,使用一台 Redis 实例显然无法满足需求,这时就需要使用多台 Redis作为缓存数据库。但是如何保证数据存储的一致性呢,这时就需要搭建redis集群.采用合理的机制,保证用户的正常的访问需求.
采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性.并且在内部实现高可用的机制.实现了服务故障的自动迁移.
参见搭建文档.
1)集群搭建计划
主从划分:
3台主机 3台从机共6台 端口划分7000-7005

7.1 集群搭建

7.1.1准备集群文件夹:Mkdir cluster
.在cluster文件夹中分别创建7000-7005文件夹
在这里插入图片描述
7.1.2复制配置文件
说明:
将redis根目录中的redis.conf文件复制到cluster/7000/ 并以原名保存
cp redis.conf cluster/7000/
7.1.3 编辑配置文件
1.注释本地绑定IP地址
在这里插入图片描述
2.关闭保护模式
在这里插入图片描述
3.修改端口号
在这里插入图片描述
4.启动后台启动
在这里插入图片描述
5.修改pid文件
在这里插入图片描述
6.修改持久化文件路径
在这里插入图片描述
7.设定内存优化策略
在这里插入图片描述
8.关闭AOF模式
在这里插入图片描述
9.开启集群配置
在这里插入图片描述
10.开启集群配置文件
在这里插入图片描述
11.修改集群超时时间
在这里插入图片描述
7.1.4 复制修改后的配置文件
说明:将7000文件夹下的redis.conf文件分别复制到7001-7005中
[root@localhost cluster]# cp 7000/redis.conf 7001/ …略
7.1.5 批量修改
说明:分别将7001-7005文件中的7000改为对应的端口号的名称,
在这里插入图片描述
7.1.6 通过脚本编辑启动/关闭指令
1.创建启动脚本 vim start.sh
2.编辑关闭的脚本 vim shutdown.sh
3.启动redis节点
sh start.sh
4.检查redis节点启动是否正常

ps -ef |drep redis

7.2 创建redis集群

#5.0版本执行 使用C语言内部管理集群
redis-cli --cluster create --cluster-replicas 1 192.168.126.129:7000 192.168.126.129:7001 192.168.126.129:7002 192.168.126.129:7003 192.168.126.129:7004 192.168.126.129:7005
7.2.1 Redis集群高可用测试
1.关闭redis主机.检查是否自动实现故障迁移.
2.再次启动关闭的主机.检查是否能够实现自动的挂载.
一般情况下 能够实现主从挂载
个别情况: 宕机后的节点重启,可能挂载到其他主节点中(7001-7002) 正确的

7.3 Redis集群原理

7.3.1 Redis集群高可用推选原理
如图-24所示
原理说明:
Redis的所有节点都会保存当前redis集群中的全部主从状态信息.并且每个节点都能够相互通信.当一个节点发生宕机现象.则集群中的其他节点通过PING-PONG检测机制检查Redis节点是否宕机.当有半数以上的节点认为宕机.则认为主节点宕机.同时由Redis剩余的主节点进入选举机制.投票选举链接宕机的主节点的从机.实现故障迁移.
7.3.2 Redis集群宕机条件
特点:集群中如果主机宕机,那么从机可以继续提供服务,
当主机中没有从机时,则向其它主机借用多余的从机.继续提供服务.如果主机宕机时没有从机可用,则集群崩溃.
答案:9个redis节点,节点宕机5-7次时集群才崩溃.

在这里插入图片描述
7.3.4 Redis hash槽存储数据原理 分区算法/hash槽算法
说明: RedisCluster采用此分区,所有的键根据哈希函数(CRC16[key]%16384)映射到0-16383槽内,共16384个槽位,每个节点维护部分槽及槽所映射的键值数据.根据主节点的个数,均衡划分区间.
算法:哈希函数: Hash()=CRC16[key]%16384
当向redis集群中插入数据时,首先将key进行计算.之后将计算结果匹配到具体的某一个槽的区间内,之后再将数据set到管理该槽的节点中.
在这里插入图片描述

8.SpringBoot整合Redis集群

8.1编辑pro配置文件

在这里插入图片描述

8.2编辑配置类

@Configuration //标识我是一个配置类 一般与@Bean注解联用
@PropertySource(“classpath:/properties/redis.properties”)
public class RedisConfig {
@Value("${redis.nodes}")
private String nodes; //node,node,node
@Bean
public JedisCluster jedisCluster(){
Set nodesSet = new HashSet<>();
String[] nodeArray = nodes.split(",");
for (String node : nodeArray){ //host:port
String host = node.split("😊[0];
int port = Integer.parseInt(node.split("😊[1]);
HostAndPort hostAndPort = new HostAndPort(host, port);
nodesSet.add(hostAndPort);
}
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(1000);
config.setMaxIdle(60);
config.setMinIdle(20);
return new JedisCluster(nodesSet,config);
}
}

8.3编辑CacheAOP

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值