2021 10 25
2021-10-25¶
DB Replication에서 Transaction에 관한 논의¶
- 참고: https://github.com/woowacourse-teams/2021-nolto/pull/639#pullrequestreview-787599584
- 나의 질문
- 해당 메서드는 피드를 조회해온뒤 수정/삭제 할 때에도 쓰이는 메서드 인데, 그 경우엔 다음과 같이 동작하나요?
1. Slave에서 feedId로 조회해와 Feed 엔티티 구성
2. 해당 Feed 엔티티 수정/삭제
3. 해당 Feed 엔티티 정보 Master에 반영
4. Master의 binlog 정보로 Slave도 업데이트
- 아니면 트랜잭션의 전파 설정이 기본값이 부모 트랜잭션으로 합류하는 REQUIRED 이니, 다음과 같이 동작할까요?
1. 해당 메서드를 호출한 곳이 그냥
@transactional어노테이션이니, master db에서 feedId로 조회해온뒤 Feed 엔티티 구성 2. 해당 Feed 엔티티 수정/삭제 3. 해당 Feed 엔티티 정보 Master에 반영 4. Master의 binlog 정보로 Slave도 업데이트 - 저도 레플리케이션은 처음이라 만약 전자처럼 동작한다면, (개인적으로 후자처럼 동작할 것 같긴 합니다만) hoxy slave에서 조회해온 엔티티를 master에 넣을라고 할 때 문제가 생기진 않겠죠?
- 찰리 답변 - 우선 트랜잭션 전파레벨을 따름 - (readOnly=false) 읽기 -> (readOnly=false) 수정: 첫번째 트랜잭션으로 시작해서 updateAll까지 전파 - (readOnly=true) 읽기 -> (readOnly=false) 수정: 첫번째 트랜잭션으로 시작해서 수정이 되지 않음 - readOnly=true의 장점 - FlushMode.MANUAL로 동작 - 강제로 flush 하지 않는한 영속성 컨텍스트 flush 안함 - commit 도 당연히 안함 - Dirty Checking 할필요없어서 스냅샷 저장도 안함 - 즉, 트랜잭션 사용의 시간이 줄어들어!
DB Replication 관련 공부¶
- 참고: https://parkadd.tistory.com/127
- 참고: https://cheese10yun.github.io/spring-transaction/
- 참고: https://tech.yangs.kr/22
- 왜 필요한가?
- Scale Out Solution
- 부하 분산을 통한 성능 향상
- 모든 쓰기/수정/삭제는 Source에서, 읽기는 하나 이상의 Replica 서버에서 담당
- 데이터 보안
- replica 서버는 replication을 일시 중지할 수 있어. 백업 서비스 실행가능
- 분석
- 데이터 분석에 대한 부하를 replica에만 줄 수 있음. - 서비스 성능에 영향 안주고 분석 가능 - 장거리 데이터 배포 - Replication을 사용해 source 서버에 대한 영구 액세스 없이 로컬 복사본 생성 가능
- Source(Master) - Replica(Slave) 구조
- Master: Create, Update, Delete 업무를 진행
- Slave: Read 업무 진행
-
- 마스터의 변경을 기록하기 위한 binlog
- 슬레이브에 데이터를 전송하기 위한 마스터 스레드
- 슬레이브에서 데이터 받아 릴레이 로그에 기록하기 위한 I/O 스레드
- 릴레이 로그에서 데이터를 읽어 재생하기 위한 슬레이브 SQL 스레드
- DB 설정 과정
- binlog 활성화해주기
- my.cnf에서 설정 변경
- 고유한 서버 ID 설정해주기
- Replication 구성을 위해서는 source 서버와 replica 서버들의 server_id가 달라져야함
- 각각의 서버의 server_id는 고유해야함
- Replication을 위한 유저 생성
- Replication Source 서버 바이너리 로그 좌표값 얻기
- Source 서버의 모든 테이블과 블록에 쓰기 명령 플러시
- mysqldump로 데이터베이스 덤프 덮어써주기
- replica 서버에서 source 서버 구성 설정
- replication을 위해 replica 서버와 source 서버가 통신할 수 있도록 replica 서버에 연결 정보 설정
- source에서 설정
mysql> CHANGE REPLICATION SOURCE TO > SOURCE_HOST='172.17.0.1', > SOURCE_USER='replication_usesrname', > SOURCE_PASSWORD='password', > SOURCE_FILE='mysql-bin.000002', > SOURCE_LOG_POS=73;- replication에서 설정 ```mysql mysql> CHANGE MASTER TO > MASTER_HOST='172.17.0.1', > MASTER_USER=' replication_usesrname', > MASTER_PASSWORD='password', > MASTER_FILE=' mysql-bin.000002', > MASTER_LOG_POS=73; ```
- Spring 설정 과정
- yml DataSource 설정
- DataSource 두가지로 써주자
- 환경설정 값을 매핑할 빈 생성
-
@ConfigurationProperties를 사용해 JavaBeans에 매핑 - AbstactRoutingDataSource를 상속받은 환경 설정 생성 - 조회 키를 기반으로 다양한 DataSource 중 하나로 getConnection() 메서드 호출 라우팅 - determineCurrentLookupKey() 메서드를 필수로 오버라이딩!@Override protected Object determineCurrentLookupKey() { final boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); if (isReadOnly) { String nextReplicaDataSourceName = replicaDataSourceNames.getNextName(); log.info("Using Replica DB Name : {}", nextReplicaDataSourceName); return nextReplicaDataSourceName; } log.info("Using Source DB"); return DATASOURCE_SOURCE_KEY; }- DatabaseConfig 구현 - readOnly 설정을 기준으로 다음과 같이 바라보게 - false => Master DataSource - true => Slave DataSource
- 복습해보는 스프링의 트랜잭션 동기화 - Connection 오브젝트를 특별한 저장소에 보관해두고, 이후에 호출되는 메서드에서 저장된 Connection을 가져다가 사용
- readOnly 옵션? - 트랜잭션을 읽기 전용으로 설정 가능함 - 개발자의 실수로 해당 트랜잭션 안에서 Write 되는 것을 방지. - Hibernate에서 적용이 재미있음 - FlushMode.MANUAL 모드로 설정 - "이 트랜잭션은 커밋 시 flush를 하지 않는다!" - Hibernate는 Entity에 flush 호출 X - 그 결과, 변경은 자연스럽게 무시됨! - Dirty Checking도 안해서 성능 이점 굿