为了账号安全,请及时绑定邮箱和手机立即绑定

Mongodb千万级数据在python下的综合压力测试及应用探讨

标签:
MongoDB


曾经在收集数据的项目中,用过mongodb的数据存储,但是当数据很大的时候,还是比较的吃力。很可能当时的应用水平不高,也可以是当时的服务器不是很强。 所以这次能力比以前高点了,然后服务器比以前也高端了很多,好嘞 ~再测试下。

(更多的是单机测试,没有用复制分片的测试 ~)!

相比较MySQL,MongoDB数据库更适合那些读作业较重的任务模型。MongoDB能充分利用机器的内存资源。如果机器的内存资源丰富的话,MongoDB的查询效率会快很多。

这次测试的服务器是dell 的 r510!

235621353.jpg

内存还行,是48G的,本来想让同事给加满,但是最终还是没有说出口 ~  

235739466.jpg磁盘是10个2T的,但是因为格式化的时间太久了,哥们直接把其他的硬盘给拔出来了,就用了三个盘。。。data目录没有做raid,是为了让他们体现更好的硬盘速度。

235930831.jpg

既然说好了是在python下的应用测试,那就需要安装mongodb python下的模块 !

对了,不知道mongodb-server的安装要不要说下?

cat /etc/yum.repos.d/10.repo

[10gen]

name=10gen Repository

baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64

gpgcheck=0

000408806.jpg

Pymongo的基本用法

from pymongo import * # 导包

con = Connection(...) # 链接

db = con.database # 链接数据库

db.authenticate('username', 'password') # 登录

db.drop_collection('users') #删除表

db.logout() # 退出

db.collection_names() # 查看所有表

db.users.count() # 查询数量

db.users.find_one({'name' : 'xiaoming'}) # 单个对象

db.users.find({'age' : 18}) # 所有对象

db.users.find({'id':64}, {'age':1,'_id':0}) # 返回一些字段 默认_id总是返回的 0不返回 1返回

db.users.find({}).sort({'age': 1}) # 排序

db.users.find({}).skip(2).limit(5) # 切片

测试的代码:

#!/usr/bin/env python

from pymongo import Connection

import time,datetime

import os,sys

connection = Connection('127.0.0.1', 27017)

db = connection['xiaorui']

def func_time(func):

    def _wrapper(*args,**kwargs):

        start = time.time()

        func(*args,**kwargs)

        print func.__name__,'run:',time.time()-start

    return _wrapper

@func_time

def ainsert(num):

    posts = db.userinfo

    for x in range(num):

        post = {"_id" : str(x),

        "author": str(x)+"Mike",

        "text": "My first blog post!",

        "tags": ["xiaorui", "xiaorui.cc", "rfyiamcool.51cto"],

        "date": datetime.datetime.utcnow()}

        posts.insert(post)

if __name__ == "__main__":

    num = sys.argv[1]

    ainsert(int(num))

咱们就先来个百万的数据做做测试~

综合点的数据:

002508131.jpg

在top下看到的程序占用资源的情况 ~ 我们看到的是有两个进程的很突出,对头 ! 正是mongodb的服务和我们正在跑的python脚本 !

002605855.jpg

看下服务的io的情况 ~

002741677.jpg

脚本运行完毕,总结下运行的时间 ~

002816300.jpg

查看mongodb的状态~

他的insert也不到5k ~ 插入量也就800k左右 ~

它的输出有以下几列:

inserts/s 每秒插入次数

query/s 每秒查询次数

update/s 每秒更新次数

delete/s 每秒删除次数

getmore/s 每秒执行getmore次数

command/s 每秒的命令数,比以上插入、查找、更新、删除的综合还多,还统计了别的命令

flushs/s 每秒执行fsync将数据写入硬盘的次数。

mapped/s 所有的被mmap的数据量,单位是MB,

vsize 虚拟内存使用量,单位MB

res 物理内存使用量,单位MB

faults/s 每秒访问失败数(只有Linux有),数据被交换出物理内存,放到swap。不要超过100,否则就是机器内存太小,造成频繁swap写入。此时要升级内存或者扩展

locked % 被锁的时间百分比,尽量控制在50%以下吧

idx miss % 索引不命中所占百分比。如果太高的话就要考虑索引是不是少了

q t|r|w 当Mongodb接收到太多的命令而数据库被锁住无法执行完成,它会将命令加入队列。这一栏显示了总共、读、写3个队列的长度,都为0的话表示mongo毫无压力。高并发时,一般队列值会升高。

conn 当前连接数

time 时间戳

瞅下面的监控数据 !

003310317.jpg

然后我们在测试下在一千万的数据下的消耗时间情况 ~

共用了2294秒,每秒插入 4359个数据 ~

010140526.jpg看看他的内存的使用情况:

虚拟内存在8gb左右,真实内存在2gb左右

010245223.jpg

再换成多线程的模式跑跑 ~  个人不太喜欢用多线程,这东西属于管你忙不忙,老大说了要公平,我就算抢到了,但是没事干,我也不让给你。。。属于那种蛮干的机制 ~

nima,要比单个跑的慢呀 ~  线程这东西咋会这么不靠谱呀 ~

应该是没有做线程池pool,拉取队列。导致线程过多导致的。不然不可能比单进程都要慢~

还有就是像这些涉及到IO的东西,交给协程的事件框架更加合理点 !!!

def goodinsert(a):

    posts.insert(a)

def ainsert(num):

    for x in range(num):

        post = {"_id" : str(x),

        "author": str(x)+"Mike",

        "text": "My first blog post!",

        "tags": ["mongodb", "python", "pymongo"],

        "date": datetime.datetime.utcnow()}

#       goodinsert(post)

        a=threading.Thread(target=goodinsert,args=(post,))

        a.start()

023536618.jpg

python毕竟有gil的限制,虽然multiprocess号称可以解决多进程的。但是用过的朋友知道,这个东西更不靠谱 ~  属于坑人的东西 ~

要是有朋友怀疑是python的单进程的性能问题,那咱们就用supervisord跑了几个后台的python压力脚本 ~ supervisord的配置我就不说了,我以前的文章里面有详述的 ~

015034609.jpg

cpu方面是跑的有点均匀了,但是mongodb那边的压力总是上不去

当加大到16个后台进程做压力测试的时候 ~ 大家会发现insert很不稳定。 看来他的极限也就是2MB左右的数据 ~

015448335.jpg

当减少到8个压力进程的时候 ~ 我们发现他的insert慢慢的提供到正常了,也就是说  他真的是2MB的极限 ~

015559242.jpg

脚本里面是有做有序的id插入的,我们试试把id的插入给去掉,看看有没有提升~

结果和不插入id差不多的结果 ~

085221687.jpg

调优之后~ 再度测试

ulimit的优化

cat /etc/security/limits.conf

*       soft   nofile       102400

*       hard   nofile       102400

内核的tcp优化

cat /etc/sysctl.conf

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_timestsmps = 0

net.ipv4.tcp_synack_retries = 2

net.ipv4.tcp_syn_retries = 2

net.ipv4.tcp_wmem = 8192 436600 873200

net.ipv4.tcp_rmem = 32768 436600 873200

net.ipv4.tcp_mem = 94500000 91500000 92700000

net.ipv4.tcp_max_orphans = 3276800

net.ipv4.tcp_fin_timeout = 30

#直接生效

/sbin/sysctl -p

启动的时候,加上多核的优化参数

多核问题可以在启动时加入启动参数: numactl --interleave=all

insert的频率已经到了2w左右 ~  内存占用了8G左右 ~

143629965.png

143630829.png

我想到的一个方案:

当然不用非要celery,就算咱们用socket写分发,和zeromq的pub sub也可以实现这些的。这是celery的调度更加专业点。

021114653.jpg

刚才我们测试的都是insert,现在我们再来测试下在千万级别数据量下的查询如何:

查询正则的,以2开头的字符

posts = db.userinfo

for i in posts.find({"author":re.compile('^2.Mike')}):

    print i

013606877.jpg

精确的查询:

查询在5s左右 ~

013944841.jpg

225244177.jpg225244313.jpg

225244670.jpg

225244798.jpg

总结:

典型的高读低写数据库 !

©著作权归作者所有:来自51CTO博客作者rfyiamcool的原创作品,谢绝转载,否则将追究法律责任

pymongopython mongodbpython pymongopython应用

18


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消