linux安装redis
- 安装centos-releases-scl:yum install centos-release-scl
- 安装devtoolset:yum install devtoolset-9-gcc*
- 激活对应的devtoolset:scl enable devtoolset-9 bash
- 下载redis安装包:wget http://download.redis.io/releases/redis-6.0.8.tar.gz
- 解压:tar -zxvf redis-6.0.8.tar.gz
- 进入redis目录:cd redis-6.0.8
- 编译:make
- 安装到指定目录:make PREFIX=/usr/local/redis install
redis启动方式
- 默认启动(默认端口6379):
1.服务器:redis-server
2.客户端:redis -cli - 指定端口启动
1.服务器:redis-server --port 端口号
2.客户端:redis-cli -p 端口号 - 配置文件启动,多个配置文件对应多个redis服务器
1.服务器:redis-server 配置文件名
2.客户端:redis-cli -p 端口号
3.基本配置:daemonize yes(以守护进程方式启动,即后台启动,redis将以服务形式存在,日志不再打印到命令窗口中);port xxxx(设定服务器启动端口号);dir “”(设置当前服务文件保存位置,包含日志文件,持久化文件);logfile “xxxx.log”(日志文件名)
服务器基础配置
- 设置服务器以守护进程的方式运行:daemonize yes|no
- 绑定主机地址:bind ip地址
- 设置服务器端口号:port 端口号
- 设置数据库数量:databases 数量
- 设置服务器以指定日志记录级别:loglevel debug|verbose|notice|warning
- 设置日志记录文件名:logfie 文件名
- 设置同一时间最大客户端连接数,默认无限制,当客户端连接达到上限时,redis会关闭新的连接:maxclients 数量
- 客户端闲置等待最大时长,达到最大之后关闭连接,设置为0则关闭该功能:timeout 时间/秒
- 导入并加载指定配置文件信息,用于快速创建redis公共配置较多的实例配置文件,便于维护:include 配置文件
持久化
问题引入
redis的数据存在内存中,如果遇到服务器崩溃,断电关机等等意外情况,重启后数据将意外丢失,这时就需要作数据持久化来解决这一问题
概述
所谓持久化,就是利用永久性存储介质将数据进行保存,在特定的时间内将保存的数据进行恢复的工作机制;目的是为了防止数据的意外丢失,确保数据安全
两种持久化方式
- 将当前的数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据(RDB)
- 将数据的操作过程进行保存,日志形式,存储操作过程,存储格式复杂,关注点在数据的操作过程(AOF)
RDB
相关配置
- dbfilename 文件名:指定快照文件文件名,默认值为dump.rdb,通常设置为dump-端口号.rdb
- dir 路径:存储文件.rdb的路径,通常设置到存储空间大的目录中,目录名称为data
- rdbcompression yes:设置存储到本地时是否压缩数据,默认为yes,采用LZF压缩(通常默认为开启状态,如果设置为no,可以节省cpu运行时间,但会使存储的文件变得巨大)
- rdbchecksum yes:设置是否进行rdb文件格式校验,该校验过程在写文件和读文件的过程均可进行(通常默认为开启状态,如果设置为no,可以节约读写过程月10%时间损耗,但是存储存在一定数据损坏风险)
启动方式
- save指令:手动执行依次保存操作,每保存一次会在配置文件指定的dir目录下生成一个rdb文件保存当前的数据快照信息
save指令与其他一般的指令相同,直接发送给服务器
由于redis内部单线程工作,如果遇到save指令将组测当前Redis服务器,知道当前RDB过程完成为止,这就有可能造成长时间的阻塞,所以线上环境不建议使用save指令
- bgsave指令:手动启动后台保存操作,但不是立即执行
bgsave指令不参与到redis的指令的序列中,当发送bgsave指令后,redis会调用fork函数生成子进程来创建rdb文件
bgsave指令时针对save阻塞问题的优化,Redis内部所有设计到RDB操作都采用bgsave方式,save指令可以放弃使用
- save配置:
save second changes
,second监控的时间范围,changes为监控key的变化量;满足限定时间范围内key的变化数量达到指定数量进行持久化
save配置要根据实际业务情况进行设置,频度过高或过低都会出现性能问题,结果可能是灾难性的
save配置中对有second与changes设置通常具有互补对应关系,尽量不要设置成包含关系(比如设置了save 1 1将会包含save 100 100这样save 100 100的配置没有任何意义)
save配置启动后执行的是bgsave操作
启动方式对比
方式 | save指令 | bgsave指令 |
---|---|---|
读写 | 同步 | 异步 |
阻塞客户端指令 | 是 | 否 |
额外内存消耗 | 否 | 是 |
启动新进程 | 否 | 是 |
RDB的优缺点
优点
- RDB是一个紧凑压缩的二进制文件,存储效率高
- RDB内部存储的是redis在某个时间点快照,非常适合用于数据备份,全量复制等场景
- RDB恢复数据的速度比AOF快很多
- 应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复
缺点
- 基于快照思想,每次读写都是全部的数据,存储的数据量大,效率低
- RDB方式无论是执行指令还是利用配置,都无法做到实时的持久化,具有较大可能性丢失数据
- bgsave指令每次运行都要执行fork操作创建子进程,要牺牲掉一些性能
- Redis众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象
AOF
概述
- AOF(append only file):以独立日志的方式记录每次写命令,重启时在重新执行AOF文件中的命令达到恢复数据的目的,与RDB相比可以简单描述为改记录数据为记录数据的产生
- AOF主要作用是解决了数据持久的实时性,目前已经是Redis持久化的主流方式
- AOF将指令存在缓存区,然后根据策略生成.aof文件,使用aof文件来重新执行指令
相关配置
- appendonly yes|no:将appendonly指定为yes表示开启AOF持久化功能,默认为关闭
- appendssync alwawys|everysec|no:指定策略
- appendfilename 文件名:AOF持久化文件名,默认文件名为appendonly.aof,建议配置为appendonly-端口号.aof
- dir 路径:aof文件保存路径,与rdb一致即可
策略
- always(每次):每次写入操作均同步到AOF文件中,数据零误差,性能较低
- everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高,在系统突然宕机的情况下丢失1秒内的数据
- no(系统控制):由操作系统控制每次同步到AOF问文件的周期,整体过程不可控
AOF重写
随着命令不断写入aof,文件会越来越大,为了解决这个问题,redis引入了aof重写机制压缩文件体积。aof重写是将redis进程内数据转化为写命令同步到新aof文件的过程,简单说就是将对同一个数的若干条命令执行结果转化称最终结果数据对应的指令进行记录
规则
- 进程内已超时的数据不在写入文件
- 忽略无效指令,重写时使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令
- 对同一数据的多条命令合并为一条命令
方式
- 手动重写,指令
bgrewriteraof:手动执行后台重写,流程与bgsave类似 - 自动重写,配置文件
auto-aof-rewrite-min-size size:当前aof文件的大小大于这里配置的size就重写
auto-aof-rewrite-percentage percent:当前aof文件大小减去基础尺寸大小之后与基础尺寸大小比值小于这里配置的percent就重写
工作流程
RDB与AOF对比
持久化方式 | RDB | AOF |
---|---|---|
占用存储空间 | 小(数据级,压缩) | 大(指令级,重写) |
存储速度 | 慢 | 快 |
恢复速度 | 快 | 慢 |
数据安全性 | 会丢失数据 | 依据策略而定 |
资源消耗 | 高 | 低 |
启动优先级 | 低 | 高 |
选择
- 对数据非常敏感,使用默认的aof持久化方案
AOF持久化策略使用everysec,每秒钟处理一次,改策略redis仍可以保持较好的处理性能,出现问题最多丢失0-1秒的数据 - 数据呈现阶段有效性,建议使用RDB持久化方案
数据可以良好的做到阶段内无丢失,且恢复速度较快,阶段点数据恢复通常采用RDB方案 - 不能承受分钟以内的数据丢失,对业务数非常敏感,使用AOF
- 能承受分钟以内的数据丢失,且追求大数据集的恢复速度,选用RDB
- 灾难恢复选用RDB
- 双保险策略,同时开启RDB和AOF,重启后Redis优先使用AOF来恢复数据,降低数据丢失量
事务
概述
当redis服务器收到两个客户端对相同的字段进行操作时,可能会造成数据的错误,比如a客户端存入name为zhangsan,此时b客户端存入name为lisi就覆盖了a客户端的存值,接下来a取到的值就不是a想要的
redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列),当执行时,一次性按照添加顺序依次执行,中间不会被打断或者干扰
基本操作
- 开启事务:
multi
,设定事务的开始位置,此指令执行后,后续的所有指令均加入到事务中 - 执行事务:
exec
,设定事务的结束位置,同时执行事务,与multi程对出现,成对使用 - 取消事务:
discard
,终止当前事务的定义,发生在multi之后exec之前
加入的事务命令暂时进入到任务队列中,并没有立即执行,只有执行exec命令才开始执行
如果存在语法错误,整体事务中所有命令将不会执行,包括正确的命令
如果存在运行错误,能够正确运行的命令会执行,运行错误的命令不会执行,已经执行完毕的命令不会自动回滚,需要程序员自己在代码中实现回滚
工作流程
锁
事务锁
如果多个客户端将对同一个key进行操作,并且需要保证该操作只能被执行一次,即可在操作之前锁定要操作的数据,一旦数据发生变化,终止当前操作
- 对key添加监视锁:
watch key1 [key2 ...]
,在执行exec前如果key发生了变化,终止事务的执行 - 取消对所有key的监视:
unwatch
分布式锁
多个客户端对一个key进行操作,并且需要避免这个值被同时修改并做出及时的响应,此时使用watch监控一个key是否被改变已经不使适用,此处需要监控的是具体的数据
- 设置一个公共锁:
setnx lock-key value
,利用setnx命令的返回值特征,有值则返返回设置失败,对该数据不具有控制权;无值则返回设置成功,可以进行下一步操作 - 释放公共锁:
del lock-key
死锁问题
如果客户端对某个key设置了分布式锁,此时出现客户端宕机等问题,客户端无法解锁,此时就会出现死锁,造成其他客户端永远无法操作该数据;所以需要解锁操作不能依赖用户控制,系统级别需要给出对应的保底处理方案
- 使用expire为锁添加事件限定:
expire lock-key second
,时间到自动放弃锁
删除策略
过期数据
诸如expire,expireat这样的指定时效性数据的指令,当时间到达后,考虑到性能,并不会让redis立即释放掉这些数据,而是在redis的内存空间和cpu的性能之间寻找一个平衡点
过期数据存储结构
三种删除策略
- 定时删除:创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作
优点:节约内存,到时就删除
缺点:cpu压力大,无论cpu当时负载多高,都会占用cpu资源,影响redis服务器响应时间 - 惰性删除:数据到达过期时间,不做处理,等待下一次访问该数据时执行删除操作
优点:节约cpu性能,发现必须删除时才执行删除
缺点:内存压力大,出现长期占用内存的数据 - 定期删除:在redis启动服务器初始化时,赌球配置server.hz的值(默认10),每秒钟执行server.hz次检查时间存储的空间部分expires,对某个expires进行检测时随机挑选W个key检测:
如果key超时,删除key
如果一轮中删除key的数量大于W*25%,循环检测该expires
如果一轮中删除key的数量<=W*25%,检查下一个expires
W的取值为ACTIVE_EXPIRE_CYCEL_LOOKUPS_PRE-LOOP属性值
参数current_db用于记录进入哪一个expires执行
逐出算法
redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNedded()检测内存是否充足,如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间,清理数据的策略称为逐出算法
逐出数据的过程不是100%能够清理出足够的可使用的内存空间的,如果不成功则反复执行,当对所有数据尝试完毕后,如果不能达到内存中的存储要求,将报错
相关配置
- 最大可用内存:maxmemory,占用物理内存的比例,默认值为0,表示不限制,生产环境中根据需求指定,通常设置在50%以上
- 每次选取待删除数据个数:maxmemory-sample,选取数据时不会全库扫描,导致严重的性能消耗,降低读写性能,因此采用随机获取数据的方式作为待检测删除数据
- 逐出策略:maxmemory-policy,达到最大内存后的,对被挑选出来的数据进行删除的策略
逐出策略
- 检查易失数据(可能会过期的数据集server.db[i].expires)
volatitle-lru:挑选最近最少使用的淘汰,推荐
volatitle-lfu:挑选最近使用次数最少的数据淘汰
volatitle-ttl:挑选将要过期的数据淘汰
volatitle-random:任意选择数据淘汰 - 检测全库数据(所有数据集server.db[i].dict)
allkeys-lru:挑选最近最少使用的淘汰
allkeys-lfu:挑选最近使用次数最少的数据淘汰
allkeys-random:任意选择数据淘汰 - 放弃数据逐出
no-enviction:禁止驱逐数据(redis4.0中默认策略),超过最大内存报错OOM
高级数据类型
高级数据类型都是为了解决某一个单一的业务场景,是建立在基础数据类型之上的,并不是新的数据类型
Bitmaps
仅存储数据的状态时,最大化节省空间
基本操作
- 获取指定key对应偏移量上的bit值:
getbit key offset
- 设置指定key对应偏移量上的bit值,value只能是1或0:
setbit key offset value
扩展操作
- 对指定的key按位进行交(and)、并(or)、非(not)、异或(xor)操作,并将结果保存到destKey中:
bitop op destKey key1 [key2 ...]
- 统计指定key中1的数量:
bitcount key [start end]
HyperLogLog
统计不重复的数据的数量,作基数集的统计
用于基数统计,不是集合,不保存数据,只记录数量而不是具体数据
核心是基数估算算法,最终数值存在一定的误差
误差范围:基数估计的结果是一个带有0.81%标准错误的近似值
耗空间极小,每个heyperloglog占用了12k内存用于标记基数
操作
- 添加数据:
pfadd key element [element ...]
- 统计数据:
pfcount key [key ...]
- 合并数据:
pfmerge destkey sourcekey [sourcekey ...]
GEO
统计坐标距离,常用于地图显示距离差
操作
- 添加坐标点:
geoadd key longitude latitude member [longitude latitude member...]
,key地图集,longitude横坐标,latitude纵坐标,member坐标名称 - 获取坐标点:
geopos key member [member...]
- 计算坐标点距离:
geodist key member member2 [unit]
- 根据坐标求范围内的数据:
georadius key longitude latitude radius m|km|ft|mi [withcoord] [withdist] [withhash] [count count]
,radius范围 - 根据点求范围内数据:
georadiusbymember key member radius m|km|ft|mi [withcoord] [withdist] [withhash] {count count]
- 获取指定点对应的坐标的hash值:
geohash key member [member...]