1、Redis为什么这么快
C语言编写
网络IO是nio
单线程避免了多线程上下文切换造成的性能损耗
在内存中运算速度快
2、Redis网络模型
IO多路复用(reactor)
redis利用epoll实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。
3、Redis数据结构
4、Redis持久化
1、RDB快照(snapshot)
配置# save 60 1000 //关闭RDB只需要将所有的save保存策略注释掉即可
2、AOF(append-only file)
将修改的每一条指令记录进文件appendonly.aof中(先写入os cache,每隔一段时间fsync到磁盘)。
AOF重写:AOF文件里可能有太多没用指令,所以AOF会定期根据内存的最新数据生成aof文件。AOF重写redis会fork出一个子进程去做(与bgsave命令类似),不会对redis正常命令处理有太多影响。bgrewriteao手动重写。
Redis 4.0 混合持久化:aof-use-rdb-preamble yes
如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,因此重启效率大幅得到提升。
3、RDB与AOF区别
4、Redis数据备份策略
(1)写crontab定时调度脚本,每小时都copy一份rdb或aof的备份到一个目录中去,仅仅保留最近48小时的备份。
(2)每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份。
(3)每次copy备份的时候,都把太旧的备份给删了。
(4)每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏。
5、Redis管道(Pipeline)
客户端可以一次性发送多个请求而不用等待服务器的响应,待所有命令都发送完后再一次性读取服务的响应,这样可以极大的降低多条命令执行的网络传输开销,管道执行多条命令的网络开销实际上只相当于一次命令执行的网络开销。需要注意到是用pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并不是打包的命令越多越好。
pipeline中发送的每个command都会被server立即执行,如果执行失败,将会在此后的响应中得到信息;也就是pipeline并不是表达“所有command都一起成功”的语义,管道中前面命令失败,后面命令不会有影响,继续执行。
6、Redis使用lua脚本
1、减少网络开销:本来5次网络请求的操作,可以用一个请求完成,原先5次请求的逻辑放在redis服务器上完成。使用脚本,减少了网络往返时延。这点跟管道类似。
2、原子操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。管道不是原子的,不过redis的批量操作命令(类似mset)是原子的。
3、替代redis的事务功能:redis自带的事务功能很鸡肋,而redis的lua脚本几乎实现了常规的事务功能,官方推荐如果要使用redis的事务功能可以用redis lua替代。
7、Redis分布式锁
nx通过共享内存实现
8、Redis主从架构
9、Redis哨兵架构
sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。
10、Redis集群
11、Redis优化
1、redis配置
合理的配置最大连接数;最大,最小空闲数。
2、规约
3、慢日志
slowlog
Redis慢日志命令说明:
config get slow* #查询有关慢日志的配置信息
config set slowlog-log-slower-than 20000 #设置慢日志使时间阈值,单位微秒,此处为20毫秒,即超过20毫秒的操作都会记录下来,生产环境建议设置1000,也就是1ms,这样理论上redis并发至少达到1000,如果要求单机并发达到1万以上,这个值可以设置为100
config set slowlog-max-len 1024 #设置慢日志记录保存数量,如果保存数量已满,会删除最早的记录,最新的记录追加进来。记录慢查询日志时Redis会对长命令做截断操作,并不会占用大量内存,建议设置稍大些,防止丢失日志
config rewrite #将服务器当前所使用的配置保存到redis.conf
slowlog len #获取慢查询日志列表的当前长度
slowlog get 5 #获取最新的5条慢查询日志。慢查询日志由四个属性组成:标识ID,发生时间戳,命令耗时,执行命令和参数
slowlog reset #重置慢查询日志
4、操作系统配置
(1)vm.swapiness
如果linux内核版本<3.5,那么swapiness设置为0,这样系统宁愿swap也不会oom killer(杀掉进程)
如果linux内核版本>=3.5,那么swapiness设置为1,这样系统宁愿swap也不会oom killer
cat /proc/version #查看linux内核版本
echo 1 > /proc/sys/vm/swappiness
echo vm.swapiness=1 >> /etc/sysctl.conf
cat /proc/sys/vm/overcommitmemory echo "vm.overcommitmemory=1" >> /etc/sysctl.conf
sysctl vm.overcommit_memory=1
(2)合理设置文件句柄数
ulimit -a #查看系统文件句柄数,看open files那项
ulimit -n 65535 #设置系统文件句柄数
12、Redis问题
1、缓存穿透
缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,通常出于容错的考虑,如果从存储层查不到数据则不写入缓存层。缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义。
第一,自身业务代码或者数据出现问题。
第二,一些恶意攻击、爬虫等造成大量空命中。
(1)缓存空对象
(2)布隆过滤器
2、缓存失效(击穿)
由于大批量缓存在同一时间失效可能导致大量请求同时穿透缓存直达数据库,可能会造成数据库瞬间压力过大甚至挂掉,对于这种情况我们在批量增加缓存时最好将这一批数据的缓存过期时间设置为一个时间段内的不同时间。
3、缓存雪崩
(1)保证缓存层服务高可用性,比如使用Redis Sentinel或Redis Cluster。
(2)依赖隔离组件为后端限流熔断并降级。比如使用Sentinel或Hystrix限流降级组件。比如服务降级,我们可以针对不同的数据采取不同的处理方式。当业务应用访问的是非核心数据(例如电商商品属性,用户信息等)时,暂时停止从缓存中查询这些数据,而是直接返回预定义的默认降级信息、空值或是错误提示信息;当业务应用访问的是核心数据(例如电商商品库存)时,仍然允许查询缓存,如果缓存缺失,也可以继续通过数据库读取。
(3)提前演练。在项目上线前,演练缓存层宕掉后,应用以及后端的负载情况以及可能出现的问题,在此基础上做一些预案设定。