Redis基础整理
redis简介
redis启动
命令:redis-server.exe redis.windows.conf
redis核心文件
- redis-server.exe 服务器启动命令
- redis-cli.exe 命令行客户端
- redis.windows.conf redis核心配置文件
- redis-benchmark.exe 性能测试工具
- redis-check-aof.exe AOF文件修复工具
- redis-check-dump.exe RDB文件检查工具(快照持久化文件)
基本操作
- 添加:设置 key,value 数据;设置 key,value 数据(set name itheima)
- 多个添加查询:(mset key1 value1 key2 value2)(mget key1 key2)
- 查询:根据 key 查询对应的 value,如果不存在,返回空;get key(get name)
- 删除数据:del key(del name)
- 清除屏幕信息;clear
- 获取数据字符个数(字符串长度)(strlen key)
- 追加信息到原始信息后部(如果原始信息存在就追加,否则新建)(append key value)
- 退出quit exit
数据存储类型介绍
Redis 数据类型(5种常用)
string :String
hash:HashMap
list:LinkedList
set:HashSet
sorted_set:TreeSet
String
redis 自身是一个 Map,其中所有的数据都是采用 key : value 的形式存储数据类型指的是存储的数据的类型,也就是 value 部分的类型,key 部分永远都是字符串
string 类型数据的增减操作
-
设置数值数据增加指定范围的值
incr key
incrby key increment
incrbyfloat key incre -
设置数值数据减少指定范围的值
decr key
decrby key incrementstring在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算。
redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响。
按数值进行操作的数据,如果原始数据不能转成数值,或超越了redis 数值上限范围,将报错。
Tips :
- redis用于控制数据库表主键id,为数据库表主键提供生成策略,保障数据库表的主键唯一性
- 此方案适用于所有数据库,且支持数据库集群
控制生命周期操作
设置数据具有指定的生命周期
setex key seconds value
psetex key milliseconds value(设置毫秒)
Tips 2:
redis 控制数据的生命周期,通过数据是否失效控制业务行为,适用于所有具有时效性限定控制的操作
String 类型数据命名规范
数据库中的热点数据key命名惯例
表名:主键命:主键值:字段名(eg:order🆔12345678:name)
hash类型
新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
需要的存储结构:一个存储空间保存多个键值对数据
hash类型:底层使用哈希表结构实现数据存储
hash 类型数据的基本操作
- 添加/修改数据 hset key field value
- 获取数据 hget key field :hgetall key
- 删除数据 hdel key field1 [field2]
- 添加/修改多个数据 hmset key field1 value1 field2 value2
- 获取多个数据hmget key field1 field2
- 获取哈希表中字段的数量 hlen key
- 获取哈希表中是否存在指定的字段 hexists key field
- 获取哈希表中所有的字段名或字段值 hkeys key (hvals key)
- 设置指定字段的数值数据增加指定范围的值hincrby key field increment: hincrbyfloat key field increment
- hsetnx key field value (没有数据才更改,已有数据就不更改)
hash 类型数据操作的注意事项
- *hash类型下的value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取到,对应的值为(nil)
- 每个 hash 可以存储 2 32 - 1 个键值对
- hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了存储大量对象而设计的,切记不可滥用,更不可以将hash作为对象列表使用
- hgetall 操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很会低,有可能成为数据访问瓶颈*
list 类型
- 数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
- 需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
- list类型:保存多个数据,底层使用双向链表存储结构实现
list 类型数据基本操作
- 添加/修改数据
lpush key value1 [value2]....
rpush key value1 [value2]....
- 获取数据
lrange key start stop
lindex key index
llen key
//查看整个list
lrange key 0 -1
- 获取并移除数据
lpop key
rpop key
- 限时获取数据(给定一个timeout,在这个时间能获得就获取否则就不能获取)
blpop key1 [key2] timeout
brpop key1 [key2] timeout
- 移除指定数据
lrem key count value
set 类型
- 新的存储需求:存储大量的数据,在查询方面提供更高的效率
- 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
- set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
set 类型数据的基本操作
1.添加数据
sadd key member1 [member2]
- 获取全部数据
smembers key
- 删除数据
sdel keymember1 [member2]
- 获取集合数据总量
scard key
注意事项
- set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份
- set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
sorted_set 类型
- 新的存储需求:数据排序有利于数据的有效展示,需要提供一种可以根据自身特征进行排序的方式
- 需要的存储结构:新的存储模型,可以保存可排序的数据
- sorted_set类型:在set的存储结构基础上添加可排序字段(score字段用于排序)
sorted_set 类型数据的基本操作
- 添加数据
zadd key score1 member1 [score2 member2]
- 获取全部数据
zrange key start end [withscores]
//降序
zrevrange key start end [withscores]
//例:
zrange key 0 -1
- 删除数据
zrem key member [member....]
- 获取数据对应的索引(排名)
zrank key member
zrevrank key member
- score值获取与修改
zscore key member
zincrby key increment member
sorted_set 类型数据操作的注意事项
- score保存的数据也可以是一个双精度的double值,基于双精度浮点数的特征,可能会丢失精度
- sorted_set 底层存储还是基于set结构的,因此数据不能重复,如果重复添加相同的数据,score值将被反复覆盖,保留最后一次修改的结果
key 通用指令
key 基本操作
- 删除指定key
del key
- 判断是否存在
exists key
- 获取key的类型
type key
- 为指定key设置有效期
expire key seconds
pexpire key milliseconds
expireat key timestamp
pexpireat key milliseconds-timestamp
- 获取key有效时间
ttl key
pttl key
- 切换key从时效性转换为永久性
persist key
- 查询keys
keys patterns
8. 更改key
rename key newkey
renamenx key newkey
- 对key排序
sort
数据库操作
redis为每个服务提供有16个数据库,编号从0到15,每个数据库之间的数据相互独立
- 切换数据库
select index
- 确定数据库是否连通
ping
- 数据移动
move key db
数据持久化
持久化简介
利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化。
防止数据意外丢失,确保数据安全。
RDB&AOF
两种数据持久化方式
- RDB: 将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据
启动方式:save指令(手动执行一次保存操作)
保存之后会生成 dump.rdb文件
相关指令:
dbfilename dump.rdb: 设置本地数据库文件名,默认值为 dump.rdb,通常设置为dump-端口号.rdb
dir: 设置存储.rdb文件的路径,通常设置成存储空间较大的目录中,目录名称data
RDB启动方式 —— save指令工作原理
注意:save指令的执行会阻塞当前Redis服务器,直到当前RDB过程完成为止,有可能会造成长时间阻塞,线上环境不建议使用。
数据量过大,单线程执行方式造成效率过低如何处理?
解决方案:bgsave指令(启动后后台保存操作,并不会立即执行),
save配置
配置: save second changes
作用: 满足限定时间内达到指定数量即进行持久化
参数:
second:监控时间范围
changes: 监控key的变化量
位置: 在conf配置文件中配置
bgsave指令工作原理
bgsave指令是针对save阻塞问题做出的优化,RDB操作都使用bgsave操作,通过生成子进程后台创建rdb文件,从而解决redis服务器被阻塞的问题。但伴随额外内存消耗。
RDB优点
RDB是一个紧凑的二进制文件,存储效率较高
RDB内部存储的是redis在某个时间点的数据快照,非常适合数据备份,全量复制等
RDB数据恢复的数据比AOF快很多
应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。
RDB缺点
RDB无论是通过配置还是指令无法做到数据实时持久化,很有可能丢失数据
bgsave每次进行运行都要执行fork操作创建子进程,会牺牲一些性能
Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象
- AOF(append only file)持久化: 以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令达到数据恢复的命令。与RDB的区别可以描述为改记录数据为记录数据的生产过程。AOF主要是为了解决redis数据持久化的实时性,目前是redis的主流方式。
AOF写数据三种策略(appendfsync) - always(每次),每次写入操作均同步到AOF文件中,数据零误差,效率较低
- everysec(每秒),每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高在系统突然宕机的情况下丢失1秒内的数据
- no(系统控制),由操作系统控制每次同步到AOF文件的周期,整体过程不可控
AOF功能开启
配置:appendonly yes|no
AOF 写数据策略:appendfsync always|everysec|no
AOF重写
随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。AOF文件重写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。简单说就是将***对同一个数据的若干个条命令执行结果转化成最终结果数据对应的指令进行记录***。
- RDB与AOF区别
事务基本操作
开启事务:设定事务开始位置,此指令执行后后续所有操作均加入到事务
multi
执行事务:设定事务的结束位置,同时执行事务。与multi成对出现,成对使用
exec
注意:加入到事务中的命令暂时没有执行,只有执行exec命令才开始执行
取消事务: 终止当前事务发生在multi之后exec之前
discard
锁
多个客户端有可能同时操作同一组数据,并且该数据一旦被操作修改后,将不适用于继续操作,在操作之前锁定要操作的数据,一旦发生变化,终止当前操作
对 key 添加监视锁,在执行exec前如果key发生了变化,终止事务执行
watch key1 [key2]
取消对所有key的监视
unwatch
使用watch监控一个key有没有改变已经不能解决问题,此处要监控的是具体数据,虽然redis是单线程的,但是多个客户端对同一数据同时进行操作时,如何避免不被同时修改?(解决超卖问题)
分布式锁
使用setnx设置一个公共锁
setnx lock-key value
利用setnx命令的返回值特征,有值则返回设置失败,无值则返回设置成功对于返回设置成功的,拥有控制权,进行下一步的具体业务操作对于返回设置失败的,不具有控制权,排队或等待操作完毕通过del操作释放锁(操作值前尝试给key加锁,如果加锁成功则修改值,如果加锁失败证明锁正被占用,则无法修改值,排队或者等待)
分布式锁的改良
由于锁操作由用户控制加锁解锁,必定会存在加锁后未解锁的风险需要解锁操作不能仅依赖用户控制,系统级别要给出对应的保底处理方案
使用expire为锁添加时间限定,到时则必须释放锁
expire lock-key second
expire lock-key milliseconds
数据删除策略
-
定时删除
创建一个定时器,当key设置有过期时间 ,且过期时间到达时,由定时器任务立即执行对键的删除
优点:节约内存,到时就删除,快速释放掉不必要的内存占用
缺点:CPU压力很大,无论CPU此时负载量多高,均占CPU,会影响redis服务器的响应时间和指令吞吐量(拿时间换空间) -
惰性删除
数据到达过期时间,不做处理,等下次访问时:
如果未过期,返回数据
发现已过期,删除然后返回不存在优点: 节约CPU性能,发现必须删除的时候再删除
缺点: 内存压力很大,出现长期占用内存的数据(拿空间换时间) -
定期删除
周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度.
周期性抽查存储空间(随机抽查,重点抽查)
Redis启动服务器初始化时,读取配置server.hz的值,默认为10
每秒钟执行server.hz次 activeExpireCycle()
activeExpireCycle()对每个expires[]逐一进行检测
对某个expires[]检测时,随机挑选W个key检测
如果key超时,删除key
如果一轮中删除的key的数量>W25%,循环该过程
如果一轮中删除的key的数量≤W25%,检查下一个expires[],0-15循环
参数current_db用于记录activeExpireCycle() 进入哪个expires[] 执行
如果activeExpireCycle()执行时间到期,下次从current_db继续向下执行
特点1:CPU性能占用设置有峰值,检测频度可自定义设置
特点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
数据删除策略对比
-
定时删除
节约内存,无占用
不分时段占用CPU资源,频度高
拿时间换空间 -
惰性删除
内存占用严重
延时执行,CPU利用率高
拿空间换时间 -
定期删除
内存定期随机清理
每秒花费固定的CPU资源维护内存
随机抽查,重点抽查
逐出算法
Redis使用内存存储数据,在执行每一个命令前,会调用**freeMemoryIfNeeded()**检测内存是否充足。如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法。
逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所
有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息。(OOM)
数据逐出策略
检测易失数据(可能会过期的数据集server.db[i].expires )
- volatile-lru:挑选最近最少使用的数据淘汰(最长时间没用的数据)
- volatile-lfu:挑选最近使用次数最少的数据淘汰(使用次数最少的数据)
- volatile-ttl:挑选将要过期的数据淘汰(最快过期的数据)
- volatile-random:任意选择数据淘汰(随机逐出)
检测全库数据(所有数据集server.db[i].dict ) - allkeys-lru:挑选最近最少使用的数据淘汰
- allkeys-lfu:挑选最近使用次数最少的数据淘汰
- allkeys-random:任意选择数据淘汰
- no-enviction(驱逐)(放弃逐出)
主从复制
简介
单机redis存在许多风险与问题:
- 机器故障
- 容量瓶颈
为了避免单点Redis服务器故障,准备多台服务器,互相连通。将数据复制多个副本保存在不同的服
务器上,连接在一起,并保证数据是同步的。即使有其中一台服务器宕机,其他服务器依然可以继续
提供服务,实现Redis的高可用,同时实现数据冗余备份。
解决方案:
主客户端master负责收集数据(写);
从客户端slave负责提供数据(读);
主从复制即将master中的数据即时、有效的复制到slave中
主从复制的作用
读写分离:master写、slave读,提高服务器的读写负载能力
负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
高可用基石:基于主从复制,构建哨兵模式与集群,实现Redis的高可用方案
主从复制工作流程
- 建立连接
- 数据同步
- 命令传播
建立连接:
步骤1:设置master的地址和端口,保存master信息
步骤2:建立socket连接
步骤3:发送ping命令(定时器任务)
步骤4:身份验证
步骤5:发送slave端口信息,主从连接成功!
数据同步:
分为全量复制和部分复制
步骤1:请求同步数据
步骤2:创建RDB同步数据
步骤3:恢复RDB同步数据
步骤4:请求部分同步数据
步骤5:恢复部分同步数据,数据同步工作完成!
命令传播
当master数据库状态被修改后,导致主从服务器数据库状态不一致,此时需要让主从数据同步到一致的状态,同步的动作称为命令传播
master将接收到的数据变更命令发送给slave,slave接收命令后执行命令
命令传播阶段出现了断网现象
网络闪断闪连 忽略
短时间网络中断 部分复制
长时间网络中断 全量复制
部分复制的三个核心要素
服务器的运行 id(run id)
主服务器的复制积压缓冲区
主从服务器的复制偏移量
服务器运行ID(runid)
概念:服务器运行ID是每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行id
组成:运行id由40位字符组成,是一个随机的十六进制字符
作用:运行id被用于在服务器间进行传输,识别身份如果想两次操作均对同一台服务器进行,必须每次操作携带对应的运行id,用于对方识别
实现方式:运行id在每台服务器启动时自动生成的,master在首次连接slave时,会将自己的运行ID发送给slave,slave保存此ID,通过info Server命令,可以查看节点的runid
复制缓冲区
概念:复制缓冲区,又名复制积压缓冲区,是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区
组成:偏移量,字节值
工作原理:
通过offset区分不同的slave当前数据传播的差异
master记录已发送的信息对应的offset
slave记录已接收的信息对应的offset
主从服务器复制偏移量(offset)
概念:一个数字,描述复制缓冲区中的指令字节位置
分类:
master复制偏移量:记录发送给所有slave的指令字节对应的位置(多个)
slave复制偏移量:记录slave接收master发送过来的指令字节对应的位置(一个)
数据来源:
master端:发送一次记录一次
slave端:接收一次记录一次
作用:同步信息,比对master与slave的差异,当slave断线后,恢复数据使用
心跳机制
进入命令传播阶段候,master与slave间需要进行信息交换,使用心跳机制进行维护,实现双方连接保持在线
哨兵
哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的
master并将所有slave连接到新的master。
哨兵的作用:
监控
不断的检查master和slave是否正常运行。
master存活检测、master与slave运行情况检测
通知(提醒)
当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知。
自动故障转移
断开master与slave连接,选取一个slave作为master,将其他slave连接到新的master,并告知客户端新的服
务器地址