大規模なトランザクションを処理することは、GaleraClusterでは常に問題点でした。 Galeraライトセット認証が機能する方法は、トランザクションが長い場合、または単一の行が複数のノードで頻繁に変更される場合に問題を引き起こします。その結果、トランザクションをロールバックして再試行する必要があり、パフォーマンスが低下します。幸い、この問題は、CodershipからのGaleraの新しいリリースであるGalera4で対処されています。このライブラリはMariaDB10.4で使用されるため、MariaDB 10.4をインストールすると、新しく導入された機能をテストする最も簡単な方法になります。このブログ投稿では、ストリーミングレプリケーションを使用して、以前のGaleraバージョンで標準的な問題であった問題を軽減する方法を見ていきます。
ガレラバージョン26.4.2に付属するMariaDBガレラクラスターバージョン10.4.6の3つのノードを使用します。
MariaDB [(none)]> show global status like 'wsrep_provider%';
+-----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value |
+-----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| wsrep_provider_capabilities | :MULTI_MASTER:CERTIFICATION:PARALLEL_APPLYING:TRX_REPLAY:ISOLATION:PAUSE:CAUSAL_READS:INCREMENTAL_WRITESET:UNORDERED:PREORDERED:STREAMING:NBO: |
| wsrep_provider_name | Galera |
| wsrep_provider_vendor | Codership Oy <[email protected]> |
| wsrep_provider_version | 26.4.2(r4498) |
+-----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.001 sec)
ストリーミングレプリケーションが対処することを目的とした3つの主な問題点があります。
- 長いトランザクション
- 大規模なトランザクション
- テーブルのホットスポット
それらを1つずつ検討し、ストリーミングレプリケーションがそれらの処理にどのように役立つかを見てみましょう。ただし、最初に、これらの問題が発生する根本的な原因であるライトセット認証に焦点を当てましょう。
GaleraClusterでのライトセット認定
Galeraクラスターは、複数の書き込み可能なノードで構成されています。 Galeraクラスターで実行される各トランザクションは、書き込みセットを形成します。すべての書き込みセットは、認証のためにクラスター内のすべてのノードに送信する必要があります。これは、すべてのノードが特定のトランザクションを適用できることを保証するプロセスです。書き込みセットはすべてのクラスターノードで実行する必要があるため、競合がある場合、トランザクションをコミットできません。トランザクションをコミットできない一般的な理由は何ですか?さて、前にリストした3つのポイント:
- 長いトランザクション-トランザクションに時間がかかるほど、その間に別のノードが更新を実行し、最終的に書き込みセットと競合して、認証に合格できなくなる可能性が高くなります
- 大規模なトランザクション-まず、大規模なトランザクションは小規模なトランザクションよりも長いため、最初の問題が発生します。大規模なトランザクションに厳密に関連する2番目の問題は、変更の量です。より多くの行が更新され、別のノードへの書き込みによって競合が発生し、トランザクション全体をロールバックする必要が生じる可能性が高くなります。
- テーブルのホットスポット-特定の行が更新される可能性が高く、そのような更新が複数のノードで同時に発生し、一部のトランザクションがロールバックされる可能性があります
ここでの主な問題は、Galeraが、トランザクションが開かれた最初のノード以外のノードにロックを導入しないことです。認証プロセスは、1つのノードがトランザクションを実行できれば、他のノードもそれを実行できるようになるという希望に基づいています。それは本当ですが、私たちが議論したように、これが起こる可能性が大幅に低下するコーナーケースがあります。
Galera 4では、ストリーミングレプリケーションを使用すると、動作が変更され、すべてのノードですべてのロックが取得されます。トランザクションは部分に分割され、各部分はすべてのノードで認証されます。認定が成功すると、クラスター内のすべてのノードで行がロックされます。これがどのように正確に行われるかを制御する変数がいくつかあります。wsrep_trx_fragment_sizeとwsrep_trx_fragment_unitは、フラグメントのサイズと定義方法を定義します。これは非常にきめ細かい制御です。フラグメント単位をバイト、ステートメント、または行として定義できます。これにより、トランザクションで変更されたすべての行に対して認証を実行できます。実生活でストリーミングレプリケーションからどのように利益を得ることができるかを見てみましょう。
ストリーミングレプリケーションの操作
次のシナリオを考えてみましょう。少なくとも30秒かかるトランザクションがあります:
BEGIN; UPDATE sbtest.sbtest1 SET k = k - 2 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; SELECT SLEEP(30); COMMIT;
次に、実行中に、同様の行にアクセスするSQLを実行します。これは別のノードで実行されます:
BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;
結果はどうなりますか?
最初のトランザクションは、2番目のトランザクションが実行されるとすぐにロールバックされます:
MariaDB [sbtest]> BEGIN; UPDATE sbtest.sbtest1 SET k = k - 2 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; SELECT SLEEP(30); COMMIT;
Query OK, 0 rows affected (0.001 sec)
Query OK, 667 rows affected (0.020 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (0.010 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (0.009 sec)
Rows matched: 667 Changed: 667 Warnings: 0
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
Query OK, 0 rows affected (0.001 sec)
2番目のノードでのトランザクションは成功しました:
MariaDB [(none)]> BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;
Query OK, 0 rows affected (0.000 sec)
Query OK, 7 rows affected (0.002 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 7 rows affected (0.001 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 0 rows affected (0.004 sec)
これを回避するためにできることは、最初のトランザクションにストリーミングレプリケーションを使用することです。すべての行の変更を証明するようにGaleraに依頼します:
MariaDB [sbtest]> BEGIN; SET SESSION wsrep_trx_fragment_size=1 ; SET SESSION wsrep_trx_fragment_unit='rows' ; UPDATE sbtest.sbtest1 SET k = k - 2 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; SELECT SLEEP(30); COMMIT; SET SESSION wsrep_trx_fragment_size=0;
Query OK, 0 rows affected (0.001 sec)
Query OK, 0 rows affected (0.000 sec)
Query OK, 0 rows affected (0.000 sec)
Query OK, 667 rows affected (1.757 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (1.708 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (1.685 sec)
Rows matched: 667 Changed: 667 Warnings: 0
ご覧のとおり、今回は問題なく動作しました。 2番目のノード:
MariaDB [(none)]> BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;
Query OK, 0 rows affected (0.000 sec)
Query OK, 7 rows affected (33.942 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 7 rows affected (0.001 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 0 rows affected (0.026 sec)
興味深いことに、UPDATEの実行には約34秒かかりました。これは、最初のトランザクションがストリーミングレプリケーションを介して、すべてのノードの変更されたすべての行をロックし、2番目のトランザクションが待機する必要があったためです。両方のトランザクションが異なるノードで実行された場合でも、最初に完了するトランザクション。
ストリーミングレプリケーションに関しては、基本的にこれです。要件とトラフィックに応じて、それほど厳密ではない方法で使用できます。すべての行を認定しましたが、n番目の行ごとまたはすべてのステートメントに変更できます。証明するデータの量を決定することもできます。これは、環境の要件に一致するのに十分なはずです。
覚えておいてほしいことがいくつかあります。まず第一に、ストリーミングレプリケーションは、デフォルトで使用されるべきソリューションではありません。これが、デフォルトで無効になっている理由です。推奨される使用例は、ストリーミングレプリケーションの恩恵を受けるトランザクションを手動で決定し、セッションレベルで有効にすることです。これが、例が次で終わる理由です:
SET SESSION wsrep_trx_fragment_size=0;
このステートメント(wsrep_trx_fragment_sizeを0に設定)は、現在のセッションのストリーミングレプリケーションを無効にします。
覚えておく価値のあるもう1つのことは、ストリーミングレプリケーションを使用する場合、ストリーミング中のデータを永続的に保存するために「mysql」スキーマの「wsrep_streaming_log」テーブルを使用することです。このテーブルを使用すると、ストリーミングレプリケーションを使用してクラスター間で転送されているデータに関するアイデアを得ることができます。
最後に、パフォーマンス。これは、ストリーミングレプリケーションを常に使用したくない理由の1つでもあります。その主な理由はロックです。ストリーミングレプリケーションでは、すべてのノードで行ロックを取得する必要があります。これにはロックの取得に時間がかかり、トランザクションをロールバックする必要がある場合は、ロールバックを実行するようにすべてのノードにプレッシャーがかかります。ストリーミングレプリケーションがパフォーマンスに与える影響の非常に迅速なテストを実行しました。環境は厳密にテスト環境であるため、これらの結果が実稼働グレードのハードウェアで同じであると想定しないでください。影響がどのようなものかを確認する必要があります。
4つのシナリオをテストしました:
- ベースライン、グローバルwsrep_trx_fragment_size=0を設定;
- set global wsrep_trx_fragment_unit ='rows';グローバルwsrep_trx_fragment_size=1を設定します;
- set global wsrep_trx_fragment_unit ='statements';グローバルwsrep_trx_fragment_size=1を設定します;
- set global wsrep_trx_fragment_unit ='statements';グローバルwsrep_trx_fragment_size=5を設定します;
sysbench r / wテストを使用しました:
sysbench /root/sysbench/src/lua/oltp_read_write.lua --threads=4 --events=0 --time=300 --mysql-host=10.0.0.141 --mysql-user=sbtest --mysql-password=sbtest --mysql-port=3306 --tables=32 --report-interval=1 --skip-trx=off --table-size=100000 --db-ps-mode=disable run
結果は次のとおりです。
- トランザクション:1秒あたり82.91、クエリ:1秒あたり1658.27。 (100%)
- トランザクション:1秒あたり54.72、クエリ:1秒あたり1094.43。 (66%)
- トランザクション:1秒あたり54.76、クエリ:1秒あたり1095.18 (66%)
- トランザクション:1秒あたり70.93、クエリ:1秒あたり1418.55。 (86%)
ご覧のとおり、影響は大きく、パフォーマンスは33%も低下します。
このブログ投稿が参考になり、Galera4とMariaDB10.4に付属するストリーミングレプリケーションについての洞察が得られたことを願っています。この新しいテクノロジーに関連するユースケースと潜在的な欠点をカバーしようとしました。