2023-07-21-TIL
2023-07-21-TIL
Today I Learned
Optimistic Lock vs Pessimistic Lock
동시에 같은 데이터를 수정할 때 갱신 손실을 막는 두 접근이다.
- 낙관적 락: 충돌이 드물다고 보고 락을 잡지 않는다. JPA에서는
@Version필드를 두면 UPDATE의 WHERE 절에 읽었던 버전을 넣어, 그 사이 다른 트랜잭션이 수정했다면 갱신 행 수가 0이 되고OptimisticLockException이 발생한다. 충돌은 커밋 시점에 발견되므로 재시도나 사용자 안내가 필요하다. - 비관적 락: 충돌이 잦다고 보고 읽는 시점에 DB 락을 잡는다. JPA의
LockModeType.PESSIMISTIC_WRITE는 보통SELECT ... FOR UPDATE로 실행되고, 다른 트랜잭션은 락이 풀릴 때까지 기다린다. 충돌을 확실히 막지만 대기와 데드락 위험이 있고, 락 대기 시간 제한을 함께 정해야 한다.
Spring Data JPA에서는 리포지토리 메서드에 @Lock(LockModeType.OPTIMISTIC)이나 @Lock(LockModeType.PESSIMISTIC_WRITE)를 붙여 쿼리별로 지정할 수 있다. 링크한 글은 리포지토리를 이용해 낙관적 락을 구현하는 과정을 다룬다. 재고 차감처럼 충돌이 잦고 실패 비용이 크면 비관적 락, 게시글 수정처럼 충돌이 드물면 낙관적 락이 일반적인 선택이다.
- https://sabarada.tistory.com/185
- LockModeType (Java EE 7 API)
Spring 6.1의 RestClient
Spring 블로그는 2023년 7월 13일 Spring Framework 6.1 M2에 새 동기 HTTP 클라이언트 RestClient가 들어온다고 소개했다. 글의 설명대로 RestClient는 WebClient의 fluent API를 RestTemplate의 인프라 위에 올린 것이다. RestTemplate처럼 모든 HTTP 기능을 템플릿 메서드로 노출하다 보니 오버로드 메서드가 너무 많아졌다는 반성에서, WebClient와 비슷한 API를 쓰되 메시지 컨버터, 요청 팩토리, 인터셉터 같은 RestTemplate의 기반 구성 요소를 그대로 쓴다. RestClient.create(restTemplate)로 기존 RestTemplate 설정을 이어받을 수도 있다.
1
2
3
4
5
RestClient restClient = RestClient.create();
String result = restClient.get()
.uri("https://example.com")
.retrieve()
.body(String.class);
리액티브 스택이 아닌 애플리케이션에서 WebClient를 쓰려고 WebFlux 의존성을 추가하던 경우에 대안이 생긴 셈이다.
- https://spring.io/blog/2023/07/13/new-in-spring-6-1-restclient
트랜잭션 전파
전파 속성은 트랜잭션 메서드가 이미 진행 중인 트랜잭션 안에서 호출될 때 어떻게 할지를 정한다. Spring 문서 기준으로 자주 쓰는 세 가지는 다음과 같다.
REQUIRED(기본값): 진행 중인 트랜잭션이 있으면 참여하고, 없으면 새로 시작한다. 안쪽 메서드가 롤백을 표시하면 바깥까지 롤백되고, 바깥이 이를 모르고 커밋하려 하면UnexpectedRollbackException이 발생한다.REQUIRES_NEW: 항상 독립된 물리 트랜잭션을 새로 시작한다. 바깥 트랜잭션은 일시 중단(suspend)되었다가 안쪽이 끝나면 재개되고, 둘은 따로 커밋, 롤백된다. 문서는 바깥 트랜잭션의 커넥션을 잡은 채 새 커넥션을 요구하므로 커넥션 풀이 동시 스레드 수보다 최소 하나 이상 커야 고갈을 피할 수 있다고 경고한다.NESTED: 하나의 물리 트랜잭션 안에서 세이브포인트를 만들어, 안쪽만 부분 롤백하고 바깥은 계속 진행할 수 있다. JDBC 세이브포인트를 쓰므로 JPA 트랜잭션 매니저에서는 제약이 있다.
질문으로 남겨 둔 “트랜잭션을 일시 중단한다”는 말은, 현재 스레드에 묶인 트랜잭션 자원(커넥션 등)을 떼어 보관해 두고 새 트랜잭션을 진행한 뒤 다시 붙인다는 뜻이다.
- https://www.javainuse.com/spring/boot-transaction-propagation
- https://dzone.com/articles/spring-transaction-propagation
- https://stackoverflow.com/questions/33729810/what-does-suspending-a-transaction-means
- Transaction Propagation (Spring Framework Reference)
@Transactional(readOnly = true)
readOnly = true는 트랜잭션이 읽기만 한다는 힌트다. Spring 문서에 따르면 이 속성도 격리 수준처럼 새 트랜잭션을 시작하는 REQUIRED나 REQUIRES_NEW에서만 적용된다. 실제 효과는 트랜잭션 매니저와 구현체에 달려 있다. JPA와 Hibernate 조합에서는 Spring의 HibernateJpaDialect가 세션의 flush 모드를 MANUAL로 바꾸고 세션을 기본 읽기 전용으로 설정한다. 그래서 더티 체킹을 위한 스냅샷 비교와 flush가 생략되어 조회 성능과 메모리 사용에 이점이 있고, 실수로 엔티티를 수정해도 반영되지 않는다. 또 JDBC 연결에도 읽기 전용이 전달되므로, AbstractRoutingDataSource로 읽기 요청을 복제본에 보내는 구성에서 라우팅 판단 기준으로 쓰이기도 한다.
링크한 글들은 이런 이유로 조회 메서드에 readOnly = true를 붙이고, 클래스 레벨에 기본으로 걸어 둔 뒤 쓰기 메서드에만 @Transactional을 다시 붙이는 패턴을 권한다. Spring Data JPA의 SimpleJpaRepository도 클래스에 @Transactional(readOnly = true)를 두고 save() 같은 쓰기 메서드에만 일반 @Transactional을 붙인다.
- https://velog.io/@jurlring/TransactionalreadOnly-true%EC%97%90%EC%84%9C-readOnly-true%EB%8A%94-%EB%AC%B4%EC%8A%A8-%EC%97%AD%ED%95%A0%EC%9D%B4%EA%B3%A0-%EA%BC%AD-%EC%8D%A8%EC%95%BC%ED%95%A0%EA%B9%8C
- https://hungseong.tistory.com/74
- https://willseungh0.tistory.com/75
External Token
같은 “외부 토큰”이라는 말이 맥락에 따라 다른 것을 가리켜서 세 가지를 정리했다.
- API 게이트웨이의 서드파티 OAuth 토큰: Apigee 문서는 Apigee가 직접 발급하지 않은, 외부 인가 서버가 발급한 OAuth 토큰을 받아들여 검증하는 방법을 다룬다. 이미 사내 인증 서버가 있을 때 게이트웨이가 토큰 발급까지 떠맡지 않고 검증과 정책 적용만 하게 하는 구성이다.
- 분산 락의 fencing token: Designing Data-Intensive Applications 8장 정리 글은 락 서버가 락을 줄 때마다 증가하는 번호를 함께 주고, 저장소는 이 번호가 이전보다 작은 쓰기를 거부하게 해서, 락이 만료된 줄 모르는 느린 노드가 데이터를 망가뜨리는 것을 막는 방법을 설명한다. ZooKeeper라면 트랜잭션 ID나 노드 버전을 이 토큰으로 쓸 수 있다. 다만 악의적으로 가짜 토큰을 보내는 노드까지 막지는 못한다.
데이터 보호의 외부 토큰화: Snowflake의 External Tokenization은 민감한 값을 외부 토큰화 서비스가 만든 토큰으로 저장하고, 조회 시 마스킹 정책과 외부 함수로 권한 있는 역할에게만 원래 값을 복원해 보여 준다.
- https://cloud.google.com/apigee/docs/api-platform/security/oauth/use-third-party-oauth-system?hl=ko
- https://azderica.github.io/til/docs/data/designing-data-intensive-applications/ch8/
- https://docs.snowflake.com/ko/user-guide/security-column-ext-token-use
Token Synchronization
OTP 하드웨어 토큰 맥락의 토큰 동기화다. Thales SafeNet Trusted Access 문서에 따르면 이벤트 기반 토큰은 사용자가 OTP를 생성만 하고 인증에 쓰지 않으면 서버의 카운터와 어긋나고, 시간 기반 토큰은 내부 시계가 서버 시간과 조금씩 벌어진다. 서버는 사용자가 인증할 때 정해진 범위(window) 안에서 앞쪽 값까지 찾아 일치하는 OTP를 발견하면 자동으로 다시 맞춘다. window를 넓히면 편하지만 추측 공격에 유리해지므로 보안과 편의의 균형을 맞춰 정한다. IBM 문서는 외부 인증 서버의 토큰 그룹 설정 화면을 설명한다.
- https://thalesdocs.com/sta/operator/tokens/tkn_sync/index.html
- https://www.ibm.com/docs/en/external-auth-server/6.0.2?topic=menu-token-group-configuration-tab
댓글
아직 댓글이 없습니다