[Aurora DB] Aurora DB 는 읽기 전용 커넥션일 때 알아서 라우팅을 해준다고?

Hocaron·2023년 8월 14일
3

DB

목록 보기
9/10
post-thumbnail

"Aurora DB 사용하면 Transaction readOnly 인 경우에 Reader(Slave) Connection 타지 않아요?"
어플리케이션에 있는 설정 정보라고는 Cluster 설정뿐인데, 어떻게 Reader DNS를 찾아서 커넥션을 맺는걸까?

위 그림처럼 mariadb-connector-j 를 사용하여 Aurora DB 로 connection 을 맺게 되면 ReadOnly 설정에 따라 다른 DNS 로 라우팅되게 된다. 그 과정을 살펴보자.

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 Parsing

HostAddress.java parse() 에서 DB 주소 정보를 파싱한다.

Writer, Reader DNS 정보를 조회

AuroraListener.java getCurrentEndpointIdentifiers() 에서 클러스터에 존재하는 DB 정보를 조회한다.


실제 위 쿼리를 DB 에 조회해보면 위와 같이 설정된 같이 나오는 것을 알 수 있다.

✍️ connection 의 readOnly = false 로 세팅

MariaDbStatement 에서 protocol.execute() 호출 후, FailoverProxy invoke() 호출

이때 AuroraProtocol.java 에는 FailoverProxy.java 가 Proxy 로 걸려있기 때문에 FailoverProxy 의 invoke() 가 호출된다.


FailoverProxy.java 에는 AuroraProtocol.java 의 각 함수들이 호출되었을때 수행되어야하는 프록시 로직들이 swtich case 문으로 정의 되어있다.

readOnly = false 상태로 쿼리 실행

MasterSlaveListener.java 에서 currentProtocol.executeQuery() 함수를 invoke 하였으므로 AbstarctQueryProtocol.java executeQuery() 가 실행되었고 여기에서 실제 네트워크 작업이 실행된다.

브레이크 포인트를 통한 확인

currentProtocolmasterProtocol 과 주소가 일치하며 currentProtocol 의 socketwrite endPoint 가 사용되고 있음을 알 수 있다.

📖 connection 의 readOnly = true 로 세팅

readOnly = true 상태로 쿼리 실행

connection 의 setReadOnly() 가 호출되면 MariaDbConnection.java setReadOnly() 가 호출되고 이 함수 내부에서 protocol.setReadOnly() 가 호출된다.

Protocol 의 함수가 호출되면 어김없이 프록시인 FailoverProxy.java 의 invoke() 가 호출된다.


FailoverProxy.java 에서 setReadOnly 함수가 호출되면 listener.switchReadOnlyConnection() 를 호출해주게 된다.

이로 인해 MasterSlaveListener.class switchReadOnlyConnection() 가 호출된다.
currentReadOnlyAskedtrue 이며 currentProtocol 이 MasterConnection 이므로 currentProtocolsecondayProtocol 로 세팅하게된다.

SecondayProtocol 에는 1번에서 확인한대로 Reader Machine DNS 가 저장되어있다.

readOnly=false 상태로 쿼리 실행하는 과정과 동일하지만, MasterSlaveListener.java 에서 invoke() 함수가 호출되었을때 this.currentProtocolsecondaryProtocol 로 변경되어있다.

브레이크 포인트를 통한 확인

currentProtocolsecondaryProtocol 과 주소가 일치하며 currentProtocol 의 socketread endPoint 가 사용되고 있음을 알 수 있다.

🤔 connection 의 @Transactional 없이 세팅없이 수행하면 어디로 수행이 될까?


readOnly = true 옶션이 없는 경우, 모두 마스터로 조회가 된다!

각 클래스별 다이어그램

MasterSlaveListener.java 에 저장된 primary, secondary protocol 은 이것을 상속받은 AuroraListener 에서 사용될 수 있다.

버전 이슈

aurora 모드를 지원하지 않는다고?

v3.0.3 이상의 mariadb driver 는 AWS aurora 를 지원하지 않는다.
https://mariadb.com/kb/en/about-mariadb-connector-j/#failover-and-load-balancing-modes

AWS JDBC 드라이버로 해결이 가능할까?

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 대의 버전을 명시하여 사용하는 것도 방법이 될 것 같다.

정리

  • mariadb-connector-j 는 aurora 모드일때 Writer endpoint 만 있으면 query 를 통해 나머지 클러스터 정보를 얻어올 수 있다.
  • 각 모드별로 사용되는 Proxy 가 있으며 Aurora Mode 일때는 FailoverProxy 가 사용되어 Protocol 이 호출되기 전에 Listener 함수를 호출한다.
  • MasterSlaveListener 에는 currentProtocol 를 맴버 변수로 가지고 있으며 currentProtocol 을 통해 DB 와 통신한다.
  • default 로 currentProtocol 은 MasterProtocol 이다.
  • connection.setReadOnly() 호출되면 currentProtocol 이 secondaryProtocol 로 변경된다.

References

profile
기록을 통한 성장을

2개의 댓글

comment-user-thumbnail
2023년 8월 14일

좋은 글 감사합니다. 자주 방문할게요 :)

1개의 답글