前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【腾讯云 MongoDB】 基于snapshot的从库读优化

【腾讯云 MongoDB】 基于snapshot的从库读优化

原创
作者头像
腾讯云数据库 TencentDB
修改2019-04-08 20:57:25
2.7K0
修改2019-04-08 20:57:25
举报

导语

我们发现腾讯云上一些腾讯云MongoDB实例在主库写压力比较大的情况下,这时从库上会出现很多慢查询,经过调查发现,从库在回放oplog的时候加了全局锁,阻塞了所有的读直到回放结束。经过我们的优化,使得从库的读延时降低几倍到几十倍不等,qps也有一个明显的提升。

背景知识

  • mongodb复制集原理 mongodb复制集是由一系列mongod实例组成的,包含一个primary和若干个secondary,数据通过primary写入, primary与secondary之间通过oplog来同步数据,primary上的写操作完成后,会向local.oplog.rs特殊集合写入一条oplog,secondary负责从复制源(一般为primary,但是mongo也支持链式复制,即secondary也可以作为复制源)拉取oplog,在secondary上回放,从而保持主从之间数据的一致性。 下图是一个典型的mongo复制集,包含1个primary和2个secondary:

当一个新节点加入复制集时,首先要执行initial-sync,如果执行成功,就开始不停的从复制源拉取oplog,然后在从上面回放。

       if (memberState.primary() && !replCoord->isWaitingForApplierToDrain()) {
            sleepsecs(1);
            continue;
        }
        bool initialSyncRequested = BackgroundSync::get()->getInitialSyncRequestedFlag();
        
  • WT snapshot mongodb从3.2开始默认的底层存储引擎改为WiredTiger(简称WT),snapshot是WT实现事务的基础,那WT中snapshot是什么呢?其实就是事务开始或者进行操作之前对整个 WT 引擎内部正在执行或者将要执行的事务进行一次快照,保存当时整个引擎所有事务的状态,确定哪些事务是对自己见的,哪些事务都自己是不可见。说白了就是一些列事务 ID 区间。搜索关注“腾讯云数据库”官方微信立得10元腾讯云无门槛代金券,体验移动端一键管理数据库,学习更多数据库技术实战教程。

WT的事务并发区间如下图所示:

如果在T6时刻创建了一个snapshot,那么只能读到(0,T1],以及[T1,T5]之间已经提交的事务的修改即T2,其他都是不可见的。

问题分析

从库在回放oplog的过程中会加Lock::ParallelBatchWriterMode(PBWM)锁,这个锁会阻塞所有的读,直到这一批oplog回放结束。对于有读从库需求的业务来说,会导致很多慢查询,甚至会影响业务正常服务。 代码主要在sync_tail.cpp的syncTail::oplogApplication()中:

OpTime SyncTail::multiApply(OperationContext* txn,
                            const OpQueue& ops,
                            boost::optional<BatchBoundaries> boundaries) {
    invariant(_applyFunc);
    if (getGlobalServiceContext()->getGlobalStorageEngine()->isMmapV1()) {
        

通过分析代码,可以得出从库加全局锁PBWM的目的:

  1. 避免脏读 这里的脏读可以分为两块,一是用户数据的脏读,这个很好理解。二是由于mongodb支持链式复制,如果从库作为复制源,其他的从库会来读源的oplog,所以要保证其他从库读取的oplog是完整的。对于mmap从库写入oplog是顺序写,而WT的话不一定要保证顺序,如果不加锁的话,其他从库读的话可能会漏掉部分oplog。

如上图所示,secondary插入oplog是乱序的,如果10这个点去读oplog,由于是B树遍历,会漏掉6,9两条记录。

  1. 资源争抢,影响同步性能 这点我们在测试的时候也遇到,当主库的写入压力很大时,从库的同步写入也很高,这时候如果从库上面又有大量的写入,会出现资源争抢的情况,影响同步的性能,造成主从同步的延时。搜索关注“腾讯云数据库”官方微信立得10元腾讯云无门槛代金券,体验移动端一键管理数据库,学习更多数据库技术实战教程。

我们的优化

基于WT的snapshot我们知道,一个snapshot可以理解为是对数据库某个点的状态。所以我们的优化就是去掉全局锁,所有的从库读都改为读snapshot,这样就可以解决上面说到的脏读和oplog丢失的情况,具体的做法如下:

  • 创建snapshot 对于支持snapshot的引擎,从库在每次applyOplog结束的时候我们会去创建一个snapshot,在创建的过程中要保证不会有新的写入,创建的snapshot由snapshotManager管理,如果已经存在snapshot的话就更新,然后删除旧的snapshot。 注:由于写入很多的时候,applyOplog会非常频繁,所以要控制snapshot的创建频率。
  • 修改所有外部读为snapshot读 所谓的外部读就是通过OP_QUERY和OP_GETMORE的方式来查询的请求,由于mongo协议的特殊性,OP_QUERY中根据ns又分为Command和Query两种,对于这些读请求入口,如果是从库读都需要改成读snapshot。
  • 修改内部读为snapshot读 如果设置了readConcern为readMajority的话,mongo会开启一个后台线程,对已经同步到大多数节点的oplog做一个snapshot,来实现readMajority。代码:
           SnapshotName name(0);  

从上面的代码可以看出,从库去读自己的oplog并不是通过命令的形式,而是调用内部的接口,所以为了保证从库在读取oplog时数据的一致性,也要改成从snapshot中读。

测试

WT cacheSize:10G 测试工具:ycsb 测试指标:从库读延时(这里的延时取的是ycsb 99.99%操作的平均延时)和qps

为了测试的准确性,要保证两次测试下面的条件相同:

  1. 主库的写压力相同,并且压力足够大,模拟线上主库写入压力大,这样从库回放的写入也很高。每次测试的写入数据为5千万条,数据量大于WT cacheSize。
  2. 由于mongo server端是多线程处理的请求,所以要限制cpu,保证从库cpu使用不能超过我们设定的值

但是在测试的过程中我们发现在限制cpu的情况下,snapshot版本的从库上面会出现资源争抢的情况,导致从库的写降读升,使得写入压力不同,导致测试结果不准。所以我们在后面的测试中不限制cpu,通过其他方法来分析从库qps的变化。搜索关注“腾讯云数据库”官方微信立得10元腾讯云无门槛代金券,体验移动端一键管理数据库,学习更多数据库技术实战教程。对测试结果进行统计分析之后得出下图:

通过测试发现,snapshot版本在在4种不同单条数据大小的情况下,从库读的延时都有明显的减小,延时的减小带来的是qps的提高。从延时数据可以看出,假设在cpu使用相同并且写入压力相同的情况下,qps也是有一个很大的提升,下图以4k大小的单条数据为例:

左边是snapshot版本读的qps数据,右边是原生版本的,对比发现snapshot版本的读qps也有明显的提升,而且还是在原生版本cpu使用高于snapshot版本的情况下。

小结

通过去掉从库的全局锁PBWM,使得从库在主库写入压力很大的情况下,从库的读性能有一个很大的提升,但是并不是所有的场景都适用,下面两点需要注意。

  • 前面说到的资源争抢的情况,在去掉全局锁PBWM之后,这个问题在读写压力都很大的情况下可能更加显著,这个需要看具体业务了,决定是否开启从库snapshot读。
  • 在小内存(WT默认最小内存1G)的情况下,如果创建了老的snapshot没有删除,并且写入非常大的情况下,WT的dirty占比会很高,这时候用户线程也会参与eviction,造成写入性能的骤降。这个问题在原生的mongo中如果设置了readMajority的话也会出现,后面的话会去深入WT内部去研究这个问题。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导语
  • 背景知识
  • 问题分析
  • 我们的优化
  • 测试
  • 小结
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档