@shinyaz

Aurora Blue/Green 実践検証 — AWS JDBC Driver プラグインでゼロダウンタイムに迫る

目次

はじめに

前回の記事では、Aurora PostgreSQL の Blue/Green Switchover 中に psql で26秒・6回の接続失敗を観測した。DNS TTL 60秒がダウンタイムの主要因であることも確認した。

AWS の公式ブログでは、AWS JDBC Driver の Blue/Green プラグインを使うことで「ほぼゼロダウンタイム」を実現できるとしている。しかし、多くの Java アプリケーションは HikariCP などのコネクションプールを使っており、「リトライロジックを入れれば十分では?」という疑問がある。

本記事では、同一の Blue/Green Switchover に対して以下の3パターンを同時に実行し、ダウンタイムを比較する。

  1. Plain JDBC(リトライなし)— ベースライン
  2. HikariCP + アプリ側リトライ(3回リトライ、1秒バックオフ)— 多くの現場の現状
  3. AWS JDBC Driver Blue/Green プラグイン — 公式推奨

検証環境

項目
リージョンap-northeast-1(東京)
エンジンAurora PostgreSQL 16.9(Blue)→ 17.6(Green)
インスタンスクラスdb.r6g.large
構成Writer × 1 + Reader × 1
VPCデフォルト VPC(3 AZ)
JavaOpenJDK 21
PostgreSQL JDBC42.7.5
AWS JDBC Wrapper2.6.4
HikariCP6.2.1
接続テスト間隔1秒(SELECT inet_server_addr() を400回実行)

前提条件:

  • AWS CLI セットアップ済み(rds:*ec2:* の操作権限)
  • Java 21 + Maven

結果だけ知りたい場合は まとめ にスキップできる。

テストアプリケーション

3パターンを1つの Java アプリにまとめた。各パターンは1秒間隔で400回クエリを実行し、タイムスタンプ・成功/失敗・レイテンシ・接続先 IP を CSV 形式で出力する。

pom.xml
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>bgtest</groupId>
    <artifactId>bg-switchover-test</artifactId>
    <version>1.0</version>
    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.7.5</version>
        </dependency>
        <dependency>
            <groupId>software.amazon.jdbc</groupId>
            <artifactId>aws-advanced-jdbc-wrapper</artifactId>
            <version>2.6.4</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>6.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.16</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.16</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.4.2</version>
                <configuration>
                    <archive><manifest><mainClass>bgtest.SwitchoverTest</mainClass></manifest></archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.8.1</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals><goal>copy-dependencies</goal></goals>
                        <configuration><outputDirectory>${project.build.directory}/lib</outputDirectory></configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Pattern 1: Plain JDBC

毎回新しい接続を作成し、リトライなしでクエリを実行する。最もシンプルな構成だ。

Plain JDBC(核心部分)
String url = "jdbc:postgresql://" + endpoint + ":5432/postgres"
        + "?connectTimeout=3&socketTimeout=3";
try (Connection conn = DriverManager.getConnection(url, "postgres", password);
     Statement stmt = conn.createStatement();
     ResultSet rs = stmt.executeQuery("SELECT inet_server_addr()::text")) {
    // success
} catch (Exception e) {
    // fail — no retry
}

Pattern 2: HikariCP + リトライ

コネクションプール経由で接続し、失敗時は最大3回リトライ(1秒バックオフ)する。多くの本番アプリケーションに近い構成だ。

HikariCP + リトライ(核心部分)
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://" + endpoint + ":5432/postgres");
config.setMaximumPoolSize(5);
config.setConnectionTimeout(3000);
HikariDataSource ds = new HikariDataSource(config);
 
for (int attempt = 1; attempt <= 3; attempt++) {
    try (Connection conn = ds.getConnection();
         Statement stmt = conn.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT inet_server_addr()::text")) {
        // success — break
    } catch (Exception e) {
        if (attempt == 3) { /* fail */ }
        else { Thread.sleep(1000); }
    }
}

Pattern 3: AWS JDBC Driver Blue/Green プラグイン

AWS JDBC Wrapper の bg プラグインを有効にする。接続 URL を jdbc:aws-wrapper:postgresql:// に変更し、プラグインパラメータを設定するだけだ。

AWS JDBC Wrapper BG プラグイン(核心部分)
String url = "jdbc:aws-wrapper:postgresql://" + endpoint + ":5432/postgres";
Properties props = new Properties();
props.setProperty("user", "postgres");
props.setProperty("password", password);
props.setProperty("wrapperPlugins", "bg,failover2,efm2");
props.setProperty("bgdId", "bg-test-demo");
props.setProperty("bgSwitchoverTimeoutMs", "600000");
 
try (Connection conn = DriverManager.getConnection(url, props);
     Statement stmt = conn.createStatement();
     ResultSet rs = stmt.executeQuery("SELECT inet_server_addr()::text")) {
    // success — plugin handles routing automatically
}
SwitchoverTest.java(テストアプリ全体)
SwitchoverTest.java
package bgtest;
 
import java.sql.*;
import java.time.Instant;
import java.time.Duration;
import java.util.Properties;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
 
public class SwitchoverTest {
    static final int CONNECT_TIMEOUT_SEC = 3;
    static final int QUERY_TIMEOUT_SEC = 3;
 
    public static void main(String[] args) throws Exception {
        if (args.length < 3) {
            System.err.println("Usage: SwitchoverTest <plain|hikari|wrapper> <endpoint> <password> [intervalMs] [maxQueries]");
            System.exit(1);
        }
        String mode = args[0], endpoint = args[1], password = args[2];
        int intervalMs = args.length > 3 ? Integer.parseInt(args[3]) : 1000;
        int maxQueries = args.length > 4 ? Integer.parseInt(args[4]) : 400;
 
        System.out.println("timestamp,query_num,status,latency_ms,server_ip,error");
 
        switch (mode) {
            case "plain"   -> runPlain(endpoint, password, intervalMs, maxQueries);
            case "hikari"  -> runHikari(endpoint, password, intervalMs, maxQueries);
            case "wrapper" -> runWrapper(endpoint, password, intervalMs, maxQueries);
        }
    }
 
    static void runPlain(String endpoint, String password, int intervalMs, int max) throws Exception {
        String url = "jdbc:postgresql://" + endpoint + ":5432/postgres"
                + "?connectTimeout=" + CONNECT_TIMEOUT_SEC + "&socketTimeout=" + QUERY_TIMEOUT_SEC;
        int ok = 0, fail = 0;
        for (int n = 1; n <= max; n++) {
            Instant start = Instant.now();
            try (Connection c = DriverManager.getConnection(url, "postgres", password);
                 Statement s = c.createStatement();
                 ResultSet r = s.executeQuery("SELECT inet_server_addr()::text")) {
                r.next();
                long ms = Duration.between(start, Instant.now()).toMillis();
                System.out.println(Instant.now()+","+n+",OK,"+ms+","+r.getString(1)+",");
                ok++;
            } catch (Exception e) {
                long ms = Duration.between(start, Instant.now()).toMillis();
                System.out.println(Instant.now()+","+n+",FAIL,"+ms+",,"+e.getMessage().replace('\n',' ').substring(0,Math.min(100,e.getMessage().length())));
                fail++;
            }
            Thread.sleep(intervalMs);
        }
        System.err.println("=== Plain: OK="+ok+" FAIL="+fail+" ===");
    }
 
    static void runHikari(String endpoint, String password, int intervalMs, int max) throws Exception {
        HikariConfig cfg = new HikariConfig();
        cfg.setJdbcUrl("jdbc:postgresql://"+endpoint+":5432/postgres");
        cfg.setUsername("postgres"); cfg.setPassword(password);
        cfg.setMaximumPoolSize(5); cfg.setConnectionTimeout(3000);
        HikariDataSource ds = new HikariDataSource(cfg);
        int ok = 0, fail = 0;
        for (int n = 1; n <= max; n++) {
            Instant start = Instant.now();
            boolean success = false;
            for (int a = 1; a <= 3 && !success; a++) {
                try (Connection c = ds.getConnection();
                     Statement s = c.createStatement();
                     ResultSet r = s.executeQuery("SELECT inet_server_addr()::text")) {
                    r.next();
                    long ms = Duration.between(start, Instant.now()).toMillis();
                    System.out.println(Instant.now()+","+n+",OK,"+ms+","+r.getString(1)+","+(a>1?"retry="+a:""));
                    success = true; ok++;
                } catch (Exception e) {
                    if (a == 3) {
                        long ms = Duration.between(start, Instant.now()).toMillis();
                        System.out.println(Instant.now()+","+n+",FAIL,"+ms+",,"+e.getMessage().replace('\n',' ').substring(0,Math.min(100,e.getMessage().length())));
                        fail++;
                    } else Thread.sleep(1000);
                }
            }
            Thread.sleep(intervalMs);
        }
        ds.close();
        System.err.println("=== HikariCP: OK="+ok+" FAIL="+fail+" ===");
    }
 
    static void runWrapper(String endpoint, String password, int intervalMs, int max) throws Exception {
        String url = "jdbc:aws-wrapper:postgresql://"+endpoint+":5432/postgres";
        Properties p = new Properties();
        p.setProperty("user","postgres"); p.setProperty("password",password);
        p.setProperty("wrapperPlugins","bg,failover2,efm2");
        p.setProperty("bgdId","bg-test-demo");
        p.setProperty("bgSwitchoverTimeoutMs","600000");
        p.setProperty("blue-green-monitoring-connectTimeout","20000");
        p.setProperty("blue-green-monitoring-socketTimeout","20000");
        p.setProperty("connectTimeout",String.valueOf(CONNECT_TIMEOUT_SEC));
        p.setProperty("socketTimeout",String.valueOf(QUERY_TIMEOUT_SEC));
        p.setProperty("wrapperLoggerLevel","fine");
        int ok = 0, fail = 0;
        for (int n = 1; n <= max; n++) {
            Instant start = Instant.now();
            try (Connection c = DriverManager.getConnection(url, p);
                 Statement s = c.createStatement();
                 ResultSet r = s.executeQuery("SELECT inet_server_addr()::text")) {
                r.next();
                long ms = Duration.between(start, Instant.now()).toMillis();
                System.out.println(Instant.now()+","+n+",OK,"+ms+","+r.getString(1)+",");
                ok++;
            } catch (Exception e) {
                long ms = Duration.between(start, Instant.now()).toMillis();
                System.out.println(Instant.now()+","+n+",FAIL,"+ms+",,"+e.getMessage().replace('\n',' ').substring(0,Math.min(100,e.getMessage().length())));
                fail++;
            }
            Thread.sleep(intervalMs);
        }
        System.err.println("=== Wrapper: OK="+ok+" FAIL="+fail+" ===");
    }
}

検証手順

Aurora クラスターの構築

Aurora PostgreSQL 16.9 クラスター(Writer + Reader)を構築し、論理レプリケーションを有効化する。

Aurora クラスター構築手順
Terminal
# サブネットグループ作成
aws rds create-db-subnet-group \
  --db-subnet-group-name bg-test-subnet-group \
  --db-subnet-group-description "Subnet group for Blue/Green test" \
  --subnet-ids '["subnet-xxxxx","subnet-yyyyy","subnet-zzzzz"]' \
  --region ap-northeast-1
 
# カスタムパラメータグループ(論理レプリケーション有効化)
aws rds create-db-cluster-parameter-group \
  --db-cluster-parameter-group-name bg-test-apg16-params \
  --db-parameter-group-family aurora-postgresql16 \
  --description "Custom params for Blue/Green test"
aws rds modify-db-cluster-parameter-group \
  --db-cluster-parameter-group-name bg-test-apg16-params \
  --parameters "ParameterName=rds.logical_replication,ParameterValue=1,ApplyMethod=pending-reboot"
 
# クラスター作成
aws rds create-db-cluster \
  --db-cluster-identifier bg-test-apg \
  --engine aurora-postgresql --engine-version 16.9 \
  --master-username postgres --master-user-password '<your-password>' \
  --db-subnet-group-name bg-test-subnet-group \
  --db-cluster-parameter-group-name bg-test-apg16-params \
  --storage-encrypted --no-deletion-protection \
  --region ap-northeast-1
 
# Writer / Reader インスタンス(パブリックアクセス有効)
aws rds create-db-instance \
  --db-instance-identifier bg-test-apg-writer \
  --db-cluster-identifier bg-test-apg \
  --db-instance-class db.r6g.large \
  --engine aurora-postgresql --publicly-accessible \
  --region ap-northeast-1
aws rds create-db-instance \
  --db-instance-identifier bg-test-apg-reader \
  --db-cluster-identifier bg-test-apg \
  --db-instance-class db.r6g.large \
  --engine aurora-postgresql --publicly-accessible \
  --region ap-northeast-1
 
# インスタンスが available になったら再起動(パラメータグループ適用)
aws rds reboot-db-instance --db-instance-identifier bg-test-apg-writer
aws rds reboot-db-instance --db-instance-identifier bg-test-apg-reader
 
# SG にローカル IP からの接続を許可
SG_ID=$(aws rds describe-db-clusters --db-cluster-identifier bg-test-apg \
  --query 'DBClusters[0].VpcSecurityGroups[0].VpcSecurityGroupId' \
  --output text --region ap-northeast-1)
MY_IP=$(curl -s https://checkip.amazonaws.com)
aws ec2 authorize-security-group-ingress \
  --group-id "${SG_ID}" --protocol tcp --port 5432 \
  --cidr "${MY_IP}/32" --region ap-northeast-1

Java プロジェクトのビルド

Java プロジェクトのビルド手順
Terminal
# Java 21 + Maven のインストール(Ubuntu)
sudo apt-get install -y openjdk-21-jdk maven
 
# プロジェクトディレクトリ作成
mkdir -p bg-switchover-test/src/main/java/bgtest
 
# pom.xml と SwitchoverTest.java を配置(上記のコードを使用)
 
# ビルド
cd bg-switchover-test
mvn package -q
 
# クラスパスの構築
CP="target/bg-switchover-test-1.0.jar"
for jar in target/lib/*.jar; do CP="$CP:$jar"; done
 
# 動作確認(2回だけ実行)
ENDPOINT="bg-test-apg.cluster-xxxxx.ap-northeast-1.rds.amazonaws.com"
java -cp "$CP" bgtest.SwitchoverTest plain "$ENDPOINT" '<password>' 1000 2

Blue/Green デプロイメントの作成と Switchover

Green 環境用のパラメータグループを作成し、Blue/Green デプロイメントを作成する。

Blue/Green デプロイメント作成手順
Terminal
# Green 用パラメータグループ(PG 17)
aws rds create-db-cluster-parameter-group \
  --db-cluster-parameter-group-name bg-test-apg17-params \
  --db-parameter-group-family aurora-postgresql17 \
  --description "Custom params for PG17 green environment"
aws rds modify-db-cluster-parameter-group \
  --db-cluster-parameter-group-name bg-test-apg17-params \
  --parameters "ParameterName=rds.logical_replication,ParameterValue=1,ApplyMethod=pending-reboot"
 
# Blue/Green デプロイメント作成(約30分かかる)
aws rds create-blue-green-deployment \
  --blue-green-deployment-name bg-test-upgrade \
  --source arn:aws:rds:ap-northeast-1:<account-id>:cluster:bg-test-apg \
  --target-engine-version 17.6 \
  --target-db-cluster-parameter-group-name bg-test-apg17-params \
  --region ap-northeast-1
 
# 進捗確認
aws rds describe-blue-green-deployments \
  --blue-green-deployment-identifier bgd-xxxxx \
  --query 'BlueGreenDeployments[0].{Status:Status,Tasks:Tasks[].{Name:Name,Status:Status}}' \
  --region ap-northeast-1

Green 環境が AVAILABLE になったら、3パターンを同時にバックグラウンドで起動し、Switchover を実行する。

Terminal
ENDPOINT="bg-test-apg.cluster-xxxxx.ap-northeast-1.rds.amazonaws.com"
 
# 3パターンを同時起動
java -cp "$CP" bgtest.SwitchoverTest plain  "$ENDPOINT" '<password>' 1000 400 > switchover-plain.log  2>&1 &
java -cp "$CP" bgtest.SwitchoverTest hikari "$ENDPOINT" '<password>' 1000 400 > switchover-hikari.log 2>&1 &
java -cp "$CP" bgtest.SwitchoverTest wrapper "$ENDPOINT" '<password>' 1000 400 > switchover-wrapper.log 2>&1 &
 
# Switchover 実行
aws rds switchover-blue-green-deployment \
  --blue-green-deployment-identifier bgd-xxxxx \
  --switchover-timeout 300 \
  --region ap-northeast-1

検証結果

Pattern 1: Plain JDBC — 8回の接続失敗

Output(Plain JDBC)
04:56:35.879  #44  OK     90ms  172.31.47.234  ← Blue Writer (PG 16.9)
04:56:39.894  #45  FAIL  3006ms               ← タイムアウト開始
04:56:43.899  #46  FAIL  3003ms
04:56:47.904  #47  FAIL  3004ms
04:56:51.933  #48  FAIL  3029ms
04:56:55.938  #49  FAIL  3004ms
04:56:59.933  #50  FAIL  2994ms
04:57:03.937  #51  FAIL  3003ms
04:57:07.941  #52  FAIL  3003ms               ← 8回連続タイムアウト
04:57:11.071  #53  OK   2128ms  172.31.47.234  ← 復旧(まだ旧 IP)
  ... #53〜#60 は旧 IP に接続 ...
04:57:19.921  #61  OK    115ms  172.31.32.43   ← Green Writer (PG 17.6)

前回の psql テスト(6回失敗)と同様のパターンだが、Java の connectTimeout=3 の挙動により8回の失敗となった。ダウンタイムは約32秒(#45 の 04:56:39 〜 #53 の 04:57:11)。さらに、復旧後も約8秒間は旧 IP に接続し続け、#61 で初めて Green に切り替わった。

Pattern 2: HikariCP + リトライ — 2回の接続失敗、だが重大な落とし穴

Output(HikariCP + リトライ)
04:56:35.953  #48  OK      17ms  172.31.47.234  ← 最後の正常
04:56:47.961  #49  FAIL  11006ms               ← リトライ3回すべて失敗(3秒×3 + バックオフ)
04:56:59.956  #50  FAIL  10992ms               ← 同上
04:57:11.429  #51  OK    10471ms 172.31.47.234  ← 3回目のリトライで復旧(旧 IP のまま)

リトライにより接続失敗は2回に減った。しかし、400回のクエリすべてが旧 Writer の IP(172.31.47.234)に接続し続けた

IP 遷移(HikariCP)
398回  172.31.47.234  ← 旧 Blue Writer(Switchover 後は Reader に降格)

これは HikariCP の重大な落とし穴だ。コネクションプールは既存の TCP 接続を再利用するため、DNS が更新されても新しい Writer に切り替わらない。Switchover 後、アプリケーションは 旧 Writer(現在は Reader)に接続し続ける。読み取りクエリは成功するが、書き込みクエリは read-only transaction エラーになる。

補足: AWS のドキュメントによると、Switchover 中に両環境の全接続が強制切断される。その後、HikariCP が新規接続を作成する際、DNS キャッシュがまだ旧 Writer の IP を返していると旧環境(Reader に降格済み)に再接続してしまう。DNS の伝播タイミングによっては新しい Writer に接続できるケースもあるが、DNS TTL 60秒の間は旧環境に接続し続けるリスクがある。

Pattern 3: AWS JDBC Wrapper BG プラグイン — 0回の接続失敗

Output(AWS JDBC Wrapper)
04:56:35.838  #43  OK      100ms  172.31.47.234  ← Blue Writer
04:57:12.511  #44  OK    35662ms  172.31.47.234  ← IN_PROGRESS 中、プラグインが一時停止
04:57:13.614  #45  OK       93ms  172.31.32.43   ← POST フェーズ、Green に自動ルーティング
  ... 全て OK ...
04:57:50.xxx  #78  OK       94ms  172.31.47.234  ← DNS 更新後、ホスト名ベースに復帰

400回のクエリ中、接続失敗は0回だった。ただし #44 のレイテンシが約36秒に跳ね上がっている点に注目だ。これはプラグインが IN_PROGRESS フェーズ中にクエリ実行を一時停止(suspend)し、切り替え完了後に再開したためだ。接続は切れないが、アプリケーション側ではタイムアウト設定によっては影響を受ける可能性がある。

IP 遷移が Blue → Green → Blue に戻っているのは、POST フェーズで一時的に Green の IP に直接ルーティングした後、DNS 更新が完了してホスト名ベースの接続に復帰したためだ。最終的にはクラスターエンドポイントが Green 環境を指すようになっている。

BG プラグインのログから、Switchover のタイムラインが確認できる。

Output(BG プラグインのフェーズ遷移ログ)
04:55:48.233  -47890ms  NOT_CREATED
04:55:48.508  -47616ms  CREATED
04:56:31.485   -4633ms  PREPARATION
04:56:36.119       0ms  IN_PROGRESS
04:56:48.585   12466ms  POST
04:57:01.421   25311ms  Green topology changed
04:57:50.168   74064ms  Green DNS removed
04:57:50.433   74329ms  Blue DNS updated
04:57:50.433   74329ms  COMPLETED

IN_PROGRESS フェーズ(実際の切り替え)は約12秒間だったが、その間もクエリは失敗していない。プラグインがクエリ実行を一時停止し、POST フェーズに入った時点で IP ベースのルーティングで Green 環境に直接接続を再開したためだ。

まとめ

検証結果の比較

指標Plain JDBCHikariCP + リトライAWS JDBC Wrapper BG
接続失敗8回2回0回
ダウンタイム約32秒約12秒(リトライ含む)0秒(ただし36秒の一時停止あり)
Switchover 後の接続先✅ Green に切替(約8秒遅延)❌ 旧 Blue のまま✅ Green に切替
書き込みワークロードの安全性✅(切替後)❌ read-only エラーのリスク
導入の複雑さなし低い中程度(依存追加 + 設定)

得られた知見

  • HikariCP のリトライだけでは不十分 — リトライで接続失敗は減るが、Switchover 中に全接続が切断された後、HikariCP が新規接続を作成する際に DNS キャッシュが旧 Writer の IP を返すと、旧環境(Reader に降格済み)に再接続してしまう。書き込みワークロードでは read-only transaction エラーが発生する。DNS の伝播タイミングによっては新しい Writer に接続できるケースもあるが、DNS TTL 60秒の間は旧環境に接続し続けるリスクがある。確実な切り替えが必要な場合は BG プラグインの使用を推奨する。
  • AWS JDBC Driver BG プラグインは検証3回すべてで接続失敗0回を記録した — 400回のクエリ中0回の接続失敗。プラグインが RDS のメタデータテーブルを監視し、DNS に依存せず IP ベースで接続先を切り替えるため、DNS TTL の問題を完全に回避できる。ただし、IN_PROGRESS フェーズ中はクエリ実行が一時停止されるため、1回のクエリに約36秒かかるケースがあった。アプリケーション側のタイムアウト設定(HTTP リクエストタイムアウト等)がこれより短い場合は、上位レイヤーでタイムアウトする可能性がある。
  • プラグインの導入コストは低い — 接続 URL を jdbc:aws-wrapper:postgresql:// に変更し、wrapperPluginsbg を追加するだけ。アプリケーションコードの変更は不要だ。ただし、Java(JDBC)以外の言語では利用できない点に注意が必要だ。
  • コネクションプールを使う場合は接続の有効性検証が重要 — HikariCP の connectionTestQueryvalidationTimeout を適切に設定し、Switchover 後に古い接続を検出・破棄する仕組みが必要だ。ただし、これだけでは新しい Writer への切り替えは保証されない。

クリーンアップ

リソース削除コマンド
Terminal
# Blue/Green デプロイメントの削除
aws rds delete-blue-green-deployment \
  --blue-green-deployment-identifier bgd-xxxxx \
  --region ap-northeast-1
 
# 旧 Blue 環境のインスタンス・クラスター削除
aws rds delete-db-instance --db-instance-identifier bg-test-apg-reader-old1 --skip-final-snapshot
aws rds delete-db-instance --db-instance-identifier bg-test-apg-writer-old1 --skip-final-snapshot
aws rds delete-db-cluster --db-cluster-identifier bg-test-apg-old1 --skip-final-snapshot
 
# 新クラスター(Green が昇格)のインスタンス・クラスター削除
aws rds delete-db-instance --db-instance-identifier bg-test-apg-reader --skip-final-snapshot
aws rds delete-db-instance --db-instance-identifier bg-test-apg-writer --skip-final-snapshot
aws rds delete-db-cluster --db-cluster-identifier bg-test-apg --skip-final-snapshot
 
# パラメータグループ・サブネットグループ削除
aws rds delete-db-cluster-parameter-group --db-cluster-parameter-group-name bg-test-apg16-params
aws rds delete-db-cluster-parameter-group --db-cluster-parameter-group-name bg-test-apg17-params
aws rds delete-db-subnet-group --db-subnet-group-name bg-test-subnet-group
 
# セキュリティグループのインバウンドルール削除
aws ec2 revoke-security-group-ingress --group-id sg-xxxxx --protocol tcp --port 5432 --cidr <your-ip>/32

共有する

田原 慎也

田原 慎也

ソリューションアーキテクト @ AWS

AWS ソリューションアーキテクトとして金融業界のお客様を中心に技術支援を行っています。クラウドアーキテクチャや AI/ML に関する学びをこのサイトで発信しています。このサイトの内容は個人の見解であり、所属企業の公式な意見や見解を代表するものではありません。

関連記事