

# Amazon Aurora PostgreSQL를 사용한 빠른 장애 조치
<a name="AuroraPostgreSQL.BestPractices.FastFailover"></a>

다음에서는 장애 조치가 가능한 한 빨리 발생하도록 하는 방법을 배울 수 있습니다. 장애 조치 후 신속하게 복구하기 위해 Aurora PostgreSQL DB 클러스터에 대한 클러스터 캐시 관리를 사용할 수 있습니다. 자세한 내용은 [장애 조치 후 Aurora PostgreSQL용 클러스터 캐시 관리를 통한 신속한 복구](AuroraPostgreSQL.cluster-cache-mgmt.md) 섹션을 참조하세요.

장애 조치가 빠르게 이루어지도록 하기 위해 수행할 수 있는 몇 가지 단계는 다음과 같습니다.
+ 장애가 있는 경우 읽기 제한 시간이 만료되기 전에 더 긴 실행 쿼리를 중지하려면 짧은 시간 프레임으로 전송 제어 프로토콜(TCP) Keepalives를 설정합니다.
+ Java 도메인 이름 시스템(DNS) 캐싱에 대한 제한 시간을 적극적으로 설정합니다. 이를 통해 Aurora 읽기 전용 엔드포인트가 나중에 연결을 시도할 때 읽기 전용 노드를 적절히 순환할 수 있습니다.
+ JDBC 연결 문자열에 사용되는 제한 시간 변수를 가능한 낮게 설정합니다. 단기 및 장기 실행 중인 쿼리에 별도의 연결 객체를 사용합니다.
+ 읽기 및 쓰기 Aurora 엔드포인트를 사용하여 클러스터에 연결합니다.
+ RDS API 작업을 사용하여 서버 측 장애에 대한 애플리케이션 응답을 테스트합니다. 또한 패킷 삭제 도구를 사용하여 클라이언트 측 장애에 대한 애플리케이션 응답을 테스트합니다.
+ AWS JDBC 드라이버를 사용하여 Aurora PostgreSQL의 장애 조치 기능을 최대한 활용합니다. AWS JDBC 드라이버에 대한 자세한 내용 및 사용 방법에 대한 전체 지침은 [Amazon Web Services (AWS) JDBC Driver GitHub repository](https://github.com/aws/aws-advanced-jdbc-wrapper)를 참조하세요.

이에 대해서는 다음에 이어지는 섹션에서 자세히 설명합니다.

**Topics**
+ [TCP Keepalives 파라미터 설정](#AuroraPostgreSQL.BestPractices.FastFailover.TCPKeepalives)
+ [애플리케이션에 빠른 장애 조치 구성](#AuroraPostgreSQL.BestPractices.FastFailover.Configuring)
+ [장애 조치 테스트](#AuroraPostgreSQL.BestPracticesFastFailover.Testing)
+ [Java의 빠른 장애 조치 예](#AuroraPostgreSQL.BestPractices.FastFailover.Example)

## TCP Keepalives 파라미터 설정
<a name="AuroraPostgreSQL.BestPractices.FastFailover.TCPKeepalives"></a>

TCP 연결을 설정하면 타이머 집합이 연결과 연결됩니다. keepalive 타이머가 0에 도달하면 keepalive 프로브 패킷을 연결 엔드포인트로 전송합니다. 프로브가 응답을 수신하면 연결이 계속 유지되는 것으로 가정할 수 있습니다.

TCP keepalive 파라미터를 활성화하고 적극적으로 설정하면 클라이언트가 더 이상 데이터베이스에 연결할 수 없을 경우 활성 연결이 빠르게 종료됩니다. 그러면 애플리케이션이 새 엔드포인트에 연결할 수 있습니다.

다음 TCP keepalive 파라미터를 설정해야 합니다.
+ `tcp_keepalives_idle`은 시간을 초 단위로 제어하며, 이후 소켓으로부터 데이터가 전송되지 않을 경우 keepalive 패킷이 전송됩니다. ACK는 데이터로 간주되지 않습니다. 다음 설정을 권장합니다.

   `tcp_keepalives_idle = 1`
+ `tcp_keepalives_interval`은 초기 패킷이 전송된 후 후속 keepalive 패킷을 전송하는 시간 주기를 초 단위로 제어합니다. `tcp_keepalives_idle` 파라미터를 사용하여 이 시간을 설정합니다. 다음 설정을 권장합니다.

  `tcp_keepalives_interval = 1`
+ `tcp_keepalives_count`는 애플리케이션에 알림이 전달되기 전 발생하는 승인되지 않은 keepalive 프로브의 개수입니다. 다음 설정을 권장합니다.

  `tcp_keepalives_count = 5`

이러한 설정은 데이터베이스가 응답을 중단하고 5초 안에 애플리케이션에 알려야 합니다. keepalive 패킷이 애플리케이션의 네트워크 내에서 자주 삭제되는 경우 `tcp_keepalives_count` 값을 높게 설정할 수 있습니다. 이렇게 하면 실제 장애를 탐지하는 데 걸리는 시간이 늘어나지만 덜 안정적인 네트워크에서 더 많은 버퍼를 허용합니다.

**Linux에서 TCP keepalive 파라미터를 설정하려면**

1. TCP keepalive 파라미터가 어떻게 구성되어 있는지 테스트합니다.

   명령줄에서 다음 명령을 사용하여 이 작업을 수행하는 것이 좋습니다. 이 권장 구성은 시스템 전체에 적용됩니다. 즉, `SO_KEEPALIVE` 옵션이 켜진 상태에서 소켓을 생성하는 다른 모든 애플리케이션에도 영향을 미칩니다.

   ```
   sudo sysctl net.ipv4.tcp_keepalive_time=1
   sudo sysctl net.ipv4.tcp_keepalive_intvl=1
   sudo sysctl net.ipv4.tcp_keepalive_probes=5
   ```

1. 애플리케이션에 적합한 구성을 찾은 경우, 사용자가 변경한 내용을 포함해 `/etc/sysctl.conf`에 다음 줄을 추가하여 이러한 설정을 유지합니다.

   ```
   tcp_keepalive_time = 1
   tcp_keepalive_intvl = 1
   tcp_keepalive_probes = 5
   ```

## 애플리케이션에 빠른 장애 조치 구성
<a name="AuroraPostgreSQL.BestPractices.FastFailover.Configuring"></a>

다음에서는 빠른 장애 조치를 위해 수행할 수 있는 Aurora PostgreSQL의 여러 구성 변경 사항에 대한 설명을 찾을 수 있습니다. PostgreSQL JDBC 드라이버 설정 및 구성에 대한 자세한 내용은 [PostgreSQL JDBC Driver](https://jdbc.postgresql.org/documentation/head/index.html)를 방문하여 확인하세요.

**Topics**
+ [DNS 캐시 제한 시간 축소](#AuroraPostgreSQL.BestPractices.FastFailover.Configuring.Timeouts)
+ [빠른 장애 조치를 위한 Aurora PostgreSQL 연결 문자열 설정](#AuroraPostgreSQL.BestPractices.FastFailover.Configuring.ConnectionString)
+ [호스트 문자열을 가져올 수 있는 다른 옵션](#AuroraPostgreSQL.BestPractices.FastFailover.Configuring.HostString)

### DNS 캐시 제한 시간 축소
<a name="AuroraPostgreSQL.BestPractices.FastFailover.Configuring.Timeouts"></a>

애플리케이션이 장애 조치 이후 연결을 설정할 때는 이전 리더가 새로운 Aurora PostgreSQL 라이터로 사용됩니다. 이전 리더는 DNS 업데이트가 완전히 전파되기 전에 Aurora 읽기 전용 엔드포인트를 사용해 찾을 수 있습니다. java DNS 유지 시간(TTL) 값을 30초 미만과 같이 낮게 설정하면 후속 연결 시도 시 리더 노드 사이에 순환이 이루어집니다.

```
// Sets internal TTL to match the Aurora RO Endpoint TTL
java.security.Security.setProperty("networkaddress.cache.ttl" , "1");
// If the lookup fails, default to something like small to retry
java.security.Security.setProperty("networkaddress.cache.negative.ttl" , "3");
```

### 빠른 장애 조치를 위한 Aurora PostgreSQL 연결 문자열 설정
<a name="AuroraPostgreSQL.BestPractices.FastFailover.Configuring.ConnectionString"></a>

Aurora PostgreSQL 빠른 장애 조치를 사용하려면 애플리케이션의 연결 문자열에 단일 호스트가 아닌 호스트 목록이 있어야 합니다. 다음은 Aurora PostgreSQL 클러스터에 연결하는 데 사용할 수 있는 연결 문자열의 예입니다. 이 예에서는 호스트가 굵게 표시됩니다.

```
jdbc:postgresql://myauroracluster.cluster-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432,
myauroracluster.cluster-ro-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432
/postgres?user=<primaryuser>&password=<primarypw>&loginTimeout=2
&connectTimeout=2&cancelSignalTimeout=2&socketTimeout=60
&tcpKeepAlive=true&targetServerType=primary
```

최상의 가용성과 RDS API에 대한 종속성을 피하기 위해 연결할 파일을 유지 관리하는 것이 좋습니다. 이 파일에는 데이터베이스에 연결할 때 애플리케이션이 읽는 호스트 문자열이 포함되어 있습니다. 이 호스트 문자열에는 클러스터에 제공된 모든 Aurora 엔드포인트가 있습니다. Aurora 엔드포인트에 대한 자세한 내용은 [Amazon Aurora 엔드포인트 연결](Aurora.Overview.Endpoints.md) 섹션을 참조하세요.

예를 들어, 다음과 같이 로컬 파일에 엔드포인트를 저장할 수 있습니다.

```
myauroracluster.cluster-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432,
myauroracluster.cluster-ro-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432
```

애플리케이션이 이 파일에서 읽어 들여 JDBC 연결 문자열의 호스트 섹션을 채웁니다. DB 클러스터 이름을 바꾸면 이러한 엔드포인트가 변경됩니다. 이벤트가 발생할 경우 애플리케이션이 이 이벤트를 처리하는지 확인하세요.

다른 방법은 다음과 같이 DB 인스턴스 노드 목록을 사용하는 것입니다.

```
my-node1.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432,
my-node2.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432,
my-node3.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432,
my-node4.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432
```

이 방식의 장점은 PostgreSQL JDBC 연결 드라이버가 이 목록에서 모든 노드를 통해 순환하며 유효한 연결을 찾는다는 것입니다. 이와는 반대로 Aurora 엔드포인트를 사용하는 경우 각 연결 시도에서 두 개의 노드만 시도됩니다. 하지만 DB 인스턴스 노드를 사용하는 데에는 단점이 있습니다. 사용자가 클러스터에 노드를 추가하거나 제거하고 인스턴스 엔드포인트 목록이 무효로 되면 연결 드라이버가 연결할 올바른 호스트를 찾을 수 없다는 것입니다.

애플리케이션이 한 호스트에 연결하기 위해 너무 오래 기다리지 않도록 하려면 다음 파라미터를 적극적으로 설정합니다.
+ `targetServerType` – 드라이버가 쓰기 노드에 연결되는지 아니면 읽기 노드에 연결되는지를 제어합니다. 애플리케이션이 쓰기 노드에만 다시 연결되도록 하려면 `targetServerType` 값을 `primary`로 설정합니다.

  `targetServerType` 파라미터에 사용할 수 있는 값에는 `primary`, `secondary`, `any`, `preferSecondary`가 있습니다. 이 `preferSecondary` 값은 먼저 리더와의 연결 설정을 시도합니다. 리더 연결을 설정할 수 없는 경우 라이터에 연결합니다.
+ `loginTimeout` – 소켓 연결이 설정된 후 애플리케이션이 데이터베이스에 로그인하기까지 대기하는 시간을 제어합니다.
+ `connectTimeout` – 소켓이 데이터베이스에 연결을 설정하기까지 대기하는 시간을 제어합니다.

애플리케이션을 얼마나 적극적으로 설정하고 싶은지에 따라, 다른 애플리케이션 파라미터를 수정하여 연결 프로세스의 속도를 높일 수 있습니다.
+ `cancelSignalTimeout` – 일부 애플리케이션에서는 시간 초과 쿼리에 "최대한" 취소 신호를 보내야 할 수 있습니다. 이 취소 신호가 장애 조치 경로에 있는 경우, 잘못된 호스트로 이 신호가 전달되지 않도록 적극적으로 설정하는 것이 좋습니다.
+ `socketTimeout` – 이 파라미터는 소켓이 읽기 작업을 대기하는 시간을 제어합니다. 쿼리가 이 값보다 길게 대기하지 않도록 이 파라미터를 글로벌 "쿼리 제한 시간"으로 사용할 수 있습니다. 연결 핸들러를 두 개 사용하는 것이 좋습니다. 하나의 연결 핸들러는 수명이 짧은 쿼리를 실행하고 이 값을 낮게 설정합니다. 장기 실행 쿼리를 위한 또 다른 연결 핸들러에서는 이 값이 훨씬 더 높게 설정되어 있습니다. 이 방식으로는 서버가 다운될 경우 TCP keepalive 파라미터를 이용해 장기 실행 쿼리를 중단할 수 있습니다.
+ `tcpKeepAlive` – 이 파라미터를 켜면 사용자가 설정한 TCP keepalive 파라미터가 적용되도록 합니다.
+ `loadBalanceHosts` – 이 파라미터를 `true`로 설정하면 애플리케이션을 후보 호스트 목록에서 선택한 임의의 호스트에 연결합니다.

### 호스트 문자열을 가져올 수 있는 다른 옵션
<a name="AuroraPostgreSQL.BestPractices.FastFailover.Configuring.HostString"></a>

`aurora_replica_status` 함수 및 Amazon RDS API 사용을 비롯해 여러 소스로부터 호스트 문자열을 가져올 수 있습니다.

대부분의 경우 클러스터 라이터를 확인하거나 클러스터의 다른 리더 노드를 찾아야 합니다. 이를 위해 애플리케이션에서 DB 클러스터의 DB 인스턴스에 연결하고 `aurora_replica_status` 함수를 쿼리할 수 있습니다. 이 함수를 사용하면 연결할 호스트를 찾는 데 걸리는 시간을 줄일 수 있습니다. 그러나 특정 네트워크 장애 시나리오에서는 `aurora_replica_status` 기능이 오래되었거나 불완전한 정보를 표시할 수 있습니다.

애플리케이션이 연결할 노드를 찾도록 보장하는 좋은 방법 중 하나는클러스터 라이터 엔드포인트에 연결한 다음 클러스터 리더 엔드포인트에 연결을 시도하는 것입니다. 읽기 가능한 연결을 설정할 때까지 이 작업을 수행합니다. 이러한 엔드포인트는 DB 클러스터의 이름을 변경하지 않는 한 변경되지 않습니다. 따라서 일반적으로 이들을 애플리케이션의 정적 멤버로 남겨두거나 애플리케이션이 읽는 리소스 파일에 저장할 수 있습니다.

이러한 엔드포인트 중 하나를 사용하여 연결을 설정한 후 클러스터의 나머지 부분에 대한 정보를 얻을 수 있습니다. 이렇게 하려면 `aurora_replica_status` 함수를 호출합니다. 예를 들어 다음 명령은 `aurora_replica_status`로 정보를 검색합니다.

```
postgres=> SELECT server_id, session_id, highest_lsn_rcvd, cur_replay_latency_in_usec, now(), last_update_timestamp
FROM aurora_replica_status();

server_id | session_id | highest_lsn_rcvd | cur_replay_latency_in_usec | now | last_update_timestamp
-----------+--------------------------------------+------------------+----------------------------+-------------------------------+------------------------
mynode-1 | 3e3c5044-02e2-11e7-b70d-95172646d6ca | 594221001 | 201421 | 2017-03-07 19:50:24.695322+00 | 2017-03-07 19:50:23+00
mynode-2 | 1efdd188-02e4-11e7-becd-f12d7c88a28a | 594221001 | 201350 | 2017-03-07 19:50:24.695322+00 | 2017-03-07 19:50:23+00
mynode-3 | MASTER_SESSION_ID | | | 2017-03-07 19:50:24.695322+00 | 2017-03-07 19:50:23+00
(3 rows)
```

이를테면 연결 문자열의 호스트 섹션은 라이터와 리더 클러스터 엔드포인트 모두로 시작할 수 있습니다.

```
myauroracluster.cluster-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432,
myauroracluster.cluster-ro-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432
```

이 시나리오에서 애플리케이션은 기본 또는 보조 노드 유형에 연결을 설정하려 할 것입니다. 애플리케이션이 연결되면 먼저 명령 의 결과를 쿼리하여 노드의 읽기/쓰기 상태를 검사하는 것이 좋습니다. 이렇게 하려면 `SHOW transaction_read_only` 명령 결과를 쿼리해야 합니다.

쿼리의 반환 값이 `OFF`인 경우 프라이머리 노드에 성공적으로 연결된 것입니다. 그러나 반환 값이 `ON`이고 애플리케이션에 읽기/쓰기 연결이 필요하다고 가정합니다. 이 경우 `aurora_replica_status` 함수를 호출하여 `session_id='MASTER_SESSION_ID'`인 `server_id`를 확인할 수 있습니다. 이 함수는 프라이머리 노드의 이름을 반환합니다. 다음에 설명하는 `endpointPostfix`와 함께 사용할 수 있습니다.

단, 오래된 데이터가 있는 복제본에 연결하는 경우에는 주의해야 합니다. 이 경우 `aurora_replica_status` 함수에 오래된 정보가 표시될 수 있습니다. 애플리케이션 수준에서 부실 임계값을 설정할 수 있습니다. 이를 확인하기 위해 서버 시간과 `last_update_timestamp` 값의 차이를 확인할 수 있습니다. 일반적으로 애플리케이션은 `aurora_replica_status` 함수에 의해 반환된 충돌 정보로 인한 두 호스트 사이의 대칭 이동을 방지해야 합니다. 애플리케이션은 `aurora_replica_status`에서 반환된 데이터를 따르는 대신 알려진 모든 호스트를 먼저 시도해야 합니다.

#### DescribeDBClusters API 작업을 사용하여 인스턴스를 나열(Java 예제)
<a name="AuroraPostgreSQL.BestPractices.FastFailover.Configuring.HostString.API"></a>

[AWS SDK for Java](https://aws.amazon.com/sdk-for-java/), 특히 [DescribeDBClusters](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBClusters.html) API 작업을 사용하여 프로그래밍 방식으로 인스턴스 목록을 찾을 수 있습니다.

다음은 java 8에서 이와 같이 검색하는 방법에 대한 작은 예입니다.

```
AmazonRDS client = AmazonRDSClientBuilder.defaultClient();
DescribeDBClustersRequest request = new DescribeDBClustersRequest()
   .withDBClusterIdentifier(clusterName);
DescribeDBClustersResult result = 
rdsClient.describeDBClusters(request);

DBCluster singleClusterResult = result.getDBClusters().get(0);

String pgJDBCEndpointStr = 
singleClusterResult.getDBClusterMembers().stream()
   .sorted(Comparator.comparing(DBClusterMember::getIsClusterWriter)
   .reversed()) // This puts the writer at the front of the list
   .map(m -> m.getDBInstanceIdentifier() + endpointPostfix + ":" + singleClusterResult.getPort()))
   .collect(Collectors.joining(","));
```

여기에서 `pgJDBCEndpointStr`은 다음과 같이 형식이 지정된 끝점 목록을 포함합니다.

```
my-node1.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432,
my-node2.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com:5432
```

변수 `endpointPostfix`는 애플리케이션이 설정하는 상수일 수 있습니다. 또는 클러스터의 단일 인스턴스에 대해 `DescribeDBInstances` API 작업을 쿼리하여 애플리케이션에서 이를 가져올 수 있습니다. 이 값은 AWS 리전 내에서 그리고 개별 고객에 대해 일정하게 유지됩니다. 따라서 API 호출을 저장하여 애플리케이션이 읽어 들이는 리소스 파일에서 이 상수를 유지합니다. 앞의 예에서는 다음과 같이 설정됩니다.

```
.cksc6xlmwcyw.us-east-1-beta.rds.amazonaws.com
```

API가 응답하지 않거나 응답하는 데 너무 오래 걸리는 경우 가용성을 위해 기본적으로 DB 클러스터의 Aurora 엔드포인트를 사용하는 것이 좋습니다. 엔드포인트는 DNS 레코드를 업데이트하는 데 걸리는 시간 내에 최신 상태가 됩니다. DNS 레코드를 엔드포인트로 업데이트하는 데 보통 30초도 걸리지 않습니다. 이는 애플리케이션이 사용하는 리소스 파일에 저장할 수 있습니다.

## 장애 조치 테스트
<a name="AuroraPostgreSQL.BestPracticesFastFailover.Testing"></a>

모든 경우에 두 개 이상의 DB 인스턴스를 포함한 DB 클러스터가 있어야 합니다.

서버 측에서 특정 API가 애플리케이션의 응답 방식을 테스트하는 데 사용할 수 있는 중단을 유발할 수 있습니다.
+ [FailoverDBCluster](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_FailoverDBCluster.html) - 이 작업은 DB 클러스터의 새 DB 인스턴스를 기록기로 승격하려고 시도합니다.

  다음 코드 예에서는 `failoverDBCluster`를 사용하여 중단을 일으키는 방법을 보여줍니다. Amazon RDS 클라이언트 설정에 대한 자세한 내용은 [AWS SDK for Java 사용](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/basics.html)을 참조하세요.

  ```
  public void causeFailover() {
      
      final AmazonRDS rdsClient = AmazonRDSClientBuilder.defaultClient();
     
      FailoverDBClusterRequest request = new FailoverDBClusterRequest();
      request.setDBClusterIdentifier("cluster-identifier");
  
      rdsClient.failoverDBCluster(request);
  }
  ```
+ [RebootDBInstance](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RebootDBInstance.html) – 이 API 작업에서는 장애 조치가 보장되지 않습니다. 하지만 라이터의 데이터베이스는 종료됩니다. 이를 사용하여 애플리케이션이 연결 끊기에 어떻게 반응하는지 테스트할 수 있습니다. `ForceFailover` 파라미터는 Aurora 엔진에 적용되지 않습니다. 대신 `FailoverDBCluster` API 작업을 사용합니다.
+ [ModifyDBCluster](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_ModifyDBCluster.html) – `Port` 파라미터를 변경하면 클러스터의 노드가 새 포트에서 수신을 시작할 경우 중단을 유발합니다. 일반적으로 애플리케이션만 포트 변경을 제어하도록 하여 이 실패에 먼저 응답할 수 있습니다. 또한 종속된 엔드포인트를 적절하게 업데이트할 수 있는지 확인하세요. 이렇게 하려면 API 수준에서 수정한 사람이 포트를 수동으로 업데이트하도록 하면 됩니다. 또는 애플리케이션의 RDS API를 사용하여 포트가 변경되었는지 확인할 수 있습니다.
+ [ModifyDBInstance](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_ModifyDBInstance.html) - `DBInstanceClass` 파라미터를 수정하면 중단이 발생합니다.
+ [DeleteDBInstance](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DeleteDBInstance.html) – 기본(라이터)을 삭제하면 새 DB 인스턴스가 DB 클러스터의 라이터로 승격됩니다.

애플리케이션 또는 클라이언트 측에서 Linux를 사용하는 경우 애플리케이션이 갑작스러운 패킷 드롭에 응답하는 방식을 테스트할 수 있습니다. 포트, 호스트 또는 iptables 명령을 사용하여 TCP keepalive 패킷을 보내거나 받는지 여부에 따라 이 작업을 수행할 수 있습니다.

## Java의 빠른 장애 조치 예
<a name="AuroraPostgreSQL.BestPractices.FastFailover.Example"></a>

다음 코드 예는 애플리케이션이 Aurora PostgreSQL 드라이버 관리자를 설정하는 방식을 보여줍니다.

애플리케이션이 연결해야 할 때 `getConnection` 함수를 호출합니다. `getConnection` 호출은 유효한 호스트를 찾지 못할 수 있습니다. 라이터를 찾을 수 없지만 `targetServerType` 파라미터가 `primary`로 설정된 경우를 예로 들 수 있습니다. 이 경우 호출 애플리케이션에서 함수 호출을 다시 시도해야 합니다.

재시도 동작을 애플리케이션에 푸시하지 않으려면 이 재시도 호출을 연결 풀러로 래핑할 수 있습니다. 대부분의 연결 풀러에서는 JDBC 연결 문자열을 지정할 수 있습니다. 따라서 애플리케이션은 `getJdbcConnectionString`을 호출하고 이를 연결 풀러에 전달할 수 있습니다. 이렇게 하면 Aurora PostgreSQL에서 더 빠른 장애 조치를 사용할 수 있습니다.

```
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.joda.time.Duration;

public class FastFailoverDriverManager {
   private static Duration LOGIN_TIMEOUT = Duration.standardSeconds(2);
   private static Duration CONNECT_TIMEOUT = Duration.standardSeconds(2);
   private static Duration CANCEL_SIGNAL_TIMEOUT = Duration.standardSeconds(1);
   private static Duration DEFAULT_SOCKET_TIMEOUT = Duration.standardSeconds(5);

   public FastFailoverDriverManager() {
       try {
            Class.forName("org.postgresql.Driver");
       } catch (ClassNotFoundException e) {
            e.printStackTrace();
       }

       /*
         * RO endpoint has a TTL of 1s, we should honor that here. Setting this aggressively makes sure that when
         * the PG JDBC driver creates a new connection, it will resolve a new different RO endpoint on subsequent attempts
         * (assuming there is > 1 read node in your cluster)
         */
        java.security.Security.setProperty("networkaddress.cache.ttl" , "1");
       // If the lookup fails, default to something like small to retry
       java.security.Security.setProperty("networkaddress.cache.negative.ttl" , "3");
   }

   public Connection getConnection(String targetServerType) throws SQLException {
       return getConnection(targetServerType, DEFAULT_SOCKET_TIMEOUT);
   }

   public Connection getConnection(String targetServerType, Duration queryTimeout) throws SQLException {
        Connection conn = DriverManager.getConnection(getJdbcConnectionString(targetServerType, queryTimeout));

       /*
         * A good practice is to set socket and statement timeout to be the same thing since both 
         * the client AND server will stop the query at the same time, leaving no running queries 
         * on the backend
         */
        Statement st = conn.createStatement();
        st.execute("set statement_timeout to " + queryTimeout.getMillis());
        st.close();

       return conn;
   }

   private static String urlFormat = "jdbc:postgresql://%s"
           + "/postgres"
           + "?user=%s"
           + "&password=%s"
           + "&loginTimeout=%d"
           + "&connectTimeout=%d"
           + "&cancelSignalTimeout=%d"
           + "&socketTimeout=%d"
           + "&targetServerType=%s"
           + "&tcpKeepAlive=true"
           + "&ssl=true"
           + "&loadBalanceHosts=true";
   public String getJdbcConnectionString(String targetServerType, Duration queryTimeout) {
       return String.format(urlFormat, 
                getFormattedEndpointList(getLocalEndpointList()),
                CredentialManager.getUsername(),
                CredentialManager.getPassword(),
                LOGIN_TIMEOUT.getStandardSeconds(),
                CONNECT_TIMEOUT.getStandardSeconds(),
                CANCEL_SIGNAL_TIMEOUT.getStandardSeconds(),
                queryTimeout.getStandardSeconds(),
                targetServerType
       );
   }

   private List<String> getLocalEndpointList() {
       /*
         * As mentioned in the best practices doc, a good idea is to read a local resource file and parse the cluster endpoints. 
         * For illustration purposes, the endpoint list is hardcoded here
         */
        List<String> newEndpointList = new ArrayList<>();
        newEndpointList.add("myauroracluster.cluster-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432");
        newEndpointList.add("myauroracluster.cluster-ro-c9bfei4hjlrd.us-east-1-beta.rds.amazonaws.com:5432");

       return newEndpointList;
   }

   private static String getFormattedEndpointList(List<String> endpoints) {
       return IntStream.range(0, endpoints.size())
               .mapToObj(i -> endpoints.get(i).toString())
               .collect(Collectors.joining(","));
   }
}
```