1. SQLite를 활용한 물리적 데이터 격리
37 Signals는 신규 서비스 ‘Fizzy’를 개발하면서 각 고객마다 별도의 SQLite 데이터베이스 파일을 할당하는 파격적인 방식을 시도했습니다. 이는 기존의 ‘공유 데이터베이스(Co-mingled database)’ 방식이 가진 보안 리스크를 제거하기 위함이었습니다. - 기술적 이점: SQLite는 파일 기반 데이터베이스이므로 네트워크 오버헤드가 없고, 고객별로 데이터베이스를 복사, 삭제, 이동하기가 매우 용이합니다. - 글로벌 스케일링의 도전: 하지만 지리적으로 분산된 데이터 센터 환경에서 SQLite의 단일 쓰기(Single Writer) 특성을 유지하며 실시간 복제 및 장애 조치(Failover)를 구현하는 것은 매우 복잡한 문제였습니다. 네트워크 라우팅 레이어와 데이터베이스 레이어를 긴밀하게 연결해야 하는 이 과제는 ‘Beamer’라는 프로젝트로 이어졌으나, 출시 일정 문제로 Fizzy는 최종적으로 MySQL을 선택하게 되었습니다.
2. active_record-tenanted 젬: 안전하고 직관적인 구현
Mike는 멀티테넌시 구현을 돕기 위해 active_record-tenanted라는 새로운 젬을 개발하여 오픈 소스로 공개했습니다. 이 젬은 기존의 ‘Apartment’ 젬이 가진 스레드 안전성 문제와 성능 한계를 극복했습니다.
- 자동 컨텍스트 전환: 요청이 들어오면 서브도메인이나 URL 경로 등을 분석하여 적절한 테넌트 데이터베이스로 자동 연결합니다. 개발자는 쿼리마다 테넌트 조건을 추가할 필요가 없습니다.
- 강력한 안전 장치(Safety Checks): 가장 핵심적인 기능은 ‘데이터 혼입 방지’입니다. 예를 들어, 테넌트 A의 컨텍스트에서 테넌트 B에 속한 레코드를 수정하려 하면 런타임 에러를 발생시켜 데이터 오염을 원천 차단합니다.
- Rails 구성 요소 통합: 단순 DB 연결 외에도 뷰 프래그먼트 캐싱(Fragment Caching) 시 테넌트별 키 분리, Active Storage의 파일 저장 경로에 테넌트 ID 자동 포함 등 Rails 프레임워크 전반에 걸친 멀티테넌시를 지원합니다.
3. 실전 적용 및 확장성
영상에서 Mike는 ‘Writebook’ 애플리케이션을 단 5분 만에 멀티테넌트 구조로 전환하는 데모를 선보였습니다. - 유연한 테넌트 식별: 람다(Lambda) 함수를 통해 요청(Request) 객체에서 테넌트 이름을 추출하는 로직을 자유롭게 정의할 수 있습니다. - 다차원 테넌팅 지원: 고객별 격리뿐만 아니라, 백그라운드 작업(Solid Queue)을 지역(Region)별로 분리하는 등 복합적인 테넌팅 요구사항을 처리할 수 있는 유연한 API를 설계했습니다. 이는 젬이 전역 싱글톤 방식이 아닌 각 모델 클래스에 테넌팅 기능을 주입하는 방식을 취했기 때문에 가능했습니다.
4. 향후 전망과 Rails 코어 통합
현재 37 Signals는 ‘Once’ 제품군에 이 젬을 적용하여 실질적인 운영 데이터를 쌓고 있습니다. Mike는 Rails가 자체적으로 ‘기본/보조(Primary/Passive)’ 모드와 같은 장애 조치 프리미티브를 갖추어야 한다고 주장하며, 멀티테넌시가 Rails의 표준 기능으로 자리 잡을 수 있도록 지속적으로 기여할 계획임을 밝혔습니다.