MongoDB + Redis 任务队列性能瓶颈
迷茫
迷茫 2017-04-22 08:56:16
0
3
758

问题背景: 近期在重构公司内部一个重要的任务系统,由于原来的任务系统使用了MongoDB来保存任务,客户端从MongoDB来取,至于为什么用MongoDB,是一个历史问题,也是因为如果使用到MongoDB的数组查询可以减少任务数量很多次,假设这样的情况,一个md5需要针对N种情况做任务处理,如果用到MongoDB的数组,只需要将一个md5作为一条任务,其中包含一个长度为N的待处理任务列表(只有N个子任务都处理完后整个任务才算处理完毕),这样整个任务系统的数量级就变为原来的 1/N。

细节描述: 1.当MongoDB的任务数量增多的时候,数组查询相当的慢,任务数达到5K就已经不能容忍了。 2.任务处理每个md5对应的N个子任务必须要全部完成才从MongoDB中删除 3.任务在超时后可以重置

改进方案如下: 由于原有代码的耦合,不能完全抛弃MongoDB,所以决定加一个Redis缓存。一个md5对应的N个子任务分发到N个Redis队列中(拆分子任务)。一个单独的进程从MongoDB中向Redis中将任务同步,客户端不再从MongoDB取任务。这样做的好处是抛弃了原有的MongoDB的数组查询,同步进程从MongoDB中取任务是按照任务的优先级偏移(已做索引)来取,所以速度比数组查询要快。这样客户端向Redis的N个队列中取子任务,把任务结果返回原来的MongoDB任务记录中(根据md5返回子任务)。

改进过程遇到的问题: 由于客户端向MongoDB返回时候会有一个update操作,如果N个子任务都完成,就将任务从MongoDB中删除。这样的一个问题就是,经过测试后发现MongoDB在高并发写的情况下性能很低下,整个任务系统任务处理速度最大为200/s(16核, 16G, CentOS, 内核2.6.32-358.6.3.el6.x86_64),原因大致为在频繁写情况下,MongoDB的性能会由于锁表操作急剧下降。

具体问题: (Think out of the Box)能否提出一个好的解决方案,能够保存任务状态(子任务状态),速度至少超过MongoDB的?

迷茫
迷茫

业精于勤,荒于嬉;行成于思,毁于随。

全員に返信(3)
迷茫

いくつかの予備的な検討の後、参考までに:

  1. まず最初に、これにインデックスを追加する必要があると思います。
  2. 確認したいことがあります。mongodb の最新バージョンのロック粒度はまだデータベース レベルです。ロック テーブル (コレクション) の粒度にはまだ達していません。したがって、書き込み同時実行性が大きい場合はさらに悪化しますが、それはそのはずです。パフォーマンスは説明したほど悪くありませんか?理解できませんが、タスクのサブライブラリの可能性を検討してみてはいかがでしょうか。
  3. サブタスクのステータスとメインタスクのステータスを別々に保存することを検討できますか?サブタスクのステータスを Redis に配置し、メイン タスクは自身のステータスのみを担当するようにすることで、各メイン タスクの更新頻度が 1/N に削減され、メイン タスクへの負担が大幅に軽減されます。 mongodbのテーブル。
  4. サブタスクが完了またはタイムアウトした後、mongodb のメインタスクのステータスをバックグラウンドで非同期、シングルスレッドで順次同期することを検討できますか?
いいねを押す +0
阿神

個人的には、質問者が指摘した MongoDB 配列クエリと更新のパフォーマンスの問題は、スキーマ設計の問題である可能性が高いと思います。しかし、質問者は具体的なデザインについては言及しなかったので、参考までに、注目に値するいくつかのポイントを提示します:

  1. インデックス、前述のように、配列にインデックスを付ける必要があります。ただし、配列フィールドのインデックスは通常のフィールドのインデックスよりもはるかに大きいことに注意してください (配列のサイズに応じて、配列が大きくなるほど、インデックスが占めるスペースも大きくなります)。これにより問題が発生する可能性があります。インデックスが (完全に) メモリ内にありません。 その結果、各クエリに追加の IO 操作が必要となり、パフォーマンスが急激に低下します。
  2. クエリはドキュメントのサイズを返します。各クエリに対して返されるドキュメント データの量が多く、クライアントと mongodb が同じマシン上にない場合、ネットワーク送信に必要な時間が増加します (この時間を過小評価しないでください)。そのため、必要なすべてのデータのみを返すようにしてください。フィールド。
  3. その場で更新: スキーマレス機能により、mongodb はフィールドやデータを追加するときに使用するために各ドキュメント レコード用にスペースを予約し、更新パフォーマンスを向上させます。ただし、ドキュメントのサイズが頻繁に拡大する場合 (フィールドの追加、配列の長さの増加など)、書き込みパフォーマンスの問題が発生します。MongoDB は、増大するドキュメントを別の場所に移動する必要があります。 (ハードディスク上のある場所から、より空いている別の場所に移動することに相当します) このとき、パフォーマンスは大幅に低下します。

Mongodb はインメモリ データベースであり、すべてのホットスポット データがメモリ内にある場合、そのパフォーマンスは非常に優れていますが、これはスキーマの設計に大きく依存します。

追記: mongodb が常に宣伝してきたスキーマレスの利点は多くの人々を誤解させてきました。実際、これは mongodb がスキーマを設計する必要がないというよりも、動的スキーマであることを示すためです。

いいねを押す +0
大家讲道理

さらに、mongodb はそれほど遅くないはずですよね?または、上限付きコレクションをお試しください。

いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート