"Aurora DB 사용하면 Transaction readOnly 인 경우에 Reader(Slave) Connection 타지 않아요?"
어플리케이션에 있는 설정 정보라고는 Cluster 설정뿐인데, 어떻게 Reader DNS를 찾아서 커넥션을 맺는걸까?
위 그림처럼 mariadb-connector-j 를 사용하여 Aurora DB 로 connection 을 맺게 되면 ReadOnly 설정에 따라 다른 DNS 로 라우팅되게 된다. 그 과정을 살펴보자.
@Test
void connectionRoutingTest() {
String jdbcUrl = "jdbc:mariadb:aurora://dev.cluster.rds.amazonaws.com:3306/test";
String username = "username";
String password = "password";
try {
Class.forName("org.mariadb.jdbc.Driver"); // 드라이버 클래스 로드
Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
// 쓰기 전용 설정
Statement statement1 = connection.createStatement();
connection.setReadOnly(false); // 🔴 디버깅 포인트
statement1.execute("SELECT 1 /*readOnly=false*/;"); // 🔴 디버깅 포인트
// 읽기 전용 설정
Statement statement2 = connection.createStatement();
connection.setReadOnly(true); // 🔴 디버깅 포인트
statement2.execute("SELECT 1 /*readOnly=true*/;"); // 🔴 디버깅 포인트
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
HostAddress.java parse() 에서 DB 주소 정보를 파싱한다.
AuroraListener.java getCurrentEndpointIdentifiers() 에서 클러스터에 존재하는 DB 정보를 조회한다.
실제 위 쿼리를 DB 에 조회해보면 위와 같이 설정된 같이 나오는 것을 알 수 있다.
이때 AuroraProtocol.java 에는 FailoverProxy.java 가 Proxy 로 걸려있기 때문에 FailoverProxy 의 invoke() 가 호출된다.
FailoverProxy.java 에는 AuroraProtocol.java 의 각 함수들이 호출되었을때 수행되어야하는 프록시 로직들이 swtich case 문으로 정의 되어있다.
MasterSlaveListener.java 에서 currentProtocol.executeQuery() 함수를 invoke 하였으므로 AbstarctQueryProtocol.java executeQuery() 가 실행되었고 여기에서 실제 네트워크 작업이 실행된다.
currentProtocol
이 masterProtocol
과 주소가 일치하며 currentProtocol 의 socket
도 write endPoint
가 사용되고 있음을 알 수 있다.
connection 의 setReadOnly() 가 호출되면 MariaDbConnection.java setReadOnly() 가 호출되고 이 함수 내부에서 protocol.setReadOnly() 가 호출된다.
Protocol 의 함수가 호출되면 어김없이 프록시인 FailoverProxy.java 의 invoke() 가 호출된다.
FailoverProxy.java
에서 setReadOnly 함수가 호출되면 listener.switchReadOnlyConnection()
를 호출해주게 된다.
이로 인해 MasterSlaveListener.class switchReadOnlyConnection() 가 호출된다.
currentReadOnlyAsked
가 true
이며 currentProtocol 이 MasterConnection 이므로 currentProtocol
를 secondayProtocol
로 세팅하게된다.
SecondayProtocol 에는 1번에서 확인한대로 Reader Machine DNS 가 저장되어있다.
readOnly=false
상태로 쿼리 실행하는 과정과 동일하지만, MasterSlaveListener.java
에서 invoke()
함수가 호출되었을때 this.currentProtocol
이 secondaryProtocol
로 변경되어있다.
currentProtocol
이 secondaryProtocol
과 주소가 일치하며 currentProtocol 의 socket
도 read endPoint
가 사용되고 있음을 알 수 있다.
readOnly = true 옶션이 없는 경우, 모두 마스터로 조회가 된다!
MasterSlaveListener.java 에 저장된 primary, secondary protocol 은 이것을 상속받은 AuroraListener 에서 사용될 수 있다.
v3.0 이상의 mariadb driver 는 AWS aurora 를 지원하지 않는다.
https://mariadb.com/kb/en/about-mariadb-connector-j/#failover-and-load-balancing-modes
AWS 문서 Amazon Aurora DB 클러스터에 연결에서는 MySQL용 AWS JDBC 드라이버로 이동할 것을 권장하고 있다.
runtimeOnly "software.aws.rds:aws-mysql-jdbc"
datasource:
hikari:
driver-class-name: software.aws.rds.jdbc.mysql.Driver
jdbc-url: jdbc:mysql:aws://dev.cluster.rds.amazonaws.com:3306/test
권장 문서를 참고하여 드라이버를 변경하면 되지만, read/write split 기능은 제공하지 않고 있다.
runtimeOnly "org.mariadb.jdbc:mariadb-java-client"
datasource:
hikari:
driver-class-name: org.mariadb.jdbc.Driver
jdbc-url: jdbc:mysql:replication://dev-read.cluster.rds.amazonaws.com:3306,dev.cluster.rds.amazonaws.com:3306/test
replication 설정을 해주면 된다. schema 를 포함한 설정들은 write cluster 뒤에 한번만 명시하면 된다!
참고로, Spring Boot 버전을 올리면서 MariaDB 드라이버 버전이 2.x
-> 3.0.x
로 업그레이드되는 경우가 있으니, 기존에 잘 도작하던 2.x
대의 버전을 명시하여 사용하는 것도 방법이 될 것 같다.
Writer endpoint
만 있으면 query 를 통해 나머지 클러스터 정보
를 얻어올 수 있다.MasterProtocol
이다.secondaryProtocol
로 변경된다.
좋은 글 감사합니다. 자주 방문할게요 :)