Redis持久化、复制和集群

Redis持久化

RDB方式

RDB方式持久化是通过快照(snapshotting)完成的,当符合一定条件时自动将内存中的所有数据生成一份副本并存在硬盘上。 
根据配置规则进行自动快照 
由两个参数:时间窗口M和改动的键的个数N,每当时间M内被更改的键的个数大于N时,即符合自动快照条件,每条快照条件占一行并且以save参数开头,例: 
15分钟内(900秒)有一个或一个以上的键被更改进行快照 
save 900 1 
save 300 10 
save 60 1000 

*当执行SAVE命令时,Redis同步地进行快照操作,在快照执行的过程中会阻塞所有来自客户端的请求。当数据比较多时,这一过程会导致Redis较长时间不能响应 
*BGSAVE命令可以在后台异步地进行快照操作,快照的同时服务器还能继续响应客户端的请求。 
*LASTSAVE命令获取最近一次成功快照的时间,返回Unix时间戳 
*FLUSHALL会清除数据库中的所有数据,不论清空数据库的过程是否触发了自动快照条件,只要自动快照条件不为空,Redis就会执行一次快照操作。如果没有定义自动快照条件,执行FLUSHALL则不会进行快照 
*执行复制(replication)时,当设置了主从模式时,Redis会在复制初使化时进行快照。 
*Radis默认会将快照文件存储在Redis当前进程的工作目录中的dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别指定快照文件存储的路径和文件名。 

快照过程如下: 
1.Redis使用fork函数复制一份当前进程(父进程)的副本(子进程) 
2.父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件 
3.当子进程写入完所有数据后会用该临时文件替换旧的RDB文件 

在执行fork的时候操作系统会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时,系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据。 
写时复制微略也保证了fork时刻虽然看上去生成两份内存副本,但实际内存的占用量不会增加一倍。 

/etc/sysctl.conf文件中加入vm.overcommit_memory =1 linux系统设置应用可以申请超过可用内存(物理内存和交换分区)的空间,重启系统或执行sysctl vm.overcommit_memory=1 使生效。 

当快照过程中,如果写入操作过多,造成fork前后数据差异较大,会使内存使用量显著超过实际数据大小。 
RDB文件是经过压缩的二进制格式,rdbcompression参数可以设置禁用压缩节省cpu。 
Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存,通常一个记录1000万个字符串类型键,大小为1G的快照文件载入到内存需要20-30秒。 

AOF方式

当使用Redis存储非临时数据时,一般需要打开AOF持久化来降低进程中止导致的数据丢失,AOF将Redis执行的每一条写命令追加到硬盘文件中。 
默认是没有开启AOF(append only file)方式持久化,可以通过appendonly参数启用 
appendonly true 
目录和RDB文件目录一样,默认文件名是appendonly.aof,可通过append filename参数修改: 
appendfilename appendonly.aof 

设置AOF文件的重写 
auto-aof-rewrite-percentage 100 
当目前的AOF文件大小超过上一次重写时的大少的百分之多少时会进行重写,如果之前没有重写,则以启动进的大小为依据 

auto-oaf-rewrite-min-size 60mb 
限制允许重写的最小AOF文件大小 

BGREWRITEAOF命令手动执行AOF重写 

由于操作系统的缓存机制,数据并没有立即写入硬盘,而是进入了硬盘的缓存,默认系统每30秒会执行一次同步操作,以将缓存中的数据真正地写入硬盘,在这30的过程中如果异常退出则会导制硬盘缓存中的数据丢失,设置同步的时机: 
appendfsync everysec|always|no 
everysec即每秒执行一次同步操作,always表示每次执行写入都会执行同步,no表示交同操作系统来做即30秒一次。 
Redis允许同时开始AOF和RDB,此时重启Redis会使用AOF来恢复数据. 

扫描二维码关注公众号,回复: 11571216 查看本文章

复制replication

在复制的概念中,数据库为为两类,主数据库master和从数据库slave,master可以进行读写操作,当写操作会自动将数据同步给slave,而slave一般只读,并接受master同步过来的数据。slave可以有多个,而只能拥有一个master。 
Redis中使用slave,只需要在slave配置中加入”slaveof masterip:masterport”。 
例: 
$redis-server 
默认监听6379端口 
$redis-server —port 6380 —slaveof 127.0.0.1 6379 
此时在master中的任何数据变化都会自动地同步到slave中。 
$redis-cli -p6379 
$info replication 
可以查看主从信息 

通过设置slave的slave-read-only为no使slave可读写,默认是中读。但对slave的修改不会同步给任何其它数据库,并且master中更新了对应的数据就会覆盖slave的改动。 
除了配置文件或命令行参数设置slaveof参数,还可以在运行时使用SLAVEOF命令修改。 
$SLAVE 127.0.0.1 6379 

slave还可以通过slaveof no one 命令使当前数据库停止接收其它数据库的同步,并转换为主数据库。 

min-slaves-to-write 3 
表示只有当3个或以上的slaves连接到master,master才是可写的,否则会返回错误 “noreplicas not enough good slaves to write.”

min-slaves-max-lag 10 
表示允许slave最长失去连接的时间,(即发送REPLCONF ACK命令)的时间小于这个值,则认为slaves还在保持与master的连接。例: 
master与3个slave相连,其中一个slave上一次与master联系是9秒前,这时master是可以写入的,一旦10秒过后,该slave仍没联系,则master认为只有2个slaves,从而拒绝写入数据。这一特性默认是关闭的。在分布式中,打开并合理配置可以降低主从架构中因为网络分区导致的数据不一致问题。 

slave也可以同时作为master存在(master→slave(master)→slave) 
通过复制可以实现读写分离。 

Slave持久化

可以在master中禁用持久化 ,并在slave中开启持久化,如果slave崩溃了,master会自动同步过来,但master崩溃后,手工通过slave 恢复数据时需要严格按照以下两频进行 
在slave中使用SLAVEOF NO ONE命令将从数据库提升成master继续服务。 
启动之前崩溃的master,然后使用salveof命令将其设置成新的master的slave。 
***当开启复制且master关闭持久化功能时,一定不能使用Supervisor以及类似进程管理工具令master自动重启。 
同样当master因故关闭时,也要避免直接重新启动,因为master重启会因没有持久化,所有数据都被清空了,这时slave依然会从master中同步数据。致使slave也被清空。 

无硬盘复制

前面的复制都是基于RDB持久化实现 
当master禁用RDB快照时(即删除了所有的配置文件中的save语句),如果执行了复制初使化操作,Redis依然会生成RDB快照,所以下次启动后master会以该快照恢复据。因为复制的时间不确定,使得恢复的数据可能是在任何时间点的。 
复制初使化时需要创建RDB快照文件,导致性能降低。 

无硬盘复制选项,开启该选项时,Redis在与slave进行复制初始化时将不会将快照内容存储在硬盘上,而是直接通过网络发送给slave。 
repl-diskless-sync yes 

增量复制

slave会存储master的运行id,每个Redis运行实例都会拥有一个唯一的id,重启后会生成一个新id. 
在复制同步阶段,master每将一个命令传给salve时,都会把该命令存放在一个积压队列中,并记录下当前积压队列中存入的命令的偏移量范围。 
slave接收到master传来的命令时,会记录下该偏移量。 
主从连接准备就绪后,slave发送psync “PSYNC masterid 断开前的偏移量” 
master会判断slave传来的id是否正确 
master判断偏移量是否在积压队列中,如果存在执行增量复制,并将积压队列中相应的命令发送给slave,如果条件不符则会进行一次全部同步 

repl-backlog-size 设置积压队列的大小,默认为1M,积压队列越大,其允许的主从数据断线的时间就越长。 
repl-backlog-ttl 设置主从断开连接后多久会释放积压的内存空间,默认是1 小时。 

Sentinel哨兵

哨兵 监控Redis运午的状况,是一个独立的进程,监控master和slave是否运行正常,master出现故障时自动将slave转换为master 

1.创建sentinel.conf配置文件,添加以下一行内容 

sentinel monitor mymaster 127.0.0.1 6379 1 
其中mymaster 表示要监控的master的名字,可以自定义一个,大小写字母,数字或“.-_”字符组成。后面两个参数表示master的ip和端口号。最后的1表示最低通过票数 
2.运行 $redis-sentinel /path/to/sentinel.conf

*哨兵监控一个系统,只需要配置其监控master即可,哨兵会自动发现所有slave。 
*当master停止服务后,sentinel会选举一个slave转换会maste,并把原master转换为slave (当原master重新提供服务后就会是slave身份) 

3.选举优先规则 选择优先级最高的slave,(通过slave-priority)来配置 
复制命令偏移量越大越优先 
运行id越小越优先 
哨兵以独立的进程方式对方从系统进行监控,一个哨兵可以监控多个主从系统,一个主从系统也可以设置多个哨兵sentinel 

sentinel和主从数据库建立连接后,sentinel 会定时执行下面3个操作 
1.每10秒sentinel向master和slave发送ping 命令 
2.每2秒sentinel向master和slave的_sentinel_:hello 频道发送自己的信息 
3.第1秒sentinel向master和slave和其它sentinel发送ping命令。 

配置ping的时间间隔 
大于1秒的会每一秒执行一次ping 
sentinel down-after-milliseconds my master 60000 
小于秒的会按配置的时间来发送ping 
sentinel down-after-milliseconds my master 6000 

如果超过down-after-milliseconds选项时间还没有回复,则sentinel认为其主观下线(subjective down +sdown) 
sentinel 发送SENTINEL is-master-down-by-addr 命令询问其它sentinel, 
如果认为下线达到指定数量时(大于前面配置的”sentinel monitor my master 127.0.0.1 6379 1”中的数量1),sentinel会认为其客观下线(objectively down +odown) 
并选择领头的sentinel对主从系统发起故障恢复 

sentinel 选举规则 
1.发现主数据库客观下线的节点向每个节点哨兵节点发送请求对方选自己成为领头sentinel 
2.如果目标sentinel没有选择过别的节点,就会同意 
3.如果有超过半数且超过quorum参数值的节点同意则选举成功 
4.如果多个sentinel同时参选出现没有任何节点当选,刚随机时间后重新选举 

*使用复制功能,总数据量的存储量受限于内存最小的节点,形成木桶效应。 
解决方案1.使用客户端分片解决,即启动多个 Redis数据库节点,由客户端决定哪个键存放在哪个节点。维护成本高,增加移除节点麻烦 
解决方案1.使用集群,集群支持几乎所有的单机实例支持的命令,对于涉及多键的命令(如MGET),如果每个键都位于一个节点中,则可以正常支持,否则会提示错误。除此之外,集群只能使用默认的0号数据库。如果执行select切换数据库会报错。

集群

1.打开配置cluster-enabled启用集群功能,每个集群中至少需要3个master才能正常运行 

2.启动多个redis独立节点,集群会将当前节点记录的集群状态持久化地存储在指定文件中,当前工作目录下的nodes.conf文件。每个节点对应的文件必须同。 

redis连接任意一个节点查看当前集群状态 
3.INFO cluster 

4.初使化集群 redis-trib.rb create —replicas 1 ip:port ip:port ip:port [ip:port…] 
create表示要初使化集群, —replicas表示每个master拥有一个slave。redis-trib.rb会输出集群分配方案,如果同意输入yes。

获得集群中节点信息 
CLUSTER NODES 

添加新节点,ip和port是集群是任意节点的地址和端口 CLUSTER MEET ip port 

Redis将每个键名的效部分使用 CRC16算法计算出散列值,然后对16384进行取取余,使每个键都能分配到16384个插槽中,进行分配指定的节点处理。 
键的有效部分是指 
如果键名包含{符号,且在{符号后面存在}符号,并且{和}符号间至少有一个字符,则有效部分是指{和}之间的内容; 
如果不满足上一条规则,那么整个键名为有效部分 

分配slot 如果slot之前没被分配过可以采用 
对点应节点执行,将指定slot分配给当前节点,如果slot分配过了就会报错 
CLUSTER ADD SLOT S 
CLUSTER ADDSLOTS slot1 [slot2…] 
例: CLUSTER ADDSLOTS 100 101 

查看slot分配情况 
CLUSTER SLOTS 
将slot从127.0.0.1:6379移到127.0.0.1:6380 
按提示执行后面步骤可完成slot的重分配 
redis-trib.rb reshard 127.0.0.1:6379 

-c参数支持集群自动重定向,如果键不在该节点上,会自动重定请求,并返回结果,该过程对客户端是透明的。 redis-cli -c -p 6379 
如果一个至少负责一个 solt的master停止服务,且没有相应的slave可以进行故障恢复,则整个集群会进入下线状态无未能继续工作。 
设置cluster-require-full-coverage no(默认为yes)使集群在该情况下仍能工作。 

安全配置

参数指定Redis接受发送请求的地址。 
bind 127.0.0.1 

设置客户端每次连接都需要发送密码 requirepass password 

如果master设置了密码,slave中需要配置密码 
masterauth 

将命令重命名 rename-commnad FLUSHALL newflushallcommandname 

设置成空串,禁用该命令 
rename-command FLUSHALL “” 

猜你喜欢

转载自blog.csdn.net/huanghuitan/article/details/61659980