什么是持久化?
将数据从掉电易失的内存存放到能够永久存储的设备上
Redis为什么需要持久化
基于内存的
缓存服务器,需要吗?
内存数据库,需要吗?
消息队列,需要吗?
Redis持久化方式
RDB(Redis DB) hdfs: fsimage
AOF(AppendOnlyFile) hdfs : edit logs 默认关闭的
RDB:
在默认情况下,Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中
方式:产生一个RDB:
1,阻塞方式:
客户端中执行save命令
2,非阻塞方式:(复杂度高?)
Bgsave
策略:
自动:按照配置文件中的条件满足就执行BGSAVE
save 60 1000,Redis要满足在60秒内至少有1000个键被改动,会自动保存一次
手动:客户端发起SAVE、BGSAVE命令
SAVE命令:
redis > save
阻塞Redis服务,无法响应客户端请求
创建新的dump.rdb替代旧文件(覆盖 需要手动写脚本扫描目录)
![090c2d69fbf39325df045f2dbe88fca1.png](https://i-blog.csdnimg.cn/blog_migrate/bc16f543a3d0ea22743cefd96379af9d.png)
BGSAVE命令:
redis > bgsave
非阻塞,Redis服务正常接收处理客户端请求
Redis会fork()一个新的子进程来创建RDB文件,子进程处理完后会向父进程发送一个信号,通知它处理完毕
父进程用新的dump.rdb替代旧文件
![cfedaf34c1ce8ffecb49ae01cff7e79c.png](https://i-blog.csdnimg.cn/blog_migrate/4cff94238212b37a490281e81c50ea12.png)
![df2e8e749d479a01ea66ee14ca306408.png](https://i-blog.csdnimg.cn/blog_migrate/67a73122e9b845f258d51ef0835c9148.png)
![3148527648ced5dd338f368bae9a23cb.png](https://i-blog.csdnimg.cn/blog_migrate/51062f0a9437eb93e6f525cbbafa3cd8.png)
SAVE 和 BGSAVE 命令:
SAVE不用创建新的进程,速度略快
BGSAVE需要创建子进程,消耗额外的内存
SAVE适合停机维护,服务低谷时段
BGSAVE适合线上执行
自动执行:
本质上就是BGSAVE
默认配置:
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /var/lib/redis/6379
只要上面三个条件满足一个,就自动执行备份。
创建RDB文件之后,时间计数器和次数计数器会清零。所以多个条件的效果不是叠加的
RDB:
优点:
完全备份,不同时间的数据集备份可以做到多版本恢复(会覆盖 手动写脚本扫描目录拿走不同阶段备份,异地备份)
紧凑的单一文件,方便网络传输,适合灾难恢复
恢复大数据集速度较AOF快
缺点:
会丢失最近写入、修改的而未能持久化的数据
fork过程非常耗时,会造成毫秒级不能响应客户端请求
生产环境:
创建一个定时任务cron job,每小时或者每天将dump.rdb复制到指定目录
确保备份文件名称带有日期时间信息,便于管理和还原对应的时间点的快照版本
定时任务删除过期的备份
如果有必要,跨物理主机、跨机架、异地备份
AOF:
Append only file,采用追加的方式保存
默认文件appendonly.aof
记录所有的写操作命令,在服务启动的时候使用这些命令就可以还原数据库
![a35d7cb9b218160d6a9928db218d13fb.png](https://i-blog.csdnimg.cn/blog_migrate/5e6b2cd15b0ebff28997a11414e3f421.png)
![67f96e80ffaaa8a4c05370481a428a0f.png](https://i-blog.csdnimg.cn/blog_migrate/3d6ee6e781e7df47ff11581e42de9784.png)
![2b4ec001f751929e09650a217e85f382.png](https://i-blog.csdnimg.cn/blog_migrate/24b43eaa26967b2623351ccbb18d2168.png)
调整AOF持久化策略,可以在服务出现故障时,不丢失任何数据,也可以丢失一秒的数据。相对于RDB损失小得多.
AOF写入机制:
AOF方式不能保证绝对不丢失数据。默认关闭,一旦开启,则rdb不作为恢复的选择。
目前常见的操作系统中,执行系统调用write函数,将一些内容写入到某个文件里面时,为了提高效率,系统通常不会直接将内容写入硬盘里面,而是先将内容放入一个内存缓冲区(buffer)里面,等到缓冲区被填满,或者用户执行fsync调用和fdatasync调用时才将储存在缓冲区里的内容真正的写入到硬盘里,未写入磁盘之前,数据可能会丢失.
写入磁盘的策略;
appendfsync选项,这个选项的值可以是always、everysec或者no
Always:服务器每写入一个命令,就调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,也不会丢失任何已经成功执行的命令数据
Everysec(默认):服务器每一秒重调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据
No:服务器不主动调用fdatasync,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的
运行速度:always的速度慢,everysec和no都很快
AOF重写机制:
AOF文件过大
合并重复的操作,AOF会使用尽可能少的命令来记录
重写过程
fork一个子进程负责重写AOF文件
子进程会创建一个临时文件写入AOF信息
父进程会开辟一个内存缓冲区接收新的写命令
子进程重写完成后,父进程会获得一个信号,将父进程接收到的新的写操作由子进程写入到临时文件中
新文件替代旧文件
注:如果写入操作的时候出现故障导致命令写半截,可以使用redis-check-aof工具修复
AOF重写触发的条件:
手动:客户端向服务器发送BGREWRITEAOF命令
自动:配置文件中的选项,自动执行BGREWRITEAOF命令
auto-aof-rewrite-min-size <size>,触发AOF重写所需的最小体积:只要在AOF文件的体积大于等于size时,才会考虑是否需要进行AOF重写,这个选项用于避免对体积过小的AOF文件进行重写
auto-aof-rewrite-percentage <percent>,指定触发重写所需的AOF文件体积百分比:当AOF文件的体积大于auto-aof-rewrite-min-size指定的体积,并且超过上一次重写之后的AOF文件体积的percent %时,就会触发AOF重写。(如果服务器刚刚启动不久,还没有进行过AOF重写,那么使用服务器启动时载入的AOF文件的体积来作为基准值)。将这个值设置为0表示关闭自动AOF重写
优点:
写入机制,默认fysnc每秒执行,性能很好不阻塞服务,最多丢失一秒的数据
重写机制,优化AOF文件
如果误操作了(FLUSHALL等),只要AOF未被重写,停止服务移除AOF文件尾部FLUSHALL命令,重启Redis,可以将数据集恢复到 FLUSHALL 执行之前的状态
缺点:
相同数据集,AOF文件体积较RDB大了很多
恢复数据库速度叫RDB慢(文本,命令重演)
Redis主从复制
主从复制 Replication:
一个Redis服务可以有多个该服务的复制品,这个Redis服务称为Master,其他复制品称为Slaves
只要网络连接正常,Master会一直将自己的数据更新同步给Slaves,保持主从同步
只有Master可以执行写命令,Slaves只能执行读命令
![a6fa6e78c1c437e32cd3a34c09349beb.png](https://i-blog.csdnimg.cn/blog_migrate/3a5e6efbf37971307a3cf3904abf7927.png)
![f1f8de8ea6028cae09a9ecef98e2b832.png](https://i-blog.csdnimg.cn/blog_migrate/11367fa369f2091873d79b104e8e706e.png)
从服务器执行客户端发送的读命令,比如GET、LRANGE、SMEMMBERS、HGET、ZRANGE等等
客户端可以连接Slaves执行读请求,来降低Master的读压力。
相对于无主模型,更加简单. 主单点返回确认即可。Redis采用异步主从同步数据,有瑕疵。另外主单点,使用哨兵解决单点故障。
![0f8e585aa6d7f75af646f3a09d1944b7.png](https://i-blog.csdnimg.cn/blog_migrate/4190fb7449506e09382f6a64ccd0a3cd.png)
![aea434a42a9bed5eef3b4076636aee70.png](https://i-blog.csdnimg.cn/blog_migrate/a12d541b90f11d9e44b02f014c25a839.png)
主从复制创建
每个redis实例默认自己是主,需要手动变更
redis-server --slaveof <master-ip> <master-port>,配置当前服务称为某Redis服务的Slave
# redis-server --port 6380 --slaveof 127.0.0.1 6379
SLAVEOF host port命令,将当前服务器状态从Master修改为别的服务器的Slave
redis > SLAVEOF 192.168.1.1 6379,将服务器转换为Slave
redis > SLAVEOF NO ONE ,将服务器重新恢复到Master,不会丢弃已同步数据
配置方式:启动时,服务器读取配置文件,并自动成为指定服务器的从服务器
slaveof <masterip> <masterport>
slaveof 127.0.0.1 6379
Redis哨兵 paxos
监控 Monitoring:
Sentinel会不断检查Master和Slaves是否正常
每一个Sentinel可以监控任意多个Master和该Master下的Slaves
![dffdc484c26142340f74f92f2448fbba.png](https://i-blog.csdnimg.cn/blog_migrate/317ad68a5eee496038359b923930cbd7.jpeg)
Sentinel网络
监控同一个Master的Sentinel会自动连接,组成一个分布式的Sentinel网络,互相通信并交换彼此关于被监视服务器的信息
下图中3个Sentinel监控着S1和它的2个Slave
![b5d3399dbbeaa11172c2e5cfe1740efd.png](https://i-blog.csdnimg.cn/blog_migrate/3c5bc28bba2a4a5cf9794c534d109a0c.png)
服务器下线:
当一个sentinel认为被监视的服务器已经下线时,它会向网络中的其他Sentinel进行确认,判断该服务器是否真的已经下线
如果下线的服务器为主服务器,那么sentinel网络将对下线主服务器进行自动故障转移,通过将下线主服务器的某个从服务器提升为新的主服务器,并让其从服务器转为复制新的主服务器,以此来让系统重新回到上线的状态。
![096e26b3bf2384067f20d6d495ea4871.png](https://i-blog.csdnimg.cn/blog_migrate/2e7b8eb350cde7cefe893a210ac97446.png)
![27763b7cb6601446e2ac5ea9b117c75e.png](https://i-blog.csdnimg.cn/blog_migrate/7d07857bd483f42bfdb92235735e0636.png)
![fc6b96cd7f9f3130c857df9451dca0ce.png](https://i-blog.csdnimg.cn/blog_migrate/d59022cfaf3e5ba796823733d60da32d.png)
服务器下线后重新上线
Redis Twemproxy:
Twitter开发的代理服务器,他兼容Redis和Memcached,允许用户将多个redis服务器添加到一个服务器池(pool)里面,并通过用户选择的散列函数和分布函数,将来自客户端的命令请求分发给服务器池中的各个服务器
通过使用twemproxy我们可以将数据库分片到多台redis服务器上面,并使用这些服务器来分担系统压力以及数据库容量:在服务器硬件条件相同的情况下,对于一个包含N台redis服务器的池来说,池中每台平均1/N的客户端命令请求
向池里添加更多服务器可以线性的扩展系统处理命令请求的能力,以及系统能够保存的数据量。
重试超时配置:
server_retry_timeout <time>选项
当一个服务器被twemproxy判断为下线之后,在time毫秒之内,twemproxy不会再尝试向下线的服务器发送命令请求,但是在time毫秒之后,服务器会尝试重新向下线的服务器发送命令请求
如果命令请求能够正常执行,那么twemproxy就会撤销对该服务器的下线判断,并再次将键交给那个服务器来处理
但如果服务器还是不能正常处理命令请求,那么twemproxy就会继续将原本应该交给下线服务器的键转交给其他服务器来处理,并等待下一次重试的来临。
![30ba75c3aa3cb3cdc2a983960bc3f859.png](https://i-blog.csdnimg.cn/blog_migrate/efcc1c9006e1ad53221ea6135d7a5c83.png)
![acccab44df0dbb26829a7e7d75f47b6c.png](https://i-blog.csdnimg.cn/blog_migrate/2aa551044da2b3bb7ad926adc1a44137.png)
总结:
前端使用 Twemproxy 做代理,后端的 Redis 数据能基本上根据 key 来进行比较均衡的分布。
后端一台 Redis 挂掉后,Twemproxy 能够自动摘除。恢复后,Twemproxy 能够自动识别、恢复并重新加入到 Redis 组中重新使用
Redis 挂掉后,后端数据是否丢失依据 Redis 本身的持久化策略配置,与 Twemproxy 基本无关
如果要新增加一台 Redis,Twemproxy 需要重启才能生效;并且数据不会自动重新 Reblance,需要人工单独写脚本来实现
如原来已经有 2 个节点 Redis,后续有增加 2 个 Redis,则数据分布计算与原来的 Redis 分布无关,现有数据如果需要分布均匀的话,需要人工单独处理
如果 Twemproxy 的后端节点数量发生变化,Twemproxy 相同算法的前提下,原来的数据必须重新处理分布,否则会存在找不到key值的情况
不管 Twemproxy 后端有几台 Redis,前端的单个 Twemproxy 的性能最大也只能和单台 Redis 性能差不多
如同时部署多台 Twemproxy 配置一样,客户端分别连接多台 Twemproxy可以在一定条件下提高性能
Redis集群
Redis集群:
3.0支持
由多个Redis服务器组成的分布式网络服务集群
每一个Redis服务器称为节点Node,节点之间会互相通信。两两相连
Redis集群无中心节点
![5e3b98d9da493ec33dc7895ac934a848.png](https://i-blog.csdnimg.cn/blog_migrate/1cb7ed0f024feba6db24535ecbd036c2.png)
Redis集群节点复制:
Redis集群的每个节点都有两种角色可选:主节点master node、从节点slave node。其中主节点用于存储数据,而从节点则是某个主节点的复制品。
当用户需要处理更多读请求的时候,添加从节点可以扩展系统的读性能,因为Redis集群重用了单机Redis复制特性的代码,所以集群的复制行为和我们之前介绍的单机复制特性的行为是完全一样的。
![8e75b060099ffaa9ea381182f8ee9836.png](https://i-blog.csdnimg.cn/blog_migrate/5b48eb4a655421d726b1ea8592c6aa53.png)
Redis集群故障转移:
Redis集群的主节点内置了类似Redis Sentinel的节点故障检测和自动故障转移功能,当集群中的某个主节点下线时,集群中的其他在线主节点会注意到这一点,并对已下线的主节点进行故障转移
集群进行故障转移的方法和Redis Sentinel进行故障转移的方法基本一样,不同的是,在集群里面,故障转移是由集群中其他在线的主节点负责进行的,所以集群不必另外使用Redis Sentinel。
![0cc31f631f476b993547b4697a24a16c.png](https://i-blog.csdnimg.cn/blog_migrate/fe54a97578908395762ec4e0f8dbe2f4.png)
Redis集群分片:
集群将整个数据库分为16384个槽位slot,所有key都属于这些slot(槽位)中的一个,key的槽位计算公式为slot_number=crc16(key)%16384,其中crc16为16位的循环冗余校验和函数
集群中的每个主节点都可以处理0个至16383个槽,当16384个槽都有某个节点在负责处理时,集群进入上线状态,并开始处理客户端发送的数据命令请求
举例:
三个主节点7000、7001、7002平均分片16384个slot槽位
节点7000指派的槽位为0到5060
节点7001指派的槽位为5461到10022
节点7002指派的槽位为10923到16383
节点7003指派的槽位为5061到5460,10023-10922
Redis集群Redirect转向:
由于Redis集群无中心节点(无主模型),请求会发给任意主节点。
主节点只会处理自己负责槽位的命令请求,其它槽位的命令请求,该主节点会返回客户端一个转向错误。
客户端根据错误中包含的地址和端口重新向正确的负责的主节点发起命令请求。
![1536d8333ff0aea5ba3c436b9ea42e4f.png](https://i-blog.csdnimg.cn/blog_migrate/4ac2561f7ccb5633e86f201c25979046.png)
![ba697e49bdca79d14e30042868c50077.png](https://i-blog.csdnimg.cn/blog_migrate/45e7e6a952992ba1f9e61680993a6001.png)
Redis集群总结:
Redis集群是一个由多个节点组成的分布式服务集群,它具有复制、高可用和分片特性。
Redis的集群没有中心节点,并且带有复制和故障转移特性,这可用避免单个节点成为性能瓶颈,或者因为某个节点下线而导致整个集群下线。
集群中的主节点负责处理槽(储存数据),而从节点则是主节点的复制品。
Redis集群将整个数据库分为16384个槽,数据库中的每个键都属于16384个槽中的其中一个
集群中的每个主节点都可以负责0个至16384个槽,当16384个槽都有节点在负责时,集群进入上线状态,可以执行客户端发送的数据命令。
主节点只会执行和自己负责的槽有关的命令,当节点接收到不属于自己处理的槽的命令时,它将会处理指定槽的节点的地址返回给客户端,而客户端会向正确的节点重新发送。
如果需要完整地分片、复制和高可用特性,并且要避免使用代理带来的性能瓶颈和资源消耗,那么可以选择使用Redis集群;如果只需要一部分特性(比如只需要分片,但不需要复制和高可用等),那么单独选用twemproxy、Redis的复制和Redis Sentinel中的一个或多个。
![ad3c999fac27436a315414cda4b937d9.png](https://i-blog.csdnimg.cn/blog_migrate/6fbcffc5aa73c4d8c49047b701d33bd4.jpeg)
推荐:
https://visualgo.net/zh
麻省理工:算法导论:网易公开课
清华大学:数据结构:学堂在线
<<db2 教材 官方>> join
《深入理解计算机系统》
《MR设计模式》