Active Record의 복원력 향상은 크게 세 가지 영역에서 이루어졌습니다.
1. 연결 검증 (Connection Verification)의 발전
-
초기 방식 (Rails 1.1 이전): 쿼리 실행 후 실패 시에만 연결을 재설정하여, 쿼리 재시도 가능성이라는 복잡한 문제를 야기했습니다.
-
Rails 1.1 도입: 쿼리 실행 전 연결을 핑(ping)하여 검증하는
verify before checkout패턴을 도입, 연결 오류 가능성을 현저히 줄였습니다. 이 방식은 추가적인 왕복 시간을 필요로 하지만, 안정성을 높이는 합리적인 트레이드오프로 간주되었습니다. -
Rails 7.1의 혁신: Matthew의 대규모 리팩토링을 통해 쿼리를
재시도 가능(retriable)으로 표시하는 기능이 추가되었습니다.- 예시:
BEGIN트랜잭션 시작 쿼리는 안전하게 재시도 가능하므로, 초기 연결 검증 핑을 생략하여 지연 시간을 줄일 수 있게 되었습니다. 이는 복원력 향상의 중요한 기반을 마련했습니다.
- 예시:
2. 연결 고정 (Connection Pinning)의 변화
-
기존 방식 (Rails 7.1까지): 한 요청 처리 스레드가 연결을 체크아웃하면, 해당 연결은 요청이 끝날 때까지 스레드에
고정(pinned)되었습니다. 이는 동일한 연결이 여러 쿼리에 사용되도록 보장했지만, 연결 풀 크기에 제약을 주었습니다. - Rails 7.2의 세분화된 체크아웃 (Granular Connection Checkouts): Jean은 연결이 쿼리 사용 후 바로 풀로 반환되도록 Active Record를 리팩토링했습니다.
- 장점: 요청이 쿼리 외 다른 작업을 하는 시간이 길 경우, 필요한 총 연결 수를 줄일 수 있습니다.
- 문제점: 각 쿼리마다 연결을 체크아웃하고 재검증하는 과정에서 불필요한 지연 시간이 발생할 수 있었습니다.
- Rails 8.0.2의 개선: Matthew는 검증 핑이 마지막 성공적인 쿼리 이후 2초 이상 경과했을 때만 발생하도록 시간 기반 로직을 추가하여, 세분화된 체크아웃의 성능 저하를 해결하고 7.1의 효율적인 검증 동작을 복원했습니다.
3. 쿼리 재시도 가능성 (Query Retriability)의 확장
-
재시도 기준: Active Record는 기본적으로
멱등성(idempotent)을 가지는 쿼리(여러 번 실행해도 안전한 쿼리)만 자동으로 재시도해야 합니다.SELECT쿼리가 이에 해당하지만, 데이터베이스를 수정할 수 있는 함수나 서브쿼리를 포함할 경우 멱등성이 깨질 수 있습니다. -
Rails 7.2의 자동 재시도 가능한 SELECT 쿼리: Adriana의 기여로, Active Record는 쿼리 빌드 과정에서
SQL literal과 같이 재시도 불가능한 요소를 감지하여 해당 쿼리를 자동으로 재시도 불가능으로 표시합니다. 이는 대부분의SELECT쿼리를 재시도 가능하게 하여 연결 오류로부터의 복구 가능성을 크게 높였습니다. -
Rails 8.1의 추가 개선: 연사는 Active Record 내부적으로 사용되는
SQL literal(예:1 as 1)이 쿼리를 재시도 불가능하게 만드는 문제를 발견했습니다.- 해결책:
Arel.sql(sql_string, retriable: true)옵션을 통해 개발자가알려진 안전한(known safe)SQL 문자열에 대해 명시적으로 재시도 가능하다고 표시할 수 있게 했습니다. 이는 Rails 7.2부터 사용 가능하며, Rails 8.1에서 더욱 개선되어 기본적으로 더 많은 쿼리가 재시도 가능하도록 내부 수정이 이루어졌습니다.
- 해결책: