• Mongodb CPU占用率达90%的优化调整报告


    1问题描述

    1.1现场的数据库部署情况

        服务器基本情况如下:

    CPU

    20逻辑核,40线程

    内存

    64 G

    硬盘

    D盘 :1T SSD

    E盘:3T SATA

    F盘:3T SATA

    在这台机器上同时部署有postgresql和mongodb数据库。其中postgresql数据库存储入库后的矢量数据,mongodb存储矢量瓦片数据。

    生成矢量切片的大致流程为:

    1. 查询mongodb数据库,检查哪些切片还未生成;
    2. 查询postgresql数据库,根据切片范围进行空间查询;
    3. 对第2)步查询结果进行切片处理,并将切片写入mongodb

    1.2异常情况说明

        刚开始作业时,效率尚可。然而当作业持续进行一段时间后,效率变得很低,甚至完全hang住不动了。同事分析,认为可能是postgresql空间查询效率过低导致。

    2问题诊断

        由于机器上部署有两个不同的数据库,并且,切片全流程会涉及到两个数据库。因此需要首先定位,到底慢在哪个数据库上?又或者,甚至还可能是操作系统级别的某种问题?

        先通过性能监视器查看系统性能。一看就发现了问题,在切片程序hang住不动的时候,mongodb服务进程占用CPU的比率达到了90%以上,以至于服务器CPU负载长时间处于92%-99%。

        首先定位到了是mongodb拖慢了速度,那么接下来,需要分析到底是mongodb中的什么操作拖慢了速度。

        通过设置profile=1,slowms=100 ,并开启httpinterface option,然后在http://localhost:28017上监控mongodb中的log,发现了这样的一些日志信息:

        -----------------------------------------------------------------------------------------------------------

    ……(省略若干行)

    Command vindex.矢量瓦片测试_道路_线 command {count : "矢量瓦片测试_道路_线"} ,query :{fx:808 ,fy:189 ,flevel:10} } planSummary COLLSCAN keysExamined 0 docsExamined:2627694 numYields:20529 reslen:44 locks :{acquireCount :{r:41060}} ,MMAPV1Journal :{acquireCount :{r:20569}},Database :{acquireCount :{r:20530}},Collection:{acquireCount :{R:20530},acquireWaitCount : {R:39},timeAcquiringMicros:{R:}

    ……(省略若干行)

    2017-01-17T17:32:11.816+0800 I COMMAND [conn187] vindex.矢量瓦片测试_道路_线 query: {$query: { flevel:3}, $orderby : {$natural:1}} planSummary : COLLSCAN ntoreturn : 500000 ntoskip:500000 keysExamined :0 docsExamined:3288241 cursorExhausted :1 numYields:25694 nreturned:0 reslen:20 locks:{ Global: {acquireCount :{r:51390}} ,MMAPV1Journal:{acquireCount: {r:25695}},Database:{ acquireCount:{r:25695}},Collection:{acquireCount:{R:25695}}} 8121ms

    ……(省略若干行)

    -----------------------------------------------------------------------------------------------------------

    先看第一条日志记录。一个简单的count查询,执行计划显示进行了COLLSCAN,即扫描集合。该次扫描扫描了2627694个文档,然而返回的数据集只有44KB,另外,执行这样一次查询,获得锁的次数为41060,其中为了获得锁等待了39次。

    再看第二条日志记录。这是一个query操作,查询结果进行了基于$natural(即基于数据在磁盘中的存储顺序)的排序。执行计划显示进行了COLLSCAN,即扫描集合。该查询使用了limit(500000).skip(500000)条件,为了获得500000个文档记录,共扫描了3288241个文档,可是nreturned返回结果为0,说明查询了这么多,却没有符合条件的文档。另外,执行这样一次查询,获得锁的次数为51390。

    分析到这里,问题已经很明显了。之所以发生这么多无效的扫描,原因在于集合中没有创建合适的索引,导致每次查询都要对集合进行扫描,而该集合目前已经达到了550GB的体量。

    3调整方式

    1. 创建索引。

    通过vindex.矢量瓦片测试_道路_线.ensureIndex({flevel:1,fx:1,fy:1}{unique:true})

    方法创建基于flevel,fx,fy三列的唯一值索引;

    1. 修改query查询语句

    第二条SQL中使用于基于$natural的排序,一般情况下使用$natural排序,是要告诉mongodb,本次查询不要使用索引。这样就意味着将从磁盘的顺序返回数据,强制mongodb不使用索引。它适用如这样一种场景:如果你创建了索引,但是要求返回大量的数据,通过索引来查询是很低效的,这时候你可以通过再sort中指定{"$natural":1}来强制不使用索引。而在本例中,flevel=3(还有flevel=4,flevel=5等)是从大量数据中返回极少量的数据,因此,使用$natural排序是不合适的。可将sort方式改为基于_id排序。

    4调整后效果

        在使用上述调整方式调整之后,服务器CPU使用率稳定在10%左右,切片进程不再出现hang住的情况。广东省整省数据,用1个小时就全部切片完毕。

    5其它说明

        尽管当前效率尚可,但通过mongostat进程监控mongodb服务器进程的性能发现,qw(队列中等待写的客户端进程数)达到30-50,说明在往mongodb中写的过程仍然存在很大的优化空间。改善写的性能,可以通过分片的技术手段解决。不过目前未在现场实施改造。其原因有二:

    1. 目前的切片效率满足要求,不需要另行改造
    2. 目前没有其它的服务器来部署分片架构
    3. 虽然当前服务器有3块可用磁盘(1.1现场的数据库部署情况),但通过HDTunePro的测试,发现两块SATA盘的iops仅为60-70左右,不适合用做数据库文件存储。因此,预计,即便在多块磁盘上实现了分片,也不会改善性能,甚至会降低性能。
  • 相关阅读:
    关于AJAX与form表单提交数据的格式
    MongoDB
    Redis
    在django中使用django_debug_toolbar进行日志记录
    python第三方库,你要的这里都有
    Django之用户认证auth模块
    Django中常用命令
    form表单钩子,局部钩子和全局钩子
    当我开始爱自己
    FOR YOU
  • 原文地址:https://www.cnblogs.com/6yuhang/p/6295934.html
Copyright © 2020-2023  润新知