Redis的学习笔记 目录
本笔记记录在学习Redis过程中的知识点
学习视频来源于——哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
https://www.bilibili.com/video/av51989396/?p=1
1. Redis 介绍
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,hash,zset等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
2. Redis键
Redis实例默认创建16个库,各个库的数据不相通,默认进入“0”号库。
当获取value时的位置索引是0和-1时,获取对象全部value
通用命令 | 描述 |
---|---|
SELECT SourcesNumber | 进入对应的库 |
MOVE key SourcesNumber | 将键值对移动到新的库内 |
TYPE key | 查看key是什么类型 |
KEYS pattern | 展示对应模式(pattern)的key |
DEL key | 当key存在时删除 |
TTL key | 查看还有多少秒过期 |
EXPIRE key sec | 设置key在sec秒后过期 |
EXISTS key | 判断某个key是否存在 |
2.1. Redis 字符串(String)
键值对形式,一个key对应一个value。
命令 | 描述 |
---|---|
SET key value | 创建key和value或更新key对应的value |
GET key | 获取key对应的value |
APPEDN key value | 在key的原value后拼接上新的value |
STRLEN key | 获取key的value长度 |
INCR key | 将key的value增加1 |
DECR key | 将key的value减少1 |
INCRBY key number | 将key的value增加number |
DECRBY key number | 将key的value减少number |
GETRANGE key num1 num2 | 摘取key的value中从num1到num2的值 |
SETRANGE key number value | 在key原value的number位置上插入新value值 |
SETEX key sec value | 创建key时给该key设置sec秒的存活时间 |
SETNX key value | 创建key对象如果原本不存在 |
MSET key1 value1 key2 value2 … | 批量创建多个key对象 |
MGET key1 key2 … | 批量查询多个key对应的value |
MSETNX key1 value1 key2 value2 … | 对应的多个key对象都不存在时创建多个key对象 |
2.2. Redis 列表(List)
- 一个list对应多个value,类似双向链表,可双向插入value。
- 如果list对象不存在,则创建新链表,如果存在则新增内容,如果value值全部移除,list对象也被移除。
- 链表头尾操作效率极高,但中间元素的操作效率很低。
命令 | 描述 |
---|---|
LPUSH list value1 value2 … | 创建一个list对象并赋多个value,左边插入 |
LRANGE list num1 num2 … | 从左边开始获取list对象从num1到num2位置的值 |
RPUSH list value1 value2 … | 创建一个list对象并赋多个value,右边插入 |
LPOP list | 抛出list对象最左边的的单个value |
RPOP list | 抛出list对象最右边的的单个value |
LINDEX list number | 查找list对象的number位置上的value |
LLEN list | 获取list对象的value个数 |
LREM list number value | 在list对象中删除number个value |
LTRIM key index end | list对象只保留从index到end位置(包括)的值 |
RPOPLPUSH list1 list2 | 在list1对象中抛出最右边的单个value插入到list2对象的最左边 |
LSET list index value | 将list对象index位置上的原value改为新的value |
LINSERT key before value1 value2 | 在list对象value1前面插入一个value2 |
LINSERT key after value1 value2 | 在list对象value1后面插入一个value2 |
2.3. Redis 集合(Set)
一个set对应多个value,类似于list,但value自动去重。
命令 | 描述 |
---|---|
SADD set value1 value2 … | 创建或更新set对象在去重后增加多个value |
SMEMBERS set | 获取set对象的所有value |
SISMEMBER set value | 判断value是否存在于set对象中 |
SCARD set | 获取set对象中的元素个数 |
SREM set value | 删除set对象中的value元素 |
SRANDMEMBER set number | 在set对象中随机取出number个value |
SPOP set | 随机抛出一个value元素 |
SMOVE set1 set2 value | 将set1中的value赋值给set2 |
SDIFF set1 set2 | 差集,获取在set1中不在set2中的value元素 |
SINTER set1 set2 | 交集,获取在set1和set2中共同拥有的value元素 |
SUNION set1 set2 | 并集,合并set1和set2中的元素 |
2.4. Redis 哈希(Hash)
一个hash对象对应一个键值对,相当于hash是第一层索引,key是二层索引,最后才是对应的值。
可参考数据库索引优化的B+树。
命令 | 描述 |
---|---|
HSET hash key value | 在hash对象创建一个key-value键值对 |
HGET hash key | 获取hash对象中key的value |
HMSET hash key1 value1 key2 value2 … | 在hash对象中创建多个键值对 |
HMGET hash key1 key2 … | 获取hash对象中多个key的value |
HGETALL hash | 获取hash对象的所有键值对 |
HDEL hash | 删除hash对象 |
HDEL hash key | 删除hash对象中的key对应的键值对 |
HLEN hash | 获取hash对象键值对个数 |
HEXISTS hash key | 判断hash对象是否存在key对应的键值对 |
HKEYS hash | 获取hash对象里面的全部key |
HVALS | 获取hash对象里面的所有value |
HINCRBY hash key number | 将hash对象中key对应的value增加number |
HINCRBYFLOAT hash key float | 将hash对象中key对应的value增加float |
HSETNX hash key value | 当hash对象中不存在当前key的时候增加当前key和value这一个键值对 |
2.5. Redis 有序集合(sorted set)
在set的基础上加一个score,score为一个数字。
下表中Score-Value键值对简称为键值对,sorted set集合对象简称为zset对象。
命令 | 描述 |
---|---|
ZADD zset score1 value1 score2 value2 … | 创建一个zset对象 |
ZRANGE zset 0 -1 | 获取zset对象的所有value |
ZRANGE zset 0 -1 withscores | 获取zset对象的所有score和value |
ZRANGEBYSCORE zset score1 score2 | 获取在score1(包含)到score2(包含)中的所有value |
ZRANGEBYSCORE zset score1 (score2 | 获取在score1(包含)到score2(不包含)中的所有value |
ZRANGEBYSCORE zset (score1 (score2 | 获取在score1(不包含)到score2(不包含)中的所有value |
ZREM zset value | 移除zset对象中的value值,score值同时移除 |
ZCARD zset | 获取zset中的键值对个数 |
ZCOUNT zset score1 score2 | 统计zset中处于score1和score2中的键值对个数 |
ZRANK zset value | 获取value对应的下标值 |
ZSCORE zset value | 获取value对应的score值 |
ZREVRANK zset value | 逆序获取value对应的下标值 |
ZREVRANGE zset | 逆序获取zset对象的所有value |
ZREVRANGEBYSCORE zset score1 score2 | 获取在score1(包含)到score2(包含)中的所有value |
2.5.1. 关于Score
Score前面带0
Score带小数点
Score带字符,d和f是代表double和float类型的后缀,但是Score直接支持小数。
3. Redis持久化
因Redis的数据在RAM中使用,若发生宕机或停电的情况,RAM内的数据会丢失,因此需要对数据进行持久化操作。
3.1. RDB(Redis DataBase)
Redis停止主进程的IO操作后创建(Fork)一个与主进程一模一样的子进程对数据进行持久化操作,每次持久化好的快照文件替换上一次的快照文件,Redis重启时会通过加载dump.rdb文件恢复数据。
优点:适合大规模的数据恢复,对数据完整性和一致性要求不高
缺点:RDB是周期性的备份,如果Redis因意外关掉就会丢失最后一次快照后的所有修改,创建(Fork)的子进程可能会导致系统因资源不足而崩溃
RDB默认触发保存的机制是
默认save命令参数 | 含义 |
---|---|
save 900 1 | 900秒内修改1次 |
save 120 10 | 120秒内修改10次 |
save 60 10000 | 60秒内修改10000次 |
RDB的手动保存命令为
> save
//全部阻塞后进行保存
> bgsave
//在后台异步进行快照操作,快照同时还可以相应客户端请求
//可以通过lastsave命令获取最后一次成功执行快照的时间
# Redis-check-dump --fix
//RDB文件修复
RDB总结:
- RDB是一个非常紧凑的文件
- RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,其余的工作交由子进程进行,父进程需要停止所有IO操作
- 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些
- 数据丢失风险大
- RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大时,fork的过程非常耗时,可能会导致Redis在一些毫秒内不能响应客户端请求
3.1.1. 配置文件(SNAPSHOTTING块)
stop-writes-on-bgsave-error no
//当bgsave出错时数据将不能修改,默认配置是yes
rdbcompression yes
//设置持久化的快照文件是否进行LZF算法进行压缩
rbdchecksum yes
//设置持久化的快照文件是否进行CRC64算法进行数据校验
3.2. AOF(Append Only File)
采用日志的形式来记录每个写操作,并追加到文件中。Redis 重启后会根据日志文件的内容将写入指令顺序执行一次以完成数据的恢复工作。
优点:可以通过修改配置对同步机制进行修改
缺点:相同数据集的数据文件会远大于RDB文件,恢复速度慢于RDB,AOF运行效率要慢于RDB,每秒同步策略效率较好,不同步效率和RDB相同
# Redis-check-aof --fix
//AOF文件修复
AOF总结:
- AOF文件是一个只进行追加的日志文件
- Redis可以在AOF文件体积变得过大时,自动在后台对AOF进行重写
- AOF文件有序的保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,容易被人读懂,文件分析较为轻松
- 对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积
- 根据所使用的fsync策略,AOF的速度可能会慢于RDB
3.2.1. Rewrite(AOF文件重写)
AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩。
触发机制:默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
auto-aof-rewrite-percentage 100
//上一次rewrite的文件大小的100%
auto-aof-rewrite-min-size 64mb
//自动rewrite文件的最小大小64mb
> bgrewriteaof
//只保留可以恢复数据的最小指令集
3.2.2. 配置文件(APPEND ONLY MODE块)
appendonly yes
//开启AOF,默认是no
Appendfsync everysec
//AOF同步策略
//always 同步持久化,每次发生数据变更会被立即记录到磁盘,性能差但完整性比较好
//everysec 出厂默认推荐,异步操作,每秒记录,如果宕机,有数据丢失
//no 从不同步
3.3. 持久化总结
- RBD持久化方式能够在指定的时间间隔能对数据进行快照存储
- AOF持久化方式记录每次对服务器的写操作,当服务器重启的时候会重写执行这些命令来恢复原始的数据,AOF命令以Redis协议追加保存每次写的操作到文件末尾,Redis能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
- 只做缓存:如果只需要数据在服务器运行的时候存在,可以不使用任何持久化方式
- 同时开启两种持久化方式
- 当Redis重启的时候会优先载入AOF文件来恢复原始数据,因为通常情况下AOF文件保存的数据集要比RBD文件保存的数据集更完整
- 不建议只使用AOF进行数据持久化,RDB更适合对数据集的完整的备份,AOF可能会存在一些BUG
4. Redis 事务
Redis对事务仅部分支持,部分出错不会导致回滚
命令 | 含义 |
---|---|
DISCARD | 取消事务,放弃执行事务块内的所有命令 |
EXEC | 执行所有事务块内的命令 |
MULTI | 标记一个事务块的开始 |
UNWATCH | 取消WATCH命令对所有key的监视 |
WATCH key [key…] | 监视一个(或多个)key,如果在事务执行之前这些key被其它命令所改动,那么事务将被打断 |
4.1. 事务的三个阶段
- 开启:MULTI命令开启事务
- 入队:将多条命令入队到事务中,这些命令不会被立即执行,而是在事务队列中等待
- 执行:EXEC命令触发事务的执行
4.2. 事务的三个特性
- 单独的隔离操作:事务中的所有命令都会被序列化,按顺序的执行。事务在执行的过程中,不会被其它客户端发送来的请求所打断
- 没有隔离级别:队列中的命令没有提交之前都不会被实际的执行,因此不存在“事务内查询本次事务里的更新,但事务未提交之前事务外的查询不能获取”的问题
- 不保证原子性:Redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
4.3. WATCH监控
监控key,如果key对应的value被修改,则事务中断。一旦执行EXEC后,之前加的watch锁都会被取消掉。
4.3.1. 加锁
4.3.1.1. 乐观锁(常用)
为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
乐观锁的机制是:CAS(Check And Set)
4.3.1.2. 悲观锁
指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
4.4. 事务总结
- WATCH指令类似于乐观锁,事务提交时,如果key的value已被别的客户端改变,整个事务队列都不会被执行
- 通过WATCH命令在事务执行之前监控了多个key,如果在WATCH之后有任何key的value发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败
5. Redis的复制(Master/Slave)
主机数据更新后根据配置和策略,自动同步到备用机的master/slaver机制,Master以写为主,Slave以读为主。
作用:读写分离,容灾备份
5.1. 常见用法
5.1.1. 一主二从
Slave:从机,跟随Master,连接到主机后复制一遍Master已有的数据,只能对数据进行读取,不能写入,关闭后会断开与Master的连接,重启需要重新手动与Master进行连接(除非写入配置文件自动连接)
slaveof 主机IP 主机端口
Master:主机,关闭后Slave会原地待命,重启后仍是Master
5.1.2. 薪火相传
- 上一个Slave可以是下一个Slave的Master,Slave同样可以接受其它Slave的连接和请求,那么该Slave作为链条中的下一个的Master,可以有效减轻Master的写压力
- 中途变更转向会清除之前的数据,重新建立拷贝最新的Master的数据
slaveof 新主机IP 新主机端口
5.1.3. 反客为主
使当前数据库停止与其它数据库的同步,转成主数据库
slaveof no one
//手动将从机变为主机
5.2. 复制的原理
- Slave启动成功连接到Master后会发送一个sync命令
- Master接到命令启动后台的存盘进程,同时收集所有收集到的用于修改数据集命令,在后台进程执行完毕后,Master将传送整个数据文件到Slave,以完成一次完全同步
- 全量复制:Slave在接收到数据库文件数据后,将其存盘并加载到内存中。
- 增量复制:Master继续将新的所有收集到的修改命令依次传给Slave,完成同步
- 只要是重新连接Master,自动完成一次全量复制
5.3. 哨兵模式
自动版的反客为主,Slave后台监控主机是否故障,如果故障了则投票选举一个Slave作为Master,原Master重启后变为Slave
5.3.1. 使用步骤
- 先使用一主二从模式
- 自定义的/myredis 目录下新建sentinel.conf文件
- 配置哨兵,填写内容
sentinel monitor 自定义名字 被监视的主机IP 被监视的主机端口 当选的票数
- 启动哨兵
# redis-sentinel /myredis/sentinel.conf
5.4. 复制缺点
由于所有的写操作都先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave会有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题变得更加严重
表格外的注解说明:
> 是在数据库里的操作命令
# 是Linux命令
没有前缀的是Redis配置文件的内容