故障与恢复
JanusGraph 是一个高可用、健壮的图数据库。在大型 JanusGraph 部署中,故障是不可避免的。本页描述了一些故障情况以及 JanusGraph 如何处理它们。
事务故障
事务可能因多种原因失败。如果事务在提交前失败,更改将被丢弃,应用程序可以根据业务逻辑重试事务。同样,锁定或其他一致性故障会导致在持久化之前抛出异常,因此可以重试。事务的持久化阶段是 JanusGraph 开始将数据持久化到各种后端系统的时候。
JanusGraph 首先将所有图变动持久化到存储后端。此持久化作为一次批量变动执行,以确保对于支持原子性的后端,变动是原子提交的。如果批量变动由于存储后端中的异常而失败,则整个事务失败。
如果对存储后端的主持久化成功,但对索引后端或日志系统的次持久化失败,则事务仍被认为是成功的,因为存储后端是图的权威来源。
然而,这可能导致索引和日志不一致。为了自动修复此类不一致,JanusGraph 可以维护一个事务预写日志,通过配置启用。
tx.log-tx = true
tx.max-commit-time = 10000
max-commit-time 属性用于确定事务何时失败。如果事务的持久化阶段耗时超过此时间,JanusGraph 会在必要时尝试恢复它。因此,此超时应配置为持久化最大持续时间的一个宽泛上限。请注意,这不包括提交之前花费的时间。
此外,必须设置一个单独的进程来读取日志以识别部分失败的事务并修复引起的任何不一致。建议在连接到集群的独立机器上运行事务修复进程,以隔离故障。配置一个单独控制的进程来运行以下命令,其中 start time 指定了自纪元以来恢复进程应从预写日志开始读取的时间。
recovery = JanusGraphFactory.startTransactionRecovery(graph, startTime, TimeUnit.MILLISECONDS);
启用事务预写日志会导致变动事务的额外写入操作,从而增加延迟。另请注意,需要额外的空间来存储日志。事务预写日志具有可配置的 2 天存活时间 (time-to-live),这意味着日志条目在此时间后过期,以保持存储开销较小。有关所有日志相关配置选项的完整列表,请参阅配置参考,以微调日志行为。
JanusGraph 实例故障
JanusGraph 能够抵御单个实例故障,即 JanusGraph 集群的其他实例不受此类故障的影响,可以在失败实例重新启动时继续处理事务而不会降低性能。
但是,某些与模式相关的操作(例如安装索引)需要所有 JanusGraph 实例的协调。因此,JanusGraph 维护所有正在运行实例的记录。如果一个实例失败,即未正确关闭,JanusGraph 认为它是活动的,并期望它参与集群范围的操作,这些操作随后会失败,因为该实例未参与或未确认该操作。
在这种情况下,用户必须手动从集群中移除失败实例的记录,然后重试操作。要移除失败实例,请针对任何正在运行的 JanusGraph 实例打开一个管理事务,检查正在运行的实例列表以识别失败的实例,最后将其移除。
mgmt = graph.openManagement()
mgmt.getOpenInstances() //all open instances
==>7f0001016161-dunwich1(current)
==>7f0001016161-atlantis1
mgmt.forceCloseInstance('7f0001016161-atlantis1') //remove an instance
mgmt.commit()
当前 JanusGraph 实例的唯一标识符标记有后缀 (current),以便于识别。此实例不能通过 forceCloseInstance 方法关闭,而应通过 g.close() 关闭
必须确保手动移除的实例确实不再活动。从集群中移除活动的 JanusGraph 实例可能导致数据不一致。因此,在使用此方法时务必小心,尤其是在 JanusGraph 在实例自动重启的环境中运行时。