Redis 是什么?
REmote Dictionary Server (Redis) 是由Salavtore Safilippo 编写的Key-Value 存储系统,它是一个开源的使用ANIS C 编写,遵守PSD协议,支持网络,可基于内存,分布式,可选持久性的存储数据库,并提供多种语言API。
Redis 通常被称为数据结构服务器,因为值(Value)可以是字符串(String)、哈希(Hash),列表(List),集合(sets)和有序集合等类型。
为什么要用Redis
- 性能高:Redis 以其极高的性能而著称,能够支持每秒数十万次的读写操作,使得Redis 成为处理高并发的理想选择,尤其是在需要快速响应的场景中,如:缓存,会话管理,排行榜等
- 丰富的数据类型:Redis 不仅支持基本的键值存储,还提供了丰富的数据类型,包含字符串,哈希表,集合,有序集合等
- 原子性操作:Redis的所有操作都是原子性的,这意味着操作要么完全执行,要么完全不执行,这种特性对于确保数据的一致性和完整性至关重要。
- 持久化:Redis 支持数据的持久化,可以i将内存中的数据保存到磁盘中,以便系统重启后恢复数据,这位Redis提供了数据安全性,确保数据不会因为系统故障丢失。
- 支持发布/订阅模式:Redis 内置了发布订阅模式(Pub/Sub),允许客户端之间通过消息传递进行通讯,这使得Redis可以作为消息队列和实时数据传输平台。
- 单线程模型:尽管Redis 是单线程的,但它通过高效的事件驱动模型来处理并发请求,确保了高性能和低延迟,单线程模型也简化了并发控制的复杂性。
- 主从复制:Redis 支持主从复制,可以通过从节点来备份数据或分担读请求。同哈皮手机壳i的可用性和系统的伸缩性。
- 应用场景广泛:Redis 被广泛应用于各种场景,包括但不限于缓存系统,会话存储,排行榜,实时分析,地理空间数据索引等等。
- 社区支持:Redis 拥有一个活跃的开发者社区,提供了大量的文档,教程和三方库,这为开发者提供了强大的支持和丰富的资源。
- 跨平台兼容性:Redis 可以在多种操作系统上运行,包括Linux,Mac OS和Windows ,这使得它能够在不同的技术栈中灵活部署。
Redis在Linux上的安装
下载地址 http://redis.io/download
安装步骤:
yum install gcc
下载Redis 源码文件
wget http://download.redis.io/releases/redis-5.0.3.tar.gz
tar -zxvf redis-5.0.3.tar.gz
cd redis-5.0.3
进入到解压好的redis-5.0.3目录下,进行编译与安装
make
进入conf 目录修改配置文件
daemonize yes #后台启动
protected-mode no #关闭保护模式,开启的话,只有本机才可以访问redis
# 需要注释掉bind
#bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可)
启动服务:
src/redis-server redis.conf
验证是否启动成功
ps -ef | grep redis
进入Redis客户端
src/redis-cli
退出客户端
quit
退出Redis服务
pkill redis-server
kill 进程号
src/redis-cli shutdown
Redis 指令
- keys
- 全量遍历键:用来列出所有满足正则字符串规则的keys,当Redis 中的数据量比较大时,需要避免使用。因为它这时的性能比较差,会造成Redis 卡顿。
- scan 渐进式遍历键
- 语法如下:Scan cursor [Match pattert] [Count count]
- scan 指令提供了三个参数,第一个是Cursur整数值(hash 桶的索引值)。第二个是正则模式,第三个是一次遍历的key的数量。(注意,这里是一个参考值,底层不一定遍历了这么次。)并不会返回符合条件结果的数量。比如:第一次遍历时,cursur 为 0 ,然后将返回结果中第一个整数值作为下一次遍历的cursor ,一直遍历到返回的cursor 的值为0时结束。
- 特别注意:scan 并非完美无暇,如果在Scan 的过程中如果有键的变化(增加,删除,修改),那么遍历的效果可能会碰到如下的问题:新增的键可能没有被遍历到,遍历出了重复的键等问题,也就是说scan 并不能保证完整的遍历出来所有的键。
- info 查看Redis 服务运行的信息,分为9快,每块的都有非常多的参数,这9块分别时
- Server 服务器运行的环境参数
- Clients 客户端相关信息
- Memory 服务器运行内存统计数据
- Persistence 持久化信息
- Stats 通用统计数据
- Replication 主从复制相关信息
- CPU CPU 使用情况
- Cluster 集群信息
- KeySpace 键值对统计数量信息
Redis的单线程和高性能
Redis 是单线程吗 ?
Redis 的单线程主要是指Redis 的网络IO 和键值对的读写是由一个线程来完成的,这也是Redis对外提供键值存储服务的主要流程。但是Redis的其他功能,比如持久化,异步删除,集群数据同步等等,其实都是由额外的线程执行的。
Redis单线程为什么还能那么快?
因为它的所有数据都在内存中,所有的运算都是内存级别的运算,而且单线程避免了因切换线程所带来的性能损耗,正因为Redis 是单线程,所以要小心使用Redis指令。对于那些耗时的指令(比如Keys),一定要谨慎使用,一不小心就可能会导致Redis 卡顿。
Redis 单线程是如何处理那么多的并发客户端连接
Redis 的IO 多路复用:Redis 利用Epoll 来时先IO的多路复用,将连接信息和事件放在队列中,依次放到文件事件分派器,由事件分发器分发给事件处理器。
下图为处理并发客户端链接的示例流程图
这里需要注意的时,在Redis.conf 文中修改,maxclients
Config get maxClients
Redis持久化
RDB 快照(Snapshot)
默认情况下,Redis 会将内存数据库保存到一个名为dump.rdb的二进制文件中。在默认情况下是在60s内修改1000次时会触发这个保存条件。
当然也可以通过对Redis 进行设置,让它可以满足在 “N 秒内数据集中至少由M个改动”这一条件被满足时,自动保存数据库
举例说明:
save 60 1000 #表示在60S 内,至少由1000个键值被改动就会触发保存
当然还可以手动执行生成RDB 快照,进入Redis 客户端执行命令save 或者bgsave 可以生成dump.rdb 文件,每次命令执行都会将所有redis内存快照到一个新的rdb文件中,并覆盖原有的rdb文件。
bgsave 的写时复制机制(COW)
redis 借助操作系统提供的写时复制机制(Copy-On-Write).生成快照的同时,依然可以正常处理命令。简单来说,bgsave 子进程是由主进程fork 生成的,可以共享主进程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入到RDB文件,此时,如果主线程对这些数据也都是度的操作,那么主线程和bgsave 的子进程互不影响,但是,如果主进程一定要修改数据,那么这块儿数据就会被复制一份出来,生成该数据的副本数据。然后,bgsave 子进程会把这个副本数据写入RDB文件按,而在这个过程中,主线程仍然可以直接修改原来的数据。
save 和 bgsave的对比
命令 | save | bgsave |
---|---|---|
IO 类型 | 同步 | 异步 |
是否阻塞Redis 命令 | 阻塞 | 否(在线程的子进程中调用fork函数是会有短暂的阻塞) |
复杂度 | O(n) | O(n) |
优点 | 不会额外消耗内存 | 不会阻塞客户端命令 |
缺点 | 阻塞客户端命令 | 需要在Fork 子进程,消耗内存 |
配置自动生成的RDB 文件后台配合的是bgsave
AOF (Append-only-file)
AOF 功能模式是不开启的,需要在配置文件中打开AOF 功能
# appendonly yes //放开这个注释
这里有三个选项:
- appendfsync always :表示每次有命令就追加到AOF 文件中,非常慢,但是非常安全
- appendfsync everysec:表示每秒fsync一次,足够快,并且故障时只会丢失1秒钟的数据
- appendfsync no : 表示从不Fsync,将数据交给操作系统来处理,更快,也更不安全。
这里推荐的是:appendfsync everysec ,并且也是默认措施,一秒钟执行一次fsync的策略,可以兼顾速度和安全性。
快照功能并不是非常耐久(durabler):如果Redis因为某些原因而造成的宕机,那么服务器将丢失最新写入,且仍未保存的数据。所以从Redis 1.1 开始,Redis 增加了一种完全耐久的持久化方式:AOF 持久化。将修改的每条指令记录进文件appendonly.aof 中,(先写入OS cache 中,每隔一段时间fsync到磁盘。)
举例说明一下:
set moran 666
*3
set
$5
zhuge
$3
666
这是一样Resp 协议的数据格式,*号后面的数字表示命令有多少个参数,$后面的数字表示这个参数有几个字符。
注意:如果执行带过期时间的set命令,aof文件里面记录的并不是原始命令,而是记录key 过期的时间戳
set zhangsan 888 ex 1000
*3
$3
set
$8
zhangsan
$3
666
*3
$9
PEXPTIREAT
zhangsan
$13
1604249786301
AOF 重写
AOF 文件中可能会有太多没用的指令,所以AOF 会定期根据内存的最新数据生成aof文件。
举例说明:
127.0.0.1:6379> incr readcount
(integer) 1
127.0.0.1:6379> incr readcount
(integer) 2
127.0.0.1:6379> incr readcount
(integer) 3
127.0.0.1:6379> incr readcount
(integer) 4
127.0.0.1:6379> incr readcount
(integer) 5
这时在redis中,aof 重写后的内容会变成
*3
set
$2
readCount
$1
5
在配置文件中可以配置AOF 自动重写的频率
# auto‐aof‐rewrite‐min‐size 64mb //aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就很快,重写的意义不大
2 # auto‐aof‐rewrite‐percentage 100 //aof文件自上一次重写后文件大小增长了100%则再次触发重写
手动重写AOF
进入redis 客户端,执行
bgrewriteof #进行AOF 重写
这里AOF 重写是在Redis fork出来的子进程中(与bgsave 的命令类似)。不会对redis正常处理命令有太多的影响。
RDB 与 AOF 对比
命令 | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 容易丢失数据 | 根据策略决定 |
Redis 4.0 混合持久化
重启 Redis 时,我们很少使用 RDB来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 RDB来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。 Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化
通过如下配置可以开启混合持久化(必须先开启aof)
# aof‐use‐rdb‐preamble yes
如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将
重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一
起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改
名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。
于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可以完全替代之前的
AOF 全量文件重放,因此重启效率大幅得到提升。
Redis 数据备份策略
- 写crontab定时调度脚本,每小时都copy一份rdb或aof的备份到一个目录中去,仅仅保留最近48小时的备份
- 每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份
- 每次copy备份的时候,都把太旧的备份给删了
- 每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏