前述
本篇先讲解Redis持久化的两种方式:快照和AOF,然后讲解集群的工作原理和优缺点,最后谈谈分片的机制和应用。本篇内容主要是一些理论上的知识,至于其中一些应用和常见解决方案,后面会视情况单独写。
本篇大部分内容是我学习相关知识的笔记整理,所以并不能成为很好的入门阅读。当然,如果对相关概念已经有所了解,完全可以分散的读相应小节的内容。
部分概念和内容来源于官网和其他网络博文,文中都有链接,可以跟随链接做扩展或深入了解。
Redis持久化
Redis持久化有两种方式,快照(snapshotting)和只追加文件(AOF)。
快照持久化
客户端可以通过save
命令手动触发快照备份,此时Redis会被阻塞,直到快照备份完成。除了save
命令,还可以通过bgsave
命令开启一个子进程在后台备份快照。
bgsave
备份快照时不阻塞Redis服务。但我们知道,克隆子进程是需要复制父进程的内存空间的。如果Redis里的数据很大,比如几十个G,克隆子进程就会花费很长时间,这段时间仍然会阻塞Redis服务。因此,bgsave
命令不一定比save
命令快,需要视情况而定。
除了手动命令触发快照备份,还可以通过配置让Redis服务自动执行快照备份。下面是Redis服务快照备份相关命令。
save 60 10000
stop-writes-on-bgsave-error no
rdbcompression yes
dbfilename dump.rdb
save配置指定触发快照备份规则,上面的配置表示当60秒之内有10000次写入,Redis服务就会自动触发bgsave
命令执行快照备份。
由于快照是一定条件才触发,因此可能造成一段时间数据丢失。
AOF持久化
AOF文件类似MySQL数据库的bin-log日志,它会记录Redis服务即将执行的写命令,以此来跟踪数据发生的变化。
通过下面的配置选项启动AOF持久化。
appendonly yes
appendsync always
appendsync配置选型表示刷新缓冲区内容到磁盘的方式。缓冲区内容刷新到磁盘会造成Redis服务阻塞。appendsync有三个选项,always、everysec、no。always会对每个命令都刷新到磁盘才返回,这样Redis响应速度降低明显。everysec每秒刷新一次缓冲区到硬盘,因此可能丢失1秒的数据。no表示让操作系统决定什么时候刷新缓冲区内容到磁盘。因此,建议的配置选择是everysec。
AOF虽然只会丢失1秒的请求命令,但是它文件增长很快。Redis重启执行AOF恢复数据的时候,AOF很大的情况,还原时间会非常长。
为了防止AOF文件增长过大,可以通过auto-aof-rewrite-percentage和auto-aof-rewrite-min-size配置选项对AOF文件进行重写。客户端也可以发送bgrewriteaof
命令触发重写。bgrewriteaof
命令和bgsave
命令类似,都会克隆一个子进程在后台进行,因此克隆子进程时会造成Redis服务阻塞。
Redis集群
Redis集群是分片的一种实现方式,提供在多个Redis节点间共享数据的程序集。关于分片,请参考下面的小节。
Redis集群实现了所有在非分布式Redis版本中处理单一key的命令。那些使用多个key的复杂操作,比如set里的unions和intersections操作,就没有实现。Redis集群不像单机版本的Redis那样支持多个数据库,集群只有数据库0,而且也不支持SELECT命令。
Redis集群数据一致性
由于Redis集群采取异步复制,所以不能保证强一致。
Redis造成命令丢失的另一种可能情况是集群出现网络分区,即一个master节点的网络不可达形成孤立的节点,此时写入的命令,在从新加入集群后,可能被新选出来的master节点数据覆盖。
Redis集群数据分片实现
Redis集群没有使用一致性hash, 而是引入了哈希槽的概念.
Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽。
关于Hash槽实现,参考官方文档
Redis集群客户端查询方式
Redis客户端可以向集群的任何一个节点发起查询。如果命令是该节点可以处理的,则执行并返回结果。如果节点不能处理,它会分析处理,将查询重定向到能处理的集群节点上。Redis集群客户端重定向主要有两种模式:MOVED重定向和ASK重定向。
MOVED重定向和ASK重定向的区别:
如果是MOVED重定向,比如8号槽被MOVED重定向到A节点,客户端认为所有属于8号槽的key查询都在A节点,如果客户端缓存了映射关系,下次8号槽的数据查询,可以直接向A请求。ASK重定向,只是将某个具体的key查询重定向到一个节点,但是8号槽的其余key查询,可能还在A节点。
ASK重定向的用途是hash槽重分配时,比如A节点的8号hash槽转移到B节点,在没转移完成之前(数据是分部分转移的,避免一次转移造成阻塞时间太长),A节点和B节点之间就存在ASK重定向。
Redis集群客户端重定向方式,允许客户端不需要存储集群槽的映射关系,但是为了高效,当集群稳定后,客户端可以缓存集群映射关系,这样避免了过多重定向。
失效检测
Redis 集群失效检测是用来识别出大多数节点何时无法访问某一个主节点或从节点。当这个事件发生时,就提升一个从节点来做主节点;若如果无法提升从节点来做主节点的话,那么整个集群就置为错误状态并停止接收客户端的查询。
当一个节点在超过NODE_TIMEOUT时间后仍无法访问某个节点,那么它会用PFAIL(可能失效)来标识这个不可达的节点。这是某个节点对另一个节点的主观判断。
单独一个PFAIL标识只是每个节点的一些关于其他节点的本地信息。此时节点会和其它节点同步本地信息,如果大部分节点(通常需要超过一半)标识某个节点为PFAIL,被标识的节点就成为确认失效(FAIL标识)。FAIL标识会强制每个接收到这消息的节点把对应的节点标识为FAIL状态。
更多redis集群知识,参考Redis集群规范
Redis分片
分片,就是将Redis数据分不到不同主机上,每个主机只拥有完整数据的一部分。
分片优势
- 通过利用多台计算机内存的和值,允许我们构造更大的数据库。
- 通过多核和多台计算机,允许我们扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽。
分片缺点
- 涉及多个key的操作通常是不被支持的。举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作。
- 涉及多个key的redis事务不能使用。
- 当使用分区时,数据处理较为复杂,比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件。
- 增加或删除容量也比较复杂。
Redis支持的分片类型
1)范围分区
这种方式实现简单,直观,但是需要管理一个区间范围到实例的映射表。
2)哈希分区
这种方式高效,不需要管理映射表。但是可能数据比较分散或冲突。
分片的不同实现
-
客户端分片:客户端直接选择正确的节点来写入和读取指定键。
-
代理协助分片:我们的客户端发送请求到一个可以理解Redis协议的代理上,代理会根据配置好的分片模式,来转发我们的请求到正确的Redis实例,并返回响应给客户端。代理Twemproxy实现了代理协助分片。
-
查询路由:你可以发送你的查询到一个随机实例,这个实例会保证转发你的查询到正确的节点。Redis集群实现了类似功能,但它采用客户端重定向。
更多分片知识,参考官网和Redis分片
后述
其他一些资料: