상민,
뒤로가기

시리즈 게시글


Wednesday, May 31, 2023

#daily

TODOs

  • HeyDuck

WORK

  • ReadReplica 컨벤션 제안
  • LiveActivity 대응
  • HeyDuck

TIL

  • 아래 3가지 설정값들은 data source 를 가져오기 위한 연산이자, 일반적으로 Spring Data 내부에서 이런 정보들이 ThreadLocal 을 통해 관리되는 공통점이 있음.
    • ReadReplica 로 보낼 것이냐
    • ReadOnly Transaction 이냐
    • Transaction IsolationLevel 이 어떻게 되냐
  • But ThreadLocal 은 Coroutine 과 공생하기 어려운 object 임. (ThreadLocal 을 CoroutineContext 로 넘겨주는 방법이 존재하긴 하지만, 결국 write 에 대해서 자연스럽지 못하기도 하고 표현의 어색함이 존재한다.)
rrEnable {
	// 여기서는 rr 이 켜져있다.
    RequestScope.async {
		// 여기 내부에서는 rr 이 안 켜져있다.
    }
	// 여기서는 rr 이 켜져있다.
}

제안 1

  • rrEnable 의 값을 ThreadLocal 에서 가져와 CoroutineContext 로 주입받는 형태로 만든다.
val RequestScope = CoroutineScope(rrEnableThreadLocal.asContextElement())

rrEnable {
	// 여기서는 rr 이 켜져있다.
    RequestScope.async {
		// 여기 내부에서도 rr 이 켜져있다.
    }
	// 여기서는 rr 이 켜져있다.
}
  • 데이빗 의견: Tx 와 RR 이 유사한 위계의 값이며, Tx 는 코루틴 내부로 전파되지 않는 사용성을 서버팀에서 자연스럽게 사용하는데 RR 은 이와 다른 패턴이 되면 어색하고 실수하기 쉽다.
  • 제이콥 의견: 하지만 Tx 와 다르게 RR 은 아직 사람들이 익숙하지 않아서 위 예시에서 async 내부 블럭도 RR 을 탈거라고 착각하기 쉽다.

제안 2

  • Coroutine 내부에서는 꼭 새로운 Tx 를 여는 행동을 자연스럽게 하는데, ReadReplica 또한 이런 멘탈모델의 연장으로 고려되는 것이 유리한 것 같다. (ThreadLocal 의 관점에도, 명시적인 Scoping 관점에도)
  • 그러면... 아예 RR 로 꽃을지 말지를 withTx 에서 관리하게 만들어서
    • 확실하게 non coroutine function 만 실행 시킴을 보장 시키고 (시그니쳐가 suspend fun 이 아니므로)
    • Tx, RR 여부와 같은 DB 접근 레이어를 withTx 에 책임을 몰아넣어서 스코핑 실수를 하지 않도록 만들자
RequestScope.async {
	// 여기서는 rr 이 꺼져있다.
	withTx(useReadReplica = true) {
		// 여기서는 rr 이 켜져있다.
	}
	// 여기서는 rr 이 꺼져있다.
}

변경내역

  • 제안 2를 기준으로 withTx 의 새로운 인터페이스를 제안해본다.
  • 추가로, withTx 에서 RR 을 처리하게 명시함에 따라, 기존 JPA 접근 방식이 readOnly 인 경우 RR 로 쏘는 쿼리들 또한 강제하지 않고, withTx 를 통한 선택지 중 하나로 master & readOnly 인 케이스를 열어둔다.