raft-06-LogCabin 是一个分布式系统,提供少量高度复制和一致性的存储。
前言
大家好,我是老马。
分布式系统中,一致性算法是最重要的基石,也是最难学习的部分。
本系列根据 jraft 作为入口,学习一下 raft 的原理和实现。
raft 系列
logcabin
之所以介绍这个库 LogCabin,是因为这个库是Raft作者的开源实现。
概述
LogCabin 是一个分布式系统,提供少量高度复制和一致性的存储。
它是其他分布式系统存储其核心元数据的可靠地方,并在解决集群管理问题时非常有用。
LogCabin 内部使用 Raft 共识算法,并且实际上是 Raft 算法的首个实现。
它以 ISC 许可证 发布(等同于 BSD 许可证)。
外部资源:
有关发布的信息,请查看 RELEASES.md。
本 README 将指导您如何编译和运行 LogCabin。
问题
关于 LogCabin 实现的最佳提问场所是 logcabin-dev 邮件列表。您还可以尝试在 freenode IRC 网络的 #logcabin
频道提问,尽管并不是总有人在线。使用 GitHub Issues 报告问题或建议功能。
如果您对 Raft 共识算法有问题或想讨论,Raft 的实现由 LogCabin 提供,您可以使用 raft-dev 邮件列表。
构建
前提条件:
- Linux x86-64(应支持 v2.6.32 及以上版本)
- git(应支持 v1.7 及以上版本)
- scons(已知 v2.0 和 v2.3 可用)
- g++(已知 v4.4 至 v4.9 和 v5.1 可用)或 clang(已知 v3.4 至 v3.7 可用,且支持 libstdc++ 4.9,libc++ 也支持;更多信息请参见 CLANG.md)
- protobuf(建议使用 v2.6.x,v2.5.x 应该也可用,v2.3.x 不支持)
- crypto++(已知 v5.6.1 可用)
- doxygen(可选;已知 v1.8.8 可用)
简而言之,RHEL/CentOS 6 及更新版本应该适用。
获取源代码:
git clone git://github.com/logcabin/logcabin.git
cd logcabin
git submodule update --init
构建客户端库、服务器二进制文件和单元测试:
scons
对于自定义构建环境,您可以将配置变量放在 Local.sc
文件中。例如,该文件可能如下所示:
BUILDTYPE='DEBUG'
CXXFLAGS=['-Wno-error']
要查看可用的配置参数,请运行:
scons --help
运行基础测试
在继续之前,建议先运行包含的单元测试:
build/test/test
您还可以运行一些系统范围的测试。首先运行烟雾测试,这将通过嵌入在 LogCabin 客户端中的内存数据库进行(不涉及服务器):
build/Examples/SmokeTest --mock && echo 'Smoke test completed successfully'
要在真实的 LogCabin 集群上运行相同的烟雾测试,需要进行更多的设置。
运行真实集群
本节介绍如何在一个三服务器的 LogCabin 集群上运行 HelloWorld
示例程序。我们将暂时在本地主机上运行所有服务器:
- 服务器 1 将监听 127.0.0.1:5254
- 服务器 2 将监听 127.0.0.1:5255
- 服务器 3 将监听 127.0.0.1:5256
端口 5254 是 LogCabin 的默认端口,由 IANA 为 LogCabin 保留。其他两个端口则为其他使用,应该不会在您的网络中冲突。
我们首先需要创建三个配置文件。您可以基于 sample.conf
创建,或者以下内容在当前也有效:
文件 logcabin-1.conf
:
serverId = 1
listenAddresses = 127.0.0.1:5254
文件 logcabin-2.conf
:
serverId = 2
listenAddresses = 127.0.0.1:5255
文件 logcabin-3.conf
:
serverId = 3
listenAddresses = 127.0.0.1:5256
现在您几乎准备好启动服务器。首先,初始化其中一台服务器的日志,配置一个只包含它自己的集群成员配置:
build/LogCabin --config logcabin-1.conf --bootstrap
ID 为 1 的服务器现在会有一个有效的集群成员配置。此时,集群中只有 1 台服务器,所以只需要 1 票:它可以选举自己为领导者并提交新条目。现在我们可以启动该服务器(保持运行):
build/LogCabin --config logcabin-1.conf
但是我们不想停在这里,因为只有一台服务器的集群并不具备容错能力!我们将启动另外两台服务器,并将它们添加到第一台服务器的集群中。
首先,在另一个终端中启动第二台服务器(保持运行):
build/LogCabin --config logcabin-2.conf
请注意,这台服务器只是空闲,等待集群成员配置。它仍然不属于集群。
同样,启动第三台服务器(LogCabin 会检查确保您的新配置中的所有服务器都可用,才会提交切换,避免您做出错误操作):
build/LogCabin --config logcabin-3.conf
现在使用重新配置命令将第二和第三台服务器添加到集群中:
ALLSERVERS=127.0.0.1:5254,127.0.0.1:5255,127.0.0.1:5256
build/Examples/Reconfigure --cluster=$ALLSERVERS set 127.0.0.1:5254 127.0.0.1:5255 127.0.0.1:5256
该 Reconfigure
命令是一个特殊的 LogCabin 客户端。它首先查询每个在命令行参数中给定的服务器(空格分隔),以获取其服务器 ID 和监听地址。然后,它连接到通过 --cluster
选项指定的集群(逗号分隔),并请求领导者将集群成员设置为这些服务器。注意,如果现有集群成员也要保留在集群中,它们应该包括在命令行参数中,否则它们将被驱逐。
如果成功,您应该看到第一台服务器已将其他服务器添加到集群中,第二和第三台服务器现在也在参与。输出应该类似于:
Current configuration:
Configuration 1:
- 1: 127.0.0.1:5254
Attempting to change cluster membership to the following:
1: 127.0.0.1:5254 (given as 127.0.0.1:5254)
2: 127.0.0.1:5255 (given as 127.0.0.1:5255)
3: 127.0.0.1:5256 (given as 127.0.0.1:5256)
Membership change result: OK
Current configuration:
Configuration 4:
- 1: 127.0.0.1:5254
- 2: 127.0.0.1:5255
- 3: 127.0.0.1:5256
注意:如果您在所有服务器之间共享一个磁盘,并且负载较重,集群可能会遇到难以保持领导者的问题。有关症状和解决方法,请参见 issue 57。
最后,您可以运行 LogCabin 客户端以测试集群:
build/Examples/HelloWorld --cluster=$ALLSERVERS
该程序并没有做任何特别有趣的事情。另一个工具 TreeOps
可以在命令行上展示 LogCabin 的数据结构:
echo -n hello | build/Examples/TreeOps --cluster=$ALLSERVERS write /world
build/Examples/TreeOps --cluster=$ALLSERVERS dump
查看 --help
获取完整的可用命令列表
。
您应该能够逐个停止服务器并保持可用性,或者停止多个并重新启动它们并保持安全性(可能会有短暂的可用性中断)。
如果您发现每次都要传递 --cluster=$ALLSERVERS
很麻烦,也可以使用 DNS 名称返回所有 IP 地址。不过,您需要为每个服务器使用不同的 IP 地址,而不仅仅是不同的端口。
如果您有自己的应用程序,您可以将其链接到 build/liblogcabin.a
。您还需要链接以下库:
- pthread
- protobuf
- cryptopp
运行集群范围的测试
如上所述,在运行集群时的过程有点繁琐,特别是当您只是想跑一些测试并立即拆除集群时。为此,scripts/smoketest.py
自动化了这一过程。创建一个名为 scripts/localconfig.py
的文件来覆盖 scripts/config.py
中的 smokehosts
和 hosts
变量:
smokehosts = hosts = [
('192.168.2.1', '192.168.2.1', 1),
('192.168.2.2', '192.168.2.2', 2),
('192.168.2.3', '192.168.2.3', 3),
]
该脚本使用此文件来通过 SSH 启动服务器。每个元组代表一个服务器,包含:
- 用于 SSH 的地址,
- 用于 LogCabin TCP 连接的地址,
- 唯一的 ID。
每台服务器应该能够通过 SSH 无需密码访问,并且 LogCabin 目录应该位于相同的文件系统位置。脚本假设该目录位于共享文件系统中,例如 NFS 挂载或本地磁盘。
您还可以选择创建一个 smoketest.conf
文件,该文件可以定义适用于所有服务器的各种选项。服务器的监听地址将与您的 smoketest.conf
自动合并。
现在,您已经准备好运行:
scripts/smoketest.py && echo 'Smoke test completed successfully'
此脚本还可以被劫持/包含来运行其他测试程序。
文档
要从源代码构建文档,请运行:
scons docs
生成的 HTML 文件将放置在 docs/doxygen
目录下。
您也可以在 上找到这些文档。
安装
要在文件系统上安装一堆东西,请运行:
scons install
除了二进制文件外,这还会安装一个与 RHEL 6 兼容的初始化脚本。
如果您不希望这些文件污染您的文件系统,可以将文件安装到任何指定的目录,方法如下(将 pathtoinstallprefix
替换为您希望安装文件的路径):
scons --install-sandbox=pathtoinstallprefix pathtoinstallprefix
最后,您可以按照以下方式构建一个二进制 RPM:
scons rpm
这将创建一个名为 build/logcabin-0.0.1-0.1.alpha.0.x86_64.rpm
的文件,您可以使用 RPM 安装,效果与 scons install
相同。
贡献
请使用 GitHub 报告问题和发送拉取请求。
所有提交都应该通过预提交钩子。启用它们以在每次提交之前运行:
ln -s ../../hooks/pre-commit .git/hooks/pre-commit