1.通过redis-cli客户端连接服务器后,查看内存使用情况
info memory
说明:info命令可以显示redis服务器的许多信息,包括服务器基本信息、CPU、内存、持久化、客户端连接信息等等;memory是参数,表示只显示内存相关的信息。
2.利用共享对象,可以减少对象的创建(同时减少了redisObject的创建),节省内存空间。目前redis中的共享对象只包括10000个整数(0-9999);可以通过调整REDIS_SHARED_INTEGERS参数提高共享对象的个数;例如将REDIS_SHARED_INTEGERS调整到20000,则0-19999之间的对象都可以共享。
3.RDB持久化
save命令和bgsave命令都可以生成RDB文件,即RDB持久化。将当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),保存的文件后缀是rdb;当Redis重新启动时,可以读取快照文件恢复数据。
两命令的区别说明:
(1)save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求;
(2)bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程(即Redis主进程)则继续处理请求。
因此save已基本被废弃,线上环境要杜绝save的使用。
此外,还可以在redis配置文件中设置自动触发。通过save m n,指定当m秒内发生n次变化时,会触发bgsave。如果没有save m n配置,相当于自动的RDB持久化关闭。
4.RDB常用配置
(1)save m n:bgsave自动触发的条件;
(2)stop-writes-on-bgsave-error yes:当bgsave出现错误时,Redis是否停止执行写命令;
(3)rdbcompression yes:是否开启RDB文件压缩;
(4)rdbchecksum yes:是否开启RDB文件的校验;
(5) dir ./:RDB文件和AOF文件所在目录;dbfilename dump.rdb:RDB文件名。
5.AOF持久化
Append Only File持久化,是将Redis执行的每次写命令记录到单独的日志文件中(类似于MySQL的binlog);当Redis重启时再次执行AOF文件中的命令来恢复数据。与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢。
Redis服务器默认开启RDB,关闭AOF;要开启AOF,需要在配置文件中配置:
appendonly yes
6.文件重写(rewrite)
文件重写是指定期重写AOF文件,减小AOF文件的体积。AOF重写是把Redis进程内的数据转化为写命令,同步到新的AOF文件;不会对旧的AOF文件进行任何读取、写入操作!由于重写后AOF执行的命令减少了,文件重写既可以减少文件占用的空间,也可以加快恢复速度。
7.文件重写的触发
(1)手动触发。直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞。
(2)自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数,以及aof_current_size和aof_base_size状态确定触发时机。触发条件可以通过以下命令查看:
info persistence
8.AOF常用配置
(1)ppendonly no:是否开启AOF;
(2)ppendfilename "appendonly.aof":AOF文件名;
(3)dir ./:RDB文件和AOF文件所在目录;
(4)appendfsync everysec:fsync持久化策略;
(5)no-appendfsync-on-rewrite no:AOF重写期间是否禁止fsync;如果开启该选项,可以减轻文件重写时CPU和硬盘的负载(尤其是硬盘),但是可能会丢失AOF重写期间的数据;需要在负载和安全性之间进行平衡;
(6)auto-aof-rewrite-percentage 100 和 auto-aof-rewrite-min-size 64mb 文件重写触发条件;
(7)aof-load-truncated yes:如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件。
9.观察线上环境fork的耗时
在Redis中,无论是RDB持久化的bgsave,还是AOF重写的bgrewriteaof,都需要fork出子进程来进行操作。Redis主进程在进行fork时,是完全阻塞的,也就意味着无法响应客户端的请求,会造成请求延迟过大。对于不同的硬件、不同的操作系统,fork操作的耗时会有所差别。观察的方法如下:执行命令info stats,查看latest_fork_usec的值,单位为微秒。
10.主从复制
主从复制的开启,完全是在从节点发起的;不需要在主节点做任何事情,建立或断开都是在从节点上执行。
建立复制关系
slaveof <masterip> <masterport>
断开复制
slaveof no one
需要注意的是,从节点断开复制后,不会删除已有的数据,只是不再接受主节点新的数据变化。
11.与主从延迟相关的主要参数
(1)repl-disable-tcp-nodelay no:该配置作用于命令传播阶段,控制主节点是否禁止与从节点的TCP_NODELAY;默认no,即不禁止TCP_NODELAY。当设置为yes时,TCP会对包进行合并从而减少带宽,但是发送的频率会降低,从节点数据延迟增加,一致性变差;具体发送频率与Linux内核的配置有关,默认配置为40ms。当设置为no时,TCP会立马将主节点的数据发送给从节点,带宽增加但延迟变小。一般来说,只有当应用对Redis数据不一致的容忍度较高,且主从节点之间网络状况不好时,才会设置为yes;多数情况使用默认值no。
(2)Redis主节点中使用min-slaves-to-write和min-slaves-max-lag参数,来保证主节点在不安全的情况下不会执行写命令。例如min-slaves-to-write和min-slaves-max-lag分别是3和10,含义是如果从节点数量小于3个,或所有从节点的延迟值都大于10s,则主节点拒绝执行写命令。从节点延迟值可以通过info Replication中的lag值获取。
(3)slave-serve-stale-data, 参数控制从节点在主从不一致事的表现;如果为yes(默认值),则从节点仍能够响应客户端的命令,如果为no,则从节点只能响应info、slaveof等少数命令。该参数的设置与应用对数据一致性的要求有关;如果对数据一致性要求很高,则应设置为no。
(4)repl-timeout ,参数规定了主从复制超时时间的阈值(默认60s),对于主节点和从节点同时有效。
12.主从复制心跳机制
主从节点还维持着心跳机制:PING和REPLCONF ACK。心跳机制对于主从复制的超时判断、数据安全等有作用。
(1)主-->从【存疑】:每隔指定的时间,主节点会向从节点发送PING命令,主要是为了让从节点进行超时判断。发送频率由repl-ping-slave-period参数控制,单位是秒,默认值是10s。该参数应明显小于repl-timeout值(后者至少是前者的几倍)。
(2)从-->主:从节点会向主节点发送REPLCONF ACK命令,频率是每秒1次。命令格式为:REPLCONF ACK {offset},其中offset指从节点保存的复制偏移量。
13.其它主从复制相关的配置
配置参数 | 作用说明 | 注意事项 |
repl-diskless-sync no | 作用于全量复制阶段,控制主节点是否使用diskless复制(无盘复制)。 | diskless复制,是指在全量复制时,主节点不再先把数据写入RDB文件,而是直接写入slave的socket中,整个过程中不涉及硬盘;diskless复制在磁盘IO很慢而网速很快时更有优势。需要注意的是,截至Redis3.0,diskless复制处于实验阶段,默认是关闭的。 |
repl-diskless-sync-delay 5 | 该配置作用于全量复制阶段,当主节点使用diskless复制时,该配置决定主节点向从节点发送之前停顿的时间,单位是秒;只有当diskless复制打开时有效,默认5s。 | 如此设置的原因:(1)向slave的socket的传输一旦开始,新连接的slave只能等待当前数据传输结束,才能开始新的数据传输 (2)多个从节点有较大的概率在短时间内建立主从复制。 |
client-output-buffer-limit slave 256MB 64MB 60 | 与全量复制阶段主节点的缓冲区大小有关。 | 其含义是:如果buffer大于256MB,或者连续60s大于64MB,则主节点会断开与该从节点的连接。 |
masterauth <master-password> | 与连接建立阶段的身份验证有关。 | |
repl-backlog-size 1mb | 复制积压缓冲区的大小。 | 需要注意的是,复制缓冲区是客户端输出缓冲区的一种,主节点会为每一个从节点分别分配复制缓冲区;而复制积压缓冲区则是一个主节点只有一个,无论它有多少个从节点。 |
repl-backlog-ttl 3600 | 当主节点没有从节点时,复制积压缓冲区保留的时间,这样当断开的从节点重新连进来时,可以进行全量复制;默认3600s。 | 如果设置为0,则永远不会释放复制积压缓冲区。 |
slave-read-only yes | 从节点是否只读;默认是只读的。 | 由于从节点开启写操作容易导致主从节点的数据不一致,因此该配置尽量不要修改。 |
14.哨兵的功能
哨兵的核心功能是主节点的自动故障转移。
(1)监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常;
(2)自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点;
(3)配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址(哨兵只是配置提供者,而不是代理。);
(4)通知(Notification):哨兵可以将故障转移的结果发送给客户端。
15. 哨兵获取主节点信息
哨兵节点调用以下命令即可获取主节点信息,需要传递的参数是masterName16
sentinel get-master-addr-by-name XXXXXXXXX
16. 哨兵节点支持的主要命令
哨兵节点支持的主要命令归纳如下:
命令分类 | 主要命令 | 功能说明 |
基础查询 | info sentinel | 获取sentinel监控到的信息 |
sentinel masters | 罗列所有sentinel 监视相关的master | |
sentinel master mymaster | 获取监控的主节点mymaster的详细信息 | |
sentinel slaves mymaster | 获取监控的主节点mymaster的从节点的详细信息 | |
sentinel sentinels mymaster | 列出master相关的sentinels组其他相关的信息 | |
sentinel get-master-addr-by-name mymaster | 获取监控的主节点mymaster的地址信息 | |
sentinel is-master-down-by-addr | 哨兵节点之间可以通过该命令询问主节点是否下线,从而对是否客观下线做出判断 | |
增加/移除对主节点的监控 | SENTINEL MONITOR <mastername> <ip> <port> <quorum> | 这个命令告诉sentinel去监听一个新的master |
SENTINEL REMOVE <mastername> | 命令sentinel放弃对某个master的监听 | |
强制故障转移 | SENTINEL failover <master name> | 该命令可以强制对mymaster执行故障转移,即便当前的主节点运行完好;发起故障转移的 Sentinel 会向其他 Sentinel 发送一个新的配置,其他 Sentinel 会根据这个配置进行相应的更新 |
17.与哨兵相关的几个配置
配置参数 | 参数说明 |
sentinel monitor {masterName} {masterIp} {masterPort} {quorum} | masterName指定了主节点名称,masterIp和masterPort指定了主节点地址,quorum是判断主节点客观下线的哨兵数量阈值:当判定主节点下线的哨兵数量达到quorum时,对主节点进行客观下线。建议取值为哨兵数量的一半加1。 |
sentinel down-after-milliseconds {masterName} {time} | 哨兵使用ping命令对其他节点进行心跳检测,如果其他节点超过down-after-milliseconds配置的时间没有回复,哨兵就会将其进行主观下线。该配置对主节点、从节点和哨兵节点的主观下线判定都有效。 down-after-milliseconds的默认值是30000,即30s;可以根据不同的网络环境和应用要求来调整:值越大,对主观下线的判定会越宽松,好处是误判的可能性小,坏处是故障发现和故障转移的时间变长,客户端等待的时间也会变长。例如,如果应用对可用性要求较高,则可以将值适当调小,当故障发生时尽快完成转移;如果网络环境相对较差,可以适当提高该阈值,避免频繁误判。 |
sentinel parallel-syncs {masterName} {number} | 参数规定了每次向新的主节点发起复制操作的从节点个数。例如,假设主节点切换完成之后,有3个从节点要向新的主节点发起复制;如果parallel-syncs=1,则从节点会一个一个开始复制;如果parallel-syncs=3,则3个从节点会一起开始复制。 parallel-syncs取值越大,从节点完成复制的时间越快,但是对主节点的网络负载、硬盘负载造成的压力也越大;应根据实际情况设置。例如,如果主节点的负载较低,而从节点对服务可用的要求较高,可以适量增加parallel-syncs取值。parallel-syncs的默认值是1。 |
sentinel failover-timeout {masterName} {time} | sentinel failover-timeout与故障转移超时的判断有关,但是该参数不是用来判断整个故障转移阶段的超时,而是其几个子阶段的超时,例如如果主节点晋升从节点时间超过timeout,或从节点向新的主节点发起复制操作的时间(不包括复制数据的时间)超过timeout,都会导致故障转移超时失败。 failover-timeout的默认值是180000,即180s;如果超时,则下一次该值会变为原来的2倍。 |
18.集群(Redis Cluster)主要作用
(1)数据分区:数据分区(或称数据分片)是集群最核心的功能;
(2)高可用:集群支持主从复制和主节点的自动故障转移(与哨兵类似);当任一节点发生故障时,集群仍然可以对外提供服务。
19.集群配置文件(cluster-config-file)
该参数为Redis配置文件中的一个参数。该参数指定了集群配置文件的位置。每个节点在运行过程中,会维护一份集群配置文件;每当集群信息发生变化时(如增减节点),集群内所有节点会将最新信息更新到该配置文件;当节点重启后,会重新读取该配置文件,获取集群信息,可以方便的重新加入到集群中。也就是说,当Redis节点以集群模式启动时,会首先寻找是否有集群配置文件,如果有则使用文件中的配置启动,如果没有,则初始化配置并将配置保存到文件中。集群配置文件由Redis节点维护,不需要人工修改。
20.集群节点中的槽
在Redis集群中,借助槽实现数据分区。集群有16384个槽,槽是数据管理和迁移的基本单位。当数据库中的16384个槽都分配了节点时,集群处于上线状态(ok);如果有任意一个槽没有分配节点,则集群处于下线状态(fail)。槽是数据管理和迁移的基本单位。槽解耦了数据和实际节点之间的关系,增加或删除节点对系统的影响很小。Redis集群将数据映射到实际节点的过程:
(1)Redis对数据的特征值(一般是key)计算哈希值,使用的算法是CRC16。
(2)根据哈希值,计算数据属于哪个槽。
(3)根据槽与节点的映射关系,计算数据属于哪个节点。
21.集群中的消息类型
消息类型 | 说明 |
MEET消息 | 在节点握手阶段,当节点收到客户端的CLUSTER MEET命令时,会向新加入的节点发送MEET消息,请求新节点加入到当前集群;新节点收到MEET消息后会回复一个PONG消息。 |
PING消息 | 集群里每个节点每秒钟会选择部分节点发送PING消息,接收者收到消息后会回复一个PONG消息。PING消息的内容是自身节点和部分其他节点的状态信息;作用是彼此交换信息,以及检测节点是否在线。PING消息使用Gossip协议发送,接收节点的选择兼顾了收敛速度和带宽成本,具体规则如下:(1)随机找5个节点,在其中选择最久没有通信的1个节点(2)扫描节点列表,选择最近一次收到PONG消息时间大于cluster_node_timeout/2的所有节点,防止这些节点长时间未更新。 |
PONG消息 | PONG消息封装了自身状态数据。可以分为两种:第一种是在接到MEET/PING消息后回复的PONG消息;第二种是指节点向集群广播PONG消息,这样其他节点可以获知该节点的最新信息,例如故障恢复后新的主节点会广播PONG消息。 |
FAIL消息 | 当一个主节点判断另一个主节点进入FAIL状态时,会向集群广播这一FAIL消息;接收节点会将这一FAIL消息保存起来,便于后续的判断。 |
PUBLISH消息 | 节点收到PUBLISH命令后,会先执行该命令,然后向集群广播这一消息,接收节点也会执行该PUBLISH命令。 |
22.集群故障转移耗时估计
从主节点故障发生到完成转移,所需要的时间主要消耗在主观下线识别、主观下线传播、选举延迟等几个环节;具体时间与参数cluster-node-timeout有关,一般来说:
故障转移时间(毫秒) ≤ 1.5 * cluster-node-timeout + 1000
cluster-node-timeout的默认值为15000ms(15s),因此故障转移时间会在20s量级。
23.集群Hash Tag
Hash Tag原理是:当一个key包含 {} 的时候,不对整个key做hash,而仅对 {} 包括的字符串做hash(即允许用key的部分字符串来计算hash)。
Hash Tag可以让不同的key拥有相同的hash值,从而分配在同一个槽里;这样针对不同key的批量操作(mget/mset等),以及事务、Lua脚本等都可以支持。不过Hash Tag可能会带来数据分配不均的问题,这时需要:(1)调整不同节点中槽的数量,使数据分布尽量均匀;(2)避免对热点数据使用Hash Tag,导致请求分布不均。
24.集群槽位全覆盖 (cluster-require-full-coverage参数)
只有当16384个槽全部分配完毕时,集群才能上线。这样做是为了保证集群的完整性,但同时也带来了新的问题:当主节点发生故障而故障转移尚未完成,原主节点中的槽不在任何节点中,此时会集群处于下线状态,无法响应客户端的请求。
cluster-require-full-coverage参数可以改变这一设定:如果设置为no,则当槽没有完全分配时,集群仍可以上线。参数默认值为yes,如果应用对可用性要求较高,可以修改为no,但需要自己保证槽全部分配。
参考文献
(1)以上内容主要学习、梳理于 编程迷思 同学的 《深入学习Redis》专题
(2)官方文档资料
https://redis.io/documentation