一、什么是redis
Redis是一个NoSQL(非关系型数据库)数据库之一,是一个用C语言开发的一个开源的高性能键值对(key-value)数据库或者说是一个缓存键值对数据库 ,用作数据库、缓存、消息中间件等。它支持多种数据结构,包括字符串、哈希表、列表、集合、有序集合等,并且支持丰富的操作命令,如查找、插入、删除等。
(1)从Redis缓存中获取数据,如果存在数据,直接返回值。
(2)如果不存在,执行数据库的查询方法
(3)将数据库中的值放入缓存,并返回值
二、redis的优点
- 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) ;
- 支持丰富数据类型,支持string,list,set,sorted set,hash;
- 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
- 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除。
三、redis的数据结构
五种数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)
- String:可以是字符串、整数或者浮点数,字符串最大支持512MB。对整个字符串或者字符串的其中一部分执行操作;对象和浮点数执行自增(increment)或者自减(decrement) (使用场景:缓存数据,简单计数,定期过时)
- List:有序的字符串列表,可以当做栈、队列或者阻塞队列使用。读取单个或者多个元素;根据值来查找或者移除元素。 (使用场景:用户排队,有序消息)
- Set:无序的字符串集合,添加、获取、移除单个元素;检查一个元素是否存在于某个集合中;计算交集、并集、差集;从集合里随机获取元素。 (使用场景:去重,交集,并集,差集,获取随机数)
- Hash:包含键值对的无序散列表。添加、获取、移除单个键值对;获取所有键值对。 (使用场景:同一资源的不同属性)
- Zset:字符串成员(member)与浮点数分值(score)之间的有序映射,元素的排列顺序由分值的大小决定,添加、获取、删除单个元素;根据分值范围(range)或者成员来获取元素。 (使用场景:排行榜,分数)
四、Redis的持久化功能
Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘上,一旦服务器退出,数据库状态约会消失。所以,Redis提供了持久化功能。两种方式:
- RDB方式:在指定的时间间隔内将内存中的数据集快照写入磁盘,它恢复时是将快照文件直接读到内存里。
- AOF方式:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令,达到恢复数据的目的。
五、key过期后的回收(删除策略)
- 定时删除:在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。
- 惰性删除:放任过期键不管,每次从键空间中获取键时,检查该键是否过期,如果过期,就删除该键,如果没有过期,就返回该键。
- 定期删除:每隔一段时间,程序对数据库进行一次检查,删除里面的过期键,至于要删除哪些数据库的哪些过期键,则由算法决定。
其中定时删除和定期删除为主动删除策略,惰性删除为被动删除策略
六、逐出算法
Redis使用内存存储数据,在执行每个命令前会调用freeMenoryNeeded()方法检测内存是否充足,如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据作为当前指令清理存储空间。
检查易失数据(可能会过去的数据)
- volatile-lru:挑选最近最少使用的数据淘汰
- volatile-lfu:挑选最近使用次数最少的数据淘汰
- volatile-ttl:挑选将要过期的数据淘汰
- volatile-random:任意选择数据淘汰
检查全库数据
- allkeys-lru:挑选最近最少使用的数据淘汰
- allkeys-lfu:挑选最近使用次数最少的数据淘汰
- allkeys-random:任意选择数据淘汰
放弃数据驱逐
七、redis常见问题的解决
(1)缓存预热:
就是系统启动前,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据
问题:
解决方案:
(2)缓存雪崩:
缓存雪崩是指缓存同一时间大面积的失效,所以,所有的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉
解决方案:
- 给不同的key的TTL 添加随机值
- 利用redis集群提高服务的可用性
- 给缓存业务添加降级限流策略
- 给业务添加多级缓存
(3)缓存击穿:
是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
(4)缓存穿透:
是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:
- 缓存空对象:请求的数据即使不存在也存进redis内存中 (简单易维护)
- 布隆过滤:将数据库中所有的查询条件,放入布隆过滤器中,当一个查询请求过来时,先经过布隆过滤器进行查,如果判断请求查询值存在,则继续查;如果判断请求查询不存在,直接丢弃。
八、Redis的模板类
Redis的模板类是一种封装了常用 Redis 操作的类,它可以简化 Redis 操作的代码,并提高代码的可读性。通常情况下,使用 Redis 的模板类可以避免在代码中直接使用 Redis 命令,而是使用预定义的方法。(redis提供了两种模板类)
RedisTemplate模板类:存时先将数据先序列化成字节数组再存入Redis。
StringRedisTemplate模板类(继承自RedisTemplate):存时先将数据先序列化成字符串再存入Redis。
两者的区别:
(1)两者数据各自存,各自取,数据不互通
- RedisTemplate存入数据后,key与value在Redis中均变为了字节数组。那么,如果使用StringRedisTemplate以相同的key去Redis中查询,会查询不到该key,则会报null。
- StringRedisTemplate存入数据后,key与value在Redis中均为可读数据。那么,如果使用RedisTemplate以相同key去Redus中查询,key变为了字节数组的形式,查询不到该字节数组形式的key,则会报null。
(2)序列化策略不同
- RedisTemplate采用JDK的序列化策略
- StringRedisTemplate采用String的序列化策略
八、Redis的应用场景
- 缓存 :作为
Key-Value
形态的内存数据库,Redis 最先会被想到的应用场景便是作为数据缓存。而使用 Redis 缓存数据非常简单,只需要通过string
类型将序列化后的对象存起来即可。 - 数据共享:数据共享分布式String 类型,因为 Redis 是分布式的独立服务,可以在多个应用之间共享
- 计数器:在 Redis 的数据结构中,
string
、hash
和sorted set
都提供了incr
方法用于原子性的自增操作。 - 时间轴:list作为双向链表,不光可以作为队列使用。如果将它用作栈便可以成为一个公用的时间轴。当用户发完微博后,都通过
lpush
将它存放在一个 key 为LATEST_WEIBO
的list
中,之后便可以通过lrange
取出当前最新的微博。 - 抽奖:利用set结构的无序性,通过 Spop( Redis Spop 命令用于移除集合中的指定 key 的一个或多个随机元素,移除后会返回移除的元素。 ) 随机获得值。