java架构之路-(Redis专题)聊聊大厂那些redis
上几次说了redis的主从,哨兵,集群配置,但是内部的选举一直没说,先来简单说一下选举吧。
集群选举
redis cluster节点间采取gossip协议进行通信,也就是说,在每一个节点间,无论主节点还是从节点,他们之间都是存在相互通信的。例如你的redis端口号是6379,那么你的gossip协议端口号就是16379。
gossip协议包含多种消息,包括ping,pong,meet,fail等等。
ping:每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元 数据;
pong: 返回ping和meet,包含自己的状态和其他信息,也可以用于信息广播和更新;
fail: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。
meet:某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信,不需要 发送形成网络的所需的所有CLUSTER MEET命令。发送CLUSTER MEET消息以便每个节点能够达到其他每个节点只需通 过一条已知的节点链就够了。由于在心跳包中会交换gossip信息,将会创建节点间缺失的链接。
当我们的master节点和其slave节点中断,或和其它节点中断时,也就是连接超过了我们设置的cluster‐node‐timeout的值,这时就会认为我们的当前的master是不可用的,需要选举了,这时将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST信息到所有节点上(包括其他主从的从节点),其它主节点收到FAILOVER_AUTH_REQUEST信息会给与一个FAILOVER_AUTH_ACK反馈,其它从节点不会有任何反应,当我们的slave收到ACK反馈达到半数以上时,会当选当前选举内的master节点,其它slave节点不在进行选举,作为该新master的slave节点。广播Pong消息通知其他集群节点。
流程大概就是这样的,还有可能每个正在选举的slave节点收到的ACK反馈是一样的,这时再次触发一次选举,currentEpoch再加1,流程和上面一样。这里要注意的是,并不是每个slave都在同一时刻向外发送FAILOVER_AUTH_REQUEST信息的,一般数据较新的节点会先发,数据的新旧由SLAVE_RANK来判断,SLAVE_RANK越小,代表数据越新。
Redis的优化与实际场景
缓存穿透
我们在一般大型的互联网项目查询到的数据,都是查询的缓存内的数据,也就是我们的redis内的数据,但是第一次查询或者说根本不存在的数据,会穿过缓存到达我们的数据库去查询,如果大量这样的请求过来,我们的数据库是扛不住的。这就是我们常说的缓存穿透。处理思路很简单,只要是请求过来的,没有结果。存入缓存设置超时时间,再返回。设置时间是为了保证现在没用到,现在没缓存结果,不代表永远没有缓存结果。
@GetMapping(value = "/")
public String getIndex(String goods_id){
//优先从缓存去拿
String goods = stringRedisTemplate.opsForValue().get(goods_id);
if (goods == null){
//如果拿不到去数据库拿
goods = goodsService.getGoodsById(goods_id);
//存入缓存,设置超时时间
stringRedisTemplate.opsForValue().set(goods_id,goods,300);
}
return goods;
}
如果是黑客来了,一直拿不同的缓存来请求我们的项目,这样的思路是不可取的,我们可以使用布隆过滤器来实现阻止缓存击穿问题。
缓存预热
双11要来了,每次双11的0点,会有大批的商品进行交易,如果这些商品不是存在缓存内的,超高的并发(都不用双11,平时的秒杀就够受的),大量的线程会涌入数据库,给数据库造成超大的压力,我们这时应该提前将这些要秒杀的商品,提前存入到redis当中去,防止大批量的请求直接冲进数据库。这就是我们提到的缓存预热。
缓存失效
刚才我们的说了预热,但是我还是需要设置超时时间的时间的,不设置超时时间的话,你的数据库更新了,而我们的缓存还是我们的最开始的数据,造成数据的不一致。假设我们在预热的时候将大量的商品设置为300秒超时的时间,开始秒杀....过了300秒了。还是有一定的并发量,这时所有的缓存都失效了,还是会有大量的请求进入到我们的数据库的,所以说我在设置缓存预热时,不要设置同一个时间结束。会造成大量的缓存在同一时间失效,给我们的后台服务造成巨大压力。
缓存雪崩
有很多项目还是在停留在使用redis单机的状态,如果说redis不在对我们的项目服务了,大量的请求会涌入我们的数据访问层,造成我们的数据库压力超大,甚至数据库宕机,从导致整个服务的不可用状态。或者说我们的并发量远远超过我们的redis吞吐量。也会早成redis的拥塞,其它线程请求redis超时,早成redis假死现象,造成我们的redis雪崩。这时我们应该尽力采用高可用的缓存层架构,比如哨兵,比如集群架构,对于并发量超大的情况我们可以使用限流的方式来控制。
热点缓存重建
如果说,我们的设置了一个缓存,失效时间为300毫秒,但在失效那一刻,还是高并发的状态,我们的服务器压力还是巨大的,这些高并发的请求进入我们的数据库,后果可想而知,所以我们要在这个热点key的重建过程中,避免大量的请求进入我们的数据库。我们可以这样来做,尝试加一把简单的锁。
@GetMapping(value = "/")
public String getIndex(String goods_id) throws InterruptedException {
//优先从缓存去拿
String goods = stringRedisTemplate.opsForValue().get(goods_id);
if (goods == null){
//如果拿不到去数据库拿
//设置只有一个请求可以进入数据库,其余的线程自旋等待
Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("lock" + goods_id, goods_id, Duration.ofMinutes(3));
if(aBoolean){
goods = goodsService.getGoodsById(goods_id);
//存入缓存,设置超时时间
stringRedisTemplate.opsForValue().set(goods_id,goods,300);
}else{
//自旋等待50毫秒
Thread.sleep(50);
//再次调用该方法,尝试获取数据
getIndex(goods_id);
}
}
return goods;
}
一些Redis的使用建议
1.建议key设置为服务名:表名或者模块名:表名作为key,便于后期的查找和使用。
2.保证能识别语义的前提下,尽力设置key要简洁,不要过长。
3.不要在key中设置特殊字符,比如空格、换行等字符。
4.redis中不要设置过大的值,一个字符串最大限制512M,但建议一般是要超过10kb大小,list,set,hash,zset不建议超过5000个元素,视情况而定。
5.不要使用keys命令,建议使用scan命令进行替换。
6.建议多使用原生命令,管道等操作尽力减少使用,推荐使用mget,mset这样的命令。
这些优化其实都是围绕着我们Redis的特性,单线程来说的,如果说我们存了一个bigKey或者是一次性塞入了超多的命令,很可能阻塞后面的命令,造成我们的redis假死现象,也会造成我们的网络拥塞,占有了更多的带宽。
Redis的清除策略
1.被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key
2.主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key
3.当前已用内存超过maxmemory限定时,触发主动删除策略。
在redis启动前,我们就配置了,最大的内存使用maxmemory,当前已用内存超过maxmemory限定时,会触发主动清理策略。
默认策略是volatile-lru,即超过最大内存后,在过期键中使用lru算法进行key的剔除,保证不过 期数据不被删除,但是可能会出现OOM问题。
其他策略如下:
allkeys-lru:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间 为止。
allkeys-random:随机删除所有键,直到腾出足够空间为止。
volatile-random: 随机删除过期键,直到腾出足够空间为止。
volatile-ttl:根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到
noeviction策略。 noeviction:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息"(error)OOM command not allowed when used memory",此时Redis只响应读操作。
注意:如果没有配置我们的maxmemory属性,当我们的内存写满以后,不会触发任何清除策略,会直接将我们的数据存放在磁盘上,极具降低我们的redis性能。
总结:
redis差不多就说这么多了,再深入的c语言代码,我也不懂了,我们大概简单使用,基础的搭建主从,哨兵,集群,java链接redis,redis的优化这几个角度来讲解我们的redis,后面我会弄一篇redis的面试题,也是围绕这些来讲解的,还是那句话,真正懂得了内部的原理,什么样的面试题都不在话下了...
最进弄了一个公众号,小菜技术,欢迎大家的加入
java架构之路-(Redis专题)聊聊大厂那些redis的更多相关文章
- java架构之路(多线程)大厂方式手写单例模式
上期回顾: 上次博客我们说了我们的volatile关键字,我们知道volatile可以保证我们变量被修改马上刷回主存,并且可以有效的防止指令重排序,思想就是加了我们的内存屏障,再后面的多线程博客里还有 ...
- [转帖]java架构之路-(面试篇)JVM虚拟机面试大全
java架构之路-(面试篇)JVM虚拟机面试大全 https://www.cnblogs.com/cxiaocai/p/11634918.html 下文连接比较多啊,都是我过整理的博客,很多答案都 ...
- java架构之路-(Redis专题)简单聊聊redis分布式锁
这次我们来简单说说分布式锁,我记得过去我也过一篇JMM的内存一致性算法,就是说拿到锁的可以继续操作,没拿到的自旋等待. 思路与场景 我们在Zookeeper中提到过分布式锁,这里我们先用redis实现 ...
- java架构之路-(Redis专题)Redis的主从、哨兵和集群
我们使用的redis,单机的绝对做不到高可用的,万一单机的redis宕机了,就没有备用的了,我们可以采用集群的方式来保证我们的高可用操作. 主从架构 大致就是这样的,一个主节点,两个从节点(一般两个就 ...
- java架构之路-(Redis专题)SpringBoot连接Redis超简单
上次我们搭建了Redis的主从架构,哨兵架构以及我们的集群架构,但是我们一直还未投入到实战中去,这次我们用jedis和springboot两种方式来操作一下我们的redis 主从架构 如何配置我上次已 ...
- java架构之路-(Redis专题)Redis的高性能和持久化
上次我们简单的说了一下我们的redis的安装和使用,这次我们来说说redis为什么那么快和持久化数据 在我们现有的redis中(5.0.*之前的版本),Redis都是单线程的,那么单线程的Redis为 ...
- java架构之路-(Redis专题)redis面试助力满分+
1.Redis支持的数据类型? 答:五种,在第一节redis相关的博客我就说过,String,Hash,List,Set,zSet,也就是我们的字符串,哈希,列表,集合,有序集合五种.结构图如下. 2 ...
- java架构之路-(微服务专题)初步认识微服务与nacos初步搭建
历史演变: 以前我们都是一个war包,包含了很多很多的代码,反正我开始工作的时候做的就是这样的项目,一个金融系统,代码具体多少行记不清楚了,内部功能超多,但是实际能用到的不多,代码冗余超大,每次部署大 ...
- java架构之路-(MQ专题)RabbitMQ安装和基本使用
RabbitMQ安装 我这里安装是使用阿里云的CentOS7.5来安装的,使用CentOS版本低于7的可能会报错. 1.安装rabbitmq所需要的依赖包 输入$ yum install build- ...
随机推荐
- mysql按关键词截取字符串
按关键字截取字符串 :substring_index(被截取字段,关键字,关键字出现的次数) eg:字符串:test.docx:test2.zip substring_index(file_name, ...
- .ssh/config 文件的解释算法及配置原则
前言 SSH 是连接远程主机最常用的方式,尽管连接到耽搁主机的基本操作非常直接,但当你开始使用大量的远程系统时,这就会成为笨重和复杂的任务. 幸运的是,OpenSSH 允许您提供自定义的客户端连接选项 ...
- 痞子衡嵌入式:MCUBootUtility v2.0来袭,i.MXRT1010哪里逃
-- 恩智浦半导体从2017年10月开始正式推出业内首款跨界处理器-i.MX RT系列,如今距离该系列第一款i.MXRT1050发布已过去近2年,i.MX RT系列在行业里应用越来越广泛,i.MX R ...
- 深入集合类系列——HashMap和HashTable的区别
含义:HashMap是基于哈希表的Map接口的非同步实现.允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变. 数据结构:HashMap实际上是一个“链表散列”的数据结 ...
- jQuery鼠标滑过横向时间轴效果
jQuery鼠标滑过横向时间轴效果---效果图: jQuery鼠标滑过横向时间轴效果---全部代码: <!DOCTYPE html> <html> <head> & ...
- H5刮刮卡效果
效果图: 核心就是使用ctx.globalCompositeOperation = 'destination-out'; 全部代码: <!DOCTYPE html> <html> ...
- Mysql高手系列 - 第18篇:mysql流程控制语句详解(高手进阶)
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第18篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...
- ELK 学习笔记之 elasticsearch Shard和Segment概念
Shard和segment概念: 转载: http://blog.csdn.net/likui1314159/article/details/53217750 Shard(分片) 一个Shard就是一 ...
- MongoDB 学习笔记之 GridFS
GridFS: GridFS 是 MongoDB 的一个用来存储/获取大型数据(图像.音频.视频等类型的文件)的规范.它相当于一个存储文件的文件系统,但它的数据存储在 MongoDB 的集合中.Gri ...
- MongoDB 学习笔记之 入门安装和配置
下载MongoDB: 下载解压即可使用. 为了启动方便和统一管理, 在Mongo根目录下建立/data, /logs, /conf文件夹. 在conf文件夹下建立mongodb.conf 文件,基本配 ...