什么是redis

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

redis主从复制原理

redisearch 架构图 redis lecture_数据集


主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点。Redis的主从复制功能非常强大,一个master可以拥有多个slave,而一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架构。

默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

在 Redis 复制的基础上,使用和配置主从复制非常简单,能使得从 Redis 服务器(下文称 slave)能精确得复制主 Redis 服务器(下文称 master)的内容。每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave 都将尝试让自身成为 master 的精确副本。

这个系统的运行依靠三个主要的机制:

1.当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave的更新,以便于将自身数据集的改变复制给 slave , :包括客户端的写入、key 的过期或被逐出等等。 2. 当 master 和slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。 3. 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave 。

Redis使用默认的异步复制,其特点是低延迟和高性能,是绝大多数 Redis 用例的自然复制模式。但是,从 Redis 服务器会异步地确认其从主 Redis 服务器周期接收到的数据量。
客户端可以使用 WAIT 命令来请求同步复制某些特定的数据。但是,WAIT 命令只能确保在其他 Redis 实例中有指定数量的已确认的副本:在故障转移期间,由于不同原因的故障转移或是由于 Redis 持久性的实际配置,故障转移期间确认的写入操作可能仍然会丢失。
接下来的是一些关于 Redis 复制的非常重要的事实:

  • Redis 使用异步复制,slave 和 master 之间异步地确认处理的数据量
  • 一个 master 可以拥有多个 slave
  • slave 可以接受其他 slave 的连接。除了多个 slave 可以连接到同一个 master 之外, slave 之间也可以像层叠状的结构(cascading-like structure)连接到其他 slave 。自 Redis 4.0 起,所有的 sub-slave 将会从 master 收到完全一样的复制流。
  • Redis 复制在 master 侧是非阻塞的。这意味着 master 在一个或多个 slave 进行初次同步或者是部分重同步时,可以继续处理查询请求。
  • 复制在 slave 侧大部分也是非阻塞的。当 slave 进行初次同步时,它可以使用旧数据集处理查询请求,假设你在 redis.conf 中配置了让 Redis 这样做的话。否则,你可以配置如果复制流断开, Redis slave 会返回一个 error 给客户端。但是,在初次同步之后,旧数据集必须被删除,同时加载新的数据集。 slave 在这个短暂的时间窗口内(如果数据集很大,会持续较长时间),会阻塞到来的连接请求。自 Redis 4.0 开始,可以配置 Redis 使删除旧数据集的操作在另一个不同的线程中进行,但是,加载新数据集的操作依然需要在主线程中进行并且会阻塞 slave 。
  • 复制既可以被用在可伸缩性,以便只读查询可以有多个 slave 进行(例如 O(N) 复杂度的慢操作可以被下放到 slave ),或者仅用于数据安全。
  • 可以使用复制来避免 master 将全部数据集写入磁盘造成的开销:一种典型的技术是配置你的 master Redis.conf 以避免对磁盘进行持久化,然后连接一个 slave ,其配置为不定期保存或是启用 AOF。但是,这个设置必须小心处理,因为重新启动的 master 程序将从一个空数据集开始:如果一个 slave 试图与它同步,那么这个 slave 也会被清空。

当 master 关闭持久化时,复制的安全性

在使用 Redis 复制功能时的设置中,强烈建议在 master 和在 slave 中启用持久化。当不可能启用时,例如由于非常慢的磁盘性能而导致的延迟问题,应该配置实例来避免重置后自动重启。
为了更好地理解为什么关闭了持久化并配置了自动重启的 master 是危险的,检查以下故障模式,这些故障模式中数据会从 master 和所有 slave 中被删除:

我们设置节点 A 为 master 并关闭它的持久化设置,节点 B 和 C 从 节点 A 复制数据。 节点 A
崩溃,但是他有一些自动重启的系统可以重启进程。但是由于持久化被关闭了,节点重启后其数据集合为空。 节点 B 和 节点 C 会从节点 A
复制数据,但是节点 A 的数据集是空的,因此复制的结果是它们会销毁自身之前的数据副本。

当 Redis Sentinel 被用于高可用并且 master 关闭持久化,这时如果允许自动重启进程也是很危险的。例如, master 可以重启的足够快以致于 Sentinel 没有探测到故障,因此上述的故障模式也会发生。
任何时候数据安全性都是很重要的,所以如果 master 使用复制功能的同时未配置持久化,那么自动重启进程这项应该被禁用。
Redis 复制功能是如何工作的
每一个 Redis master 都有一个 replication ID :这是一个较大的伪随机字符串,标记了一个给定的数据集。每个 master 也持有一个偏移量,master 将自己产生的复制流发送给 slave 时,发送多少个字节的数据,自身的偏移量就会增加多少,目的是当有新的操作修改自己的数据集时,它可以以此更新 slave 的状态。复制偏移量即使在没有一个 slave 连接到 master 时,也会自增,所以基本上每一对给定的Replication ID, offset都会标识一个 master 数据集的确切版本。
当 slave 连接到 master 时,它们使用 PSYNC 命令来发送它们记录的旧的 master replication ID 和它们至今为止处理的偏移量。通过这种方式, master 能够仅发送 slave 所需的增量部分。但是如果 master 的缓冲区中没有足够的命令积压缓冲记录,或者如果 slave 引用了不再知道的历史记录(replication ID),则会转而进行一个全量重同步:在这种情况下, slave 会得到一个完整的数据集副本,从头开始。
下面是一个全量同步的工作细节:
master 开启一个后台保存进程,以便于生产一个 RDB 文件。同时它开始缓冲所有从客户端接收到的新的写入命令。当后台保存完成时, master 将数据集文件传输给 slave, slave将之保存在磁盘上,然后加载文件到内存。再然后 master会发送所有缓冲的命令发给 slave。这个过程以指令流的形式完成并且和 Redis 协议本身的格式相同。 你可以用 telnet自己进行尝试。在服务器正在做一些工作的同时连接到 Redis 端口并发出 SYNC 命令。你将会看到一个批量传输,并且之后每一个master 接收到的命令都将在 telnet 回话中被重新发出。事实上 SYNC 是一个旧协议,在新的 Redis实例中已经不再被使用,但是其仍然向后兼容:但它不允许部分重同步,所以现在 PSYNC 被用来替代 SYNC。

之前说过,当主从之间的连接因为一些原因崩溃之后, slave 能够自动重连。如果 master 收到了多个 slave 要求同步的请求,它会执行一个单独的后台保存,以便于为多个 slave 服务。

无需磁盘参与的复制
正常情况下,一个全量重同步要求在磁盘上创建一个 RDB 文件,然后将它从磁盘加载进内存,然后 slave以此进行数据同步。
如果磁盘性能很低的话,这对 master 是一个压力很大的操作。Redis 2.8.18 是第一个支持无磁盘复制的版本。在此设置中,子进程直接发送 RDB 文件给 slave,无需使用磁盘作为中间储存介质
只读性质的 slave
自从 Redis 2.6 之后, slave 支持只读模式且默认开启。redis.conf 文件中的 slave-read-only 变量控制这个行为,且可以在运行时使用 CONFIG SET 来随时开启或者关闭。
只读模式下的 slave 将会拒绝所有写入命令,因此实践中不可能由于某种出错而将数据写入 slave 。但这并不意味着该特性旨在将一个 slave 实例暴露到 Internet ,或者更广泛地说,将之暴露在存在不可信客户端的网络,因为像 DEBUG 或者 CONFIG 这样的管理员命令仍在启用。但是,在 redis.conf 文件中使用 rename-command 指令可以禁用上述管理员命令以提高只读实例的安全性。
您也许想知道为什么可以还原只读设置,并有可以通过写入操作来设置 slave 实例。如果 slave 跟 master 在同步或者 slave 在重启,那么这些写操作将会无效,但是将短暂数据存储在 writable slave 中还是有一些合理的用例的。

例如,计算 slow Set 或者 Sorted Set 的操作并将它们存储在本地 key 中是多次观察到的使用 writable slave 的用例。

但是注意,4.0 版本之前的 writable slaves 不能用生存时间来淘汰 key 。这意味着,如果你使用 EXPIRE 或者其他命令为 key 设置了最大 TTL 的话,你将会在键值计数(count of keys)中看到这个 key ,并且它还在内存中。所以总的来说,将 writable slaves 和设置过 TTL 的 key 混用将会导致问题。
Redis 4.0 RC3 及更高版本彻底解决了这个问题,现在 writable slaves 能够像 master 一样驱逐 TTL 设置过的 key 了,但 DB 编号大于 63(但默认情况下,Redis实例只有16个数据库)的 key 除外。
另请注意,由于 Redis 4.0 writable slaves 仅能本地,并且不会将数据传播到与该实例相连的 sub-slave 上。sub-slave 将总是接收与最顶层 master 向 intermediate slaves 发送的复制流相同的复制流。所以例如在以下设置中:

A —> B —-> C

及时节点 B 是可写的,C 也不会看到 B 的写入,而是将拥有和 master 实例 A 相同的数据集。

redis主从复制实例


官网下载压缩包并且解压

[root@server1 ~]# tar zxf redis-5.0.3.tar.gz

redisearch 架构图 redis lecture_redisearch 架构图_02


安装依赖包并且编译安装

[root@server1 ~]# cd redis-5.0.3
[root@server1 redis-5.0.3]# pwd
/root/redis-5.0.3
[root@server1 redis-5.0.3]# yum install gcc -y
[root@server1 redis-5.0.3]# make && make install

redisearch 架构图 redis lecture_redis_03


redisearch 架构图 redis lecture_数据集_04


redisearch 架构图 redis lecture_redisearch 架构图_05


在相应目录下纸型安装脚本安装

[root@server1 redis-5.0.3]# cd utils/
[root@server1 utils]# ./install_server.sh

redisearch 架构图 redis lecture_数据集_06


修改配置文件

vim  /etc/redis/6379.conf

redisearch 架构图 redis lecture_redis_07


注:默认改文件的bind端口是本机的回环地址,也就是127.0.0.1,但是这样的话,访问redis只能通过本机的客户端连接,无法进行远程连接,这样可以避免redis服务暴露于危险的网络环境中,防止别人通过远程连接盗取数据,在本次实验中为了实验效果,默认是设置为0.0.0.0及任意网段的主机进行连接,如果注释的话表示接收来自于可用网络接口的连接,这在企业中是不会出现的。重启服务查看端口

redisearch 架构图 redis lecture_redis_08


安装redis(同server1)

redisearch 架构图 redis lecture_数据集_09


redisearch 架构图 redis lecture_redisearch 架构图_10


redisearch 架构图 redis lecture_redis_11


编辑server2的配置文件

这里和server1是有所不同的,要修改两处地方(因为还要设置master是谁)

redisearch 架构图 redis lecture_redis_12


redisearch 架构图 redis lecture_数据集_13


注:如果server2上有解析的话,这里还可以把172.25.15.1换成server1

主从复制的检测

在server1(master)上添加key-value数值

redisearch 架构图 redis lecture_数据集_14


在server2上进行查看

redisearch 架构图 redis lecture_redis_15


注:这里可以看出server1(master)可以对数值进行删除修改,但server2(slave)虽然能查看数值,却没有对数值进行修改的权限