redis介绍
Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API的非关系型数据库。
因为是在数据存储在内存, 所以运行速度极快。大部分情况下运用在缓存,也有运用于分布式锁当中。
redis数据结构
(以下为菜鸟教程C过来的)
字符串(String)
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象
哈希(Hash)
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
列表(List)
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
集合(Set)
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
有序集合(sorted set)
有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
Redis HyperLogLog ( 2.8.9 版本新)
用来做基数统计的算法,优点在于在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素
redis持久化
redis持久化有两种模式:RDB和AOF
RDB
在指定的时间间隔能对你的数据进行快照存储
通过redis的两个功能函数 rdbSave(生成一个RDB文件存在磁盘当中) 与 rdbLoad(读取RDB文件)
同时RDB有两种触发方式:定时触发和手动触发
手动触发: 有两个函数 save和bgsave
save:会阻塞当前redis,因为redis是单线程,所以当redis实例较多会造成长时间阻塞,一般线上不会使用。
bgsave:Redis进程执行fork操作创建子进程,由子进程去进行RDB文件写入操作,只有在执行fork的时候会阻塞, bgsave命令是针对save阻塞问题做的优化。
优点:
因为使用fork通过子进程进行备份,所以对读的操作影响很小。
恢复大数据集时的速度比 AOF 的恢复速度要快。
RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,适合做冷备份。
缺点: 数据恢复时完整性较差,如果在最后一次备份之前宕机,那么数据无法恢复
redis 持久化配置默认就是RDB
AOF
记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据。
他会先将内容写入AOF文件中,然后在同步到磁盘。如果直接写入磁盘效率很低。
如果想更加深入了解 可以看下这篇文章 https://segmentfault.com/a/1190000015983518?utm_source=tag-newest
优点: 能保持数据的一致性和完整性
缺点: AOF文件比RDB文件大,在读取过程中,会比RDB更慢一些。
发布/订阅模式
这是redis的一种消息通讯模式,类似于观察者模式。举个例子:收音机,我们需要调到一个频道(Chanel),这样我们可以统一收到消息。具体操作可以去查看一下菜鸟教程的例子,这里我就不写代码了。
什么是 缓存雪崩 缓存穿透 缓存击穿
缓存穿透 程序在处理缓存时,一般是先从缓存查询,如果缓存没有这个key获取为null,则会从DB中查询,并设置到缓存中去。
按这种做法,那查询一个一定不存在的数据值,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。
缓存雪崩: 指的是大量缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。
缓存击穿: 指的是热点key在某个特殊的场景时间内恰好失效了,恰好有大量并发请求过来了,造成DB压力。
解决方案:
(引用:https://blog.csdn.net/muyi_amen/article/details/80229647)
1、再web服务器启动时,提前将有可能被频繁并发访问的数据写入缓存。—这样就规避大量的请求在第3步出现排队阻塞。
2、规范key的命名,并且统一缓存查询和写入的入口。这样,在入口处,对key的规范进行检测。–这样保存恶意的key被拦截。
3、Synchronized双重检测机制,这时我们就需要使用同步(Synchronized)机制,在同步代码块前查询一下缓存是否存在对应的key,然后同步代码块里面再次查询缓存里是否有要查询的key。 这样“双重检测”的目的,还是避免并发场景下导致的没有意义的数据库的访问(也是一种严格避免穿透的方案)。
这一步会导致排队,但是第一步中我们说过,为了避免大量的排队,可以提前将可以预知的大量请求提前写入缓存。
4、不管数据库中是否有数据,都在缓存中保存对应的key,值为空就行。–这样是为了避免数据库中没有这个数据,导致的平凡穿透缓存对数据库进行访问。
5、第4步中的空值如果太多,也会导致内存耗尽。导致不必要的内存消耗。这样就要定期的清理空值的key。避免内存被恶意占满。导致正常的功能不能缓存数据。