2

私はこの質問がstackoverflowで複数回尋ねられることを知っています。私はこの質問を投稿して、私のデザインに最適なものを見つけます。私の仕事の詳細については、次のスキーマがあります。

_unique_key        varchar(256) NULL
_job_handle        varchar(256) NULL
_data              varchar(1024) NULL
_user_id           int(11) NULL
_server_ip         varchar(39) NULL
_app_version       varchar(256) NULL
_state             int(11) NULL
_is_set_stopped    bool

このテーブルで実行している操作:

  1. ジョブごとに、このテーブルで1つの更新と10の選択クエリがあります。したがって、読み取りと書き込みには高周波が必要です。
  2. フィルタを実行してこのテーブルを操作しているアプリケーションはたくさんあります。
    1. _unique_key
    2. _州
    3. is_set_stopped
    4. _ユーザーID
  3. _dataフィールドのサイズは、アプリケーションのタイプとユーザーに基づいて5KBから1MBまで変化します。
  4. アプリケーションは選択属性を更新できます。

私たちが考えた解決策:

MySQL InnoDB

高い読み取りと書き込みが必要なため、MySQLは十分に拡張できないと思います。

MySQLインメモリテーブル

このソリューションの問題は、

  1. 動的フィールドサイズはサポートされていません。MEMORYテーブルは、固定長の行ストレージ形式を使用します。VARCHARなどの可変長タイプは、固定長を使用して格納されます。ソースhttp://dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html
  2. select for .... updateは、テーブル全体をロックします。それが問題になるかどうかはわかりません。

Redis

Redisの外観は良い選択のようです。しかし、私のテーブルはキー値キャッシュサーバーには適していないと思います。

  1. 非常に多くのデータ型のセットのみをサポートします。リストには文字列しか保存できません。フィールドをJSONまたはその他の形式で保存する必要があります。
  2. クライアントが特定の属性を更新したい場合は、完全な値をダウンロードしてから、オブジェクトの解析を実行してサーバーに再プッシュする必要があります。 私が間違っているかもしれませんそれを行う方法はありますか?
  3. 値に基づくフィルタリングはできません。 私が間違っているかもしれませんそれを行う方法はありますか?

TMPFSファイルシステム上のMySQLInnoDB

これは有望に見えます。ただし、メモリテーブルのRedisやMySQLと同様に十分に拡張できるわけではありません。

4

2 に答える 2

4

この質問では、生のパフォーマンス(つまり効率)とスケーラビリティを混同しています。それらは異なる概念です。

InnoDBとメモリエンジンの間では、InnoDBが最もスケーラブルである可能性があります。InnoDBは、マルチバージョニングの同時実行制御をサポートし、競合に対処するための多くの最適化を備えているため、メモリエンジンよりもはるかに優れた同時アクセスを処理します。一部のI/Oバウンドの状況では遅くなる可能性があります。

Redisはシングルスレッドサーバーです。すべての操作はシリアル化されます。スケーラビリティはゼロです。それが非効率的であるという意味ではありません。それどころか、MySQLよりも多くの接続(epollベースのイベントループによる)と、より多くのトラフィック(非常に効率的なロックフリーの実装とメモリ内データ構造による)をサポートする可能性があります。

あなたの質問に答えるために、私はInnoDBでMySQLを試してみます。適切に構成されている場合(同期コミットがない、十分なキャッシュバッファーなど)、良好なスループットを維持できます。そして、tmpfs上で実行する代わりに、SSDハードウェアを検討します。

さて、Redis(リレーショナルストアではありません)を使用したい場合は、確かにそれを行うことができます。データを体系的にシリアル化/逆シリアル化する必要はありません。そして、すべてのアクセスパスを予測し、適合したデータ構造を見つけることができれば、フィルタリングは確かに可能です。

例えば:

  • ジョブごとに1つのハッシュオブジェクト。キーは_unique_keyです。ハッシュのフィールドは、リレーショナルテーブルの列に対応している必要があります。
  • 状態値ごとに1セット
  • is_set_stoppedの2セット
  • ユーザーID値ごとに1セット

ジョブを挿入するたびに、次のコマンドをパイプライン処理する必要があります。

HMSET job:AAA job_handle BBB data CCC user_id DDD server_ip EEE app_version FFF state GGG is_set_stopped HHH
SADD state:GGG AAA
SADD is_set_stopped:HHH AAA
SADD user_id:DDD AAA

対応するセットを維持していれば、任意のフィールドを個別に簡単に更新できます。

セットを交差させることにより、フィルタリングクエリを実行できます。例えば:

SINTER is_set_stopped:HHH state:GGG

Redisを使用すると、特にデータフィールドが大きい場合、ボトルネックはネットワークになる可能性があります。1MBのジョブよりも5KBのジョブの方が多いといいのですが。たとえば、1MBオブジェクトの1000書き込み/秒は8GBits /秒を表し、おそらくネットワークが維持できる量を超えています。これは、RedisとMySQLの両方に当てはまります。

于 2012-10-13T11:59:24.350 に答える
1

postgresqlをお勧めします。これは、mysqlよりも機能が高く(より多くの機能と複雑なクエリとデータ型のサポートが優れています)、多くの調整オプションがあります。

postgresqlに十分なメモリを与え、パラメータを正しく調整すると、すべてがメモリにキャッシュされます。

または、必要に応じてtmpfsで使用し、ハードコピー用にディスク上のデータベースへのストリーミングレプリケーションを使用することもできます。

ストリーミングレプリケーションには、非同期、受信時、およびfsyncの3つの動作モードがあります。最初の非同期を使用する場合は、レプリケーションサーバー上のディスクへの同期を待つ必要がないため、tmpfsを使用すると更新が非常に高速になります。

テキストフィールドもたくさんあるように見えるので、別の機能が役立つかもしれません。postgresqlはテキスト検索ベクトルを行に格納でき、それにインデックスを追加して、トリガーを介してすべての行の連結コンテンツで更新できます。を検索しています。これにより、複数の列でテキスト検索を実行する場合と、mysqlで記述できる方法と比較して、パフォーマンスが大幅に向上します。

使用するデータベースに関係なく

_dataはvarchar[1024]であると述べていますが、5Kから1Mのデータが含まれていると言いますか?これは実際にはブロブですか?長さが間違っていたとしても、mysqlは長さが65535バイトを超えるvarcharフィールドをサポートしていません。これは他の行ほど更新されていないと思います。ディスクアクセスを最小限に抑えるために、これを静的データと動的データの2つのテーブルに分割するのが賢明かもしれません。

于 2012-10-13T12:25:06.487 に答える