I/O レイテンシにより、MySQL での単純な UPDATE に数秒かかることがありますか?
質問
MySQL アプリケーションで問題が発生しています パフォーマンスが遅い 何かを実行するとき UPDATE
, INSERT
そして DELETE
クエリ。この質問では、特定の 1 つのみについてのみ説明します。 UPDATE
, 問題を実証するにはこれで十分だからです。
UPDATE projects SET ring = 5 WHERE id = 1
これ UPDATE
通常は 0.2 ミリ秒程度で十分な速度ですが、場合によっては (十分に問題になる場合もあります) 数秒かかります. 。以下はログからの抜粋です (4 行目を見てください)。
~ (0.000282) UPDATE `projects` SET `ring` = 5 WHERE `id` = 1
~ (0.000214) UPDATE `projects` SET `ring` = 6 WHERE `id` = 1
~ (0.000238) UPDATE `projects` SET `ring` = 7 WHERE `id` = 1
~ (3.986502) UPDATE `projects` SET `ring` = 8 WHERE `id` = 1
~ (0.000186) UPDATE `projects` SET `ring` = 9 WHERE `id` = 1
~ (0.000217) UPDATE `projects` SET `ring` = 0 WHERE `id` = 1
~ (0.000162) UPDATE `projects` SET `ring` = 1 WHERE `id` = 1
projects
型の 6 つの列を持つ InnoDB テーブルです。 INT
そして VARCHAR
, 、17 行とインデックス id
. 。他のテーブルでも同様のことが起こりますが、ここではこのテーブルに焦点を当てます。問題を解決しようとしたとき、クエリがすべて連続していることを確認したため、これは次のとおりです。 ロックの問題ではない. 。の UPDATE
上記はトランザクションのコンテキストで実行されます。他の サーバー上の情報:
- 4GB RAM (以前は 1GB)、12GB の空きディスク容量を備えた VPS
- CentoOS 5.8 (以前は 5.7)
- MySQL 5.5.10 (以前は 5.0.x)
上記の「だった」ビットは、アップグレードの前後で機能しなかったことを意味します。
今まで試したことは無駄だった:
- 設定
innodb_flush_log_at_trx_commit
0、1、2のいずれかに - 設定
innodb_locks_unsafe_for_binlog
オンかオフか - 設定
timed_mutexes
オンかオフか - 変化
innodb_flush_method
デフォルトからO_DSYNC
またはO_DIRECT
- 増加中
innodb_buffer_pool_size
デフォルトから 600M、その後 3000M に - 増加中
innodb_log_file_size
デフォルトから 128M に - MySQL をソースからコンパイルする
- ランニング
SHOW PROCESSLIST
, 、状態が「更新中」であることがわかります。 - ランニング
SHOW PROFILE ALL
, これは、ほぼすべての時間が「更新」に費やされ、そのステップ内では CPU サイクルにあまり時間が費やされず、多くの自発的なコンテキスト切り替え (30 回など) があったことを示しています。 - 監視
SHOW STATUS
の変化のためにInnodb_buffer_pool_pages_dirty
. 。ダーティ ページのフラッシュとクエリの遅さの間には何らかの関係がある可能性がありますが、相関関係は明らかではありません。
次に、システムの I/O レイテンシーをチェックすることにしました。 ioping
. 。初めての VPS なので、 この結果を見てびっくりしました:
4096 bytes from . (vzfs /dev/vzfs): request=1 time=249.2 ms
4096 bytes from . (vzfs /dev/vzfs): request=2 time=12.3 ms
4096 bytes from . (vzfs /dev/vzfs): request=3 time=110.5 ms
4096 bytes from . (vzfs /dev/vzfs): request=4 time=232.8 ms
4096 bytes from . (vzfs /dev/vzfs): request=5 time=294.4 ms
4096 bytes from . (vzfs /dev/vzfs): request=6 time=704.7 ms
4096 bytes from . (vzfs /dev/vzfs): request=7 time=1115.0 ms
4096 bytes from . (vzfs /dev/vzfs): request=8 time=209.7 ms
4096 bytes from . (vzfs /dev/vzfs): request=9 time=64.2 ms
4096 bytes from . (vzfs /dev/vzfs): request=10 time=396.2 ms
かなり不安定だと思います。
以上のことを述べた上で、私はこう尋ねます。
I/O レイテンシーによって MySQL のパフォーマンスが低下することがありますか? あなたが走ったとき、私はいつもそう思っていました。
UPDATE
, 、その接続を処理するスレッドは、データをディスクにフラッシュしたり、そのようなフラッシュを待機したりするつもりはありませんでした。すぐに戻り、フラッシュは別の時間に別のスレッドによって実行されます。ディスクI/Oができない場合は、 専用サーバーをレンタルする以外に何か試せることはありますか?
解決
あなたの回答に基づいて収集した追加データを使用して、私自身の質問に返信しています。
2 台のノートブックをワイヤレス ネットワークで接続して使用しました。ノートブックAで、ノートブックBのディレクトリを使用して取り付けました sshfs
. 。次に、ノートブックでAIはMySQLを起動し、そのマウントディレクトリをデータディレクトリとして指定しました。これにより、MySQLに非常に遅いI/Oデバイスを提供する必要があります。MySQL はinnodb_flush_log_at_trx_commit = 0
.
3つのセットのクエリを定義しました。各セットは、明示的なトランザクションなしで、更新と選択クエリが10,000回繰り返されることで構成されています。実験は次のとおりです。
- US1SID:同じテーブルの特定の行を更新および選択します。すべての反復で同じ行が使用されました。
- US1MID:同じテーブルの特定の行を更新および選択します。行は、反復ごとに異なるものでした。
- US2MID:さまざまなテーブルの行を更新および選択します。この場合、選択によって読まれているテーブルは、実験中にまったく変更されませんでした。
各セットはシェル スクリプトを使用して 2 回実行されました (そのため、元の質問よりもタイミングが遅くなります)。1 回目は通常の条件下で、もう 1 回目は次のコマンドを実行した後です。
tc qdisc replace dev wlan0 root handle 1:0 netem delay 200ms
上記のコマンドは、wlan0 経由でパケットを送信するときに平均 200 ミリ秒の遅延を追加します。
まず、上位99%の最速の更新と選択の平均時間と、下の1%の更新と選択を選択します。
| Delay: 0ms | Delay: 200ms |
| US1SID | US1MID | US2MID | US1SID | US1MID | US2MID |
| top99%u | 0.0064 | 0.0064 | 0.0064 | 0.0063 | 0.0063 | 0.0063 |
| top99%s | 0.0062 | 0.0063 | 0.0063 | 0.0062 | 0.0062 | 0.0062 |
| bot01%u | 1.1834 | 1.2239 | 0.9561 | 1.9461 | 1.7492 | 1.9731 |
| bot01%s | 0.4600 | 0.5391 | 0.3417 | 1.4424 | 1.1557 | 1.6426 |
明確であるように、本当に、本当に貧弱なI/Oパフォーマンスがあっても、MySQLはほとんどのクエリを非常に速く実行することができます。しかし、私が最も関心を持つのは最悪の場合ですので、ここに別のテーブルがあり、10の最も遅いクエリを示しています。「u」は、それがアップデート、「s」a selectであったことを意味します。
| Delay: 0ms | Delay: 200ms |
| US1SID | US1MID | US2MID | US1SID | US1MID | US2MID |
| 5.443 u | 5.946 u | 5.315 u | 11.500 u | 10.860 u | 11.424 s |
| 5.581 u | 5.954 s | 5.466 u | 11.649 s | 10.995 u | 11.496 s |
| 5.863 s | 6.291 u | 5.658 u | 12.551 s | 11.020 u | 12.221 s |
| 6.192 u | 6.513 u | 5.685 u | 12.893 s | 11.370 s | 12.599 u |
| 6.560 u | 6.521 u | 5.736 u | 13.526 u | 11.387 u | 12.803 u |
| 6.562 u | 6.555 u | 5.743 u | 13.997 s | 11.497 u | 12.920 u |
| 6.872 u | 6.575 u | 5.869 u | 14.662 u | 12.825 u | 13.625 u |
| 6.887 u | 7.908 u | 5.996 u | 19.953 u | 12.860 u | 13.828 s |
| 6.937 u | 8.100 u | 6.330 u | 20.623 u | 14.015 u | 16.292 u |
| 8.665 u | 8.298 u | 6.893 u | 27.102 u | 22.042 s | 17.131 u |
結論:
実際、I/O パフォーマンスが低いと、MySQL の速度が異常に遅くなる可能性があります。それははっきりしていません なぜまたは いつ まさにその通りですが、それは起こります。
減速は、選択と更新の両方に適用され、更新はより多くのことに苦しんでいます。
何らかの理由で、上記のUS2MIDから明らかなように、どのような変更にも関与しておらず、最近住んでいたテーブルの上でも選択されました。
MentATKGSによって提案されたテストケースについては、同じ行の代わりに異なる行を更新することは少し役立ちますが、問題は解決しないようです。
私は自分のソフトウェアをそのような遅延を許容するために私のソフトウェアを適応させるか、別のプロバイダーに移そうとすると思います。専用サーバーのレンタルは、このプロジェクトには高すぎます。
コメントをくださった皆様、ありがとうございました。
他のヒント
クラウドで VPS をホストしていると、完全に制御不能な問題に遭遇する可能性があります。
VPS は、それを実行するホスト サーバーの気まぐれに左右されます。たとえば、Rackspace Cloud での CPU サイクルの優先順位は、VPS のサイズに基づいて重み付けされます。VPS が大規模であればあるほど、アプリがスムーズに実行される可能性が高くなります。使用しているホスト上に大規模な VPS がある場合は、 可能 責任の重みが爆発しているということ。言うのはかなり難しいです。
これを自分のマシンでローカルに実行してみましたか?独自のシステムで完全に動作し、保証されたパフォーマンスが必要な場合は、専用サーバーに移行するのが最善の策です。
VPS 関連の IO 問題が発生しています。それは MySQL のせいではありません。
もしかして、Amazon または RDS で Elastic Block Store を使用していますか?どちらもリモート ストレージと、ストレージと通信するための IP プロトコル層を使用します。時々ひどい遅れが生じることがあります。
質問1) はい。
それを確認するには、2 つのアプリを作成します。
テストケース 1:これを数時間毎分行います
UPDATE `projects` SET `ring` = 5 WHERE `id` = 1
UPDATE `projects` SET `ring` = 6 WHERE `id` = 1
テストケース 2:これを数時間にわたって毎分実行します
UPDATE `projects` SET `ring` = 7 WHERE `id` = 1
UPDATE `projects` SET `ring` = 8 WHERE `id` = 2
テスト ケース 1 には遅延が発生するはずですが、テスト ケース 2 には遅延が発生しないはずです。
質問 2) noSQL データベースを使用します。