国内唯一 阿里云荣膺MongoDB“2024年度DBaaS认证合作伙伴奖”

本文涉及的产品
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,通用型 2核4GB
简介: 阿里云连续第五年斩获MongoDB合作伙伴奖项,也是唯一获此殊荣的中国云厂商。一起学习MongoDB副本集的选举机制以及可能会出现的特殊情况。

近日,在MongoDB用户大会纽约站上,阿里云荣膺MongoDB“2024年度DBaaS认证合作伙伴奖”。这是阿里云连续第五年斩获 MongoDB 合作伙伴奖项,也是唯一获此殊荣的中国云厂商。


MongoDB是当今全球最受开发者欢迎的非关系型数据库。凭借灵活的模式和丰富的文档结构,MongoDB帮助企业客户及百万开发者们使用丰富的数据结构快速开发应用,多快好省地构建现代应用程序。


阿里云是国内唯一首发MongoDB新版本的云服务厂商。基于阿里云的云原生环境,客户可以更好体验到MongoDB数据库的崭新能力和性能,进而实现业务的快速迭代、开发,降低开销、增加效率。

拟封面.png

自2019年阿里云与MongoDB达成战略合作伙伴关系以来,阿里云数据库MongoDB版已广泛应用于互联网、游戏、汽车出行、零售、金融等行业,累计为数万家客户提供MongoDB云数据库服务,MongoDB也取得了国内营收增长8倍的里程碑式成绩,目前阿里云已经成为MongoDB在中国最大的云服务提供商。


MongoDB全球合作伙伴高级副总裁Alan Chhabra表示,阿里云始终如一地提供优秀的云服务,集成新的 MongoDB产品功能,为中国各行各业提供强大、可扩展且安全的数据库解决方案。通过提供新的 MongoDB云服务,阿里云致力于本地化产品和服务以满足中国市场的新需求,进一步印证了阿里云领先的 DBaaS 提供商的地位。


阿里云数据库负责人李飞飞也表示,与MongoDB合作的四年是非常甜蜜的四年,阿里云不仅仅是单纯的OEM MongoDB数据内核,更多是把MongoDB能力和阿里云云原生的环境紧密结合起来。通过使用具有阿里云特色的MongoDB数据库,客户们能够实现业务的快速迭代、开发、降低开销、增加效率。


2023年,阿里云与MongoDB续签了战略合作协议,双方致力于将MongoDB的最新产品成果与阿里云企业级服务相结合,深耕国内市场,携手技术创新,打造最佳实践。


在今年的用户大会,MongoDB上也宣布推出一项新的云合作伙伴认证计划,该计划名为“Certified by MongoDB DBaaS”(数据库即服务),旨在为云基础设施合作伙伴提供最新MongoDB产品特性的访问权限,并允许他们向自己的客户提供一流的托管数据库服务,包括全文搜索、向量搜索和行业领先的数据加密等功能。阿里云NoSQL数据库产品线负责人张为表示,在当今AI应用飞速发展的时代,MongoDB与仅存储向量数据的附加解决方案不同,其向量搜索能力通过与原有的高性能和可扩展的主数据库紧密集成,客户能够安全地在整个数据库中充分利用生成式 AI 和专有数据,以更少的代码开发和运营开销来更快地实现业务价值。


不远的将来,阿里云作为MongoDB 重要的云合作伙伴之一,也将能够在阿里云MongoDB托管服务中提供向量搜索和全文搜索能力,客户将可以第一时间在阿里云MongoDB使用该能力来构建高级搜索和生成式AI应用程序。

image.png

MongoDB总裁兼首席执行官Dev Ittycheria 及 MongoDB全球合作伙伴高级副总裁Alan Chhabra 共同向 阿里云NoSQL数据库产品线负责人张为 授予“MongoDB 2024年度DBaaS认证合作伙伴”奖项


学习拓展:

MongoDB副本集选举分析


1. 背景

1.1 副本集架构

图1是官方普通三节点副本集的结构图,由一个Primary节点和两个Secondary节点组成,各节点通过Hearbeat判断其他节点是否存活。

image.png

图1 MongoDB副本集架构

图2是云MongoDB的三节点副本集架构,由一个Primary节点、一个Secondary节点和一个Hidden节点组成。Hidden节点是特殊的Secondary节点,它对客户端不可见,通过设置内核priority=0保证不参与选举,提供高可用和备份服务。

image.png 图2 云MongoDB副本集架构

1.2 名词说明

探活机制

MongoDB副本集的探活是通过Heartbeats实现。心跳检测的周期是默认2s,超过10s没有返回后会标记该节点为不可达。

优先级 priority

表示节点成为primary的相对可能性,在相同条件下更倾向于选举优先级最高的节点成为primary(优先级等于0的节点不会被选举为Primary)

投票 vote

选举投票权,副本集内最多允许7个节点有投票权(优先级大于0的节点投票不能为0)

2. 选举阶段解析

在选举过程中,副本集的Primary不支持读写,Secondary支持读

图3是最常见的选举场景,副本集中Primary节点下线,触发选举。其中一个Secondary节点要求进行选举来保证副本集可用,在获得足够多的投票(超过1/2的总投票)后选举成为新的Primary。

image.png

图3

2.1 触发选举

a. 触发选举的原因
  • 副本集无主超时:无主时间超过electionTimeoutMillis,图3
  • 设置非Primary节点为更高的优先级:Secondary优先级提高,优先选举Secondary为Primary
  • 选举的Primary在追赶阶段发生takeover:后面会解释追赶阶段
  • 单节点选举:单节点结构下选举自己为Primary
b. 候选者需满足的条件
  • 该节点是Secondary或Primary
  • 有最新的oplog
  • 可以"看到"大多数的节点(超过1/2)
  • 不是新加入的节点且不是arbiter
  • 该节点优先级大于0
  • 近期没有执行stepDown命令

2.2 预选举

候选者会进行预选举,判断自身是否可以发起真正选举。

a. 节点投赞成票的条件
  • 该节点不处于以下状态
  • DOWN
  • STARTUP
  • 该节点具有投票能力 — votes > 0
  • 该节点的任期不大于候选者的任期
  • 该节点与候选者版本相同
  • 该节点与候选者副本集名相同
  • 该节点的oplog不比候选者新
  • 当前Primary不健康或优先级低于候选者
b. 预选举失败的原因
  • 投票不足
  • 任期过期
  • Primary投反对票

预选举可以避免进入无意义的选举阶段。若当前节点不可能被选举成功,则预选举就会失败,且不会增加任期term,反正预选举成功term加一,进入新的任期。

下面是没有预选举环节的选举示例: image.png

图4 直接选举


如图4所示,一个互通的3节点集群发生网络隔离,S2与S1和S3不互通。

1) S2节点每次选举超时的时候都会发起一次选举并自增term;由于不能连接到S1和S3,无法获得大多数赞同,选举会失败。如此反复,term会增加到一个相对比较大的值;

2)由于S1和S3满足大多数条件,选举S1成为集群新的主节点,term变为2;

3)当网络连接恢复,S2又可以重新连接到S1和S3之后,其term会通过心跳传递给S1和S3,而这会导致S1 step down成为从节点;

4)选举超时时间过后,集群会重新触发一次选举,无论是S1还是S3成为新的主(S2由于落后所以不可能),其term值会变成11;

上述场景中有term跳变最后一次无意义选举两个问题预选举可以有效解决在尝试自增term并发起选举之前,S2会看看自己有没有可能获得来自S1和S3的选票。如若不满足条件则不会发起真正的选举。

2.3 选举

预选举成功后会进入真正的选举阶段,此时会先自增term。节点会优先投自己一票,然后接收本次选举过程中其他节点的投票。收到超过1/2的赞成票认为预选举成功,进入状态变更阶段。

此时愿意投赞成票的节点限制与预选举大致相同,只多了一条限制:该节点当前任期没有给其他节点投票

2.4 状态变更


处理选举的结果

a.选举成功

  • 更新节点状态,选举成功的节点从SECNONDAY变成PRIMARY状态
  • 通知副本集内所有的secondary节点选举胜利
  • Primary节点进入追赶阶段

b.选举失败

无操作

2.5 追赶

虽然在选举过程中要求候选者的oplog时间比投赞成票节点新,但是选举成功的Primary节点还是会检查是否有其他节点有更新的oplog。

如图4的情况,假如S2有更新的oplog,但是由于网络分区等原因没有参与选举,在选举结束后网络正常,此时Primary节点发现S2有更新的oplog,会去拉取S2的oplog。

追赶阶段有设置超时时间,所以部分情况无法获得其他节点全部的oplog,此时其他节点会进入ROLLBACK状态回滚操作。

2.6 日志示例

a. 副本集配置

Primary:priority=2, votes=1

Secondary:priority=1,votes=1

Hidden:priority=0,votes=1

b. 场景

副本集因为Primary节点不可用,触发选举

# 触发选举
REPL_HB  Heartbeat to xx.xx.xx.xx:xx failed after 2 retries, response status: HostUnreachable: Error connecting to xx.xx.xx.xx:xx :: caused by :: Connection refused
REPL     Starting an election, since we've seen no PRIMARY in the past 10000ms
# 预选举
REPL     conducting a dry run election to see if we could be elected. current term: 3
REPL     VoteRequester(term 3 dry run) failed to receive response from xx.xx.xx.xx:xx: HostUnreachable: Error connecting to xx.xx.xx.xx:xx :: caused by :: Connection refused
REPL     VoteRequester(term 3 dry run) received a yes vote from xx.xx.xx.xx:xx; response message: { term: 3, voteGranted: true, reason: "", ok: 1.0, operationTime: Timestamp(1706176453, 1), $clusterTime: { clusterTime: Timestamp(1706176453, 1)
REPL     VoteRequester(term 4) failed to receive response from xx.xx.xx.xx:xx: HostUnreachable: Error connecting to xx.xx.xx.xx:xx :: causedby :: Connection refused
REPL     dry election run succeeded, running for election in term 4
# 选举
REPL     VoteRequester(term 4) received a yes vote from xx.xx.xx.xx:xx; response message: { term: 4, voteGranted: true, reason: "", ok: 1.0, operationTime: Timestamp(1706176453, 1), 
REPL     election succeeded, assuming primary role in term 4
# 状态变更
REPL     transition to PRIMARY from SECONDARY
REPL     Resetting sync source to empty, which was :xx
# 追赶阶段
REPL     Entering primary catch-up mode.
REPL     Caught up to the latest optime known via heartbeats after becoming primary. Target optime: { ts: Timestamp(1706176453, 1), t: 3 }. My Last Applied: { ts: Timestamp(1706176453, 1), t: 3 }
REPL     Exited primary catch-up mode.
REPL     Stopping replication producer
# 允许写入
REPL     transition to primary complete; database writes are now permitted

1.触发选举

在Heartbeat多次探活失败后,副本集内部确认无主,触发选举

2.预选举

由于当前副本集内只有Secondary priority > 0,所以只有其发起了预选举。在预选举中收到一个赞成票,由于自动投票给自己,所以满足大多数,预选举成功,term加1。

3.选举和状态变更

同上,获得大多数赞成票,选举成功,假定term 4期间为Primary,将节点状态设置为PRIMARY

4.追赶阶段

进入追赶阶段,根据heartbeats获得最新的oplog时间,确认与当前的oplog时间相同,结束追赶阶段。选举成功,允许写入。

3. 代码解析

3.1 触发选举

_startElectSelfIfEligibleV1(reason)

根据传递的选举原因判断该节点是否可以为候选者 (becomeCandidateIfElectable)

switch (reason) {
    case StartElectionReasonEnum::kElectionTimeout:
        # 无主,副本集内探活10s内无primary
        LOG_FOR_ELECTION(0) << 
          "Starting an election, since we've seen no PRIMARY in the past "
                            << _rsConfig.getElectionTimeoutPeriod();
        break;
    case StartElectionReasonEnum::kPriorityTakeover:
        # 优先级抢占,有节点设置更高优先级
        LOG_FOR_ELECTION(0) << 
          "Starting an election for a priority takeover";
        break;
    case StartElectionReasonEnum::kStepUpRequest:
    case StartElectionReasonEnum::kStepUpRequestSkipDryRun:
        # 主动提升为primary
        # 跳过预选举
        LOG_FOR_ELECTION(0) << 
          "Starting an election due to step up request";
        break;
    case StartElectionReasonEnum::kCatchupTakeover:
        # 追赶抢占,primary处于catchup阶段时发生了takeover
        LOG_FOR_ELECTION(0) << 
          "Starting an election for a catchup takeover";
        break;
    case StartElectionReasonEnum::kSingleNodePromptElection:
        # 单节点选举
        LOG_FOR_ELECTION(0) << 
          "Starting an election due to single node replica set prompt election";
        break;
    default:
        MONGO_UNREACHABLE;
}

_startElectSelfV1_inlock(reason)
_startElectSelfV1_inlock

处理中间过程,对于kStepUpRequestSkipDryRun跳过预选举直接进入选举步骤,否则进入预选举阶段。


预选举与跳过预选举

// 获取当前term
long long term = _topCoord->getTerm();
int primaryIndex = -1;
// 跳过预选举
if (reason == TopologyCoordinator::StartElectionReason::kStepUpRequestSkipDryRun) {
    // term自增
    long long newTerm = term + 1;
    log() << "skipping dry run and running for election in term " << newTerm;
    // 真正选举
    _startRealElection_inlock(newTerm, reason);
    lossGuard.dismiss();
    return;
}

// 选举准备
_voteRequester.reset(new VoteRequester);

// Only set primaryIndex if the primary's vote is required during the dry run.
if (reason == TopologyCoordinator::StartElectionReason::kCatchupTakeover) {
    primaryIndex = _topCoord->getCurrentPrimaryIndex();
}
// 预选举
_processDryRunResult(term, reason);
lossGuard.dismiss();


3.2 预选举

_processDryRunResult

预选举失败原因

  • kInsufficientVotes:获得的投票不足
  • kStaleTerm:自身term过期
  • kPrimaryRespondedNo:primary拒绝投票
  • kSuccessfullyElected:未知问题

预选举成功则增加term,调用_startRealElection_inlock开始选举

预选举失败及成功

const VoteRequester::Result endResult = _voteRequester->getResult();
// 预选举失败
if (endResult == VoteRequester::Result::kInsufficientVotes) {
    log() << "not running for primary, we received insufficient votes";
    return;
} else if (endResult == VoteRequester::Result::kStaleTerm) {
    log() << "not running for primary, we have been superseded already";
    return;
} else if (endResult == VoteRequester::Result::kPrimaryRespondedNo) {
    log() << "not running for primary, the current primary responded no in the dry run";
    return;
} else if (endResult != VoteRequester::Result::kSuccessfullyElected) {
    log() << "not running for primary, we received an unexpected problem";
    return;
}

// 预选举成功
long long newTerm = originalTerm + 1;
log() << "dry election run succeeded, running for election in term " << newTerm;
// 选举
_startRealElection_inlock(newTerm, reason);


3.3 选举

_startRealElection_inlock

选举

// 给自己投票
_topCoord->voteForMyselfV1()
..
  // 保存副本集投票情况
  _writeLastVoteForMyElection()
....
    // 向其他节点发送投票请求
    _startVoteRequester_inlock()
......
      // 收到投票结果并处理
      _onVoteRequestComplete()
........
        // 副本集状态机更改
        _postWonElectionUpdateMemberState_inlock()

状态机更改

// 修改role等配置
_topCoord->processWinElection(_electionId, ts);
const PostMemberStateUpdateAction nextAction =
    _updateMemberStateFromTopologyCoordinator_inlock(nullptr);
// 设置同步端为空
_onFollowerModeStateChange();
// 通知其他节点选举成功
_restartHeartbeats_inlock();
// 进入追赶阶段
_catchupState->start_inlock();

3.4 追赶阶段

// 通过心跳获得最新oplog来追赶
_handleHeartbeatResponse()
// 判断自身和最新oplog的时间
CatchupState::signalHeartbeatUpdate_inlock()
// 结束追赶阶段
CatchupState::abort_inlock()

4. 案例分析

a.背景

实例写入量过大,primary cpu被打满并开始出现主备延迟(secondary有延迟,hidden无延迟),客户主动下发主备切换希望降低流量,但是切换长时间不成功,引起客户担忧,最终在客户停止写入业务一分钟后,主备切换成功。

b.分析

实例状态更改前后如下表。


HA前状态

HA后状态

Primary

A

B

Secondary

B

A

Hidden

C

C

客户下发正常主备切换后,B的优先级提高至2,A的优先级降低为1,B优先级提升,但是由于和其他节点延迟过高,导致无法成为候选者,没有触发预选举。

ELECTION  Not starting an election for a priority takeover, since we are not electable due to: Not standing for election because member is not caught up enough to the most up-to-date member to call for priority takeover - must be within 2 seconds (mask 0x80)

客户停止写入业务后,切换快速成功,预期需要等待B同步结束后才会完成选举,但是B延迟7个小时,担心数据有丢失,因此需要确定当时选举成功的原因。

查看A日志中无Rollback,确认没有数据回滚操作。

查看B日志,第一条日志显示业务写入中追oplog,但是存在很大延时,符合监控数据。

第二条日志显示Secondary 最新的oplog已经和Primary时间相同,此时可以成为候选者,后续也正常选举成功。

REPL Scheduled new oplog query Fetcher source: A database: local query: { find: "oplog.rs", filter: { ts: { $gte: Timestamp(xxx1) } }, tailable: true, oplogReplay: true, awaitData: true, term: xx}
REPL Choosing new sync source. Our current sync source is not primary and does not have a sync source, so we require that it is ahead of us. Current sync source: A, my last fetched oplog optime: { ts: Timestamp(xxx2), t: xx }, latest oplog optime of sync source: { ts: Timestamp(xxx2), t: xx } (sync source does not know the primary)


相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
12天前
|
关系型数据库 分布式数据库 数据库
阿里云618创新加速季数据库分会场全攻略
2024年阿里云618创新加速季活动已开启,数据库分会场推出多重优惠。RDS MySQL低至1折,部分产品享超值首购优惠,三个月仅需1折,续费也有折扣。此外,每天10点还有限时秒杀活动,云产品低至6.5折。新用户在新人专区购买指定规格可享首年折扣,还有数据库上云组合购优惠和开发者动手实践奖励。企业用户可申请5亿算力补贴,加速数字化转型。更多活动详情和优惠信息,可访问官方活动页面了解。
|
16天前
|
存储 关系型数据库 MySQL
最新2024年阿里云618优惠活动「创新加速季」5亿上云补贴你领了吗?
阿里云2024年618「创新加速季」推出5亿补贴活动,新用户可享云产品大幅优惠。包括云服务器E实例(2核2G,3M带宽,40G ESSD)99元/年,RDS MySQL(2核2G)99元/年,OSS存储包(500GB)118.99元/年,以及无影云电脑(4核8G)98.99元/1年。
410 0
|
19天前
|
人工智能 Cloud Native 安全
民生银行与阿里云成立联合创新实验室
民生银行与阿里云成立联合创新实验室
27 0
|
22天前
|
NoSQL 安全 MongoDB
MongoDB为提供MongoDB数据库服务的云服务合作伙伴推出认证计划
Certified by MongoDB DBaaS计划还将为云计算合作伙伴提供构建深度技术集成所需的专业支持,同时还将携手MongoDB合作伙伴生态系统(MongoDB Partner Ecosystem)共同推出一系列联合的进入市场举措,使云服务合作伙伴能够助力其客户快速走向成功。
3104 0
|
22天前
|
人工智能 NoSQL MongoDB
国内唯一!阿里云荣膺MongoDB “2024年度DBaaS认证合作伙伴奖”
这是阿里云连续第五年斩获 MongoDB 合作伙伴奖项,也是唯一获此殊荣的中国云厂商。
3078 0
|
26天前
|
人工智能 NoSQL 安全
国内唯一!阿里云连续第五年斩获MongoDB合作伙伴奖
国内唯一!阿里云连续第五年斩获MongoDB合作伙伴奖
72 1
|
1月前
|
Cloud Native 关系型数据库 分布式数据库
数据库性能诊断工具DBdoctor通过阿里云PolarDB产品生态集成认证
DBdoctor(V3.1.0)成功通过阿里云PolarDB分布式版(V2.3)集成认证,展现优秀兼容性和稳定性。此工具是聚好看科技的内核级数据库性能诊断产品,运用eBPF技术诊断SQL执行,提供智能巡检、根因分析和优化建议。最新版V3.1.1增加了对PolarDB-X和OceanBase的支持,以及基于cost的索引诊断功能。PolarDB-X是阿里巴巴的高性能云原生分布式数据库,兼容MySQL生态。用户可通过提供的下载地址、在线试用链接和部署指南体验DBdoctor。
202 0
|
21天前
|
存储 固态存储 安全
阿里云4核CPU云服务器价格参考,最新收费标准和活动价格
阿里云4核CPU云服务器多少钱?阿里云服务器核数是指虚拟出来的CPU处理器的核心数量,准确来讲应该是vCPU。CPU核心数的大小代表了云服务器的运算能力,CPU越高,云服务器的性能越好。阿里云服务器1核CPU就是一个超线程,2核CPU2个超线程,4核CPU4个超线程,这样云服务器可以同时处理多个任务,计算性能更强。如果网站流程较小,少量图片展示的企业网站,建议选择2核及以上CPU;如果网站流量较大,动态页面比较多,有视频等,建议选择4核、8核以上CPU。
阿里云4核CPU云服务器价格参考,最新收费标准和活动价格
|
2天前
|
弹性计算 缓存 安全
云服务器 ECS产品使用问题之如何解决阿里云幻兽帕鲁服务器游戏版本不兼容
云服务器ECS(Elastic Compute Service)是各大云服务商阿里云提供的一种基础云计算服务,它允许用户租用云端计算资源来部署和运行各种应用程序。以下是一个关于如何使用ECS产品的综合指南。
|
2天前
|
弹性计算 Linux 云计算
云服务器 ECS产品使用问题之如何解决阿里云幻兽帕鲁服务器转移后无法进入的问题
云服务器ECS(Elastic Compute Service)是各大云服务商阿里云提供的一种基础云计算服务,它允许用户租用云端计算资源来部署和运行各种应用程序。以下是一个关于如何使用ECS产品的综合指南。

相关产品

  • 云数据库 MongoDB 版