Redis基础
Redis基础
Redis介绍
是一个基于 C 语言开发的开源 NoSQL 数据库。
Redis 的数据是保存在内存中的(内存数据库,支持持久化),因此读写速度非常快,被广泛应用于分布式缓存方向。并且,Redis 存储的是 KV 键值对数据
为什么Redis这么快?
Redis 内部做了非常多的性能优化,比较重要的有下面 3 点:
- Redis 基于内存,内存的访问速度比磁盘快很多;
- Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型,主要是单线程事件循环和 IO 多路复用(Redis 线程模式后面会详细介绍到);
- Redis 内置了多种优化过后的数据类型/结构实现,性能非常高。
- Redis 通信协议实现简单且解析高效。
那既然都这么快了,为什么不直接用 Redis 当主数据库呢?主要是因为内存成本太高且 Redis 提供的数据持久化仍然有数据丢失的风险。
为什么要用Redis?
1、访问速度更快
传统数据库数据保存在磁盘,而 Redis 基于内存,内存的访问速度比磁盘快很多。引入 Redis 之后,我们可以把一些高频访问的数据放到 Redis 中,这样下次就可以直接从内存中读取,速度可以提升几十倍甚至上百倍。
2、高并发
一般像 MySQL 这类的数据库的 QPS 大概都在 4k 左右(4 核 8g) ,但是使用 Redis 缓存之后很容易达到 5w+,甚至能达到 10w+(就单机 Redis 的情况,Redis 集群的话会更高)。
QPS(Query Per Second):服务器每秒可以执行的查询次数;
由此可见,直接操作缓存能够承受的数据库请求数量是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。进而,我们也就提高了系统整体的并发。
3、功能全面
Redis 除了可以用作缓存之外,还可以用于分布式锁、限流、消息队列、延时队列等场景,功能强大!
Redis应用场景
- 分布式锁:通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下,我们都是基于 Redisson 来实现分布式锁
- 限流:一般是通过 Redis + Lua 脚本的方式来实现限流。如果不想自己写 Lua 脚本的话,也可以直接利用 Redisson 中的
RateLimiter
来实现分布式限流,其底层实现就是基于 Lua 代码+令牌桶算法。 - 消息队列:Redis 自带的 List 数据结构可以作为一个简单的队列使用。Redis 5.0 中增加的 Stream 类型的数据结构更加适合用来做消息队列。它比较类似于 Kafka,有主题和消费组的概念,支持消息持久化以及 ACK 机制。
- 延时队列:Redisson 内置了延时队列(基于 Sorted Set 实现的)。
- 分布式 Session :利用 String 或者 Hash 数据类型保存 Session 数据,所有的服务器都可以访问。
- 复杂业务场景:通过 Redis 以及 Redis 扩展(比如 Redisson)提供的数据结构,我们可以很方便地完成很多复杂的业务场景比如通过 Bitmap 统计活跃用户、通过 Sorted Set 维护排行榜。
- ……
Redis数据类型
5 种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)
3 种特殊数据类型:HyperLogLog(基数统计)、Bitmap (位图)、Geospatial (地理位置)
String类型
适合存简单数据
存储的数据:单个数据,最简单的数据存储类型,也是最常用的数据存储类型。
string,他就是存一个字符串,注意是value那一部分是一个字符串,它是redis中最基本、最简单的存储数据的格式。
存储数据的格式:一个存储空间保存一个数据
每一个空间中只能保存一个字符串信息,这个信息里边如果是存的纯数字,他也能当数字使用,我们来看一下,这是我们的数据的存储空间。
Hash类型
适合存对象
新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
需要的存储结构:一个存储空间保存多个键值对数据
hash类型:底层使用哈希表结构实现数据存储
List类型
适合存有顺序的数据
数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
list类型:保存多个数据,底层使用双向链表存储结构实现
Set类型
适合存不重复value的数据
新的存储需求:存储大量的数据,在查询方面提供更高的效率
需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
Redis持久化
不知道大家有没有遇见过,就是正工作的时候停电了,如果你用的是笔记本电脑还好,你有电池,但如果你用的是台式机呢,那恐怕就比较灾难了,假如你现在正在写一个比较重要的文档,如果你要使用的是word,这种办公自动化软件的话,他一旦遇到停电,其实你不用担心,因为它会给你生成一些其他的文件。
我们说自动恢复,其实基于的一个前提就是他提前把你的数据给存起来了。你平常操作的所有信息都是在内存中的,而我们真正的信息是保存在硬盘中的,内存中的信息断电以后就消失了,硬盘中的信息断电以后还可以保留下来
将文件由内存中保存到硬盘中的这个过程,我们叫做数据保存,也就叫做持久化。但是把它保存下来不是你的目的,最终你还要把它再读取出来,它加载到内存中这个过程,我们叫做数据恢复
什么是持久化
(1)什么是持久化?
利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化 。
持久化用于防止数据的意外丢失,确保数据安全性。
(2)持久化过程保存什么?
我们知道一点,计算机中的数据全部都是二进制,如果现在我要你给我保存一组数据的话,你有什么样的方式呢,其实最简单的就是现在长什么样,我就记下来就行了,那么这种是记录纯粹的数据,也叫做快照存储,也就是它保存的是某一时刻的数据状态。
还有一种形式,它不记录你的数据,它记录你所有的操作过程,比如说大家用idea的时候,有没有遇到过写错了ctrl+z撤销,然后ctrl+y还能恢复,这个地方它也是在记录,但是记录的是你所有的操作过程,那我想问一下,操作过程,我都给你留下来了,你说数据还会丢吗?肯定不会丢,因为你所有的操作过程我都保存了。这种保存操作过程的存储,用专业术语来说可以说是日志,这是两种不同的保存数据的形式啊。
总结一下:
第一种RDB文件:将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据。
第二种AOF文件:将数据的操作过程进行保存,日志形式,存储操作过程,存储格式复杂,关注点在数据的操作过程。
RDB文件存储
save指令的执行会阻塞当前Redis服务器,直到当前RDB过程完成为止,有可能会造成长时间阻塞,线上环境不建议使用。
save
bgsave指令,bg其实是background的意思,后台执行的意思
bgsave
当执行bgsave的时候,客户端发出bgsave指令给到redis服务器。注意,这个时候服务器马上回一个结果告诉客户端后台已经开始了,与此同时它会创建一个子进程,使用Linux的fork函数创建一个子进程,让这个子进程去执行save相关的操作,此时我们可以想一下,我们主进程一直在处理指令,而子进程在执行后台的保存,它会不会干扰到主进程的执行吗?
答案是不会,所以说他才是主流方案。子进程开始执行之后,它就会创建啊RDB文件把它存起来,操作完以后他会把这个结果返回,也就是说bgsave的过程分成两个过程,第一个是服务端拿到指令直接告诉客户端开始执行了;另外一个过程是一个子进程在完成后台的保存操作,操作完以后回一个消息。
RDB优点:
- RDB是一个紧凑压缩的二进制文件,存储效率较高
- RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
- RDB恢复数据的速度要比AOF快很多
- 应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。
RDB缺点
- RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据
- bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能
- Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象
AOF文件存储
AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令 达到恢复数据的目的。与RDB相比可以简单理解为由记录数据改为记录数据产生的变化
AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式
为什么要有AOF,这得从RDB的存储的弊端说起:
- 存储数据量较大,效率较低,基于快照思想,每次读写都是全部数据,当数据量巨大时,效率非常低
- 大数据量下的IO性能较低
- 基于fork创建子进程,内存产生额外消耗
- 宕机带来的数据丢失风险
那解决的思路是什么呢?
- 不写全数据,仅记录部分数据
- 降低区分数据是否改变的难度,改记录数据为记录操作过程
- 对所有操作均进行记录,排除丢失数据的风险
AOF执行策略
AOF写数据三种策略(appendfsync)
always(每次):每次写入操作均同步到AOF文件中数据零误差,性能较低,不建议使用。
everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,在系统突然宕机的情况下丢失1秒内的数据 数据准确性较高,性能较高,建议使用,也是默认配置
no(系统控制):由操作系统控制每次同步到AOF文件的周期,整体过程不可控
什么叫AOF重写?
随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。AOF文件重 写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。简单说就是将对同一个数据的若干个条命令执行结果转化成最终结果数据对应的指令进行记录。
AOF重写作用
- 降低磁盘占用量,提高磁盘利用率
- 提高持久化效率,降低持久化写时间,提高IO性能
- 降低数据恢复用时,提高数据恢复效率
AOF重写规则
进程内具有时效性的数据,并且数据已超时将不再写入文件
非写入类的无效指令将被忽略,只保留最终数据的写入命令
如del key1、 hdel key2、srem key3、set key4 111、set key4 222等
如select指令虽然不更改数据,但是更改了数据的存储位置,此类命令同样需要记录
对同一数据的多条写命令合并为一条命令
如lpushlist1 a、lpush list1 b、lpush list1 c可以转化为:lpush list1 a b c。
为防止数据量过大造成客户端缓冲区溢出,对list、set、hash、zset等类型,每条指令最多写入64个元素
手动重写:
bgrewriteaof
RDB与AOF对比(优缺点)
持久化方式 | RDB | AOF |
---|---|---|
占用存储空间 | 小(数据级:压缩) | 大(指令级:重写) |
存储速度 | 慢 | 快 |
恢复速度 | 快 | 慢 |
数据安全性 | 会丢失数据 | 依据策略决定 |
资源消耗 | 高/重量级 | 低/轻量级 |
启动优先级 | 低 | 高 |
RDB与AOF应用场景
RDB与AOF的选择之惑
- 对数据非常敏感,建议使用默认的AOF持久化方案
AOF持久化策略使用everysecond,每秒钟fsync一次。该策略redis仍可以保持很好的处理性能,当出 现问题时,最多丢失0-1秒内的数据。
注意:由于AOF文件存储体积较大,且恢复速度较慢
- 数据呈现阶段有效性,建议使用RDB持久化方案
数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),且恢复速度较快,阶段 点数据恢复通常采用RDB方案
注意:利用RDB实现紧凑的数据持久化会使Redis降的很低,慎重总结:
综合比对
- RDB与AOF的选择实际上是在做一种权衡,每种都有利有弊
- 如不能承受数分钟以内的数据丢失,对业务数据非常敏感,选用AOF
- 如能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选用RDB
- 灾难恢复选用RDB
- 双保险策略,同时开启 RDB和 AOF,重启后,Redis优先使用 AOF 来恢复数据,降低丢失数据的量