はじめに
こんにちは!NTTテクノクロスの柚木です。普段はコンテンツ配信サービスの開発を担当しています。
この記事では、AWS EC2上にSQL ServerのAlways On可用性グループによる冗長化構成を構築する際に私が遭遇した問題とその解決方法について共有します!
特に以下のような課題に直面している方の参考になればと思います!
- AWS環境において、別環境からコピーしたDBサーバを利用した冗長化構成の構築方法
システム構成の概要
環境
- IaaS: AWS EC2
- OS: Windows Server
- データベース: SQL Server Standard Edition
- クラスタリング: WSFC (Windows Server Failover Clustering)
- 冗長化: Always On可用性グループ
構成要素
- プライマリDB: DB1
- セカンダリDB: DB2
- ファイル共有サーバー: file-server(クォーラム監視用)
- 可用性グループ: failover-group
- WSFCクラスター: failover-cluster
- リスナー: listener
ネットワーク構成
- VPC内のプライベートサブネット(マルチAZ構成)
- Active Directory統合
- 各DBサーバーにセカンダリIPを2つ付与(クラスターでの冗長化用)
構築手順の流れ
標準的な構築手順は以下の通りです:
- EC2インスタンスの起動(DB1、DB2、file-server)
- OS初期設定
- Active Directoryツールのインストール
- SQL Serverサービスアカウントの作成
- WSFCの構成
- ファイル共有監視の追加
- SQL Serverの初期設定
- Always On可用性グループの初期設定
- 可用性グループの作成
本記事では、この手順の中で遭遇した問題と解決方法を、構築フェーズごとに解説します。
問題と解決方法
構築フェーズ1: WSFCクラスター構築時の問題
問題1-1: ノードが相互に参照できない
症状
- DB1からクラスター作成時、DB2が参照できない
- DB2は「既に別クラスターに参加している」と表示される
- ホスト名での登録ができない(IPアドレスでは登録可能)
原因
- DNSサフィックスとDNSサーバーの設定が不適切であった
- DNS解決が正しく行われていなかった
- 旧クラスター情報が残存していた
解決方法
Step 1: DNSサフィックスの設定変更
- ネットワーク接続を開く
- 対象のイーサネットアダプタを選択
- プロパティ → インターネットプロトコルバージョン4 → 詳細設定
- DNSタブで「以下のDNSサフィックスを順に追加する」に正しいドメインを設定
例: ad.example.local
Step 2: DNS設定の修正
- DNSマネージャーを開く
- 前方参照ゾーン → 対象ドメインを開く
- DNS解決していないサーバーのレコードを確認
- IPアドレスを正しいものに変更
Step 3: IPアドレスでの登録
ホスト名での登録ができない場合、一時的にIPアドレスで直接登録する。
Step 4: 静的IPアドレスの付与
EC2のネットワークインターフェイスで静的IPを設定:
- DB1:
10.0.x.101,10.0.x.102(サブネットに応じて変更) - DB2:
10.0.y.101,10.0.y.102(サブネットに応じて変更)
まとめ
- 上記を実施することでクラスター作成時に冗長先のサーバも参照できるようになる
構築フェーズ2: SQL Server初期設定時の問題
問題2-1: ドメインユーザー削除時のエラー
症状
Active Directoryに所属しているドメインユーザーを削除しようとすると、SQL Server関連のオブジェクトが所有者となっているためエラーが発生し、削除できなくなる。
発生タイミング
- 冗長化構築後の環境整理時
- Active Directoryに所属している不要なアカウントの削除時
解決方法
削除対象ユーザーが所有するSQL Serverオブジェクトを、他のユーザー(通常はsa)に譲渡する必要がある。
Step 1: エンドポイントの所有者変更
- 削除対象ユーザーが所有するエンドポイントを確認
SELECT e.name
FROM sys.endpoints AS e
JOIN sys.server_principals AS p ON e.principal_id = p.principal_id
WHERE p.name = 'DOMAIN\TargetUser'; -- 実際のドメイン\ユーザー名に置き換え
- エンドポイントの所有者を変更
ALTER AUTHORIZATION ON ENDPOINT::[エンドポイント名] TO sa;
- 変更確認
SELECT e.name AS endpoint_name,
p.name AS owner_name
FROM sys.endpoints e
JOIN sys.server_principals p ON e.principal_id = p.principal_id
WHERE e.name = '[エンドポイント名]';
Step 2: 可用性グループからの離脱
- 所属している可用性グループを確認
SELECT
ag.name AS AvailabilityGroupName,
ar.replica_server_name AS ReplicaServerName,
ar.endpoint_url AS EndpointUrl
FROM
sys.availability_groups AS ag
JOIN
sys.availability_replicas AS ar ON ag.group_id = ar.group_id;
- 可用性グループから離脱(必要な場合のみ)
DROP AVAILABILITY GROUP [failover-group];
Step 3: ジョブの所有者変更
- 所有しているジョブを確認
USE msdb;
GO
SELECT
sj.job_id,
sj.name AS JobName,
sl.name AS OwnerName
FROM
sysjobs AS sj
JOIN
syslogins AS sl ON sj.owner_sid = sl.sid
WHERE
sl.name = 'DOMAIN\TargetUser'; -- 削除対象ユーザー名
- ジョブを譲渡(所有している数だけ実行)
USE msdb;
GO
EXEC sp_update_job
@job_name = 'JobName', -- ジョブ名
@owner_login_name = 'sa'; -- 新しい所有者
- すべてのオブジェクトを譲渡後、ユーザー削除を再試行する
まとめ
- 所有しているジョブを譲渡することで対象のユーザの削除が可能となる。
※新たに同じ役割を持つユーザを作成した場合は、ジョブを適したユーザに譲渡しなおすことを忘れないこと。
構築手順フェーズ3: Always On可用性グループ作成時の問題
問題3-1: 可用性グループウィザードが開かない
症状
可用性グループを新規作成する際に、エラーが出力されウィザードが開かない。
原因
別環境からコピーしたサーバのため、Always Onの設定が元環境の情報を参照していた。
解決方法
SQL Server構成マネージャーでAlways On設定をリセット:
- SQL Server構成マネージャーを起動
- SQL Server (MSSQLSERVER) のプロパティを開く
- 「AlwaysOn 高可用性」タブで「Always On 可用性グループを有効にする」のチェックをOFF
- OKをクリックし、SQL Serverサービスを再起動
- 再度プロパティを開き、「Always On 可用性グループを有効にする」のチェックをON
- OKをクリックし、SQL Serverサービスを再起動
ポイント
- 単なる再起動ではなく、一度無効化してから有効化することが重要である
- 別環境からコピーした場合は必ずこの手順を実施する
問題3-2: セカンダリでデータベースが既に存在するエラー
症状
可用性グループ作成ウィザードで「セカンダリレプリカに既にデータベースが存在する」というエラーが表示される。
原因
別環境からコピーしたため、セカンダリサーバー(DB2)に既に同名のデータベースが存在している。
解決方法
- セカンダリサーバー(DB2)のSQL Serverサービスを停止
- データファイルの名前を変更
※InstallDirectory内は適宜自分の環境に置き換えてください。<InstallDirectory>\DatabaseName.mdf → DatabaseName_old.mdf に変更 <InstallDirectory>\DatabaseName_log.ldf → DatabaseName_log_old.ldf に変更 - SQL Serverサービスを起動
- 可用性グループ作成ウィザードを再実行
注意
- ファイル名は実際のデータベース名に置き換えること
- 変更前にバックアップを取得することを推奨
構築手順フェーズ4: 別環境からコピーした場合の特有の問題
問題4-1: Quartzジョブスケジューラの重複エラー
症状
- アプリケーションログにFatalエラーが出力される
- 別環境からコピーしたDBサーバで発生
- アプリケーション起動時にジョブ登録エラー
原因
Quartzジョブスケジューラで、既に登録済みのジョブを再登録しようとして失敗。別環境からコピーしたDBには既にジョブが登録されていたため、ジョブ登録スケジューラ起動時に重複が発生した。
重要: この問題は別環境からコピーした場合のみ発生する。
解決方法
Step 1: 既存ジョブの確認
対象のデータベースを選択し、以下のSQLを実行:
SELECT * FROM QRTZ_JOB_DETAILS
WHERE JOB_NAME = 'TargetJobName' -- 実際のジョブ名に置き換え
AND JOB_GROUP = 'DEFAULT';
Step 2: 既存ジョブの削除
-- トリガーを削除
DELETE FROM QRTZ_TRIGGERS
WHERE JOB_NAME = 'TargetJobName'
AND JOB_GROUP = 'DEFAULT';
-- ジョブ詳細を削除
DELETE FROM QRTZ_JOB_DETAILS
WHERE JOB_NAME = 'TargetJobName'
AND JOB_GROUP = 'DEFAULT';
Step 3: ジョブの再登録
-- ジョブ詳細を登録
INSERT INTO QRTZ_JOB_DETAILS (
SCHED_NAME, JOB_NAME, JOB_GROUP, DESCRIPTION,
JOB_CLASS_NAME, IS_DURABLE, IS_NONCONCURRENT,
IS_UPDATE_DATA, REQUESTS_RECOVERY, JOB_DATA
)
VALUES (
'SchedulerName',
'TargetJobName',
'DEFAULT',
NULL,
'YourNamespace.Jobs.TargetJobName, YourAssembly', -- 実際のクラス名に置き換え
0, 1, 0, 0, NULL
);
-- トリガーを登録
INSERT INTO QRTZ_TRIGGERS (
SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, JOB_NAME,
JOB_GROUP, DESCRIPTION, NEXT_FIRE_TIME, PREV_FIRE_TIME,
PRIORITY, TRIGGER_STATE, TRIGGER_TYPE, START_TIME,
END_TIME, CALENDAR_NAME, MISFIRE_INSTR, JOB_DATA
)
VALUES (
'SchedulerName',
'TargetTriggerName',
'DEFAULT',
'TargetJobName',
'DEFAULT',
NULL, NULL, NULL, NULL,
'WAITING', 'SIMPLE', GETDATE(), NULL, NULL, 0, NULL
);
Step 4: トリガー情報の修正
-- 現在の日時をUnixタイムスタンプに変換して設定
UPDATE QRTZ_TRIGGERS
SET NEXT_FIRE_TIME = CONVERT(BIGINT, DATEDIFF(SECOND, '1970-01-01', GETDATE())) * 1000,
TRIGGER_STATE = 'WAITING'
WHERE JOB_NAME = 'TargetJobName'
AND JOB_GROUP = 'DEFAULT';
Step 5: NULL値の確認と修正
-- NULL値の確認
SELECT *
FROM QRTZ_TRIGGERS
WHERE NEXT_FIRE_TIME IS NULL OR PREV_FIRE_TIME IS NULL;
-- NULL値の修正
UPDATE QRTZ_TRIGGERS
SET
PREV_FIRE_TIME = COALESCE(PREV_FIRE_TIME,
CONVERT(BIGINT, DATEDIFF(SECOND, '1970-01-01', GETDATE())) * 1000),
PRIORITY = COALESCE(PRIORITY, 5)
WHERE
SCHED_NAME = 'SchedulerName'
AND TRIGGER_NAME = 'TargetTriggerName'
AND TRIGGER_GROUP = 'DEFAULT'
AND (PREV_FIRE_TIME IS NULL OR PRIORITY IS NULL);
Step 6: SIMPLE_TRIGGERSテーブルへの登録
INSERT INTO QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP,
REPEAT_COUNT, REPEAT_INTERVAL, TIMES_TRIGGERED
)
VALUES (
'SchedulerName',
'TargetTriggerName',
'DEFAULT',
0, -- 繰り返し回数(0は繰り返しなし)
60000, -- 繰り返し間隔(ミリ秒)例: 60000 = 1分
0 -- トリガー実行回数
);
Step 7: 動作確認
- アプリケーションを再起動する
- ログにFatalエラーが出力されないことを確認する
- ジョブが正常にスケジュールされていることを確認する
学んだこと・Tips
1. 別環境からのサーバコピー時の必須作業
別環境からDBサーバをコピーする場合、以下を必ずリセット・再設定してください:
必須リセット項目
- Always On可用性グループの設定(無効化→有効化)
- Quartzなどのジョブスケジューラの登録情報
- ドメイン参加情報(DNS設定含む)
- 既存データベースファイルの退避
2. トラブルシューティングの参考フロー
問題発生時は以下の順序で確認:
-
ログの確認
- アプリケーションログ
- SQL Serverエラーログ
- Windowsイベントログ(システム、アプリケーション)
- クラスターログ
-
段階的な切り分け
- ネットワーク疎通(ping)
- DNS解決(nslookup)
- クラスター状態の確認
- SQL Server接続の確認
-
IPアドレスでの疎通確認
- ホスト名で接続できない場合、まずIPアドレスで試す
- DNS問題かアプリケーション問題かを切り分け
3. AWS特有の注意点
静的IPの設定
- WSFCではEC2のネットワークインターフェイスで静的IPを明示的に設定
- セカンダリIPを2つ付与(クラスター用、リスナー用)
4. バックアップ
構築作業中は各フェーズでバックアップを取得:
- AMI作成(OS・SQL Server設定完了時)
- データベース完全バックアップ(可用性グループ作成前)
まとめ
AWS上でSQL Server Always Onによる冗長化構成を構築する際、特に別環境からコピーしたサーバを使用する場合は、様々な設定のリセットや調整が必要になる。
本記事で紹介した問題と解決方法が、同様の構成を構築される方の参考になればうれしいです!