SQL Server 2017 Distributed Availability Group(DAG)でサービス再起動してもプライマリが切り替わらない原因と対策

Distributed Availability Group(DAG)を構成した環境で「SQL Server サービスを再起動したのにプライマリが切り替わらない」と悩むケースは少なくありません。本記事では、DAGと通常の可用性グループ(AG)の違い、再起動が“障害”として扱われにくい理由、設定で調整できるポイント、そして運用として確実な手順をまとめます。

目次

想定する環境:SQL Server 2017 Enterprise(CU22)+ 2クラスタ + Distributed Availability Group

ここでは、質問のような「2つのWSFCクラスタをDAGで接続している」構成を前提に話を進めます。実際のホスト名やAG名は異なっていても考え方は同じです。

拠点WSFCクラスタノードクラスタ内AG(例)DAGでの位置づけ
DC1DC1クラスタDC1-DB1 / DC1-DB2AG_DC1(ローカルAG)グローバルプライマリ側になり得る
DC2DC2クラスタDC2-DB3 / DC2-DB4AG_DC2(ローカルAG)グローバルセカンダリ側になり得る

問題となっているのは、たとえば DC1-DB1 がプライマリの状態で、管理者が SQL Server サービス(SQL Server (MSSQLSERVER) など)を再起動したところ、DC1-DB2 へ自動でプライマリ移動しないという症状です。

今回の症状を整理:どのレイヤーのフェイルオーバーを期待しているか

まず大事なのは、「切り替わってほしいのは 同一クラスタ内のAG なのか、それとも クラスタを跨ぐDAG なのか」を分けて考えることです。Distributed Availability Group(DAG)は“AGを束ねる仕組み”なので、挙動を混同すると期待がズレやすくなります。

構成要素例(質問の環境)自動フェイルオーバーの前提現実的な運用
同一WSFCクラスタ内のAGDC1-DB1 ⇔ DC1-DB2(AG_DC1)同期コミット + 自動フェイルオーバー設定 + 正常な同期状態条件を満たせば自動も可能。計画停止は手動フェイルオーバーが安全
Distributed AG(クラスタ跨ぎ)AG_DC1 ⇔ AG_DC2(DAG)基本は手動切替が前提(自動DR用途には不向き)DR切替は手順化して実行。定期的な切替訓練が重要

質問文の「DC1-DB1 の SQL Server サービスを再起動したら DC1-DB2 が自動でプライマリになる想定」という期待は、“DC1クラスタ内のAGが自動フェイルオーバーする” という話です。これはDAGそのものの自動切替とは別物です。

結論:DAGは跨拠点の自動切替を狙う仕組みではなく、サービス再起動は“障害”にならないことが多い

結論を先に言うと、次の2点が重なって「切り替わらない」現象が起きやすいです。

  • DAG(別クラスタ間)の切替は基本的に手動という設計思想で、拠点間を自動で入れ替える用途には向きません。
  • 手動のSQL Serverサービス再起動は、WSFCから見ると“計画停止/復帰”として扱われ、フェイルオーバーのトリガーにならないことが多いです(既定の回復動作として「同じノードで再起動」を優先するため)。

そのため「サービスを再起動=必ずプライマリ移動」という期待をそのまま満たすのは難しく、計画作業は“計画フェイルオーバー”として実施するのが現実解になります。どうしても再起動で切り替えたい場合は、後述の FailureConditionLevel などの調整と、十分な事前検証が必要です。

DAGと通常の可用性グループ(AG)の役割の違い

DAGは「WSFCクラスタを跨いでAG同士を接続する」ことで、拠点間レプリケーションやDR構成を作りやすくする仕組みです。一方、自動フェイルオーバーの主戦場はあくまで“同一WSFCクラスタ内のAG”です。

イメージとしては次のように理解すると、運用判断がぶれません。

(DC1 クラスタ)                         (DC2 クラスタ)
DC1-DB1  <=>  DC1-DB2(AG_DC1)         DC2-DB3  <=>  DC2-DB4(AG_DC2)
   |            (クラスタ内は自動も可能)   |            (クラスタ内は自動も可能)
   +------------------ Distributed AG(DAG) ------------------+
                       (クラスタを跨いでAG同士を接続)

この構造上、

  • DC1内の切替(DC1-DB1⇔DC1-DB2)=WSFC+AGの自動フェイルオーバー領域
  • DC1⇔DC2の切替(拠点間)=DAGの切替領域(基本は手動)

という役割分担になります。

なぜ「SQL Serverサービスの手動再起動」でプライマリが切り替わらないのか

“停止”と“障害”は違う:計画停止はフェイルオーバーを起こさない方向に倒れる

WSFC(フェールオーバークラスタリング)は、リソースが問題を起こしたときに「どう回復させるか」を段階的に判断します。多くの環境では、いきなり別ノードに切り替えるよりも、まずは 同じノードで復旧(リソース再起動) を試みる動作が優先されます。

そして、サービス再起動が“管理者の意図した操作”として行われると、クラスタは「一時的に止まったが戻る」ケースとして扱い、結果として ローカルで復帰して役割(プライマリ)が変わらない ことが起こり得ます。

「再起動=障害」とは限らない:クラスタは“復帰できるなら同一ノードで戻す”を優先しやすい

たとえば、DC1-DB1でSQL Serverサービスを再起動すると、AGのリソースは一時的にオンラインではなくなる可能性があります。しかしWSFCは、しきい値や回復ポリシーに従って 同じノードでの復旧 をまず試し、短時間で復帰できると判断すれば、そのまま同一ノードで役割が継続することがあります。

これは“フェイルオーバーが壊れている”というより、回復優先順位が「ローカル復旧」→「別ノードへ移動」になっているためです。特に計画作業(意図した再起動)では、この動きが顕著です。

セカンダリの再起動は、そもそもプライマリ移動の理由にならない

もう1点、質問にある「DC1-DB2を再起動しても役割が変わらない」件は、より直感的です。セカンダリを再起動しても、プライマリは稼働し続けているため、フェイルオーバーを起こす必然性がありません。セカンダリは「追従役」なので、止まってもプライマリの役割は維持されます(むしろ、勝手に入れ替わる方が危険です)。

まず確認したい:同一クラスタ内AGが自動フェイルオーバーできる構成になっているか

“サービス再起動で切り替わらない”現象は、実は そもそもAGが自動フェイルオーバー条件を満たしていない 場合にも起きます。運用の前提として、次のチェックを先に潰すのが近道です。

チェック項目期待値(自動フェイルオーバーしたい場合)よくあるNG確認のヒント
可用性モード同期コミット(Synchronous commit)非同期コミットのままSSMSのAGプロパティ、またはsys.availability_replicas
フェイルオーバーモード自動(Automatic)手動(Manual)のままSSMSのレプリカ設定、またはsys.availability_replicas
同期状態SYNCHRONIZED(同期済み)SYNCHRONIZING/NOT SYNCHRONIZING、SUSPENDEDsys.dm_hadr_database_replica_states
WSFCの健全性クォーラムが安定、ネットワークが健全投票構成が不適切、拠点間回線の揺れクラスタイベントログ、クラスタマネージャーの状態
リスナー/クライアント側MultiSubnetFailover等を含め適切な接続切替後に“つながらない”ため切替が失敗に見える接続文字列、名前解決、DNS TTL

確認用のT-SQL例です(AG名は環境に合わせてください)。

-- レプリカのモード(同期/非同期、自動/手動)を確認
SELECT
  ag.name AS AGName,
  ar.replica_server_name,
  ar.availability_mode_desc,
  ar.failover_mode_desc
FROM sys.availability_groups ag
JOIN sys.availability_replicas ar
  ON ag.group_id = ar.group_id
WHERE ag.name = N'AG_DC1';

-- DB単位の同期状態を確認(SYNCHRONIZED か、SUSPENDED ではないか)
SELECT
DB_NAME(drs.database_id) AS DBName,
drs.synchronization_state_desc,
drs.synchronization_health_desc,
drs.is_suspended
FROM sys.dm_hadr_database_replica_states drs
WHERE drs.group_id = (SELECT group_id FROM sys.availability_groups WHERE name = N'AG_DC1');

ここで 同期コミット+自動フェイルオーバー になっていない場合、「再起動しても切り替わらない」のはむしろ正常です。まずはAGの基本条件を満たすことが最優先になります。

それでも“再起動をトリガーに切り替えたい”なら:FailureConditionLevelを理解する

AGの自動フェイルオーバーは、単に「サービスが止まったら即切替」という単純なものではありません。WSFCはSQL Serverの状態を監視し、どのレベルの異常でフェイルオーバーと判定するかをポリシーとして持っています。その代表が FailureConditionLevel です。

FailureConditionLevelは「どの種類の障害をフェイルオーバー対象として扱うか」を段階的に定義します。既定値は環境によって異なる可能性がありますが、一般的には中間レベル(例:3)が使われることが多いです。

レベルフェイルオーバーを起こしやすさ概念的な対象運用上の注意
1最も限定的SQL Serverがダウンした(稼働していない)と判断できる状態を中心“落ちた時だけ切替”に寄せたい場合。手動再起動が必ず対象になるとは限らない
2やや広い応答不能(ハング)なども含めるイメージ短時間の負荷スパイクで誤検知しないようHealthCheckTimeoutも併せて検討
3既定として採用されやすい重大(クリティカル)なエラー条件を含めるイメージ“安全側”と“可用性”のバランス点になりやすい
4広い中程度のエラー条件まで含めるイメージ過敏にすると不要なフェイルオーバーが増える可能性
5最も広い資格のあるエラー条件を幅広く対象とするイメージ“とにかく切替たい”方向だが、本番では慎重に。検証が必須

重要:FailureConditionLevelを変更しても、「手動のサービス再起動=必ずフェイルオーバー」になるとは限りません。なぜなら、WSFCは“計画停止に見える停止”に対してはローカル復旧を優先したり、停止理由を障害とみなさないケースがあるためです。ここは環境差が出やすいので、変更するなら必ず検証環境で再現テストを行ってください。

関連するパラメータ:HealthCheckTimeoutもセットで考える

もう1つよくセットで語られるのが HealthCheckTimeout です。これは「応答がない状態をどれくらい待ってから異常とみなすか」の閾値です。例えば、瞬間的なI/O待ちやCPUスパイクで一時的に応答が遅れる環境でタイムアウトが短すぎると、誤検知でフェイルオーバーが起きやすくなります。

FailureConditionLevelを敏感側に寄せる場合ほど、HealthCheckTimeout(およびネットワーク/ストレージの健全性)をセットで設計しないと、「可用性のための設定が、逆に不安定化を招く」状態になります。

変更方法:GUI / PowerShell / T-SQL(ただし“やる前に”確認すべきこと)

FailureConditionLevelなどの変更は、主に次の方法で行えます。どの方法を選んでも、最終的にWSFC上のリソースパラメータが意図した値になっているか、そして 両ノードで同じ認識になっているか を確認するのがコツです。

フェールオーバー クラスタ マネージャー(GUI)

  • 対象のロール(可用性グループ)を開き、該当リソースのプロパティを確認
  • ポリシーや詳細パラメータから FailureConditionLevel / HealthCheckTimeout を調整
  • 変更後、イベントログと状態遷移(オンライン/オフライン)を確認

PowerShell(FailoverClusters)

スクリプトで現状把握と変更を行う例です。実際のリソース名は環境に合わせて置き換えてください。

Import-Module FailoverClusters

# まずは現在値を確認

Get-ClusterResource -Name "AG_DC1" | Get-ClusterParameter

# FailureConditionLevel を変更(例:1)

Get-ClusterResource -Name "AG_DC1" |
Set-ClusterParameter -Name "FailureConditionLevel" -Value 1

# HealthCheckTimeout を変更(例:30000ms)

Get-ClusterResource -Name "AG_DC1" |
Set-ClusterParameter -Name "HealthCheckTimeout" -Value 30000

# 変更後に再確認

Get-ClusterResource -Name "AG_DC1" | Get-ClusterParameter

“片側だけ変わっている”ように見える場合、参照しているリソース名が違ったり、AG名とクラスタリソース名が一致していないケースがあります。可用性グループのクラスタリソース(SQL Server Availability Group)に対して操作しているか、必ず確認してください。

T-SQL(ALTER AVAILABILITY GROUP)

AGの設定として変更する例です。こちらも環境により適用可否や権限、瞬断の有無が異なるため、必ず事前検証してください。

ALTER AVAILABILITY GROUP [AG_DC1]
SET (FAILURE_CONDITION_LEVEL = 1);

ALTER AVAILABILITY GROUP [AG_DC1]
SET (HEALTH_CHECK_TIMEOUT = 30000);

“再起動したら切替”を目指す前に知っておきたい、WSFCの回復シーケンス

WSFCはリソース障害を検知したとき、一般に次のような段階で回復を試みます(設定により差があります)。

段階クラスタがやりがちな動き結果として起きること現場での見え方
1同一ノードでリソースを再起動プライマリが“元のノード”に戻る「切り替わらない(でも復旧は早い)」
2一定回数失敗したら別ノードへ移動フェイルオーバーが発生「切り替わった」
3クォーラム喪失などで停止役割自体が維持できない「どちらも上がらない」

つまり、「サービス再起動をした」という行為は、クラスタの目線では 段階1(同一ノードで復帰) に収まりやすく、結果として “プライマリはそのまま” になりがちです。これは「フェイルオーバーが動いていない」というより、回復の優先順位があなたの期待と違う と捉える方が実態に近いです。

運用としての現実解:計画メンテナンスは“計画フェイルオーバー”として手順化する

可用性を高めたい運用で、最も安定するのは「計画作業は計画フェイルオーバー」「障害は自動フェイルオーバー」という住み分けです。特にDAGを使っている環境では、意図しない切替(誤検知フェイルオーバー)のコストが大きいので、計画作業は確実な手順で進めるのが安全です。

おすすめの手順(DC1クラスタ内での計画フェイルオーバー例)

  1. セカンダリ(DC1-DB2)が SYNCHRONIZED であることを確認
  2. アプリ側の接続(リスナー/接続文字列)で切替が吸収できることを確認
  3. SSMSまたはT-SQLで 可用性グループを手動フェイルオーバー
  4. 旧プライマリ(DC1-DB1)側で、パッチ適用・サービス再起動などのメンテナンスを実施
  5. 必要に応じてフェイルバック(戻す)を実施

計画フェイルオーバーのT-SQL例(同期コミットが前提):

-- 実行は“現プライマリ”に接続して行うのが基本
ALTER AVAILABILITY GROUP [AG_DC1] FAILOVER;

「サービス再起動」よりこちらの方が、意図した方向に確実に役割を動かせるため、運用手順として安定します。

DAG(DC1⇔DC2)の切替が自動にならないのは仕様に近い:設計意図と向き不向き

Distributed Availability Group(DAG)は、別のWSFCクラスタをつなぐための仕組みです。別クラスタ間で自動切替を行うと、回線断や名前解決の揺れなどで「両方が自分をプライマリだと思う」ような危険な状況(いわゆるスプリットブレイン)のリスクが上がります。

そのため、DAGは“DR切替は手動”を基本とし、運用側で「いつ・どちらに・どんな条件で切り替えるか」を意思決定できることを重視しています。自動化したい場合も、最終的には監視→判断→実行という流れを手順化(あるいはオーケストレーション)して、勝手に切り替わらないことを前提に設計した方が事故が減ります。

DAG切替を手順化する際のポイント

  • 切替判断の基準を明文化する(例:DC1拠点の停止、RPO/RTO、回線断時の方針)
  • データ遅延(ログ送信の遅れ)を確認する観点を入れる
  • 切替後に必要な作業(接続先変更、DNS、ジョブ、バックアップ方針など)を洗い出す
  • 訓練(DRリハーサル)を定期的に行い、手順の陳腐化を防ぐ

DAGのフェイルオーバーは、状況によってはデータロス許容の強制切替コマンドが絡むこともあります。ここは環境の要件(RPO/RTO)と密接なので、本番でいきなり実行せず、必ず検証環境と手順書で固めてください。

「切り替わらない」を最短で解決するためのチェック順(実務向け)

現場での切り分けは、次の順番で進めると迷いが減ります。

  1. 期待している切替が“DC1内AG”なのか“DC1⇔DC2のDAG”なのかを明確化
  2. DC1内AGが自動フェイルオーバー要件(同期コミット+自動フェイルオーバー+同期済み)を満たすか確認
  3. 手動サービス再起動時に、WSFCがリソースを「同一ノードで復帰」させていないか、クラスタログ/イベントで確認
  4. “再起動も障害扱いに寄せたい”要件が本当に必要か再検討(誤検知リスクとトレードオフ)
  5. 必要ならFailureConditionLevel/HealthCheckTimeoutを検証環境で調整し、想定通りの挙動になるかテスト
  6. 計画作業は計画フェイルオーバーに統一し、DAG切替は手順化する

よくある落とし穴:設定は合っているのに“切り替わったように見えない”パターン

  • クライアント接続がリスナー経由ではなく固定サーバ名:切替してもアプリが追従しない
  • DNSやTTL、MultiSubnetFailoverの未設定:切替後の再接続が遅く、障害が長引いたように見える
  • 同期状態が不十分:SYNCHRONIZEDではなく、フェイルオーバーがブロックされる
  • セカンダリでデータベースがSUSPENDED:意図せず同期が止まっている
  • フェイルオーバー対象のレプリカが2台以上あるのに、優先順位/所有者が想定と違う:思ったノードに移らない
  • “切替”ではなく“ローカル再起動”で復帰している:結果としてプライマリが同じノードのまま

まとめ:DAGの誤解をほどき、確実な可用性設計に寄せる

Distributed Availability Group(DAG)は、拠点間でAG同士を接続できる強力な仕組みですが、「サービス再起動したら自動で役割が入れ替わる」ことを期待するとハマりやすい領域でもあります。

  • DAGの切替(拠点間)は基本手動で、運用手順として固めるのが安全
  • 同一クラスタ内のAGは条件を満たせば自動フェイルオーバー可能だが、手動再起動は障害扱いにならないことが多い
  • どうしても寄せたい場合はFailureConditionLevel/HealthCheckTimeoutを含め、誤検知リスクとセットで設計する
  • 計画作業は計画フェイルオーバーを標準手順にするのが、最も安定してトラブルが少ない

「仕様なのか、設定不足なのか」で迷ったときは、まず “どのレイヤーの切替を期待しているか” を切り分けるところから始めると、最短で正しい打ち手にたどり着けます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次