다중 데이터베이스 구현
- 데이터베이스 분리:
Patient모델의 민감한 데이터를patients.sqlite3라는 별도의 데이터베이스로 분리합니다. 이를 위해PatientsRecord라는 추상 클래스를 생성하고connects_to database: { writing: :patients }를 사용하여 연결을 설정합니다. - 외래 키 제약: 데이터베이스 간 외래 키 제약은 작동하지 않으므로,
appointments와patients테이블 간의 외래 키를 제거해야 합니다. 이로 인해 참조 무결성(Referential Integrity)이 상실되며, 고아 데이터(orphaned data) 방지는 애플리케이션 레이어에서 관리해야 합니다. - 읽기 복제본(Read Replica): 읽기 수요가 높은 테이블을 위해
patients_replica를 추가하여 읽기 전용 접근을 구현할 수 있습니다.connects_to database: { writing: :patients, reading: :patients_replica }설정을 통해 읽기/쓰기 분할을 활성화하며,config.active_record.database_selector를 사용하여 자동 전환을 설정합니다.
ActiveRecord::Tenanted를 통한 다중 테넌시
- 젬 도입:
ActiveRecord::Tenanted젬(v0.3.0)을 사용하여 각 테넌트(Practice)별 데이터베이스를 생성하고 관리합니다.config/database.yml에서tenanted: true를 설정하고,ApplicationRecord에tenanted :primary를 지정합니다. - 초기 문제점 및 아키텍처 조정: 초기에는
primary와patients데이터베이스를 모두 테넌트화하려고 시도했으나,ActiveRecord::Tenanted젬이 단일 연결 클래스에 맞춰 설계되어 있어 충돌이 발생했습니다. 이에 따라Patient모델은ApplicationRecord아래로 이동하여primary테넌트 데이터베이스의 일부가 되었습니다. - 최종 아키텍처:
GlobalRecord(글로벌 데이터베이스):Practice(테넌트 관리),Session(인증 세션)ApplicationRecord(테넌트 데이터베이스primary):User,Staff,Appointment,Patient
- 구현 세부 사항:
Practice및Session관련 외래 키 제약 조건 제거.- 로컬 환경에서 서브도메인 해결을 위한
config.action_dispatch.tld_length = 0설정. - 다른 데이터베이스의 참조를 찾기 위한 사용자 정의 메서드(예:
Practice#patients,Patient#practice) 추가. Practice생성 시ApplicationRecord.create_tenant(slug)를 호출하여 테넌트 데이터베이스 생성.
- 테넌트 전환:
ApplicationRecord.current_tenant = "tenant_name"명령을 통해 현재 테넌트를 변경하면, 해당 테넌트의 격리된 데이터베이스에서 쿼리가 실행됨을 확인했습니다.