Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

Ruby on Rails용 LiteStack: 단일 머신에서 모든 데이터를 처리하는 원스톱 솔루션

이번 시리즈에서는 프로덕션 데이터 전체를 단일 머신에서 호스팅하고 처리하는 올인원 솔루션인 LiteStack을 살펴봅니다. LiteStack은 이름 그대로 SQLite를 활용해 다음과 같은 기능을 제공합니다:

  • LiteDB 어댑터를 사용하는 데이터베이스
  • ActiveJob 백엔드(LiteJob)
  • ActionCable 백엔드(LiteCable)
  • ActiveSupport::Cache 스토어(LiteCache)

첫 번째 포스트에서는 LiteStack의 기본 개념을 소개하고 예제 Rails 애플리케이션을 설정해 보겠습니다.

시작해 보겠습니다!

SQLite 소개

SQLite는 수십 년간 여러 산업 분야에서 사실상 표준으로 자리 잡아 온 임베디드 데이터베이스입니다. 네이티브 앱 개발, 테스트 환경, 캐싱 등 다양한 영역에서 폭넓게 사용되고 있습니다.

그런데 최근 들어 SQLite에 대한 실험과 확장이 활발해지고 있습니다. 가장 인기 있는 확장 중 하나는 Litestream으로, 데이터베이스 변경 사항을 S3 호환 버킷으로 스트리밍해 복구할 수 있게 해 줍니다. 즉, 아주 저렴한 비용으로 프로덕션 데이터베이스의 복제본을 유지할 수 있고, 언제든 장애로부터 복구할 수 있다는 뜻입니다.

덕분에 SQLite를 Rails 앱의 프로덕션 데이터베이스로 사용하는 일이 현실적인 선택지가 되었습니다. LiteStack과 같은 완성도 높은 개발 스택과 결합하면, 앱을 단일 머신에서 호스팅하는 것도 충분히 실현 가능합니다. 우리는 이 가설을 직접 검증하고 그 과정에서 마주치는 장애물들을 짚어볼 예정입니다.

이를 위해서는 잠재적인 문제점을 드러낼 만큼은 복잡하면서도, 시리즈로 다루기에는 부담스럽지 않은 수준의 예제 앱이 필요합니다.

예제 Rails 애플리케이션

우리가 만들 앱은 replicate.com의 StableDiffusion을 활용해 아동의 그림을 변환해 주는 서비스입니다.

예를 들어, 제 딸이 그린 귀여운 곰 인형 그림과 StableDiffusion이 해석한 몇 가지 결과물은 다음과 같습니다:

Ruby on Rails용 LiteStack: 단일 머신에서 모든 데이터를 처리하는 원스톱 솔루션

대략적인 설계를 그려 보면, 우리 앱은 다음 단계를 다루게 됩니다:

  1. 사용자가 이미지와 텍스트 프롬프트를 함께 업로드합니다(여기서 고급 SQLite 기법을 소개합니다).
  2. 사용자가 이미지 스타일(예: "카툰", "유화", "사실적 사진", "3D 렌더링")을 선택합니다.
  3. 이미지 처리는 백그라운드에서 진행됩니다(LiteJob 기반의 잡이 실행됩니다).
  4. 처리가 진행되는 동안에는 플레이스홀더 이미지를 표시하고, 서버가 전송하는 로그를 실시간으로 업데이트합니다. 처리가 완료되면 실제 이미지로 교체합니다. Turbo Streams로 이미지를 교체하는 과정에서 LiteCable을 탐색할 수 있습니다.
  5. 생성된 이미지 예측(prediction) 결과를 저장합니다.
  6. 연산 비용이 큰 뷰는 LiteCache로 감싸 성능을 최적화합니다.

이 단계들이 이 시리즈 전체의 뼈대가 됩니다. 다만 이번 포스트의 나머지 부분에서는 앱 설정에 집중하겠습니다.

먼저 esbuild를 JavaScript 번들러로, SASS를 CSS 전처리기로 사용해 skAItch라는 새 Rails 앱을 생성합니다:


LiteStack 설치

다음으로, 제공된 제너레이터를 사용해 LiteStack을 설치합니다:


설치가 끝나면 나머지 설정을 마무리하고 개발 서버를 시작합니다:


인증과 멀티테넌시(Tenants)

이어서 프롬프트를 사용자와 연결하기 위한 인증 체계가 필요합니다. Devise 같은 기존 솔루션 대신 저는 다른 접근 방식을 택했습니다. authentication-zero 젬은 엔진 형태로 포함하는 방식이 아니라, 인증 시스템 코드를 유연하게 생성해 줍니다. 편리하게도 다음과 같은 옵션들도 함께 제공합니다:

  • 토큰 기반 인증(API용)
  • 2단계 인증(2FA)
  • 멀티테넌시
  • 요청 속도 제한(rate limiting)
  • OmniAuth 인터페이스
  • 패스워드리스(passwordless) 인증

저는 --tenantable 옵션을 추가했습니다. 데이터베이스 레코드를 계정 단위로 자동 스코핑하는 것은 언제나 좋은 습관이기 때문입니다. authentication-zero는 AccountScoped 모델 컨선(concern)으로 이 기능을 제공합니다.


이제 시드(seeds)를 통해 첫 번째 사용자를 추가해 보겠습니다:


Prompt 스캐폴딩

이제 실제 애플리케이션 로직을 작성할 차례입니다. 먼저 앱의 핵심 모델인 Prompt를 정의합니다.

프롬프트에는 제목, 설명, 그리고 해당 프롬프트를 생성한 계정에 대한 참조가 필요합니다. 또한 SQLite의 "파일 시스템" 기능을 테스트해 보기 위해, 프롬프트 이미지를 바이너리 형태로 저장하려 합니다:


config/routes.rbprompts 리소스 항목도 추가합니다. 참고로 authentication-zero는 기본적으로 ApplicationController에 사용자를 인증하는 before_action을 자동으로 추가해 줍니다.


또한 Prompt 모델에 AccountScoped 컨선을 포함시켜, 저장된 레코드가 로그인한 계정 기준으로 스코핑되도록 합니다. 프롬프트의 제목과 이미지 존재 여부도 검증합니다.


멀티테넌시를 완성하는 마지막 단계는 프롬프트 생성 시 이를 계정과 연결하는 것입니다. 이 작업은 PromptsController에서 처리합니다:


Rails 애플리케이션과 Replicate.com 연결

Replicate.com은 고성능 그래픽 카드에서 AI 예측(prediction)을 실행하는 대표적인 플랫폼입니다. 예측 생성, 모델 학습 및 저장 등을 위한 API를 제공하며, 이용하려면 https://replicate.com/account/api-tokens 에서 API 토큰을 발급받아야 합니다.

참고: Replicate에서 예측을 실행하면 비용이 청구됩니다.

다행히 이 API와 연동되는 공식 및 비공식 클라이언트가 여럿 존재합니다. 그중 하나가 replicate-rails 젬으로, 지금 바로 설치해 보겠습니다:



API 키는 안전하게 보관하는 것이 중요하므로 Rails credentials를 사용합니다:



이 파일을 편집해 저장하면 credentials가 암호화되며, 올바른 RAILS_MASTER_KEY가 있어야만 다시 열 수 있습니다.

이제 실제로 사용해 보겠습니다. replicate-rails README의 안내에 따라 이니셜라이저에서 Replicate에 인증합니다. 웹훅 핸들러도 함께 정의하는데, 여기서는 같은 파일에 클래스 하나를 두는 수준입니다. 기능을 처음 테스트해 보기 위해 binding.irb 중단점을 추가했습니다.


replicate-rails는 위 핸들러를 호출하는 기본 웹훅 컨트롤러도 함께 제공합니다. 우리가 할 일은 config/routes.rb에 이를 마운트하는 것뿐입니다:


웹훅을 로컬 환경에서 테스트하려면 Ngrok 같은 도구로 터널을 설정해야 합니다. 설정 과정은 이 글의 범위를 벗어나지만 매우 간단하니, Ngrok 공식 문서를 참고하세요.

다만 Rails가 터널 URL의 요청을 받아들일 수 있도록 허용해야 합니다. 이를 위해 config/application.rballowed_hosts에 해당 URL을 추가합니다:


예측(Prediction) 실행하기

이제 예측 생성을 테스트해 보겠습니다. 남은 작업은 PromptsController에 이를 연결하는 것뿐입니다. 전체 흐름은 다음과 같습니다:

  1. Replicate에서 모델(여기서는 stable-diffusion-img2img 모델)을 가져옵니다.
  2. 예측에 사용할 특정 버전(여기서는 최신 버전)을 선택합니다.
  3. 예측을 실행하며 다음 항목들을 지정합니다:
    • 이미지를 설명하는 텍스트 프롬프트(여기서는 프롬프트의 제목)
    • Base64로 인코딩된 Data URL 형태로 제공해야 하는 이미지 프롬프트
    • 예측 완료 시 호출될 웹훅(replicate-rails가 제공하는 웹훅 라우트로 지정)

https://YOUR_NGROK_URL/prompts/new 에 접속해 이미지와 제목을 함께 업로드하면 예측이 트리거됩니다. 처리가 완료되면 지정된 웹훅으로 콜백이 전달됩니다. binding.irb 중단점을 설정해 두었기 때문에 컨트롤러 액션이 REPL에서 멈추고, 그 상태에서 내부를 살펴볼 수 있습니다:


보시다시피 첫 번째 image-to-image 생성이 성공했습니다. 예측 모델은 생성된 이미지의 URL을 반환하는데, 이 URL은 반드시 로컬에 저장해 두어야 합니다(Replicate에서 주기적으로 삭제되기 때문입니다). 이 부분은 다음 편에서 자세히 다루겠습니다.

다음 편: LiteDB 심층 탐구

이번 첫 포스트에서는 Rails 앱의 모든 구성 요소를 단일 머신에서 호스팅할 수 있는 흥미로운 대안으로서 LiteStack 환경을 소개했습니다. 또한 AI 이미지 생성을 위해 Replicate.com과 통신하는 예제 앱도 설정했습니다.

시리즈의 다음 편에서는 LiteStack의 첫 번째이자 핵심 요소인 LiteDB를 더 깊이 있게 파헤칠 예정입니다. LiteDB를 독특하게 강력하게 만드는 특성, 흔히 빠지기 쉬운 함정, 한계, 그리고 트레이드오프까지 살펴보겠습니다.

그때까지 즐거운 코딩 되세요!

P.S. Ruby Magic 포스트가 발행되는 즉시 읽고 싶으시다면 Ruby Magic 뉴스레터를 구독하세요. 어떤 글도 놓치지 않을 수 있습니다!