查看原文
其他

Region Failover 在 GreptimeDB 集群中的实现

Fucong Luo GreptimeDB 2024-01-30

GreptimeDB 在 v0.3.2 版本中新引入了 Region Failover 的实验功能,该实验功能对于维护集群的高可用性至关重要。本文说明了如何基于心跳、FailureDetector、和 Region 租约的核心原则,解决因 Datanode 故障引发的可用性问题,并确保 Region 在 Datanode 间的正确分布。


Introduction

Region 是 GreptimeDB 集群中数据读写最重要的基本单位,即集群中的分布式读写都是以 Region 为粒度拆分的,所以 Region 是否可用直接关系到整个集群的可用性。Region 分布在 Datanode 上,一旦 Datanode 因为硬件或网络故障导致无法响应请求,Region 也就不可用了。


关于 GreptimeDB 的集群架构,Datanode、Metasrv 和 Frontend 节点的意义,请参考我们的 “Architecture Overview”[1]


GreptimeDB 在 v0.3.2 版本中推出的集群的 Region Failover 实验功能,就是要解决 Datanode 故障导致 Region 不可用的问题。其核心思想是,令 Metasrv 充当集群的 “大脑”,确定性的设置 Region 在 Datanode 的分布,使整个集群能够在故障发生后恢复可用。


所以,Metasrv 需要解决以下三大问题:

- 如何检测 Datanode 出现故障;

- 出现故障后如何重新恢复 Region 在 Datanode 的分布;

- 以及如何确保 Region 分布的正确性。


下面我们将一一展开介绍。


Heartbeat & FailureDetector

“心跳” 是我们故障检测的起点。集群中每个 Datanode 节点都会与 Metasrv 维持一个 gRPC 双向流来作为心跳连接:service Heartbeat {
  rpc Heartbeat(stream HeartbeatRequest) returns (stream HeartbeatResponse) {}
}
每隔一定的时间(默认 5 秒),Datanode 会将自己节点上打开的 Region 信息带在心跳请求中上报给 Metasrv。于是 Metasrv 就拥有了集群中所有 Region 在 Datanode 节点的实际分布情况。


对于每一个上报的 Region 信息,Metasrv 会启动一个 FailureDetector,它会每秒检查一次 Region 是否存活,存活的依据则是由 Region 心跳的历史频率计算而来。这里我们使用了应用广泛的 “The φ accrual failure detector”[2]  算法,该算法可以很好地适应心跳的间隔规律。目前在默认配置下,如果 2 个心跳间隔时间之后,FailureDetector 仍然没有收到 Region 心跳,该 Region 就会被判定为不可用,进入 Failover 执行阶段。


Failover

执行 Failover 的关键是要保证执行过程的完整性。


Failover 不能并发执行,因此我们选择在 Metasrv 的 leader 节点上接收心跳和启动 FailureDetector;另外 Failover也不能因为 Metasrv 发生 leader 重选举而停止执行。因此我们使用了 “Procedure”[3] 框架来执行 Region 的 Failover。分布式地执行 Procedure,只需要一个持久化保存和恢复整体状态的地方,我们选择了 etcd。


整个 Region Failover Procedure 执行的状态转换步骤如下:

( source[4] )

整体思路非常简单:

- 先将故障 Region 在原来的 Datanode 中关闭;

- 待 Region Lease 过期后(Region Lease 会在下一部分介绍),在预先选出的健康 Datanode 节点上将 Region 打开;

- 最后更新 Frontend 节点的 Region 缓存。


这样一个 procedure 完成后,Region 的可用性就恢复了。


Lease

Region 在 Datanode 分布的正确性,核心是确保 Region 至多只能在一个 Datanode 打开。为此我们引入了 Region 的 “租约(Lease)” 概念。每个 Region 都有一个租约,只有在租约时间内,Datanode 才能打开这个 Region。因此,Datanode 对每个Region都有一个 “Liveness Keeper”。在租约时间结束后,Liveness Keeper 会自动关闭过期的  Region。


Region 的续租需要 Metasrv 参与。我们对续租的实现方式是:Datanode 在心跳启动时,记下一个 Instant,作为 “epoch”。每当 Datanode 上报心跳时,会带上一个 duration_since_epoch = Instant::now() - epochMetasrv在做续租时,就是简单地将这个 duration_since_epoch 和一个固定的续租时间返回。Datanode 在收到心跳返回时,可简单地将返回值中的 duration_since_epoch 加上之前的 "epoch" 再加上固定的租约时间,即可得到新的 Region Liveness Keeper 的倒计时。


由于 Instant 一定是单调递增的(除非是罕见的硬件 bug[5]),所以这个 duration_since_epoch 也一定是单调递增,倒计时一定不会回退。这样我们可以在一定程度上减少分布式环境中 Datanode 和 Metasrv 之间时钟不一致的影响。


Summary

本文总结了 GreptimeDB 在 v0.3.2 版本中 Region Failover的设计和实现。主要部分包括心跳,FailureDetector,执行 Region Failover 的 procedure 以及 Region Lease。可以看到,维护一个集群的高可用是比较复杂的。在后面的版本中我们还会对 Region 的 Failover 做进一步的优化。



Reference:

[1] https://docs.greptime.com/developer-guide/overview

[2] https://www.researchgate.net/publication/29682135_The_ph_accrual_failure_detector

[3] https://greptime.com/blogs/2023-03-30-procedure-framework-improve-capability

[4] https://github.com/GreptimeTeam/greptimedb/blob/develop/src/meta-srv/src/procedure/region_failover.rs#L268

[5] https://doc.rust-lang.org/std/time/struct.Instant.html#monotonicity

[6] https://github.com/GreptimeTeam/greptimedb/blob/develop/docs/rfcs/2023-03-08-region-fault-tolerance.md

关于 Greptime

Greptime 格睿科技于 2022 年创立,目前正在完善和打造时序数据库GreptimeDB 和格睿云 GreptimeCloud 这两款产品。

GreptimeDB 是一款用 Rust 语言编写的时序数据库,具有分布式、开源、云原生、兼容性强等特点,帮助企业实时读写、处理和分析时序数据的同时,降低长期存储的成本。

GreptimeCloud 基于开源的 GreptimeDB,为用户提供全托管的 DBaaS,以及与可观测性、物联网等领域结合的应用产品。利用云提供软件和服务,可以达到快速的自助开通和交付,标准化的运维支持,和更好的资源弹性。GreptimeCloud 已正式开放公测,欢迎关注公众号或官网了解最新动态!

官网:https://greptime.com/

GitHub: https://github.com/GreptimeTeam/greptimedb

文档:https://docs.greptime.com/

Twitter: https://twitter.com/Greptime

Slack: https://greptime.com/slack

LinkedIn: https://www.linkedin.com/company/greptime/

往期精彩文章:



👇 点击下方阅读原文,立即体验 GreptimeDB v0.3.2!

继续滑动看下一个

Region Failover 在 GreptimeDB 集群中的实现

Fucong Luo GreptimeDB
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存