背景以及需求

  1. 线上业务对数据库可用性可靠性要求较高,要求需要有双 AZ 的主备容灾机制。
  2. 主备集群要求数据和 schema 信息实时同步,数据同步平均时延要求在 1s 之内,p99 要求在 2s 之内。
  3. 主备集群数据要求一致
  4. 要求能够在主集群故障时高效自动主备倒换或者手动主备倒换,主备倒换期间丢失的数据可找回。

为什么使用 Listener

Listener:这是一种特殊的 Raft 角色,并不参与投票,也不能用于多副本的数据一致性。

原本的 NebulaGraph 中的 Listener 是一个 Raft 监听器,它的作用是将数据异步写入外部的 Elasticsearch 集群,并在查询时去查找 ES 以实现全文索引的功能。

这里我们需要的是 Listener 的监听能力,用于快速同步数据到其他集群,并且是异步的执行,不影响主集群的正常读写。

这里我们需要定义两个新的 Listener 类型:

  1. Meta Listener:用于同步表结构以及其他元数据信息
  2. Storage Listener:用于同步 storaged 服务的数据

这样 storaged 服务和 metad 服务的 part leader 节点接受到写请求时,除了同步一份数据给 follower 节点,也会同步一份给各自的 listener 节点。

备集群如何接受数据?

现在我们面临几个问题:

  1. 两个新增 Listener 在接收到 leader 同步的日志后,应该如何再同步给备集群?
  2. 我们需要匹配和解析不同的数据操作,例如添加点、删除点、删除边、删除带索引的数据等等操作;
  3. 我们需要将解析到的不同操作的数据重新组装成一个请求发送给备集群的 storaged 服务和 metad 服务;

通过走读 nebula-storaged 的内核代码我们可以看到,无论是 metad 还是 storaged 的各种创建删除表结构以及各种类型数据的插入,最后都会序列化成一个 wal 的 log 发送给 follower 以及 listener 节点,最后存储在 RocksDB 中。

因此,我们的 listener 节点需要具备从 log 日志中解析并识别操作类型的能力,和封装成原请求的能力,因为我们需要将操作同步给备集群的 metad 以及 storaged 服务。

这里涉及到一个问题,主集群的 listener 需要如何感知备集群?备集群 metad 服务的信息以及 storaged 服务的信息?从架构设计上来看,两个集群之间应该有一个接口通道互相连接,但又不干涉,如果由 listener 节点直接发送请求给备集群的 nebula 进程,两个集群的边界就不是很明显了。所以这里我们再引入一个备集群的服务 listener 服务,它用于接收来自主集群的 listener 服务的请求,并将请求转发给自己集群的 metad 以及 storaged 服务。

这样做的好处。两边集群的服务模块是对称的,方便我们后面快速地做主备切换。

Listener 节点的管理和可靠性

为了保证双 AZ 环境的可靠性,很显然 Listener 节点也是需要多节点多活的,在 nebula 内核源码中是有对于 listener 的管理逻辑,但是比较简单,我们还需要设计一个 ListenerManager 实现以下几点能力:

  1. listener 节点注册以及删除命令
  2. listener 节点动态负载均衡(尽量每个 space 各个 part 分布的 listener 要均匀)
  3. listener 故障切换

节点注册管理以及负载均衡都比较简单好设计,比较重要的一点是故障切换应该怎么做?

listener 故障切换的设计

listener 节点故障切换的需求可以拆分为以下几个部分:

  1. listener 同步 wal 日志数据时周期性记录同步的进度(commitId && appendLogId);
  2. ListenerManager 感知到 listener 故障后,触发动态负载均衡机制,将故障 listener 的 part 分配给其他在运行的 listener;
  3. 分配到新 part 的 listener 们获取原先故障 listener 记录的同步进度,并以该进度为起始开始同步数据;

至于 listener 同步 wal 日志数据时周期性记录同步的进度应该记录到哪里?可以是存储到 metad 服务中,也可以存储到 storaged 服务对应的 part 中。

nebula 主备切换设计

在聊主备切换之前,我们还需要考虑一件事,那就是双 AZ 环境中,应该只能有主集群是可读可写的,而其他备集群应该是只读不能写。这样是为了保证两边数据的最终一致性,备集群的写入只能是由主集群的 listener 请求来写入的,而不能被 graphd 服务的请求写入。

所以我们需要对集群状态增加一种“只读模式”,在这种只读模式下,表明当前集群状态是处于备集群的状态,拒绝来自 graphd 服务的写操作。同样的,备集群的 listener 节点处在只读状态时,也只能接收来自主集群的请求并转发给备集群的进程,拒绝来自备集群的 wal 日志同步。

主备倒换发生时,需要有以下几个动作:

  1. 主集群的每个 listener 记录自己所负责的 part 的同步进度(commitId && appendLogId);
  2. 备集群的 nebula 服务转换为可写;
  3. 备集群的 listener 节点转换为可写,并且开始接收来自自己集群的 metad 和 storaged 进程的 wal 日志;
  4. 主集群的 listener 以及各个服务转换为只读状态,开始接收来自新的主集群的数据同步请求;

这几个动作细分下来,最主要的内容就是状态转换以及上下文信息保存和同步,原主集群需要保存自己主备切换前的上文信息(比如同步进度),新的主集群需要加载自己的数据同步起始进度(从当前最新的 commitLog 开始)

主备切换过程中的数据丢失问题

很明显,在上面的设计中,当主备切换发生时,会有一段时间的“双主”的阶段,在这个阶段内,原主集群的剩余日志已经不能再同步给备集群了,这就是会被丢失的数据。如何恢复这些被丢失的数据,可能的方案有很多,因为原主集群的同步进度是有记录的,有哪些数据还没同步完也是可以查询到的,所以可以手动或者自动去单独地同步那一段缺失数据。

当然这种方案也会引入新的问题,这段丢失地数据同步给主集群后,主集群会再次同步一遍回现在的备集群,一段 wal 数据的两次重复操作,不知道为引起什么其他的问题。

所以关于主备切换数据丢失的问题,我们还没有很好的处理方案,感兴趣的伙伴欢迎在评论区讨论。


感谢你的阅读 (///▽///)

对图数据库 NebulaGraph 感兴趣?欢迎前往 GitHub 查看源码:https://github.com/vesoft-inc/nebula

想和其他图技术爱好者一起交流心得?和 NebulaGraph 星云小姐姐 交个朋友再进个交流群;

架构设计|基于 raft-listener 实现实时同步的主备集群的更多相关文章

  1. 基于uReplicator复制的kafka主备集群间的切换策略

    一.概述 目前基于中间件uReplicator实现了kafka集群间的迁移复制,可以实现跨区.跨云的kafka集群间复制同步,也可以实现kafka集群的冷热互备架构:在实现集群间同步以后,需要解决一个 ...

  2. 实时计算框架:Flink集群搭建与运行机制

    一.Flink概述 1.基础简介 Flink是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算.Flink被设计在所有常见的集群环境中运行,以内存执行速度和任意规模来执行计算.主要特性包 ...

  3. 基于 Clusternet 与 OCM 打造新一代开放的多集群管理平台

    背景 随着 5G.物联网设备的爆炸性增长以及智能终端不断增强的计算能力,带来了前所未有的数据量,传统的中心集中式计算捉襟见肘."新基建"战略的实施,工业互联网.车联网/自动驾驶.智 ...

  4. 基于RHCS的web双机热备集群搭建

    基于RHCS的web双机热备集群搭建 RHCS集群执行原理及功能介绍 1. 分布式集群管理器(CMAN)  Cluster Manager.简称CMAN.是一个分布式集群管理工具.它执行在集群的各个节 ...

  5. Spark运行模式_基于YARN的Resource Manager的Custer模式(集群)

    使用如下命令执行应用程序: 和"基于YARN的Resource Manager的Client模式(集群)"运行模式,区别如下: 在Resource Manager端提交应用程序,会 ...

  6. 架构设计 | 基于电商交易流程,图解TCC事务分段提交

    本文源码:GitHub·点这里 || GitEE·点这里 一.场景案例简介 1.场景描述 分布式事务在业务系统中是十分常见的,最经典的场景就是电商架构中的交易业务,如图: 客户端通过请求订单服务,执行 ...

  7. 架构设计 | 基于Seata中间件,微服务模式下事务管理

    源码地址:GitHub·点这里 || GitEE·点这里 一.Seata简介 1.Seata组件 Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata将为用 ...

  8. 基于sersync海量文件实时同步

    项目需求:最近涉及到数百万张图片从本地存储迁移到云存储,为了使完成图片迁移,并保证图片无缺失,业务不中断,决定采用实时同步,同步完后再做流量切换.在实时同步方案中进行了几种尝试. 方案1:rsync+ ...

  9. 16套java架构师,高并发,高可用,高性能,集群,大型分布式电商项目实战视频教程

    16套Java架构师,集群,高可用,高可扩展,高性能,高并发,性能优化,设计模式,数据结构,虚拟机,微服务架构,日志分析,工作流,Jvm,Dubbo ,Spring boot,Spring cloud ...

  10. MHA-结合MySQL半同步复制高可用集群(Centos7)

    目录 一.理论概述 本案例部署思路 二.环境 三.部署 部署MHA 部署二进制包MySQL及部署主从复制 部署半同步复制 配置MHA MHA测试 部署lvs+keepalived(lvs1,lvs2) ...

随机推荐

  1. chatGPT初体验

    chatGPT NLP技术,通过统计的手段模拟出更正确的答案. 他与以前的NLP不一样,他有上下文语义,他能够模拟场景,能够总结很多文章信息. 因此对于谷歌等搜索引擎就很有攻击性了,因为chatGPT ...

  2. WPF开源的一款免费、开箱即用的翻译、OCR工具

    前言 今天大姚给大家分享一款由WPF开源的.免费的(MIT License).即开即用.即用即走的翻译.OCR工具:STranslate. WPF介绍 WPF 是一个强大的桌面应用程序框架,用于构建具 ...

  3. setting.json 20210825 更新

    vue代码格式化思路 { "pasteImage.path": "${currentFileNameWithoutExt}_Images/", "up ...

  4. 项目升级到Android31版本dlopen找不到系统so库文件

    简介 最近有个海外项目需要把之前项目从30版本升级到31版本,升级后发现就发现一个问题: 因为我们的项目是系统签名的apk,所以集成到系统中后是没有任何问题的,但是当我们手动安装后就会出现使用dlop ...

  5. js原型详解

    js中的原型毫无疑问一个难点,学习如果不深入很容易就晕了! 任何一个js知识点,比如事件流,闭包,继承等,都有许许多多的说法,对于这些知识点我们都应该先熟练的使用,然后自己整理一套属于自己的理解说辞, ...

  6. JSON格式化 动态生成表格 表格转置 行列转换 Excel导出 行求和 列求和

    不需要行求和.列求和的查看 JSON格式化 动态生成表格 表格转置 行列转换 Excel导出 接上篇,新增行求和.列求和 完整代码如下: <!DOCTYPE html PUBLIC " ...

  7. Windows系统使用ODBC驱动访问KingaseES数据库及常见问题解决

    Windows系统使用KingbaseES ODBC驱动访问KingaseES数据库及常见问题解决. 一.获取KingbaseES数据库ODBC驱动: 在官网下载KingbaseES数据库安装包,选择 ...

  8. KingabseES kingbase_fdw 跨库关联查询

    背景 我们在做综合应用项目的时候,通常会面临客户的每个应用系统使用各自的数据库,或者存放在不同的服务器.查询报表可能使用多个应用数据,这样就需要跨库读取数据表或视图. KINGBASE_FDW 是一种 ...

  9. CSS样式中的各种居中方式

    1.水平居中 将margin-left和margin-right属性设置为auto,从而达到水平居中的效果. 代码: margin:0 auto; 2.文字水平垂直居中 利用line-height设为 ...

  10. #高精度,排列组合、dp#JZOJ 2755 树的计数

    题目 求\(n\)个点直径为\(d\)的标号树个数(多组数据) (\(0\leq d\leq n\leq 50,n>0\)) 分析 首先特判一下\(n==d\)无解,\(d=0\)除非只有一个点 ...