Shell's Home

Nov 16, 2011 - 1 minute read - Comments

mongo无法利用多核?

太伤心了,本来以为mongo的速度很快呢。测试插入数据,结果当场被泼了冷水。

conn = pymongo.Connection('localhost', 27017)
db = conn['perform']
coll = db['test']
testdata = []


def init_testdata():
    for i in xrange(1000):
        s1 = ''.join([random.choice(string.hexdigits) for j in xrange(16)])
        s2 = ''.join([random.choice(string.letters) for j in xrange(200)])
        testdata.append((s1, s2))
        init_testdata()


def insert_mongo():
    for s1, s2 in testdata:
        coll.insert({'_id': s1, 'content': s2})


def find_mongo():
    for s1, s2 in testdata:
        s = coll.find_one({'_id': s1})


def testfunc(funcname, times=1000):
    from timeit import Timer
    t = Timer("%s()" % funcname, "from __main__ import \*")
    print('funcname: %s used %f' % (funcname, t.timeit(times) / times))

if __name__ == '__main__':
    # os.fork()
    # os.fork()
    init_testdata()
    testfunc('insert_mongo', times=100)
    testfunc('find_mongo', times=100)

这个代码,在直接执行的情况下,获得结果是这样的。

funcname: insert_mongo used 0.179303

折合成iops,也就是5500req/s的样子。打开os.fork后,结果变成了这样。

funcname: insert_mongo used 0.516131
funcname: insert_mongo used 0.526213

只有3850req/s左右,我靠,比单进程慢那么多?打开四个进程试试?

funcname: insert_mongo used 1.039754
funcname: insert_mongo used 1.058093
funcname: insert_mongo used 1.058598
funcname: insert_mongo used 1.059101

基本稳定下来了,差不多4000req/s的样子。而且,通过top发现,最关键的问题不在于io和内存,而是mongodb这货只有一个进程,最高吃到100%的CPU——也就是——无法利用多核。

幸好,在读取测试中,情况不是那么糟糕。在单进程下是下面这样子 funcname: find_mongo used 0.350096 2850req/s,双进程就变成了这样子。

funcname: find_mongo used 0.220384
funcname: find_mongo used 0.221446

9000req/s!不但性能有所上升,而且更为惊喜的是,在top中检测发现,主要CPU消耗都放到了python这端。而分布系统的常识告诉我们,客户端的压力(就是应用服务器的压力)是可以很容易的通过添加服务器来解决的。在贝壳当前这台双核的机器上是无法进行进一步测试了,不过按照目前的状况预估,查询时即使只能使用单核,也可以支持10000req/s以上的性能。

又是一个典型的高读低写数据库呐。也罢也罢,nosql中也就mongo的各种特性比较接近sql数据库,用来跳过ORM层直接做系统比较合适。如果使用memcache或者redis,性能倒是上去了,用起来就未免太蛋疼了一点。不过偷偷的透露一点,贝壳估计,使用redis后,性能还能上去5倍。