포스트

2023-06-16-TIL

2023-06-16-TIL

Today I Learned

트랜잭션 격리 수준

격리 수준은 동시에 실행되는 트랜잭션이 서로의 변경을 어디까지 볼 수 있는지를 정한다. SQL 표준은 네 단계를 정의하고, 단계가 높을수록 막아 주는 이상 현상이 늘지만 동시성은 떨어진다.

격리 수준Dirty ReadNon-Repeatable ReadPhantom Read
READ UNCOMMITTED발생발생발생
READ COMMITTED방지발생발생
REPEATABLE READ방지방지발생
SERIALIZABLE방지방지방지
  • Dirty Read: 다른 트랜잭션이 커밋하지 않은 변경을 읽는 것이다.
  • Non-Repeatable Read: 같은 행을 두 번 읽었는데 그 사이 다른 트랜잭션의 커밋으로 값이 바뀐 것이다.
  • Phantom Read: 같은 조건으로 두 번 조회했는데 그 사이 다른 트랜잭션이 넣은 행이 새로 보이는 것이다.

표는 표준이 허용하는 최소 보장이고 실제 동작은 DBMS마다 다르다. MySQL InnoDB의 REPEATABLE READ는 MVCC 스냅샷으로 일반 SELECT의 팬텀을 대부분 막고, 잠금 읽기에서는 갭 락과 넥스트 키 락으로 다른 세션의 삽입을 막는다. Spring의 @Transactional 기본 격리 수준은 Isolation.DEFAULT로, 별도로 지정하지 않으면 DB의 기본값을 그대로 쓴다.

  • https://hudi.blog/transaction-isolation-level/
  • https://github.com/woowacourse-study/2022-cs-plant
  • https://velog.io/@jurlring/MySQL%EC%9D%98-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80%EA%B3%BC-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-Transactional-%EA%B8%B0%EB%B3%B8-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80
  • https://www.lesstif.com/dbms/mysql-mariadb-transaction-isolation-level-106857422.html#:~:text=%EC%84%B8%EC%85%98%20%EC%84%A4%EC%A0%95%20%ED%99%95%EC%9D%B8,%EC%88%98%EC%A4%80%22%EC%9D%84%20%ED%99%95%EC%9D%B8%ED%95%A0%20%EC%88%98%20%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4.
  • Transaction Isolation Levels (MySQL 8.0)

MySQL 8.0의 기본 격리 수준

MySQL 문서에 따르면 InnoDB의 기본 격리 수준은 REPEATABLE READ다. 같은 트랜잭션 안의 일반(잠금 없는) SELECT는 첫 읽기에서 만든 스냅샷을 계속 읽으므로 서로 일관된 결과를 낸다. 현재 값은 SELECT @@transaction_isolation;으로 확인하고, SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL ...로 바꾼다. Oracle과 PostgreSQL은 기본값이 READ COMMITTED라서, DB를 옮기거나 여러 DB를 함께 쓰면 같은 코드라도 동시성 동작이 달라질 수 있다.

  • https://dev.mysql.com/doc/refman/8.0/en/set-transaction.html#:~:text=The%20default%20isolation%20level%20is,isolation%20levels%2C%20see%20Section%2015.7.

비밀번호 만료 확인 API 설계

비밀번호 만료 정책이 있으면 로그인 API는 “자격 증명은 맞지만 비밀번호를 바꿔야 한다”는 세 번째 결과를 알려야 한다. 링크한 질문의 작성자가 택한 방법은 인증 결과를 성공/실패 boolean 대신 열거값(ValidCredentials, InvalidCredentials, CredentialsExpired, NoCredentials)으로 돌려주는 것이다. 클라이언트는 CredentialsExpired를 받으면 비밀번호 변경 화면으로 보낸다.

설계할 때 고민할 점은 만료 상태에서 토큰을 줄지다. 일반 토큰을 주면 비밀번호를 바꾸지 않고 다른 API를 계속 쓸 수 있으므로, 토큰을 주지 않거나 비밀번호 변경 API만 호출할 수 있는 제한된 토큰을 주는 편이 정책 취지에 맞다. 상태 코드는 인증 자체는 성공했으므로 401보다는 403과 구체적인 오류 코드를 함께 주는 방식이 흔하다.

  • https://stackoverflow.com/questions/9088354/password-change-required-response-from-restful-token-service

AWS AssumeRole

AssumeRole은 AWS STS(Security Token Service)의 API로, IAM 역할을 맡아 임시 보안 자격 증명을 받는다. STS 문서에 따르면 결과는 액세스 키 ID, 비밀 액세스 키, 세션 토큰으로 이루어진 임시 자격 증명이고, 같은 계정 안에서나 다른 계정의 리소스에 접근할 때(cross-account) 주로 쓴다. 세션 시간은 DurationSeconds로 정하며 최소 15분부터 역할에 설정된 최대 세션 시간(1시간에서 12시간 사이)까지 지정할 수 있다.

역할을 맡으려면 두 가지 정책이 맞아야 한다. 역할의 신뢰 정책(trust policy)이 호출자를 허용해야 하고, 호출자에게는 sts:AssumeRole 권한이 있어야 한다. 장기 액세스 키를 애플리케이션에 심는 대신 역할과 임시 자격 증명을 쓰면, 키가 유출돼도 피해 시간이 제한되고 권한을 역할 단위로 관리할 수 있다. EC2나 ECS에서는 인스턴스 프로파일이나 태스크 역할을 통해 SDK가 이 과정을 자동으로 처리한다.

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다