(1)数据类型
string、hash、list、set、Zset、BitMap、HyperLogLog、GEO。
string
存储的数据:单个数据,最简单的数据存储类型、数据未获取到(nil)等同于null、数据最大存储量512MB、数值计算最大范围(java中的long的最大值)2^63。
hash:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息。
list:数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分。
set: set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份。
Zset:数据排序有利于数据的有效展示,需要提供一种可以根据自身特征进行排序的方式。
BitMap:redis 应用于信息状态统计。
HyperLogLog:redis 应用于独立信息统计。
GEO:redis 应用于地理位置计算。
(2)持久化
利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化。
RDB
将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据。
RDB启动方式 —— save指令
作用:手动执行一次保存操作。
工作原理:单线程执行任务序列,排队执行。
save指令的执行会阻塞当前Redis服务器,直到当前RDB过程完成为止,有可能会造成长时间阻塞,线上环境不建议使用。
RDB启动方式 —— bgsave指令
作用:手动启动后台保存操作,但不是立即执行。
工作原理:调用fork()创建子进程去写。
bgsave命令是针对save阻塞问题做的优化。Redis内部所有涉及到RDB操作都采用bgsave的方式,save命令可以放弃使用。
RDB------自动执行
作用:满足限定时间范围内key的变化数量达到指定数量即进行持久化。
配置:save second changes.在conf文件中进行配置。
参数:second:监控时间范围、changes:监控key的变化量。
例:save 900 1 代表900秒内,有一个变化则执行。
例:save 300 10 代表300秒内有10个变化则执行
优点:
RDB是一个紧凑压缩的二进制文件,存储效率较高。
RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景。
RDB恢复数据的速度快。
缺点:
RDB无法做到实时持久化,较大的可能性丢失数据。
bgsave要执行fork操作创建子进程,要牺牲掉一些性能。
Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象。
应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。
AOF
将数据的操作过程进行保存,日志形式,存储操作的过程,存储格式复杂,关注点在数据的操作过程。
概念:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令。
作用:AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式。
AOF写数据三种策略(appendfsync)
always(每次:每次写入操作均同步到AOF文件中,数据零误差,性能较低。
everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高。
no(系统控制):由操作系统控制每次同步到AOF文件的周期,整体过程不可控。
AOF功能开启
appendonly yes | no ,是否开启AOF持久化功能,默认为不开启状态。
appendfsync always | everysec | no ,AOF写数据策略。
AOF相关配置
appendfilename filename ,AOF持久化文件名,默认文件名未appendonly.aof,建议配置为appendonly-端口号.aof。
dir:AOF持久化文件保存路径,与RDB持久化文件保持一致即可。
AOF重写
简单说就是将对同一个数据的若干个条命令执行结果转化成最终结果数据对应的指令进行记录。
作用:
降低磁盘占用量,提高磁盘利用率。
提高持久化效率,降低持久化写时间,提高IO性能。
降低数据恢复用时,提高数据恢复效率。
重写规则:
进程内已超时的数据不再写入文件。
忽略无效指令,重写时使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令。
AOF重写方式:
1.手动重写:bgrewriteaof 。
2.自动重写:auto-aof-rewrite-min-size size、auto-aof-rewrite-percentage percentage。
RDB和AOF对比
(3)事务
redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列)。
事务的基本操作:
开启事务:multi,设定事务的开启位置,此指令执行后,后续的所有指令均加入到事务中。
执行事务:exec,设定事务的结束位置,同时执行事务。与multi成对出现,成对使用。
取消事务:discard,终止当前事务的定义,发生在multi之后,exec之前。
注意:加入事务的命令暂时进入到任务队列中,并没有立即执行,只有执行exec命令才开始执行。
事务的注意事项
定义事务的过程中,命令格式输入错误怎么办?
语法错误:如果定义的事务中所包含的命令存在语法错误,整体事务中所有命令均不会执行。包括那些语法正确的命令。
定义事务的过程中,命令执行出现错误怎么办?
运行错误:指命令格式正确,但是无法正确的执行。例如对list进行incr操作。
处理结果;能够正确运行的命令会执行,运行错误的命令不会被执行。
注意:已经执行完毕的命令对应的数据不会自动回滚,需要程序员自己在代码中实现回滚。
Redis锁
基于特定条件01的事务执行——锁
对 key 添加监视锁(watch ),在执行exec前如果key发生了变化,终止事务执行。
基于特定条件02的事务执行——分布式锁
使用 setnx 设置一个公共锁:setnx lock-key value.利用setnx命令的返回值特征,有值则返回设置失败,无值则返回设置成功。对于返回设置成功的,拥有控制权,进行下一步的具体业务操作,对于返回设置失败的,不具有控制权,排队或等待。
解决死锁的方案:使用 expire 为锁key添加时间限定,到时不释放,放弃锁。
expire lock-key second,pexpire lock-key milliseconds。
删除策略
Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态
XX :具有时效性的数据
-1 :永久有效的数据
-2 :已经过期的数据 或 被删除的数据 或 未定义的数据
数据的删除策略
1. 定时删除,创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作。
2. 惰性删除, 数据到达过期时间,不做处理。等下次访问该数据时。
3. 定期删除
Redis启动服务器初始化时,读取配置server.hz的值,默认为10。
每秒钟执行server.hz次serverCron() (定时轮询),expries[0] - exprie[15]。
activeExpireCycle()对每个expires[*]逐一进行检测,每次执行250ms/server.hz。
对某个expires[*]检测时,随机挑选W个key检测,如果一轮中删除的key的数量>W*25%,循环该过程。如果一轮中删除的key的数量≤W*25%,检查下一个expires[*],0-15循环。
对比:
八逐出算法
主从复制
主从复制即将master中的数据即时、有效的复制到slave中。
master职责: 写数据, 执行写操作时,将出现变化的数据自动同步到slave,读数据(可忽略)。
slave职责:: 读数据, 写数据(禁止)。
主从复制的作用:
读写分离:master写、slave读,提高服务器的读写负载能力。
负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量。
故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复。
数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式。
高可用基石:基于主从复制,构建哨兵模式与集群,实现Redis的高可用方案。
主从复制工作流程
阶段一:建立连接阶段。
阶段二:数据同步阶段工作流程。
在slave初次连接master后,复制master中的所有数据到slave,将slave的数据库状态更新成master当前的数据库状态。
阶段三:命令传播阶段。
当master数据库状态被修改后,导致主从服务器数据库状态不一致,此时需要让主从数据同步到一致的状态,同步的动作称为命令传播。master将接收到的数据变更命令发送给slave,slave接收命令后执行命令。
哨兵模式
哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。
哨兵的作用:
监控,不断的检查master和slave是否正常运行,master存活检测、master与slave检测。
通知(提醒),当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知。
自动故障转移,断开master与slave连接,选取一个slave作为master,将其他slave连接到新的master,并告知客户端新的服务器地址。
注意:哨兵也是一台redis服务器,只是不提供数据服务,通常哨兵配置数量为单数(防止竞争打平)。
启动哨兵:redis-sentinel sentinel-端口号.conf。
常见问题
缓存雪崩
在一个较短的时间内,缓存中较多的key集中过期,此周期内请求访问过期的数据,redis未命中,redis向数据库获取数据。数据库同时接收到大量的请求无法及时处理,Redis大量请求被积压,开始出现超时现象。
解决方案:
数据有效期策略调整,根据业务数据有效期进行分类错峰,A类90分钟,B类80分钟,C类70分钟。过期时间使用固定时间+随机值的形式,稀释集中到期的key的数量。
超热数据使用永久key。
定期维护(自动+人工),对即将过期数据做访问量分析,确认是否延时,配合访问量统计,做热点数据的延时。
加锁 (慎用)。
总结:
缓存击穿就是单个高热数据过期的瞬间,数据访问量较大,未命中redis后,发起了大量对同一数据的数据库访问,导致对数据库服务器造成压力。
缓存击穿
Redis中某个key过期,该key访问量巨大,多个数据请求从服务器直接压到Redis后均未命中,Redis在短时间内发起了大量对数据库中同一数据的访问。
解决方案:
预先设定。以电商为例,每个商家根据店铺等级,指定若干款主打商品,在购物节期间,加大此类信息key的过期时长,购物节不仅仅指当天,以及后续若干天,访问峰值呈现逐渐降低的趋势。
现场调整。监控访问量,对自然流量激增的数据延长过期时间或设置为永久性key。
后台刷新数据。启动定时任务,高峰期来临之前,刷新数据有效期,确保不丢失。
二级缓存。设置不同的失效时间,保障不会被同时淘汰就行。
加锁。分布式锁,防止被击穿,但是要注意也是性能瓶颈,慎重!
总结:
缓存击穿就是单个高热数据过期的瞬间,数据访问量较大,未命中redis后,发起了大量对同一数据的数据库访问,导致对数据库服务器造成压力。
缓存穿透
Redis中大面积出现未命中,出现非正常URL访问。
分析:
获取的数据在数据库中也不存在,数据库查询未得到对应数据。
Redis获取到null数据未进行持久化,直接返回。
出现黑客攻击服务器。
解决方案:
缓存null,对查询结果为null的数据进行缓存(长期使用,定期清理),设定短时限,例如30-60秒,最高5分钟。
白名单策略Bitmaps,提前预热各种分类数据id对应的bitmaps,id作为bitmaps的offset,相当于设置了数据白名单。当加载正常数据时,放行,加载异常数据时直接拦截(效率偏低)。
使用布隆过滤器。
key加密。问题出现后,临时启动防灾业务key,对key进行业务层传输加密服务,设定校验程序过来的key校验。
总结:
缓存穿透访问了不存在的数据,跳过了合法数据的redis数据缓存阶段,每次访问数据库,导致对数据库服务器造成压力。通常此类数据的出现量是一个较低的值,当出现此类情况以毒攻毒,并及时报警。应对策略应该在临时预案防范方面多做文章。