1. Rails 기반 파일 시스템 퍼블리싱 엔진의 설계
저자는 NoraFoundry.dev 프로젝트에서 기술 노트와 아키텍처 에세이를 게시하기 위해 별도의 Hugo 스택을 유지하는 대신 Rails 내부에 직접 퍼블리싱 엔진을 구현했습니다. 이 시스템은 다음과 같은 특징을 가집니다.
* 데이터베이스 미사용: 모든 콘텐츠는 content/papers/ 디렉토리에 Markdown 파일로 저장되며, 메타데이터는 YAML 프런트매터(Frontmatter)를 통해 관리됩니다.
* 자동화된 렌더링: CommonMark(Rust 기반 GFM)와 Nokogiri, Rouge를 사용하여 Markdown을 HTML로 변환하고 목차(TOC) 생성 및 코드 하이라이팅을 수행합니다.
* 버전 관리 중심: 별도의 관리자 페이지나 CMS 없이 Git 버전 관리 시스템 자체가 퍼블리싱 워크플로우가 됩니다.
2. 컨테이너 환경에서의 캐싱 문제와 의사결정
초기 구현에서는 Solid Cache와 SQLite를 컨테이너 로컬 파일 시스템에 배치하여 캐시를 관리했습니다. 하지만 다음과 같은 치명적인 결함이 발견되었습니다.
* 배포 시 캐시 유실: 컨테이너가 재배포될 때마다 내부 파일 시스템이 교체되면서 SQLite 데이터베이스가 삭제되었고, 이는 캐시 읽기 시도 시 500 에러를 유발했습니다.
* 생명주기 결합: 캐시의 수명이 컨테이너의 실행 주기와 강하게 결합되어 있어 인프라의 유연성이 떨어졌습니다.
이를 해결하기 위해 저자는 두 가지 대안을 검토했습니다. 1. 영구 볼륨(Persistent Volume) 마운트: SQLite를 유지하되 호스트 디렉토리를 마운트하는 방식입니다. 인프라 변경은 적지만 다중 컨테이너 확장 시 관리가 어렵습니다. 2. 외부 Redis 도입: 캐시 상태를 전용 Redis 인스턴스로 이전하는 방식입니다. 인프라 복잡도는 약간 증가하지만 캐시 생명주기를 완전히 독립시킬 수 있습니다.
최종적으로 Redis를 선택함으로써 캐시 상태를 인프라 수준으로 격리하고, 중앙 집중식 가시성을 확보했습니다.
3. 효율적인 캐시 관리 및 보안 전략
단순히 Redis로 옮기는 것에 그치지 않고, 시스템의 안정성을 높이기 위해 다음과 같은 기법들을 적용했습니다.
* mtime 기반 캐시 키: 파일의 수정 시간(File.mtime)을 캐시 키의 접미사로 활용하여, Markdown 파일이 수정되면 별도의 명령 없이도 즉시 캐시가 무효화(Bust)되도록 설계했습니다.
* TTL(Time To Live) 설정: 30일의 TTL을 설정하여 사용되지 않는 오래된 캐시 키가 Redis 메모리를 점유하지 않도록 가비지 컬렉션을 자동화했습니다.
* Fail-Open 시맨틱: Redis 연결 오류 발생 시 Redis::BaseError를 구출(rescue)하여 캐시 없이 직접 렌더링하도록 구현했습니다. 이를 통해 캐시 서버 장애가 서비스 중단으로 이어지지 않도록 방어했습니다.
* 네트워크 보안: Redis를 공용 인터넷이 아닌 프라이빗 LAN에 배치하고, 인증 비밀번호 설정 및 로컬 호스트 바인딩을 통해 보안을 강화했습니다.
4. 점진적 개선의 중요성
이 프로젝트의 핵심은 처음부터 완벽한 인프라를 구축하는 것이 아니라, 실제 운영 환경에서의 요구사항과 문제점에 따라 시스템을 진화시키는 데 있습니다. 초기에는 SQLite로 단순하게 시작하고, 배포 과정에서 문제가 발생했을 때 Redis로 전환하는 결정을 내림으로써 오버엔지니어링을 피하고 지속 가능한 아키텍처를 구축할 수 있었습니다.