3

Python スクリプトがデータ セットを反復するのにかかる時間に問題があります。データセットは約 40k ドキュメントです。これは、pymongo カーソルが内部的で開発者から離れて抽象化された複数のフェッチを発行するのに十分な大きさです。問題を示すために、スクリプトを可能な限り単純化しました。

from pymongo import Connection
import time

def main():
    starttime = time.time()
    cursor = db.survey_answers.find()
    counter=0;
    lastsecond=-1;
    for entry in cursor:
        if int(time.time()-starttime)!=lastsecond:
            print "loop number:", counter, "   seconds:",int(time.time()-starttime);
            lastsecond= int(time.time()-starttime)
        counter+=1;
    print (time.time()-starttime), "seconds for the mongo query to get rows:",counter;

connection = Connection(APPSERVER)#either localhost or hostname depending on test
db = connection.beacon

if __name__ == "__main__":
    main()

私のセットアップは次のとおりです。私は 4 つの個別のホスト、mongos を実行する 1 つの APPSERVER、およびそれぞれが他の 2 つのプライマリ レプリカ セットとセカンダリ レプリカ セットである 3 つの他のシャード ホストを持っています。

これをシャード サーバーの 1 つから (APPSERVER ホスト名を指す接続を使用して) 実行すると、次のようになります。

loop number: 0    seconds: 0
loop number: 101    seconds: 2
loop number: 7343    seconds: 5
loop number: 14666    seconds: 8
loop number: 21810    seconds: 10
loop number: 28985    seconds: 13
loop number: 36078    seconds: 15
16.0257680416 seconds for the mongo query to get rows: 41541

したがって、ここで何が起こっているかは明らかです。カーソル要求の最初のバッチサイズは 100 で、その後の各バッチサイズは 4m 相当のデータであり、私にとっては 7k をわずかに超えるドキュメントのように見えます。そして、各フェッチには2〜3秒かかります!!!!

アプリケーションを mongos インスタンスの近くに移動することで、この問題を解決できると考えました。ネットワークの使用量を減らすことを期待して、上記のコードを APPSERVER で (接続が localhost を指すように) 実行しました ....しかし、それはさらに悪いことでした!

loop number: 0    seconds: 0
loop number: 101    seconds: 9
loop number: 7343    seconds: 19
loop number: 14666    seconds: 28
loop number: 21810    seconds: 38
loop number: 28985    seconds: 47
loop number: 36078    seconds: 53
53.5974030495 seconds for the mongo query to get rows: 41541

カーソルのサイズは両方のテストでまったく同じです。これは素晴らしいことですが、ここでは各カーソルのフェッチに9 ~ 10 秒かかります!!!

通信する必要がある 4 つの別々のホストがあることはわかっているので、これはすぐにはできません。しかし、おそらく 10m のレコードのコレクションを反復処理する必要があります。7k あたり 2 秒で、1 時間弱かかります。私はこれを持つことはできません !

ところで、私は python/mongo の世界に不慣れで、php と mysql に慣れていて、これがほんの一瞬で処理されることを期待しています。

$q=mysql_query("select * from big_table");//let's say 10m rows here ....
$c=0;
while($r=mysql_fetch_rows($q))
    $c++;
echo $c." rows examined";

私が提示したpymongo(〜1時間)とphp / mysql(<1秒)のアプローチの巨大な違いを誰かが説明できますか?ありがとう!

4

1 に答える 1

3

A. Jesse Jiryu Davis の助けを借りて、これを理解することができました。C拡張機能がインストールされていないことがわかりました。問題としてネットワーク遅延を除外できるように、シャードなしで別のテストを実行したかった. 新しくクリーンなホストを入手し、mongo をセットアップし、データをインポートし、スクリプトを実行しましたが、同じ時間がかかりました。したがって、シャーディング/レプリカ セットが問題とは何の関係もないことはわかっています。

修正前は、次のように印刷できました。

pymongo.has_c(): False
pymongo version 2.3

次に、指示に従って、c 拡張機能の依存関係をインストールしました。

yum install gcc python-devel

次に、pymongo ドライバーを再インストールしました。

git clone git://github.com/mongodb/mongo-python-driver.git pymongo
cd pymongo/
python setup.py install

スクリプトを再実行すると、次のように出力されます。

pymongo.has_c(): True
pymongo version 2.3+

また、上記の 16 とは対照的に、実行には約 1.8 秒かかります。40,000 件のレコードを取得して繰り返し処理するにはまだ時間がかかりますが、大幅な改善です。

これらの更新を本番 (シャード化されたレプリカ セット) 環境で実行して、うまくいけば同じ結果が得られるようにします。

**UPDATE* * 私の製品環境で pymongo ドライバーを更新したところ、改善は見られましたが、それほどではありませんでした。いくつかのテストで約 2.5 ~ 3.5 秒かかりました。ここでは、シャーディングの性質が問題だったと思います。40,000 件以上のレコードを繰り返すには、それでも信じられないほど遅いようです。

于 2012-10-10T19:12:45.620 に答える