侧边栏壁纸
博主头像
过去的,未来的博主等级

来日可期!

  • 累计撰写 277 篇文章
  • 累计创建 43 个标签
  • 累计收到 37 条评论

redis总结

过去的,未来的
2021-12-12 / 0 评论 / 0 点赞 / 151 阅读 / 20,771 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2021-12-12,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

一、基本概念

Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。 Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。 Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

二、数据结构

image.png

三、持久化底层原理和证明

由于 Redis 是一个内存数据库,所谓内存数据库,就是将数据库中的内容保存在内存中,这与传统的MySQL,Oracle等关系型数据库直接将内容保存到硬盘中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写效率)。但是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的数据将会全部丢失。

为了解决这个缺点,Redis提供了将内存数据持久化到硬盘,以及用持久化文件来恢复数据库数据的功能。Redis 支持两种形式的持久化,一种是RDB快照(snapshotting),另外一种是AOF(append-only-file)。

1、RDB 有两种触发方式,分别是自动触发和手动触发。
手动触发命令
save
  • 相关配置(配置文件中配置)
  • dbfilename:设置本地数据库文件名,默认值为 dump.rdb
  • dir:设置存储.rdb文件的路径
  • rdbcompression:设置存储至本地数据库时是否压缩数据,默认为 yes,采用 LZF 压缩,通常默认为开启状态,如果设置为no,可以节省 CPU 运行时间,但会使存储的文件变大(巨大)
  • rdbchecksum:默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但这样做会消耗大约10%的性能,如果希望获取到最大的性能提升,可以关闭此功能。
save方法工作原理

使用save命令:此命令会使用Redis的主线程进程同步存储,阻塞当前的Redis服务器,造成服务不可用,直到RDB过程完成。无论当前服务器数据量大小,线上不要用。
image.png

bgsave

使用bgsave命令:此命令会通过fork()创建子进程,在后台进程存储。只有fork阶段会阻塞当前Redis服务器,不必到整个RDB过程结束,一般时间很短。因此Redis内部涉及到RDB都采用bgsave命令。
image.png

自动持久化

一般我们是不会直接用命令生成RDB文件的,Redis支持自动触发RDB持久化机制,配置都在redis.conf文件里面。

save 900 1		# 900秒之内有1个key发生变化就保存一次
save 300 10		# 300秒之内有10个key发生变化就保存一次
save 60 10000	# 60秒之内有10000个key发生变化就保存一次

自动持久化底层采用的是bgsave指令。

总结

image.png

优点:

  • RDB是一个紧凑压缩的二进制文件,存储效率较高
  • RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
  • RDB恢复数据的速度要比AOF快很多
  • 应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。

缺点:

  • RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据,在这里有人说,把RDB持久化的频率调高一点不久可以吗?(save 1 1)你想想看,每次改变一个key,就进行一次全量快照的拍摄,这个性能是非常低的。
  • bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能
  • Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象
2、AOF持久化

AOF(append only file)持久化:AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态,也就是每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。

AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式
AOF持久化的三种策略
redis的AOF功能默认是关闭的,需要我们手动开启:

bind 127.0.0.1
port 6379
logfile "6379.log"
dir /root/redis-4.0.11/data
dbfilename drum-6379.rdb
rdbcompression yes
rdbchecksum yes
# save 10 2
daemonize yes
appendonly yes
appendfsync no
appendfilename appendonly-6379.aof
  • appendonly
yes:开启aof功能
no:关闭aof功能(默认值)
  • appendfsync
always(每次):每次写入操作均同步到AOF文件中,高并发下性能较低。
everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,默认配置
no(系统控制):由操作系统控制每次同步到AOF文件的周期,一般为30s每次。
  • appendfilename:aof文件名称

  • dir:aof文件路径

注意:AOF只会保存服务器所执行的写(set,del,add 等)的命令,对于其他对结果集并没有造成影响的命令是不会写入aof文件的。

AOF 持久化是通过保存被执行的写命令来记录数据库状态的,所以AOF文件的大小随着时间的流逝一定会越来越大,其中就包含了很多不必要的命令,如set某个key两次,其结果肯定为最后一次,那么前面一次的命令就没有必要再记录下来。

为了解决此问题,Redis引入了AOF重写机制用于压缩aof文件大小。

总结
RDB
优点
  • RDB是基于数据快照的理念设计的,每一个rdb文件都是一个已经压缩过的二进制文件,存储效率较高
  • 由于RDB是将数据全部存储在rdb文件中,即每个rdb文件都是原始数据,在恢复大数据集时的速度比 AOF 的恢复速度要快
缺点:
  • 如果对数据恢复非常敏感,那么RDB的持久化效率将没有AOF的高,虽然RDB可以设置保存点save,但是因为RDB每次拍摄数据快照需要将此次数据快照的所有数据都写入rdb文件,虽然会fork出一个子进程帮我们工作,不会影响主进程的工作,但这并不是一个轻松的操作。会影响主进程的性能。
  • RDB持久化方式并没有缓冲区的概念,如果rdb的子进程正在将数据写入到rdb文件,会导致数据库的数据和rdb文件中保存的数据不一致。
AOF
优点
  • AOF是基于日志形式的理念设计的,AOF将每一个操作指令的步骤都记录下来,因此同步的频率相对RDB来说可以非常的频繁。因此如果对数据比较敏感,不能够承受小规模的数据丢失,那么使用AOF是不错的选择。
  • AOF具有重写机制,可以有效的整理不必要的指令来压缩aof文件的大小,提升数据恢复的性能。
  • AOF 文件有序地保存了对数据库执行的所有写入操作,这些写入命令被redis保存到了aof文件上,这些指令让人可以轻松阅读,并且文件易于解析,当你中途不小心执行了flushall指令,只要aof文件没有被重写,此时可以编辑aof文件删除flushall指令,来恢复数据
缺点
  • 对于同等的数据量,AOF 文件的体积通常要大于 RDB 文件的体积。
  • 由于aof文件保存的是操作的命令,因此恢复起来速度要比RDB慢

四、混合持久化

因为RDB持久化 无法实时保存数据,数据库或者主机down机时,会丢失数据。AOF持久化虽然可以提高数据的安全性,但是在恢复数据时 需要大量时间。因此Redis 4.0 推出RDB-AOF混合持久化。

持久化时,可以根据AOF的落盘策略实时刷盘。

恢复时先加载AOF文件中的RDB部分,然后再加载AOF文件部分。

这样可以兼得RDB和AOF两种持久化的优点。

开启混合持久化

4.0版本的混合持久化功能 默认关闭,我们可以通过 aof-use-rdb-preamble配置参数控制该功能的启用。5.0 版本 默认开启。

需要特别注意的是 要开启混合持久化,必须同时设置 aof-use-rdb-preamble为yes ,开启 AOF持久化方式。

混合持久化流程

混合持久化开启,系统根据策略触发aof rewrite时,fork 一个子线程将内存数据以RDB二进制格式写入AOF文件头部,那些在重写操作执行之后执行的 Redis 命令,则以AOF持久化的方式追加到AOF文件的末尾。

开启混合模式时,AOF文件的内容

image.png

五、部署模式

1、单机模式
2、主从模式
3、哨兵模式
4、集群模式

https://www.fengpt.cn/archives/redis

六、redis配置文件分析

NETWORK

###################################  NETWORK ###################################
 
# 指定 redis 只接收来自于该IP地址的请求,如果不进行设置,那么将处理所有请求
bind 127.0.0.1
 
#是否开启保护模式,默认开启。要是配置里没有指定bind和密码。#开启该参数后,redis只会本地进行访问,拒绝外部访问。要是开启了密码和bind,可以开启。否则最好关闭,设置为no
protected-mode yes
 
#redis监听的端口号
port 6379
 
#此参数确定了TCP连接中已完成队列(完成三次握手之后)的长度, 当然此值必须不大于Linux系统定义的/proc/sys/net/core/somaxconn值,默认是511,而Linux的默认参数值是128。#当系统并发量大并且客户端速度缓慢的时候,可以将这二个参数一起参考设定。该内核参数默认值一般是128,对于负载很大的服务程序来说大大的不够。一般会将它修改为2048或者更大。#在/etc/sysctl.conf中添加:net.core.somaxconn = 2048,然后在终端中执行sysctl -p
tcp-backlog 511
 
#此参数为设置客户端空闲超过timeout,服务端会断开连接,为0则服务端不会主动断开连接,不能小于0
timeout 0
 
#tcp keepalive参数。如果设置不为0,就使用配置tcp的SO_KEEPALIVE值,使用keepalive有两个好处:检测挂掉的对端。降低中间设备出问题而导致网络看似连接却已经与对端端口的问题。在Linux内核中,设置了keepalive,redis会定时给对端发送ack。#检测到对端关闭需要两倍的设置值
tcp-keepalive 300
 
#是否在后台执行,yes:后台运行;no:不是后台运行
daemonize yes
 
#redis的进程文件
pidfile /var/run/redis/redis.pid
 
#指定了服务端日志的级别。级别包括:debug(很多信息,方便开发、测试),verbose(许多有用的信息,但是没有debug级别信息多),notice(适当的日志级别,适合生产环境),warn(只有非常重要的信息)
loglevel notice
 
#指定了记录日志的文件。空字符串的话,日志会打印到标准输出设备。后台运行的redis标准输出是/dev/null
logfile /usr/local/redis/var/redis.log
 
 
#是否打开记录syslog功能
# syslog-enabled no
 
#syslog的标识符。
# syslog-ident redis
 
#日志的来源、设备
# syslog-facility local0
 
#数据库的数量,默认使用的数据库是0。可以通过”SELECT 【数据库序号】“命令选择一个数据库,序号从0开始
databases 16
SNAPSHOTTING
###################################  SNAPSHOTTING  ###################################
 
#RDB核心规则配置 save <指定时间间隔> <执行指定次数更新操作>,满足条件就将内存中的数据同步到硬盘中。#官方出厂配置默认是 900秒内有1个更改,300秒内有10个更改以及60秒内有10000个更改,则将内存中的数据快照写入磁盘。
#若不想用RDB方案,可以把 save "" 的注释打开,下面三个注释
save 900 1
save 300 10
save 60 10000
 
#当RDB持久化出现错误后,是否依然进行继续进行工作,yes:不能进行工作,no:可以继续进行工作,可以通过info中的rdb_last_bgsave_status了解RDB持久化是否有错误
stop-writes-on-bgsave-error yes
 
#配置存储至本地数据库时是否压缩数据,默认为yes。Redis采用LZF压缩方式,但占用了一点CPU的时间。#若关闭该选项,但会导致数据库文件变的巨大。建议开启。
rdbcompression yes
 
#是否校验rdb文件;从rdb格式的第五个版本开始,在rdb文件的末尾会带上CRC64的校验和。#这跟有利于文件的容错性,但是在保存rdb文件的时候,会有大概10%的性能损耗,所以如果你追求高性能,可以关闭该配置
rdbchecksum yes
 
#指定本地数据库文件名,一般采用默认的 dump.rdb
dbfilename dump.rdb
 
#数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录
dir /usr/local/redis/var
REPLICATION
################################# REPLICATION #################################
 
# 复制选项,slave复制对应的master。
# replicaof <masterip> <masterport>
 
#如果master设置了requirepass,那么slave要连上master,需要有master的密码才行。
#masterauth就是用来配置master的密码,这样可以在连上master后进行认证。
# masterauth <master-password>
 
#当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:
#1) 如果slave-serve-stale-data设置为yes(默认设置),从库会继续响应客户端的请求。
#2) 如果slave-serve-stale-data设置为no,INFO,replicaOF, AUTH, PING, SHUTDOWN, REPLCONF, ROLE, CONFIG,SUBSCRIBE, UNSUBSCRIBE,
#PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB,COMMAND, POST, HOST: and LATENCY命令之外的任何请求都会返回一个错误”SYNC with master in progress”。
replica-serve-stale-data yes
 
#作为从服务器,默认情况下是只读的(yes),可以修改成NO,用于写(不建议)
#replica-read-only yes
 
# 是否使用socket方式复制数据。目前redis复制提供两种方式,disk和socket。
#如果新的slave连上来或者重连的slave无法部分同步,就会执行全量同步,master会生成rdb文件。
#有2种方式:
#disk方式是master创建一个新的进程把rdb文件保存到磁盘,再把磁盘上的rdb文件传递给slave。disk方式的时候,当一个rdb保存的过程中,多个slave都能共享这个rdb文件。
#socket是master创建一个新的进程,直接把rdb文件以socket的方式发给slave。socket的方式就的一个个slave顺序复制。
#在磁盘速度缓慢,网速快的情况下推荐用socket方式。
repl-diskless-sync no 
#diskless复制的延迟时间,防止设置为0。一旦复制开始,节点不会再接收新slave的复制请求直到下一个rdb传输。
所以最好等待一段时间,等更多的slave连上来
repl-diskless-sync-delay 5
 
#slave根据指定的时间间隔向服务器发送ping请求。时间间隔可以通过 repl_ping_slave_period 来设置,默认10秒。
# repl-ping-slave-period 10
 
# 复制连接超时时间。master和slave都有超时时间的设置。#master检测到slave上次发送的时间超过repl-timeout,即认为slave离线,清除该slave信息。#slave检测到上次和master交互的时间超过repl-timeout,则认为master离线。#需要注意的是repl-timeout需要设置一个比repl-ping-slave-period更大的值,不然会经常检测到超时
# repl-timeout 60
 
#是否禁止复制tcp链接的tcp nodelay参数,可传递yes或者no。默认是no,即使用tcp nodelay。#如果master设置了yes来禁止tcp nodelay设置,在把数据复制给slave的时候,会减少包的数量和更小的网络带宽。#但是这也可能带来数据的延迟。默认我们推荐更小的延迟,但是在数据量传输很大的场景下,建议选择yes
repl-disable-tcp-nodelay no
 
#复制缓冲区大小,这是一个环形复制缓冲区,用来保存最新复制的命令。#这样在slave离线的时候,不需要完全复制master的数据,如果可以执行部分同步,只需要把缓冲区的部分数据复制给slave,就能恢复正常复制状态。#缓冲区的大小越大,slave离线的时间可以更长,复制缓冲区只有在有slave连接的时候才分配内存。#没有slave的一段时间,内存会被释放出来,默认1m
# repl-backlog-size 1mb
 
# master没有slave一段时间会释放复制缓冲区的内存,repl-backlog-ttl用来设置该时间长度。单位为秒。
# repl-backlog-ttl 3600
 
# 当master不可用,Sentinel会根据slave的优先级选举一个master。#最低的优先级的slave,当选master。而配置成0,永远不会被选举
replica-priority 100
 
#redis提供了可以让master停止写入的方式,如果配置了min-replicas-to-write,健康的slave的个数小于N,mater就禁止写入。#master最少得有多少个健康的slave存活才能执行写命令。#这个配置虽然不能保证N个slave都一定能接收到master的写操作,但是能避免没有足够健康的slave的时候,master不能写入来避免数据丢失。#设置为0是关闭该功能
# min-replicas-to-write 3
 
# 延迟小于min-replicas-max-lag秒的slave才认为是健康的slave
# min-replicas-max-lag 10
 
# min-replicas-max-lag 设置1或设置0禁用这个特性。
# Setting one or the other to 0 disables the feature.
# By default min-replicas-to-write is set to 0 (feature disabled) and
# min-replicas-max-lag is set to 10.

SECURITY

#requirepass配置可以让用户使用AUTH命令来认证密码,才能使用其他命令。#这让redis可以使用在不受信任的网络中。为了保持向后的兼容性,可以注释该命令,因为大部分用户也不需要认证。#使用requirepass的时候需要注意,因为redis太快了,每秒可以认证15w次密码,简单的密码很容易被攻破,所以最好使用一个更复杂的密码
# requirepass foobared
#把危险的命令给修改成其他名称。比如CONFIG命令可以重命名为一个很难被猜到的命令,这样用户不能使用,而内部工具还能接着使用
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#设置成一个空的值,可以禁止一个命令
# rename-command CONFIG ""
CLIENTS
# 设置能连上redis的最大客户端连接数量。默认是10000个客户端连接。
# 由于redis不区分连接是客户端连接还是内部打开文件或者和slave连接等,所以maxclients最小建议设置到32。
# 如果超过了maxclients,redis会给新的连接发送’max number of clients reached’,并关闭连接
# maxclients 10000
MEMORY MANAGEMENT
#设置redis使用内存字节数,当达到内存最大值时,redis会根据选择的逐出策略尝试删除key(详细参阅maxmemory策略)#maxmemory <bytes>
#redis配置的最大内存容量。当内存满了,需要配合maxmemory-policy策略进行处理。#注意slave的输出缓冲区是不计算在maxmemory内的。所以为了防止主机内存使用完,建议设置的maxmemory需要更小一些maxmemory 122000000
#内存容量超过maxmemory后的处理策略。
#volatile-lru:利用LRU算法移除设置过过期时间的key。
#volatile-random:随机移除设置过过期时间的key。
#volatile-ttl:移除即将过期的key,根据最近过期时间来删除(辅以TTL)
#allkeys-lru:利用LRU算法移除任何key。
#allkeys-random:随机移除任何key。
#noeviction:不移除任何key,只是返回一个写错误。
#上面的这些驱逐策略,如果redis没有合适的key驱逐,对于写命令,还是会返回错误。#并且redis将不再接收写请求,只接收get请求。#写命令包括:set setnx setex append incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd # sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby zunionstore zinterstore hset # hsetnx hmset hincrby incrby decrby getset mset msetnx exec sort。
# maxmemory-policy noeviction
# lru检测的样本数。使用lru或者ttl淘汰算法,从需要淘汰的列表中随机选择sample个key,选出闲置时间最长的key移除
# maxmemory-samples 5
# 是否开启salve的最大内存
# replica-ignore-maxmemory yes
LAZY FREEING
#以非阻塞方式释放内存
#使用以下配置指令调用了
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
APPEND ONLY MODE
#Redis 默认不开启。它的出现是为了弥补RDB的不足(数据的不一致性),所以它采用日志的形式来记录每个写操作,并追加到文件中。#Redis 重启的会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作默认redis使用的是rdb方式持久化,这种方式在许多应用中已经足够用了。#但是redis如果中途宕机,会导致可能有几分钟的数据丢失,根据save来策略进行持久化,Append Only File是另一种持久化方式,可以提供更好的持久化特性。#Redis会把每次写入的数据在接收后都写入 appendonly.aof 文件,每次启动时Redis都会先把这个文件的数据读入内存里,先忽略RDB文件。#若开启rdb则将no改为yes
appendonly no
 
#指定本地数据库文件名,默认值为 appendonly.aof
appendfilename "appendonly.aof"
 
#aof持久化策略的配置
#no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快
#always表示每次写入都执行fsync,以保证数据同步到磁盘
#everysec表示每秒执行一次fsync,可能会导致丢失这1s数据
# appendfsync always
appendfsync everysec
# appendfsync no
 
# 在aof重写或者写入rdb文件的时候,会执行大量IO,此时对于everysec和always的aof模式来说,执行fsync会造成阻塞过长时间,no-appendfsync-on-rewrite字段设置为默认设置为no。#如果对延迟要求很高的应用,这个字段可以设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。#设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes。#Linux的默认fsync策略是30秒。可能丢失30秒数据
no-appendfsync-on-rewrite no
 
#aof自动重写配置。当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增长到一定大小的时候Redis能够调用bgrewriteaof对日志文件进行重写。#当前AOF文件大小是上次日志重写得到AOF文件大小的二倍(设置为100)时,自动启动新的日志重写过程
auto-aof-rewrite-percentage 100
 
#设置允许重写的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写
auto-aof-rewrite-min-size 64mb
 
#aof文件可能在尾部是不完整的,当redis启动的时候,aof文件的数据被载入内存。#重启可能发生在redis所在的主机操作系统宕机后,尤其在ext4文件系统没有加上data=ordered选项(redis宕机或者异常终止不会造成尾部不完整现象。)#出现这种现象,可以选择让redis退出,或者导入尽可能多的数据。#如果选择的是yes,当截断的aof文件被导入的时候,会自动发布一个log给客户端然后load。#如果是no,用户必须手动redis-check-aof修复AOF文件才可以
aof-load-truncated yes
 
#加载redis时,可以识别AOF文件以“redis”开头。
#字符串并加载带前缀的RDB文件,然后继续加载AOF尾巴
aof-use-rdb-preamble yes
LUA SCRIPTING
# 如果达到最大时间限制(毫秒),redis会记个log,然后返回error。
#当一个脚本超过了最大时限。只有SCRIPT KILL和SHUTDOWN NOSAVE可以用。
#第一个可以杀没有调write命令的东西。要是已经调用了write,只能用第二个命令杀
lua-time-limit 5000
REDIS CLUSTER
# 集群开关,默认是不开启集群模式
# cluster-enabled yes
 
#集群配置文件的名称,每个节点都有一个集群相关的配置文件,持久化保存集群的信息。#这个文件并不需要手动配置,这个配置文件有Redis生成并更新,每个Redis集群节点需要一个单独的配置文件,请确保与实例运行的系统中配置文件名称不冲突
# cluster-config-file nodes-6379.conf
 
#节点互连超时的阀值。集群节点超时毫秒数
# cluster-node-timeout 15000
 
#在进行故障转移的时候,全部slave都会请求申请为master,但是有些slave可能与master断开连接一段时间了,导致数据过于陈旧,这样的slave不应该被提升为master。#该参数就是用来判断slave节点与master断线的时间是否过长。判断方法是:
#比较slave断开连接的时间和(node-timeout * slave-validity-factor) + repl-ping-slave-period
#如果节点超时时间为三十秒, 并且slave-validity-factor为10,假设默认的repl-ping-slave-period是10秒,即如果超过310秒slave将不会尝试进行故障转移
# cluster-replica-validity-factor 10
 
# master的slave数量大于该值,slave才能迁移到其他孤立master上,如这个参数若被设为2,那么只有当一个主节点拥有2 个可工作的从节点时,它的一个从节点会尝试迁移
# cluster-migration-barrier 1
 
#默认情况下,集群全部的slot有节点负责,集群状态才为ok,才能提供服务。#设置为no,可以在slot没有全部分配的时候提供服务。#不建议打开该配置,这样会造成分区的时候,小分区的master一直在接受写请求,而造成很长时间数据不一致
# cluster-require-full-coverage yes
CLUSTER DOCKER/NAT support
#*群集公告IP
#*群集公告端口
#*群集公告总线端口
# Example:
# cluster-announce-ip 10.1.1.5
# cluster-announce-port 6379
# cluster-announce-bus-port 6380
SLOW LOG
# slog log是用来记录redis运行中执行比较慢的命令耗时。#当命令的执行超过了指定时间,就记录在slow log中,slog log保存在内存中,所以没有IO操作。#执行时间比slowlog-log-slower-than大的请求记录到slowlog里面,单位是微秒,所以1000000就是1秒。#注意,负数时间会禁用慢查询日志,而0则会强制记录所有命令。
slowlog-log-slower-than 10000
 
#慢查询日志长度。当一个新的命令被写进日志的时候,最老的那个记录会被删掉。#这个长度没有限制。只要有足够的内存就行。#你可以通过 SLOWLOG RESET 来释放内存
slowlog-max-len 128
LATENCY MONITOR
#延迟监控功能是用来监控redis中执行比较缓慢的一些操作,用LATENCY打印redis实例在跑命令时的耗时图表。
#只记录大于等于下边设置的值的操作。0的话,就是关闭监视。
#默认延迟监控功能是关闭的,如果你需要打开,也可以通过CONFIG SET命令动态设置
latency-monitor-threshold 0
EVENT NOTIFICATION
#键空间通知使得客户端可以通过订阅频道或模式,来接收那些以某种方式改动了 Redis 数据集的事件。因为开启键空间通知功能需要消耗一些 CPU ,所以在默认配置下,该功能处于关闭状态。
#notify-keyspace-events 的参数可以是以下字符的任意组合,它指定了服务器该发送哪些类型的通知:
##K 键空间通知,所有通知以 __keyspace@__ 为前缀
##E 键事件通知,所有通知以 __keyevent@__ 为前缀
##g DEL 、 EXPIRE 、 RENAME 等类型无关的通用命令的通知
##$ 字符串命令的通知
##l 列表命令的通知
##s 集合命令的通知
##h 哈希命令的通知
##z 有序集合命令的通知
##x 过期事件:每当有过期键被删除时发送
##e 驱逐(evict)事件:每当有键因为 maxmemory 政策而被删除时发送
##A 参数 g$lshzxe 的别名
#输入的参数中至少要有一个 K 或者 E,否则的话,不管其余的参数是什么,都不会有任何 通知被分发。详细使用可以参考http://redis.io/topics/notifications
 
notify-keyspace-events ""
ADVANCED CONFIG
# 数据量小于等于hash-max-ziplist-entries的用ziplist,大于hash-max-ziplist-entries用hash
hash-max-ziplist-entries 512
 
# value大小小于等于hash-max-ziplist-value的用ziplist,大于hash-max-ziplist-value用hash
hash-max-ziplist-value 64
 
#-5:最大大小:64 KB<--不建议用于正常工作负载
#-4:最大大小:32 KB<--不推荐
#-3:最大大小:16 KB<--可能不推荐
#-2:最大大小:8kb<--良好
#-1:最大大小:4kb<--良好
list-max-ziplist-size -2
 
#0:禁用所有列表压缩
#1:深度1表示“在列表中的1个节点之后才开始压缩,
#从头部或尾部
#所以:【head】->node->node->…->node->【tail】
#[头部],[尾部]将始终未压缩;内部节点将压缩。
#2:[头部]->[下一步]->节点->节点->…->节点->[上一步]->[尾部]
#2这里的意思是:不要压缩头部或头部->下一个或尾部->上一个或尾部,
#但是压缩它们之间的所有节点。
#3:[头部]->[下一步]->[下一步]->节点->节点->…->节点->[上一步]->[上一步]->[尾部]
list-compress-depth 0
 
# 数据量小于等于set-max-intset-entries用iniset,大于set-max-intset-entries用set
set-max-intset-entries 512
 
#数据量小于等于zset-max-ziplist-entries用ziplist,大于zset-max-ziplist-entries用zset
zset-max-ziplist-entries 128
 
#value大小小于等于zset-max-ziplist-value用ziplist,大于zset-max-ziplist-value用zset
zset-max-ziplist-value 64
 
#value大小小于等于hll-sparse-max-bytes使用稀疏数据结构(sparse),大于hll-sparse-max-bytes使用稠密的数据结构(dense)。#一个比16000大的value是几乎没用的,建议的value大概为3000。如果对CPU要求不高,对空间要求较高的,建议设置到10000左右
hll-sparse-max-bytes 3000
 
#宏观节点的最大流/项目的大小。在流数据结构是一个基数
#树节点编码在这项大的多。利用这个配置它是如何可能#大节点配置是单字节和
#最大项目数,这可能包含了在切换到新节点的时候
# appending新的流条目。如果任何以下设置来设置
# ignored极限是零,例如,操作系统,它有可能只是一集通过设置限制最大#纪录到最大字节0和最大输入到所需的值
stream-node-max-bytes 4096
stream-node-max-entries 100
 
#Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用。#当你的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。#如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存
activerehashing yes
 
##对客户端输出缓冲进行限制可以强迫那些不从服务器读取数据的客户端断开连接,用来强制关闭传输缓慢的客户端。
#对于normal client,第一个0表示取消hard limit,#第二个0和第三个0表示取消soft limit,normal client默认取消限制,因为如果没有寻问,他们是不会接收数据的
client-output-buffer-limit normal 0 0 0
 
#对于slave client和MONITER client,如果client-output-buffer一旦超过256mb,又或者超过64mb持续60秒,那么服务器就会立即断开客户端连接
client-output-buffer-limit replica 256mb 64mb 60
 
#对于pubsub client,如果client-output-buffer一旦超过32mb,又或者超过8mb持续60秒,那么服务器就会立即断开客户端连接
client-output-buffer-limit pubsub 32mb 8mb 60
 
# 这是客户端查询的缓存极限值大小
# client-query-buffer-limit 1gb
 
#在redis协议中,批量请求,即表示单个字符串,通常限制为512 MB。但是您可以更改此限制。
# proto-max-bulk-len 512mb
 
#redis执行任务的频率为1s除以hz
hz 10
 
#当启用动态赫兹时,实际配置的赫兹将用作作为基线,但实际配置的赫兹值的倍数
#在连接更多客户端后根据需要使用。这样一个闲置的实例将占用很少的CPU时间,而繁忙的实例将反应更灵敏
dynamic-hz yes
 
#在aof重写的时候,如果打开了aof-rewrite-incremental-fsync开关,系统会每32MB执行一次fsync。#这对于把文件写入磁盘是有帮助的,可以避免过大的延迟峰值
aof-rewrite-incremental-fsync yes
 
#在rdb保存的时候,如果打开了rdb-save-incremental-fsync开关,系统会每32MB执行一次fsync。#这对于把文件写入磁盘是有帮助的,可以避免过大的延迟峰值
rdb-save-incremental-fsync yes
ACTIVE DEFRAGMENTATION
# 已启用活动碎片整理
# activedefrag yes
# 启动活动碎片整理的最小碎片浪费量
# active-defrag-ignore-bytes 100mb
# 启动活动碎片整理的最小碎片百分比
# active-defrag-threshold-lower 10
# 我们使用最大努力的最大碎片百分比
# active-defrag-threshold-upper 100
# 以CPU百分比表示的碎片整理的最小工作量
# active-defrag-cycle-min 5
# 在CPU的百分比最大的努力和碎片整理
# active-defrag-cycle-max 75
#将从中处理的set/hash/zset/list字段的最大数目
#主词典扫描
# active-defrag-max-scan-fields 1000

七、redis普通锁与redlock锁

1、redis普通锁
  • 加锁
    加锁实际上就是在redis中,给Key键设置一个值,为避免死锁,并给定一个过期时间。
SET lock_key random_value NX PX 5000

值得注意的是:

random_value 是客户端生成的唯一的字符串。
NX 代表只在键不存在时,才对键进行设置操作。
PX 5000 设置键的过期时间为5000毫秒。

这样,如果上面的命令执行成功,则证明客户端获取到了锁。

  • 解锁
    解锁的过程就是将Key键删除。但也不能乱删,不能说客户端1的请求将客户端2的锁给删除掉。这时候random_value的作用就体现出来。

为了保证解锁操作的原子性,我们用LUA脚本完成这一操作。先判断当前锁的字符串是否与传入的值相等,是的话就删除Key,解锁成功。

2、redlock锁

Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁;

使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击);
这个锁的算法实现了多redis实例的情况,相对于单redis节点来说,优点在于 防止了 单节点故障造成整个服务停止运行的情况;并且在多节点中锁的设计,及多节点同时崩溃等各种意外情况有自己独特的设计方法;

最低保证分布式锁的有效性及安全性的要求如下:
1.互斥;任何时刻只能有一个client获取锁

2.释放死锁;即使锁定资源的服务崩溃或者分区,仍然能释放锁

3.容错性;只要多数redis节点(一半以上)在使用,client就可以获取和释放锁
网上讲的基于故障转移实现的redis主从无法真正实现Redlock:
因为redis在进行主从复制时是异步完成的,比如在clientA获取锁后,主redis复制数据到从redis过程中崩溃了,导致没有复制到从redis中,然后从redis选举出一个升级为主redis,造成新的主redis没有clientA 设置的锁,这是clientB尝试获取锁,并且能够成功获取锁,导致互斥失效;

思考题:这个失败的原因是因为从redis立刻升级为主redis,如果能够过TTL时间再升级为主redis(延迟升级)后,或者立刻升级为主redis但是过TTL的时间后再执行获取锁的任务,就能成功产生互斥效果;是不是这样就能实现基于redis主从的Redlock;

八、redis的过期策略以及内存淘汰机制

https://www.fengpt.cn/archives/redis%E7%9A%84%E8%BF%87%E6%9C%9F%E7%AD%96%E7%95%A5

九、缓存三大问题

1、缓存击穿

热点数据集中失效,这就是缓存击穿。
我们一般都会给缓存设定一个失效时间,过了失效时间后,该数据库会被缓存直接删除,从而一定程度上保证数据的实时性。

但是,对于一些请求量极高的热点数据而言,一旦过了有效时间,此刻将会有大量请求落在数据库上,从而可能会导致数据库崩溃。
如果某一个热点数据失效,那么当再次有该数据的查询请求[req-1]时就会前往数据库查询。但是,从请求发往数据库,到该数据更新到缓存中的这段时间中,由于缓存中仍然没有该数据,因此这段时间内到达的查询请求都会落到数据库上,这将会对数据库造成巨大的压力。此外,当这些请求查询完成后,都会重复更新缓存。

  • 缓存击穿这里强调的是并发,造成缓存击穿的原因有以下两个:
该数据没有人查询过 ,第一次就大并发的访问。(冷门数据)

添加到了缓存,reids有设置数据失效的时间 ,这条数据刚好失效,大并发访问(热点数据)
解决方案
  • 互斥锁
    此方法只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,重新从缓存获取数据即可
  • 永远不过期

##### 两种方案的比较
互斥锁 (mutex key):这种方案思路比较简单,但是存在一定的隐患,如果构建缓存过程出现问题或者时间较长,可能会存在死锁和线程池阻塞的风险,但是这种方法能够较好的降低后端存储负载并在一致性上做的比较好。
” 永远不过期 “:这种方案由于没有设置真正的过期时间,实际上已经不存在热点 key 产生的一系列危害,但是会存在数据不一致的情况,同时代码复杂度会增大。

2、缓存雪崩

如果缓存因某种原因发生了宕机,那么原本被缓存抵挡的海量查询请求就会像疯狗一样涌向数据库。此时数据库如果抵挡不了这巨大的压力,它就会崩溃。
这就是缓存雪崩。

如何避免缓存雪崩?
  • 使用缓存集群,保证缓存高可用
  • 使用Hystrix
3、缓存穿透

业务系统访问压根就不存在的数据,就称为缓存穿透。

缓存穿透的危害

如果存在海量请求查询压根就不存在的数据,那么这些海量请求都会落到数据库中,数据库压力剧增,可能会导致系统崩溃(你要知道,目前业务系统中最脆弱的就是IO,稍微来点压力它就会崩溃,所以我们要想种种办法保护它)。

缓存穿透的解决方案
  • 缓存空数据
    之所以发生缓存穿透,是因为缓存中没有存储这些空数据的key,导致这些请求全都打到数据库上。

那么,我们可以稍微修改一下业务系统的代码,将数据库查询结果为空的key也存储在缓存中。当后续又出现该key的查询请求时,缓存直接返回null,而无需查询数据库。

缓存空对象会有两个问题: 

第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。 
第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为 5 分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

  • BloomFilter
    第二种避免缓存穿透的方式即为使用BloomFilter。

它需要在缓存之前再加一道屏障,里面存储目前数据库中存在的所有key
当业务系统有查询请求的时候,首先去BloomFilter中查询该key是否存在。若不存在,则说明数据库中也不存在该数据,因此缓存都不要查了,直接返回null。若存在,则继续执行后续的流程,先前往缓存中查询,缓存中没有的话再前往数据库中的查询。

这种方法适用于数据命中不高,数据相对固定实时性低(通常是数据集较大)的应用场景,代码维护较为复杂,但是缓存空间占用少。

十、Redis集群在查找key的时候,是如何路由的?

https://www.fengpt.cn/archives/redis%E9%9B%86%E7%BE%A4%E5%9C%A8%E6%9F%A5%E6%89%BEkey%E7%9A%84%E6%97%B6%E5%80%99%E6%98%AF%E5%A6%82%E4%BD%95%E8%B7%AF%E7%94%B1%E7%9A%84

十一、主从数据同步的原理

十二、Redis事务

Redis事务的概念:

  Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。

  总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。  

Redis事务没有隔离级别的概念:

  批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到。

Redis不保证原子性:

  Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。

Redis事务的三个阶段:
开始事务
命令入队
执行事务
Redis事务相关命令:
  watch key1 key2 ... : 监视一或多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 )

  multi : 标记一个事务块的开始( queued )

  exec : 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 ) 

  discard : 取消事务,放弃事务块中的所有命令

  unwatch : 取消watch对所有key的监控

image.png

十三、redis使用

1、使用过Redis做异步队列
2、发布订阅
3、微博热搜榜

十四、redis的异步事件模型

十五、redis常见性能问题和解决方案:

Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件

如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次(AOF有3种同步方式:1.每秒同步,2.每修改同步,3.不同步)

为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内

尽量避免在压力很大的主库上增加从库

主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3…

这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

十五、Redis的rehash过程

过程是:RedisServer结构体中(Redis使用C语言完成)有一个Dictionary数组,默认容量大小是16, 每个 Dictionary结构体中有三个Dict结构体指针,Dict其实就是一个KV结构,类似于HashMap,其中两个作为数据存储的库,一个作为当前使用,一个作为备用rehash;另外一个Dict存储键的过期时间。Redis的rehash过程其实就是将上述的16个Dictionary进行rehash,Redis内部支持一个周期循环运行的ctro函数,这个函数定期检查上述的16个Dictionary是否需要rehash,如果有需要,ctro会完成Dictionary的rehash过程,周期结束后并且记录当前循环到Dictionary数组中的哪一个角标,方便再次循环时从上一次循环停止的地方开始。

其中还有一点,Redis的rehash是延迟性的,每次put会将新元素加入到新的表中,每次查询时,首先会在新的表中查找,如果没有,在旧的表中查找,查找到的话将这个元素插入到新的表中(这个过程也会涉及到检查元素是否过期的问题)

十六、异常问题

1、数据传输的时候断网了或者服务器挂了怎么办啊?
2、缓存双写问题
3、redis慢的原因排查
4、redis的异常和慢操作
1)突然删除大量的key
2)使用 keys *

image.png
参考:
https://www.imooc.com/article/36399
https://blog.csdn.net/Bb15070047748/article/details/105500236
https://www.cnblogs.com/nhdlb/p/14048083.html
https://www.cnblogs.com/rgcLOVEyaya/p/RGC_LOVE_YAYA_1003days.html
https://www.cnblogs.com/DeepInThought/p/10720132.html
https://blog.csdn.net/haoxin963/article/details/83245113

0

评论区