8

使用 RedisRaft 构建强一致的 Redis 集群 — blog.huangz.me

 4 years ago
source link: https://blog.huangz.me/2020/redisraft.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

使用 RedisRaft 构建强一致的 Redis 集群

../_images/redisraft.jpg

本文由黄健宏翻译自 RedisLabs.com/blog ,首发于 blog.huangz.me

正在开发中的 RedisRaft 是一个开源的 Redis 模块, 它可以将多个 Redis 服务器用作一个单一容错且强一致的集群来运行。 顾名思义, 这个模块基于 Raft 的共识算法并且使用了一个实现该算法的开源 C 库

RedisRaft 为 Redis 和 Redis 生态系统带来了新的强一致性与严格的序列化部署方案。 新模块使 Redis 与 Redis 现有的客户端、库和数据类型一起在需要高可靠性和一致性的超越缓存(beyond-cache)的场景中使用成为可能。

RedisRaft 的由来

RedisRaft 始于 Redis 5 发布之前的一个实验性的“副项目”。 至于 Redis 模块这一特性则从 Redis 4 开始引入, 它可以通过模块的方式实现新的数据类型和命令。 我们想探索我们能够将 API 扩展到什么程度, 并使用模块以更激进的方式扩展 Redis 。 但我们也希望最终能得到一些有用的东西 —— 一个可选的强一致的 Redis 。

RedisRaft 集群能够提供的一致性和可靠性跟 ZooKeeper 、 Etcd 等常见的可靠数据库存储处于同一水平。 简单来说, 在 RedisRaft 中:

  • 已确认的写入保证会被提交并且永不丢失。

  • 读取将始终返回最新的已提交写入。

正如人们预期的一样, 提供这种级别的一致性可靠存储带来了性能和可用性方面的折中。 在 RedisRaft 中:

  • 客户端操作依赖于集群节点的消息交换,它们将受到网络延迟的影响。

  • 写入必须在完成之前刷新到磁盘上,它们会受到磁盘 I/O 延迟的约束。

  • 只有在大多数节点都正常运行、健康并且能够相互通信的情况下,集群才是可用的。

RedisRaft 的工作原理

一旦 RedisRaft 模块被加载到 Redis 中, 它就会接管集群节点之间的通信、Raft 日志或快照的复制、持久化等工作。 Redis 核心不会察觉到这一点, 它就像是一个没有启用集群、持久化和复制特性的独立服务器。

设置一个三节点 RedisRaft 集群就像启动三个 Redis 服务器一样简单, 我们首先要做的就是执行以下命令, 载入 RedisRaft 模块:

redis-server --loadmodule /path/to/redisraft.so

接着, 执行以下命令能够连接到第一个服务器并且创建 Raft 集群:

10.0.0.1:6379> RAFT.CLUSTER INIT
OK 989645460313dd2ddb051f033c791222

之后, 我们可以执行以下两条命令, 将另外两台服务器加入到集群里面:

10.0.0.2:6379> RAFT.CLUSTER JOIN 10.0.0.1:6379
OK

10.0.0.3:6379> RAFT.CLUSTER JOIN 10.0.0.1:6379
OK

访问集群

在设置好 RedisRaft 集群之后, 我们就可以向它写入数据:

10.0.0.1:6379> INCR counter:1
(integer) 1

收到回复表明写入已经被复制到不少于半数集群节点(在我们的情况下是2个节点), 并提交到它们的持久化存储中。

Raft 基于强领导者(strong leader)概念, 这意味着所有客户端操作都应该发送至领导者节点(leader node)并由它发起。 在本例中, 我们的客户端确实连接到了领导者, 但集群领导力是动态的, 客户端不一定知道谁是领导者。

在一个跟随者(非领导者)节点上尝试同样的操作, 会产生这样的响应:

10.0.0.3:6379> INCR counter:1.
(error) MOVED 10.0.0.1:6379

客户端可以捕捉这个错误, 并按照指示重新连接至领导者节点, 然后重新执行命令。

但是, 如果我们不想修改现有的应用程序怎么办? 幸运的是, RedisRaft 也可以被配置为自动为我们处理这个问题。 通过启用 follower 代理模式, 我们可以让集群节点自动将请求转发给领导者, 并在其可用时提供回复。

10.0.0.3:6379> RAFT.CONFIG SET follower-proxy yes.
OK

10.0.0.3:6379> INCR counter:1
(integer) 2

这种做法要简单得多, 但是由于访问非领导者节点会产生额外的网络跳数, 所以对延迟和网络负载都会有影响。

改变集群

在设置集群时, 我们实际上进行了三种不同的操作。

  • 在一个节点上创建集群。

  • 添加了第二个节点。

  • 添加第三个节点。

RedisRaft 集群的配置并不是静态的, 在集群创建之后并且处于活跃状态时, 我们可以随时往集群里面添加或者移除节点。

假设现在我们需要替换第三个节点, 那么我们首先要做的就是加入一个替换该节点的新节点。 注意, 为了避免集群和宝贵的数据在数据迁移期间处于退化的冗余状态, 我们需要”先添加新节点,再移除旧节点“, 而不是”先移除旧节点再添加新节点“:

10.0.0.4:6379> RAFT.CLUSTER JOIN 10.0.0.1:6379
OK

接下来, 我们查找随机分配给我们第三个节点的 ID 。

redis-cli -h 10.0.0.1 --raw RAFT.INFO | grep 10.0.0.3
node2:id=1739451728,state=connected,voting=yes,addr=10.0.0.3,port=6379。
last_conn_secs=3537,conn_errors=0,conn_oks=1。

然后将第三个节点删除:

10.0.0.1:6379> RAFT.NODE REMOVE 1739451728
OK

RedisRaft 的发布状态

作为 RedisRaft 开发工作的一部分, 我们一直在与 Kyle Kingsbury(又名Aphyr) 合作, 使用Jepsen(一个测试分布式系统安全性和正确性的著名框架)分析和测试 RedisRaft 。 到目前为止, 这次合作已经形成了一份已发表的分析报告

虽然仍然处于开发当中, 但 RedisRaft 的大部分基本功能已经到位。 目前, 我们正在为第一个预览版而努力, 预计几个月后就会推出。 至于正式版(GA)的 RedisRaft 则会以 GNU AGPLv3 和 Redis 源码可用许可证(RSAL)双重许可证的形式发布。

文/Yossi Gottlieb · 译/黄健宏
2020.6.28

如果你对 Redis 感兴趣, 那么请不要错过我即将推出的 《Redis入门与实战》以及其他 Redis 书


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK