# 部署高可用模式 > 此文档主要介绍了高可用模式的原理、准备工作、以及服务器的操作说明 ## 1.原理 TuGraph 通过多机热备份来提供高可用(HA)模式。在高可用模式下,对数据库的写操作会被同步到所有服务器(非witness)上,这样即使有部分服务器宕机也不会影响服务的可用性。 高可用模式启动时,多个 TuGraph 服务器组成一个备份组,即高可用集群。每个备份组由三个或更多 TuGraph 服务器组成,其中某台服务器会作为`leader`,而其他复制组服务器则作为`follower`。写入请求由`leader` 提供服务,该`leader`将每个请求复制同步到`follower`,并在请求同步到服务器后才能响应客户端。这样,如果任何服务器发生故障,其他服务器仍将具有到目前为止已写入的所有数据。如果`leader` 服务器发生故障,其他服务器将自动选择出新的`leader`。 TuGraph的高可用模式提供两种类型的节点:`replica`节点和`witness`节点。其中,`replica`节点是普通节点,有日志有数据,可对外提供服务。 而`witness`节点是一种只接收心跳和日志但不保存数据的节点。根据部署需求,`leader`节点和`follower`节点可以灵活的部署为`replica`节点或`witness`节点。 基于此,TuGraph高可用模式的部署方式有两种:一是普通部署模式,二是带witness的简约部署模式。 对于普通部署模式,`leader`和所有`follower`均为`replica`类型的节点。写入请求由`leader`提供服务,该`leader`将每个请求复制同步到`follower`, 并在请求同步到超过半数的服务器后才能响应客户端。这样,如果少于半数的服务器发生故障,其他服务器仍将具有到目前为止已写入的所有数据。如果`leader` 服务器发生故障,其他服务器将自动选举出新的`leader`,通过这种方式保证数据的一致性和服务的可用性。 然而,在用户服务器资源不够或者发生网络分区时,不能建立正常的HA集群。此时,由于`witness`节点没有数据,对资源占用小,可以将`witness`节点和`replica`节点部署在一台机器上。 例如,当只有2台机器的情况下,可以在一台机器上部署`replica`节点,在另一台机器上部署`replica`节点和`witness`节点,不仅节省资源,而且不需要把日志应用到状态机上, 也不需要生成和安装快照,因此响应请求的速度很快,可以在集群崩溃或网络分区时协助快速选举出新的`leader`,这就是TuGraph HA集群的简约部署模式。 尽管`witness`节点有诸多好处,但是由于没有数据,集群实际上增加了一个不能成为`leader`的节点,因此可用性会略有降低。为提高集群的可用性, 可通过指定`ha_enable_witness_to_leader`参数为`true`,允许`witness`节点临时当主。`witness`节点在把新日志同步到其他节点之后, 会将leader角色主动切换到有最新日志的节点。 v3.6及以上版本支持此功能。 ## 2.准备工作 要启用高可用模式,用户需要: - 三台及以上的 TuGraph 服务器实例。 - 在启动 lgraph_server 时打开高可用模式,可以使用配置文件或者命令行将`enable_ha`选项设置为`true`。 - 设置正确的`rpc_port`,可通过配置文件或者命令行设置。 ## 3.启动初始备份组 安装好TuGraph之后,可以使用`lgraph_server`命令在不同的机器上启动高可用集群。本节主要讲解高可用集群的启动方式,启动之后的集群状态管理参见[lgraph_peer工具](../6.utility-tools/5.ha-cluster-management.md) ### 3.1.初始数据一致 当启动时所有服务器中的数据相同或没有数据时,用户可以通过指定`--ha_conf host1:port1,host2:port2`启动服务器。 这种方式可以将准备好的所有TuGraph实例一次性加入初始备份组,由备份组中的所有服务器根据raft协议选举出`leader`,并将其他服务器以`follower`的角色加入备份组。 启动初始备份组的命令示例如下所示: ```bash $ ./lgraph_server -c lgraph.json --rpc_port 9090 --enable_ha true --ha_conf 172.22.224.15:9090,172.22.224.16:9090,172.22.224.17:9090 ``` ### 3.2.初始数据不一致 如果第一台服务器中已有数据(以`lgraph_import`工具导入或从非高可用模式的服务器传输得到), 并且之前并未在高可用模式下使用,则用户应使用boostrap方式启动。 以`ha_bootstrap_role`参数为1在bootstrap模式下启动有数据的服务器,并通过`ha_conf`参数指定本机为`leader`。 在bootstrap模式下,服务器在将新加入的服务器添加到备份组之前会将自己的 数据复制到新服务器中,以使每个服务器中的数据保持一致。 启动有数据服务器的命令示例如下所示: ```bash $ ./lgraph_server -c lgraph.json --rpc_port 9090 --enable_ha true --ha_conf 172.22.224.15:9090,172.22.224.16:9090,172.22.224.17:9090 --ha_bootstrap_role 1 ``` 其他无数据的服务器需要指定`ha_bootstrap_role`参数为2,并通过`ha_conf`参数指定`leader`即可,命令示例如下所示 ```bash $ ./lgraph_server -c lgraph.json --rpc_port 9090 --enable_ha true --ha_conf 172.22.224.15:9090,172.22.224.16:9090,172.22.224.17:9090 --ha_bootstrap_role 2 ``` **使用bootstrap启动HA集群时需要注意两点:** 1. 需要等待`leader`节点生成snapshot并且成功启动之后再加入`follower`节点,否则`follower`节点可能加入失败。在启动`follower`节点时可以将`ha_node_join_group_s`参数配置的稍大,以在加入HA集群时多次等待和超时重试。 2. HA集群只有在第一次启动时可以使用bootstrap模式,后续再启动时只能使用普通模式(见3.1节)启动,尤其不能让同一个集群的多个节点以bootstrap模式启动,否则可能产生数据不一致的情况 ## 4.启动witness节点 ### 4.1.不允许witness节点成为leader `witness`节点的启动方式和普通节点的启动方式一致,只需要设置`ha_is_witness`参数为`true`即可。需注意,witness节点的数量应少于集群节点总数量的一半。 启动`witness`节点服务器的命令示例如下所示: ```bash $ ./lgraph_server -c lgraph.json --rpc_port 9090 --enable_ha true --ha_conf 172.22.224.15:9090,172.22.224.16:9090,172.22.224.17:9090 --ha_is_witness 1 ``` 注:默认不允许`witness`节点成为`leader`节点,这可以提高集群的性能,但是在`leader`节点崩溃时会降低集群的可用性。 ### 4.2.允许witness节点成为leader 可以通过指定`ha_enable_witness_to_leader`参数为`true`,使得`witness`节点可以临时成为`leader`节点,在将新日志同步完成之后再主动切主 启动允许成为`leader`节点的`witness`节点服务器的命令示例如下所示: ```bash $ ./lgraph_server -c lgraph.json --rpc_port 9090 --enable_ha true --ha_conf 172.22.224.15:9090,172.22.224.16:9090,172.22.224.17:9090 --ha_is_witness 1 --ha_enable_witness_to_leader 1 ``` 注:尽管允许`witness`节点成为`leader`节点可以提高集群的可用性,但是在极端情况下可能会影响数据的一致性。因此一般应保证`witness`节点数量+1少于集群节点总数量的一半。 ## 5.横向扩展其他服务器 启动初始备份组后,如果想对备份组进行横向扩展,要将新服务器添加到备份组, 应使用`--ha_conf HOST:PORT`选项,其中`HOST`可以是该备份组中已有的任何服务器的 IP 地址, 而`PORT`是其 RPC 端口。例如: ```bash ./lgraph_server -c lgraph.json --rpc_port 9090 --enable_ha true --ha_conf 172.22.224.15:9090 ``` 此命令将启动一台高可用模式的 TuGraph 服务器,并尝试将其添加到包含服务器`172.22.224.15:9090`的备份组中。 请注意,加入备份组需要服务器将其数据与备份组的`leader`服务器同步,此过程可能需要相当长的时间,具体取决于数据的大小。 ## 6.停止服务器 当服务器通过`CTRL-C`下线时,它将通知当前的`leader`服务器,告知其从备份组中删除该下线的服务器。如果`leader`服务器下线, 它将在下线前将`leader`身份权限传给另一台服务器。 如果服务器被终止或者与备份组中的其他服务器失去连接,则该服务器将被视为失败节点,`leader`服务器将在特定时限后将其从备份组中删除。 如果任何服务器离开备份组并希望重新加入,则必须从`--ha_conf HOST:PORT`选项开始,其中`HOST`是当前备份组中的某台服务器的 IP 地址。 ## 7.重启服务器 不建议重新启动整个备份组,因为它会中断服务。如果需要,可以关闭所有服务器。但在重新启动时, 必须保证关闭时的备份组中至少有N/2+1的服务器能正常启动,否则启动失败。 并且, 无论初始启动复制组时是否指定`enable_bootstrap`为true,重启服务器时都只需通过 指定`--ha_conf host1:port1,host2:port2`参数一次性重启所有服务器即可,命令示例如下所示: ```bash $ ./lgraph_server -c lgraph.json --rpc_port 9090 --enable_ha true --ha_conf 172.22.224.15:9090,172.22.224.16:9090,172.22.224.17:9090 ``` ## 8.docker部署高可用集群 在真实业务场景中,很可能遇到在多种操作系统或架构上部署高可用集群的需求。 差异化的环境可能导致编译TuGraph时缺少某些依赖。因此, 在docker中编译软件并部署高可用集群是非常有应用价值的。以centos7版本的docker为例, 部署高可用集群的步骤如下所示。 ### 8.1.安装镜像 使用如下命令下载TuGraph的编译docker镜像环境 ```shell docker pull tugraph/tugraph-compile-centos7 ``` 然后拉取TuGraph源码并编译安装 ### 8.2.创建容器 使用如下命令创建容器,使用`--net=host`使得容器运行在host模式,此模式下 docker和宿主机和共享网络namespace,即共用同一个IP。 ```shell docker run --net=host -itd -p -v {src_dir}:{dst_dir} --name tugraph_ha tugraph/tugraph-compile-centos7 /bin/bash ``` ### 8.3.启动服务 在每台服务器上使用如下命令启动服务,因为docker和宿主机共享IP,所以可以直接指定在宿主机IP上启动服务 ```shell $ lgraph_server -c lgraph.json --host 172.22.224.15 --rpc_port 9090 --enable_ha true --ha_conf 172.22.224.15:9090,172.22.224.16:9090,172.22.224.17:9090 ``` ## 9.查看服务器状态 备份组的当前状态可以在 TuGraph 可视化工具、REST API 以及 Cypher 查询中获取。 在 TuGraph 可视化工具中,可以在 DBInfo 部分中找到备份组中的服务器及其角色列表。 使用 REST API 时,可以使用`GET /info/peers` 请求获取信息。 在 Cypher 中,使用`CALL dbms.listServers()`语句来查询当前备份组的状态信息。 ## 10.高可用模式下数据同步问题 在高可用模式下,同一备份组中的不同服务器可能并不总是处于相同的状态。出于性能原因,如果请求已同步到超过一半的服务器,则`leader`服务器将认为该请求属于`committed`状态。尽管其余服务器最终将收到新请求,但服务器的状态不一致将持续一段时间。客户端也可能向刚刚重新启动的服务器发送请求,从而具有较旧的状态。 为了确保客户端看到一致连续的数据,特别是为了摆脱`反向时间旅行`问题(其中客户端读取比以前看到的状态更旧的状态),每个 TuGraph 服务器都会保持一个单调增加的数据版本号。备份组中数据版本号到数据库状态的映射全局一致,这意味着如果两台服务器具有相同的数据版本号,则它们必须具有相同的数据。响应请求时,服务器在响应中包含了其数据版本号。因此,客户端可以知道它看到了哪个版本。客户端收到旧版本的数据之后可以重新向Leader发送请求,从而获取到最新的数据。