SQL Server 2016/2017 可容性グループ セカンダリレプリカ redoモデルと性能
MSSQL Tiger Teamが投稿したBlogを基に整理した内容です。
可容性グループはSQL Server 2012で初めてリリースされました。
可容性グループセカンダリレプリカの各データベースではトランザクションログのredoは一つのredoスレッドで制御していました。
このredoモデルは、serial redoと呼ばれていました。
SQL Server 2016で、redoモデルが強化され、redo操作を分けるためにデータベース毎に複数の並列redoワーカースレッドになりました。さらに各データベースは、ダーティページディスクフラッシュIOを管理する新しいヘルパーワーカースレッドがあります。
この新しいredoモデルは、parallel redoと呼ばれます。
新しいparallel redoは、SQL Server 2016から既定の設定で、小さいトランザクションが並列に大量に実行されるケースではredo性能の改善ができました。データの暗号化、データ圧縮の有功などのCPU負荷の高いトランザクションredo操作は、serial redoと比較してparallel redoの方が高いスループット(Redone Bytes/sec)が得られます。
さらに、間接的チェックポイントがparallel redoがヘルパーワーカースレッドにディスクIOや遅いディク用のIO waitを委任し、メインのredoスレッドがセカンダリレプリカでログレコードをより受信できるようにします。redo性能を向上させます。
しかし、parallel redoはマルチスレッドモデルでコストが高いです。
- メインredoスレッドは、各トランザクションログredo操作の実行を停止しますが、各トランザクションログを列挙し、parallel redoワーカースレッドにディスパッチすることを担当します。テーブル(行数の小さい)の狭い範囲の行へのDMLトランザクションのredoのようなCPU負荷がかからないログredo操作のケースでは、それらのログをディスパッチするコストは非常に重いです。
- 新しいレコードを挿入するためにページを分割するシステムトランザクションは、parallel redoワーカースレッド間でPARALLEL_REDO_TRAN_TURN waitを利用します。頻繁にinsert操作をする場合、かなりparallel redo性能を遅くします
- 読み取りセカンダリレプリカでread-onlyクエリを実行すると、クエリスレッドはログredo操作を一時停止しようとし、DIRTY_PAGE_TABLE_LOCKでredoワーカースレッドと連携する必要があります。redoとクエリ性能が両方遅くなります。
性能研究に基づくと、次のトランザクションワークロードまたはSQL設定が既定のparallel redo モデルより良い結果となります。
- 多くの並列の小さいトランザクション
- 間接的なチェックポイントを伴う負荷のかかるログredo操作(データ暗号化またはデータ圧縮)
- 読み取りをしないセカンダリレプリカ、またはたまにread-onlyクエリを読み取りセカンダリレプリカで実行する場合
次の場合は、serial redoに切り替えた方がredoスループットがよくなります。
- 一般的なInsertや同時実効性が限られている長い時間実行するトランザクション:典型的な例は、大きなテーブルのクラスター化インデックスのオンラインIndex再構築
- parallel redoモデルでの兆候
- PARALLEL_REDO_TRAN_TURN waitがinsert処理量に比例して生成されます。多くのInsertが多くのpage splitを起こし、PARALLEL_REDO_TRAN_TURN waitを呼びます。
- 性能カウンターで監視できます。(SQLServer:General Statistics、User Connections)または、プライマリレプリカのDMV(sys.dm_exec_connection、sys.dm_exec_sessions)
- parallel redoモデルでの兆候
- 頻繁で、長時間のread-onlyクエリをセカンダリレプリカのデータベースに実行する必要がある場合
- parallel redoでの兆候
- 頻繁なDIRTY_PAGE_TABLE_LOCK wait
- 性能カウンターで監視できます(SQLServer:Database Replica、Redone Bytes/sec)クエリを実行している時としてない時でredoスループットを比較します。
- parallel redoでの兆候
- 小さなデータセットのデータページにセカンダリレプリカでread-onlyクエリが高頻度でスキャンし、プライマリレプリカで頻繁に同じデータセットに変更を加える。クエリとredoスレッド両方に劇的な性能劣化を与えます
- parallel redoでの兆候
- 大量のDPT_ENTRY_LOCK wait
- 最悪のケースでは、Latch timeoutによりSQL ErrorログにTimeout occurred while waiting for latchと記録されます。
- parallel redoでの兆候
新しいWaitの種類
いくつか紹介されていますが、個人的に興味があるものをピックアップ。
- DPT_ENTRY_LOCK
- ユーザークエリスレッドから追いつくためのREDOがあるdirty page entryへのアクセスを制御するロックがある時に発生します。
- parallel redoワーカースレッドとユーザークエリが同時に同じdirty page entryにredo処理をした時のみ発生します。
補足
SQL Serverの事例として紹介されていますが、Azure SQL Database のgeo replicationを使用してセカンダリデータベースを使用しているケースでも同様の問題が発生します。
P15を使っていると、ジオレプリケーションはparallel redoが採用されているので、ここで紹介されたことと同じ問題が発生するのです。