2011年11月16日星期三

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倍。

没有评论: