web-dev-qa-db-ja.com

プライマリで一時的に時間がかかる読み取り専用レプリカでの長時間実行クエリ

私は次のように4ノードAGセットアップを持っています。

すべてのノードのVMハードウェア構成:

  • Microsoft SQL Server 2017 Enterprise Edition(RTM-CU14)(KB4484710)
  • 16個のvCPU
  • 356 GB RAM(これについての長い話...)
  • 最大並列度:1(アプリベンダーの要求に応じて)
  • 並列処理のコストしきい値:50
  • 最大サーバーメモリ(MB):338944(331 GB)

AG設定:

  • ノード1:プライマリまたは同期コミット読み取り不可セカンダリ、自動フェイルオーバー用に構成
  • ノード2:プライマリまたは同期コミット、読み取り不可のセカンダリ、自動フェイルオーバー用に構成
  • ノード3:読み取り可能なセカンダリセット、非同期コミット、手動フェイルオーバー用に構成
  • ノード4:非同期コミットを使用した読み取り可能なセカンダリセット、手動フェイルオーバー用に構成

問題のクエリ:

このクエリについては、まったくおかしなことは何もありません。アプリケーション内のさまざまなキューにある未解決の作業項目の概要を提供します。以下の実行プランのリンクの1つからコードを確認できます。

プライマリノードでの実行動作:

プライマリノードで実行した場合、実行時間は通常約1秒です。これが 実行計画 であり、以下はSTATISTICS IOおよびプライマリノードからのSTATISTICS TIMEから取得された統計です。

(347 rows affected)
Table 'Worktable'. Scan count 647, logical reads 2491, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'workitemlc'. Scan count 300, logical reads 7125, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulertask'. Scan count 1, logical reads 29, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'wfschedulertask'. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerservice'. Scan count 1, logical reads 12, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerworkerpool'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'itemlc'. Scan count 1, logical reads 26372, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 500 ms,  elapsed time = 656 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

読み取り専用セカンダリノードでの実行動作:

読み取り専用のセカンダリNode(つまりNode 3またはNode 4)のいずれか)で実行する場合、このクエリは同じ 実行プラン (これは別のプランリンクです)とほぼ同じ実行統計が表示されます(たとえば、これらの結果は常に変化するため、さらにいくつかのページスキャンがある可能性があります)が、CPU時間は例外です、それらは非常によく似ています。読み取り専用のセカンダリノードからSTATISTICS IOおよびSTATISTICS TIMEから取得された統計は次のとおりです。

(347 rows affected)
Table 'Worktable'. Scan count 647, logical reads 2491, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'workitemlc'. Scan count 300, logical reads 7125, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulertask'. Scan count 1, logical reads 29, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'wfschedulertask'. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerservice'. Scan count 1, logical reads 12, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerworkerpool'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'itemlc'. Scan count 1, logical reads 26372, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 55719 ms,  elapsed time = 56335 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

その他の詳細:

このクエリの実行中に、セカンダリで sp_WhoIsActive および Paul RandalのWaitingTasks.sql スクリプトも実行しましたが、待機していません率直にイライラする、これまでにないことの発生:

enter image description here

同期ステータスは実際には非常に良好であるため、これはAGレイテンシの場合にも見えません。

--https://sqlperformance.com/2015/08/monitoring/availability-group-replica-sync

SELECT 
       ar.replica_server_name, 
       adc.database_name, 
       ag.name AS ag_name, 
       drs.is_local, 
       drs.synchronization_state_desc, 
       drs.synchronization_health_desc, 
       --drs.last_hardened_lsn, 
       --drs.last_hardened_time, 
       drs.last_redone_time, 
       drs.redo_queue_size, 
       drs.redo_rate, 
       (drs.redo_queue_size / drs.redo_rate) / 60.0 AS est_redo_completion_time_min,
       drs.last_commit_lsn, 
       drs.last_commit_time
FROM sys.dm_hadr_database_replica_states AS drs
INNER JOIN sys.availability_databases_cluster AS adc 
       ON drs.group_id = adc.group_id AND 
       drs.group_database_id = adc.group_database_id
INNER JOIN sys.availability_groups AS ag
       ON ag.group_id = drs.group_id
INNER JOIN sys.availability_replicas AS ar 
       ON drs.group_id = ar.group_id AND 
       drs.replica_id = ar.replica_id
ORDER BY 
       ag.name, 
       ar.replica_server_name, 
       adc.database_name;

enter image description here

このクエリは最悪の犯罪者のようです。プライマリで1秒未満かかる他のクエリNodeセカンダリノードで1〜5秒かかる場合があります。動作はそれほど深刻ではありませんが、問題を引き起こしているようです。

最後に、サーバーも調べて、A/Vスキャンなどの外部プロセス、予期しないI/Oを生成する外部ジョブなどをチェックして、手ぶらで空になりました。これは、SQL Serverプロセス以外の原因が原因ではないと思います。

質問:

私がいるのは正午だけで、すでに長い日だったので、ここで明らかな何かを見逃しているのではないかと思います。それか、設定に誤りがあります。これは、この環境に関連するベンダーとMSへの呼び出しが何度もあったために発生する可能性があります。

私の調査のすべてについて、私はこのパフォーマンスの違いを引き起こしているものを見つけることができないようです。セカンダリノードで何らかの待機が発生することを期待しますが、何も発生しません。これをトラブルシューティングして根本的な原因を特定するにはどうすればよいですか?誰かが以前にこの動作を見て、それを解決する方法を見つけましたか?

UPDATE#13番目のノード(読み取り専用レプリカの1つ)の状態を読み取り不可に交換してから、テストとして読み取り可能に戻した後、そのレプリカは、開いているトランザクションによってまだ保留されており、クライアントクエリは HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING 待機を表示しています。

DBCC OPENTRANコマンドを実行すると、次の結果が得られます。

Oldest active transaction:
    SPID (server process ID): 420s
    UID (user ID) : -1
    Name          : QDS nested transaction
    LSN           : (941189:33148:8)
    Start time    : May  7 2019 12:54:06:753PM
    SID           : 0x0
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

このSPIDをsp_who2で検索すると、QUERY STORE BACKがコマンドとしてリストされているBACKGROUNDプロセスとして表示されます。

TLogバックアップはできますが、 この解決されたバグ の同様の機能が実行されていると思われるため、MSでチケットを開く予定です今日この特定の問題について。

そのチケットの結果に応じて、Joeの提案に従ってコールスタックトレースをキャプチャして、どこに行くかを確認します。

最終更新(問題の自己解決)

(上記のように)開いているクエリストアトランザクションの52時間のマークを超えた後、AGは自動的にフェールオーバーすることを決定しました。これが発生する前に、追加のメトリックをいくつか取得しました。 Seanが提供する this link によると、問題のデータベースには、このデータベース専用の非常に大きなバージョンストアがありました。具体的には、ある時点で、reserved_page_countフィールドに1651360ページを記録し、 reserved_space_kb値。

ERRORLOGごとに、QDS base transactionおよびQDS nested transactionトランザクションに関連するトランザクション強化の障害が5分間発生した後、フェイルオーバーが発生しました。

私の場合、フェイルオーバーによって約10分の停止が発生しました。データベースのサイズは〜6TBであり、非常にアクティブであるため、実際にはかなり良いと思いました。この間、新しいプライマリノードはオンラインでしたが、すべてが QDS_LOADDB 待機タイプで待機していたため、クライアントクエリは完了できませんでした。

フェイルオーバー後、バージョンストア番号はreserved_page_countでは176、reserved_space_kbでは1408に減少しました。セカンダリ読み取り専用レプリカに対するクエリも、プライマリから実行された場合と同じくらい迅速に実行され始めたため、フェイルオーバーの結果、動作が完全に消えたように見えます。

8
John Eisbrener

バージョンストアであることが100%確実ではないため、この回答はジョーの回答に追加されていますが、問題の一部であることを示唆する証拠はこれまでにありません。

セカンダリレプリカが読み取り可能としてマークされている場合、バージョン情報の安定した状態を最初に取得して、セカンダリでのすべての読み取り操作の既知の適切な開始点を取得する必要があります。これが移行を待機していて、プライマリでまだ開いているトランザクションがある場合、これはHADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONINGはまた、プライマリがかなりの量のデータチャーンを経験している(または少なくとも誰かが本当に長いトランザクションを開いているが、これも良くない)ことを示す良い指標でもあります。トランザクションが開いている時間が長く、データの変更が多いほど、より多くのバージョン管理が行われます。

セカンダリレプリカは、セッションのカバーの下でスナップショットアイソレーションを使用して読み取り可能なステータスを実現します。ただし、セッション情報を確認すると、コミットされたデフォルトの読み取りで表示されます。スナップショットの分離は楽観的であり、バージョンストアを使用するため、すべての変更をバージョン管理する必要があります。これは、プライマリでデータのチャーンが高いときに、セカンダリで実行中のクエリ(および実行時間が長くなる可能性がある)が多い場合に悪化します。一般に、これはOLTPシステムのいくつかのテーブルでのみ現れますが、アプリケーションとワークロードに完全に依存しています。

バージョンストア自体は世代ごとに測定され、バージョンストアの使用を必要とするクエリが実行されると、バージョン管理レコードポインターがその行のTempDBチェーンを指すために使用されます。チェーンと言います。これはその行のバージョンのリストであり、トランザクションの開始タイムスタンプに基づいて適切なバージョンを見つけるためにチェーン全体を順番に調べて、結果がその時点のデータと一致するようにする必要があるためです。

プライマリレプリカとセカンダリレプリカで長時間実行されているトランザクションが原因で、バージョンストアにこれらの行の世代が多数ある場合、他のすべてのアイテムがまったく同じように見える一方で、クエリの実行に平均より長い時間がかかり、通常はより高いCPUの形になります。 -実行計画、統計、返される行など。チェーンのウォークはほぼ純粋にCPU操作であるため、チェーンが非常に長くなり、返される行の量が非常に多い場合、(線形ではありませんが、クエリの時間を増やすことができます)。

実行できる唯一のことは、プライマリとセカンダリの両方でトランザクションの長さを制限して、バージョンストアがTempDBで大きくなりすぎないようにし、世代が多くならないようにすることです。バージョンストアのクリーンアップは約1分に1回行われますが、クリーンアップでは、同じ世代のすべてのバージョンを削除してから削除する必要があり、最も古いバージョンが不要になるまで将来のすべてのバージョンをクリーンアップできません。したがって、クエリが長時間実行されると、多くの未使用の世代を効果的にクリーンアップできなくなる可能性があります。

レプリカを読み取り可能モードに切り替えたり、読み取り可能モードから切り替えたりすると、バージョンストアが読み取り不可能になるため、バージョンストアも消去されます。

他にもプレイできるアイテムは他にもありますが、現在のデータとレプリカの反応を考えると、これが最ももっともらしいようです。

TempDBバージョン管理DMV (ADRバージョン管理と混同しないでください)。

9
Sean Gallardy

免責事項:可用性グループについては何も知りませんが、必要以上にCPUを使用しているように見えるクエリのトラブルシューティングについては少し知っています。

CPUの使用量が多すぎるという問題があります。待機について言うべき重要なことの1つは、待機のほとんどすべてがCPUビジーではないことです。ワーカーが待機状態になると、ワーカーは解放され、SQLOSのスケジューラで実行されなくなります。したがって、次の実行統計を含むMAXDOP 1クエリがあるとします。

CPU時間= 55719 ms、経過時間= 56335 ms。

クエリのCPU使用率がほぼ99%に達します。そのクエリに意味のある待機統計が必要なのはなぜですか?外部待機やプリエンプティブ待機など、CPUのビジー待機がある場合に表示されることがありますが、それも保証されていません。要するに、ここでは待機統計はそれほど役に立たない可能性があるということです。

大まかな順序で確認することがいくつかあります(順序は環境についての知識に依存します)。

  • セカンダリサーバーには、拡張イベント、トレース、プロファイリングなどの高価な監視が行われていますか?
  • セカンダリサーバーのハードウェアはプライマリとほぼ同じですか?
  • セカンダリサーバーに構成またはソフトウェアの問題はありますか?
  • 重要な待機またはラッチはありますか?クエリに適用できない場合がありますが、それでも手掛かりが得られる場合があります。
  • 重要なスピンロックはありますか?
  • 手がかりを与える可能性のある他のDMVまたはSQL Server内で確認できるものはありますか?可用性グループが問題の重要な部分である可能性が高いとおっしゃいました。
  • ETWトレースは何を教えてくれますか?
  • どのようなサポート契約がありますか?

上記のほとんどは、さまざまなブログ投稿とドキュメントで十分にカバーされていますが、ETWトレースについて詳しく説明します。 SQL Serverが特定のクエリに大量のCPUを使用している理由を知りたい場合、およびホストにアクセスできる場合は、常にETWトレースを実行して、コールスタックを表示し、さまざまなコールスタックが実行しているCPUの量を確認できます。言い換えれば、ホストOSは、質問する方法を知っていれば、どのCPUが使用されているかを喜んで教えてくれます。 ETWトレースを行う一般的な方法には、 Windows Performance Recorder および PerfView があります。

これらの結果を理解するには、内部に関する深い知識が必要であり、間違った結論にたどり着きやすいです。多くの場合、生データを収集し、専門家にそれを確認するよう依頼するのが最善です。トレースを実行するときは、SQL Serverで実行するアクティビティをできるだけ少なくします。以下に、ETWトレースを使用してSQL Serverに関する結論を導き出す、いくつかの回答を示します。

あなたの場合、45秒のクエリの実行中にコールスタックを収集できれば、問題の性質について非常に役立つ手掛かりが得られると思います。

8
Joe Obbish

問題が自己解決したので、私はその原因を推測する必要があります(意図的なリズムではありません)。 Seanの投稿と、開いているQuery Storeトランザクションがバージョンストアサイズの増加の根本的な原因であるとの事実(例:HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING待機)、私は、クエリストアが提示された動作に関与していたとしか想定できません。このデータベースは大きく(〜6TB)、かなりアクティブであり、データベースにヒットするクエリの大部分はクライアントで生成され、パラメーター化されていません(つまり、アドホッククエリ)。このシナリオでは多くの用途があります。そのため、今後のメンテナンスウィンドウでこの環境のクエリストアを無効にします。その後、この動作は再び発生しないと思います。

マイクロソフトでチケットをオープンしましたが、PSSDIAGトレースなどを介して詳細な分析を行う前に問題が解決されたため、タイミングは好ましくありませんでした。これが私たちが遭遇したバグである場合、ローカライズされたテストをいくつか実行し、この問題を再現できることを期待しています。さらに恒久的な解決策に関する更新が確認された場合は、この回答も必ず更新します。

5
John Eisbrener