Redis
redis可以说是重中之重,几乎所有项目都会使用到redis。redis缓存数据库,又快又轻。
简历技能:
熟练使用Redis缓存数据库。 熟练使用基本五大数据结构命令和其他数据结构如:bitmaps、hyperloglogs、geospatial、redis事务、消息队列。 了解redis主从复制、哨兵模式、缓存穿透和雪崩。
redis基础数据结构
- string
- hash
- list
- set
- zset
Bitmaps
Redis 的 Bitmaps 不是一种独立的数据类型,它是String
5.1 谈谈redis
项目中用redis的,存储我们系统的用户token,常用的配置以及接口结果的缓存。
Redis提供了丰富的数据结构:
基础的五种:
- string(字符串,最基础的数据结构)
- list(按插入顺序排序的字符串元素的集合,基本就是链表)
- set(不重复且无序的字符串元素的集合,底层通过哈希表实现)
- sorted set(有序集合,类似set,每个元素都关联到一个叫score浮动数值)
- hash(哈希对象)
高级的4种:
HyperLog:用来基数统计,自动去重。
Bitmap:位图,支持按bit位来存储信息,可以用来实现布隆过滤器
Redis的性能极高,因为数据大部门是存储在内存中的,读写的速度极快,支持事务,支持拷贝,还有丰富的数据类型
当然Redis也有缺点,因为服务器的内存存储空间是有限的,需要开发者提前预估和删除不需要的数据,合理的发挥Redis的性能。另外当修改redis的数据之后,需要将持久化到硬盘的数据重新加入到内存中,时间比较久,这个时候Redis是无法正常运行的。
5.1redis在项目中的使用场景
- 缓存数据最常用,对经常需要查询且变动不频繁的数据常称作热点数据
- 消息队列,相当于消息订阅系统,比如ActiveMQ。List实现,PUB/SUB,stream
- 计数器,比如统计点击率、点赞率,redis具有原子性,可以避免并发问题
- 电商网站信息
- 热点数据
- 用户登录token,验证码
- 分布式锁
大白话举例:
- 项目中的业务数据和一些配置项使用缓存
- 配置项本身是在数据库中的,本身如果项目是单体架构的话,直接直接使用jvm本地缓存,或者是分布式多服务架构则就需要分布式缓存了,当然也可以使用JVM缓存,因为仅仅是配置项,不会轻易改动,改动一般发生在版本更新或者配置配错情况。因为JVM内存资源是比较紧缺的,当然也可以使用redis第三方中间键缓存。
- 业务接口返回的接口可以缓存起来,减少对数据库的压力,数据一般是修改不频繁,查询较多。另外还有用户登录之后的token,用户信息等,设置过期时间提供用户登录存活时间的功能。业务方法可以使用spring cache+redis的解决方案,快速集成和使用,通过重写RedisCache 类,在put方法时调整过期时间策略,打乱过期时间。
- 使用redis或者JVM缓存的大致流程是这样的,一般对于配置项,或者页面显示接口数据通过预热和项目启动后自动加载缓存多种方式缓存的。另外可以在处理类中在等到返回结果后保存到redis中,再次访问时先去redis查询有没有。然后提供接口:清除缓存的接口,重新加载缓存的接口,防止业务上线缓存失效或者未及时更新。
- 当redis缓存数据变大时,可以使用主从复制技术来达到读写分离
- 方便与其他系统对接,比如说,我们项目架构有PHP做接口,Java做接口和数据处理,当我们和php进行数据交互的时候,会把数据存储到redis中,达到数据共享的目的。
5.2 Redis补充
Redis缓存数据的一致性
- 真正意义上来讲数据库和缓存的数据是不可能一致的,数据分为最终一致和强一致俩俩类。如果业务中对数据的要求必须强一致那么就不能使用缓存。使用加锁的方式反而会影响性能。缓存能做的只能保证数据的最终一致性
- 不管是先删除缓存再删库或者是先删库再删缓存都有可能出现数据不一致的情况,因为读和写是并发的,我们没办法保证他们的先后顺序。尽可能的保证数据的一致性。具体应对策略还是要根据业务需求来定的。
- 解决方案:1.采用延时双删(修改前后双删)+过期时间。2:基于订阅数据库的binlog的同步机制。
Redis是如何删除key的?过期时间是如何自动过期的?
- redis过期删除采用定期删除,默认是每10ms检测一次,遇到过期的key则进行删除,这里的检测不是顺序检测而是随机检测。漏网之鱼:当我们去读/写一个已经过期的key时,会触发redis的惰性删除策略,直接干掉过期的key
- 定期删除,惰性删除,定期加惰性删除。
内存淘汰,数据淘汰策略
- 用户存储的一部分key是可以被Redis自动的删除,从而会出现从缓存中查不到数据的情况。加入我们的服务器内存是2G,但是随着业务的发展缓存的数据已经超过2G了。但是这并不影响我们程序的运行,因为操作系统的可见内存并不受物理内存的限制。物理内存不够用没关系,计算机会从硬盘中划出一片空间来作为虚拟内存。这就是Redis设计俩种应用场景的初衷:缓存、持久存储。
- volatile-lru删除过期时间最近最少使用的,volatile-ttl删除过期时间中要过期的,volatile-random过期时间任意选择淘汰allkeys-lru最少使用的alllkeys-random随机淘汰no-eviction禁止驱逐数据
- LRU算法:删除最老的数据,java实现方式 linkedHashMap,双向链表实现,新的放前面,老的在后面,删除最后的数据即可。
缓存穿透
- 缓存和数据库都没有的数据,被大量请求导致数据压力过大,甚至崩掉
- 解决方案:接口/业务层进行合法拦截;在缓存中增加一些空缓存。
缓存击穿
- 单个key缓存突然失效了,被大量请求导致数据库压力过大,可能瞬间打垮
- 解决方案:热点数据可以考虑永远不过期;如果缓存必定为空,当缓存数据为空时,设置一个互斥的锁,只让一个请求你通过,不管如何(包含异常)都需要释放锁。
缓存雪崩
- 缓存服务器宕机,不服务以及redis中大量key同时失效了,被大量请求访问到数据库,导致数据库崩溃
- 解决方案:如果redis缓存服务器没有宕机,热点数据设置用不过期,key的过期时间打散,使用2级缓存,如果1级缓存过期了使用2级缓存,如果宕机了,可以考虑多机房,集群分散开来。
Redis持久化机制
- RDB默认的持久化方法,按照一定的时间将内存的数据以快照的形式 保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件的save参数来定义快照的周期。
- 优点:只有一个文件dump.rdb,方便持久化。相对于数据集大时,比AOF的启动效率更高。
- 缺点:数据安全性低,RDB是间隔一段时间持久化,如果持久化之间redis发生故障,会发生数据丢失。
- AOF即Append Only File持久化,则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志文件恢复数据。
- 数据安全,aof持久化可以配置appendfsync属性,有always,每进行一次命令操作就记录到aof文件中一次。
- 几十中途服务器宕机,可以通过redis-check-aof工具解决数据一致性问题
- 缺点:AOF文件比RDB文件打,且恢复速度慢,数据集大的时候,比rdb启动效率低。
- 俩种方式同时开启时,数据恢复Redis会优先选择AOF恢复。
- AOF文件比RDB更新频率高,优先使用AOF还原数据
- AOF比RDB更安全也更大
- RDB性能比AOF好
- 如果俩个都配了,优先加载AOF
- RDB默认的持久化方法,按照一定的时间将内存的数据以快照的形式 保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件的save参数来定义快照的周期。
5.3 Redis集群了解吗?哨兵?主从复制?集群?
了解Redis集群的,集群是为了保证Redis的高可用,解决单点故障不能提供服务的问题。Redis中实现高可用集群还是比较简单,整个集群中包含master主节点和slave从节点,集群是超过3台及以上的redis节点。Redis中的哨兵模式维护整个集群中master、salve节点的可用性,如果master出现故障,哨兵会从slave中选出新的master节点。Redis中的主从复制是为了读写分离,提高性能,主节点将新增、修改的命令复制到从节点,从节点执行并加载到内存中,从节点提供Redis查询的功能。
- 主从复制为了数据备份,负载均衡,一个master可以有多个slave,读写分离
- 哨兵模式为了高可用,sentinel发现master挂了后,就会从slave重新选举一个master,监控,自动转移
- 集群cluster提高并发量,为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器
