基于corosync的分布式应用程序开发方案分析


难度 中等

0 结论

综上所述,并结合实际使用场景中遇到的各种问题,可得出如下结论:

1. corosync保证的数据一致性对application没用
2. corosync的机器独占性导致corosync无法共用仲裁,不适用于多套集群
3. corosync-qnetd的共用仲裁解决方案会引入qnetd的单点故障问题,需考虑qnetd的高可用性
4. corosync采用udp广播通信,会损耗一些网络带宽,不适用与节点数较多的集群

1. 概述

当基于corosync进行应用层开发时,一般使用cpg分组来进行数据收发,这种情况下我们的程序会有两个进程:

  • corosync进程
  • 基于cpg的应用进程

我们将corosync进程称作process进程,基于cpg的应用进程称为application进程。数据先通过网络在process进程中传输,保证各个process进程都能收到数据,各process进程收到数据后再通过本地ipc通信将数据传递到应用层。

2. 数据收发及数据一致性

2.1 现状

数据收发分为两个步骤:

  1. 数据先传输到process进程,通过totem协议(令牌环协议)保证每个存活的节点都收到数据(保证顺序,数据按顺序到达);
  2. 当所有的process进程都确认数据收到后,process通过本地ipc通信将数据传输到application,由application进行写入;

由上可知,corosync只保证process进程的数据一致性,无法保证application进程的数据一致性。因为process无法保证application数据一定处理成功,application进程处理失败或某条数据未处理时process进程不会将该条数据重传到application进程。

process进程不保证application数据写入成功, 当某个application进程在接收数据挂死后将导致数据丢失。因而在使用corosync进行数据收发时,需要由application再次对数据进行确认,同时application同样需要对数据进行重传,以保证接收失败的application进程能收到完整数据。

2.2 解决方案

appliction实现数据确认机制:

  1. application需要维持一套集群状态,包括quorum(多数派),master(领导节点,读取写入权限);
  2. application进程只有master具有读取和写入权限,非master节点收到数据请求时需要先转发到master,由master进行数据操作;
  3. master节点写入时,需要其他节点写入进行确认,只有超过半数节点写入成功后才认为本次写入成功;

第三点未实现可能会导致极端情况下造成数据丢失:

如三节点集群,节点1和节点2在处理旧数据时卡住,节点3为master且收到新数据写入请求,此时节点3会直接将数据写入。若此时节点3在写入数据后挂死,节点1和节点2重新选出master继续服务,此时就导致了数据丢失。

2.3 由此带来的问题

application实现数据确认机制,相当于在应用层又实现了一套分布式数据确认机制。相当于我们完全没有用到corosync的数据一致性功能,因为corosync无法保证application数据的一致性,corosync在数据层面仅仅实现了网络通信功能。我们将corosync换成通用的网络通信接口同样能实现类似的功能。

3. 投票机制

corosync与机器强绑定,一台机器只能运行一个corosync节点,且一个corosync节点只能属于一个集群,不能被多个集群共用。

当部署多套集群时,为了得到更高的可用性,往往会设置一些仲裁节点,这些仲裁节点仅具有投票功能。我们可以采用在集群中增重corosync节点来作为仲裁,但每增加一个仲裁corosync节点就需要多部署一台机器,多个集群需部署更多的仲裁机器,无法共用,相当于浪费了机器资源。

3.1 解决方案

corosync官方提供的corosync-qdevice和corosync-qnetd的公共仲裁解决方案,允许部署一个qnetd服务器进程,为多套集群提供仲裁服务。

qnetd支持两种算法:

  • 五五开算法(一般适用于偶数节点集群)

    主要是在集群出现两个网络分区,且分区节点数一致时,辅助决定哪个分区胜出。

  • LMS算法

    主要是实现集群只剩下一个节点时也能提供服务,此时qnetd占用更高的投票权重。

3.2 由此带来的问题

corosync官方提供的corosync-qdevice和corosync-qnetd的公共仲裁解决方案,但在集群节点上会多出一个corosync-qdevice进程,同时qnetd占据更高的投票权重,存在qnetd单点故障问题。

corosync-qdevicecorosync-qnetd组合的公共仲裁解决方案,需要在corosync运行的节点上再运行corosync-qdev,同时需要一台额外的机器来部署qnetd,此时虽然会增加集群的管理复杂度,但多个集群可以共有qnetd,可以节约机器资源。

qnetd作为公共仲裁时,若要支持5节点集群,还剩下2个几点也能正常工作,此时需要选用LMS算法,但使用此算法时,qnetd会占用更高的投票权重。此时若qnetd出现故障时,5节点集群一个都不能挂死才能正常服务,qnetd存在单点故障问题。此时又会引入qnetd的高可用性问题,比如qnetd的主备冗余模式。

4. 性能

corosync的process进程采用udp广播通信,即一条信息发出,正常情况下所有的节点都会接收到,而不管节点是否需要该消息。我们基于cpg分组的application通过process进行数据收发,不管我们的消息发往哪个节点,都会往所有节点发送,且保证每个节点都收到为止。

对于客户端的查询请求来说,实际上我们最多只需要访问两个节点就可以获取到数据:

  1. 客户端发出查询请求,集群中一个节点收到请求,若该节点是master,直接响应数据,此时只需要访问一个节点;
  2. 客户端发出查询请求,集群中一个节点收到请求,若该节点不是master,将请求转发给master,master收到请求后再响应,本节点再转发给客户端,此时需要访问两个节点;

对于客户端的增删改请求来说,最终需要访问所有节点,但返回给客户端响应时,只要半数以上节点响应就可以返回给客户端,而不需要所有节点都确认。

因而,每次数据发送都需要所有节点收到会占用网络带宽,当网络状况极差时,客户端很容易响应超时。导致客户端访问数据延迟高。

4.1 解决方案

按照前面的分析,对客户端查询请求进行单独处理,设计单独的查询api。当收到客户端的查询请求后,不使用process的通信机制;而是重新增加各节点之间的socket通信(TCP),这样一次查询最多只会发起两次网络请求。对于现有的使用场景来说,绝大数时候使用的是查询接口,对性能和可用性会有较大提升。

至于增删改接口,若性能满足可暂时不做修改。

4.2 由此带来的问题

  • 需要增加一套集群间的通信机制,使各节点能够单点通信(一对一)
  • 当增加了集群间节点的通信机制后,似乎corosync没有太大的作用了(有了通信就可以加心跳,有了心跳就可以计算quorum)

  目录
分类导航
随笔2 AI27 算法1 计算机基础13 博客搭建7 ChatGPT2 集群63 计算机通信1 数据库34 数据库深入80 DPDK26 Docker11 Elasticsearch4 编辑工具4 FAQ1 Go Web1 hometown2 编程语言16 网络9 OPC1 Linux38 openGauss4 页面12 PostgreSQL54 程序员自我修养1 协议11 成长之路1 stock1 存储5 工具20 VPP18 视频作品1 Vue13 Web1 代码示例11 数据库15 BenchmarkSQL1 PostgreSQL 源码修炼之路14
最热文章
1
13 逻辑复制深入
数据库深入🔥 1570
2
0 Postgresql存储、索引及系统优化、主备切换
PostgreSQL🔥 1495
3
一文读懂openguass dcf网络模块
集群🔥 1420
4
逻辑复制源码分析
数据库深入🔥 1327
5
PostgreSQL 分区表:从一行 `PARTITION BY` 到路由热路径的全链路拆解
数据库🔥 1094
6
applyparallelworker.c 之 LA 端源码深度解析:Leader Apply Worker 的指挥中枢
数据库深入🔥 1082
7
PostgreSQL Background Worker 全解:从 `RegisterBackgroundWorker` 到逻辑复制 4 类 worker 的全生命周期
数据库🔥 1078
8
PostgreSQL的后台进程walsender分析 - 关系型数据库 - 亿速云
PostgreSQL🔥 1033
9
PostgreSQL 逻辑复制的监控:六张视图 + 一组可执行 SQL,把 publisher/subscriber 的速率与健康度彻底看透
数据库🔥 1032
10
PostgreSQL 逻辑复制支持 DDL 之后:DDL 与 DML 的时序难题(重点:分区表)
数据库🔥 999
11
reorderbuffer.c 源码深度解析:PostgreSQL 逻辑复制的"事务重组引擎
数据库深入🔥 953
12
PostgreSQL 内核开发:读取一张表的 9 步标准流程与缓存全景
数据库🔥 938
13
从 `postgres` 二进制到生产级守护 —— PostgreSQL 最外层模块与启动全流程拆解
数据库🔥 936
14
支持逻辑复制同步 DDL 适配 SQL Server 方案
数据库深入🔥 934
15
PostgreSQL 逻辑复制的 ReorderBuffer 与事务机制:从一行 WAL 到一致性变更流的全链路绑定
数据库🔥 913
16
DDL同步架构(美化版)
数据库深入🔥 908
17
PostgreSQL Latch 机制详解:从一行 SetLatch 到 epoll 的内核之旅
数据库🔥 871
18
pgbench 源码全解:一个 C 文件如何撑起 PostgreSQL 官方压测工具
数据库🔥 860
19
PostgreSQL libpq 机制与缓冲区详解
数据库🔥 850
20
PostgreSQL 逻辑复制 spill 文件深度剖析:从 `xid-*.spill` 到 TPC-C 的增长方程
数据库🔥 845