集群

结构上:单台redis会发生单点故障,同时需要承受所有请求。
容量上:单台redis内存有限,容易出现存储瓶颈,需要进行数据分片。

复制

数据库分类:

  1. 主数据库:可读可写,数据变化时会自动将数据同步给从数据库
  2. 从数据库:只读,接收主数据库同步来的数据
搭建集群相关命令/配置
# --port 指定redis端口
# --slaveof 指定主数据库的ip和端口
$ redis-server --port 6380 --slaveof 127.0.0.1 6379
# 查看集群信息
> INFO replication
# 运行时修改主数据库
> SLAVEOF 127.0.0.1 6379
# 从数据库转换成主数据库
> SLAVEOF NO ONE

# redis.conf
# 配置从数据库可写
slave-read-only no
# 集群同步过程中,默认情况下,从数据库会用同步前的数据对客户端响应,但也可以配置其阻塞
slave-serve-stale-data no

# 乐观复制策略的配置项
# 允许从数据库最长失去连接的时间(默认注释的配置)
min-slaves-max-log 10
# 仅当在线的从数据库达到的配置的数量后,主数据库才可写(默认注释的配置)
min-slaves-to-write 3

# 增量复制的配置项
# 积压队列大小
repl-backlog-size
# 所有从数据库与主数据库断开连接后,经过多长时间释放积压队列的内存空间
repl-backlog-ttl
原理

复制初始化:

  1. 从数据库启动后,会向主数据库发送SYNC命令
  2. 主数据库接收到SYNC后,在后台保存快照(RDB持久化),并将快照保存过程中接收到的命令缓存起来
  3. 快照完成后,主数据库将快照和缓存的命令发给从数据库
  4. 从数据库接收到快照和命令后,载入快照并执行缓存命令

复制同步:

  • 初始化结束后,主数据库执行的任何改变数据的命令都会异步发给从数据库

复制策略:乐观复制策略

  • 容忍一定时间内主从数据库的数据差异,但最终的数据是一致的

断线重连:

  • 2.6版本及之前的版本,无论数据差异多大,都会做复制初始化,效率低
  • 2.8版本及之后的版本,增加了增量复制,大大提高了效率

增量复制:

  • 实现前提
  1. redis每次启动都会生成一个新的运行ID
  2. 复制同步阶段,主数据库每次同步命令给从数据库,都会将命令放入一个积压队列中,并记录当前积压队列中存放的命令的偏移量范围
  3. 从数据库接收到主数据库传来的命令时,会记录该命令的偏移量
  • 增量复制过程:
  1. 主数据库会判断从数据库发来的运行ID是否和自己的运行ID相同
  2. 判断从数据库最后同步成功的偏移量是否在积压队列中,如果在则可以执行增量复制,将积压队列中的命令发给从数据库,否则,只能执行全量复制
从数据库持久化

由于持久化的过程相对耗时,为了提高性能,一般来说,从数据库会开启持久化,主数据库会禁用持久化。当从数据库崩溃重启后,主数据库会自动将数据同步过来,无需担心数据丢失。然而,当主数据库崩溃时,情况就变得复杂了,需要人工干预:

  1. 在从数据库中使用 SLAVEOF NO ONE 命令将从数据库提升成主数据库继续服务
  2. 启动之前崩溃的主数据库,然后使用 SLAVEOF 命令将其设置成新的主数据库的从数据库,即可将数据同步回来

手工维护从数据库或主数据库的重启以及数据恢复都比较麻烦,万幸,redis(2.8版本)为此提供了哨兵2.0来解决这一问题。

附录

# 积压队列大小计算方式
估计主从数据库断线的时间中主数据可能执行的命令的大小

参考

本文参考自李子骅老师的《Redis 入门指南》