최적 성능을 위한 SQLite on Rails의 방법과 이유
(fractaledmind.github.io)- 지난 1년 동안 SQLite를 사용하여 Rails 애플리케이션을 성능 좋고 안정적으로 실행하는 방법을 깊이 이해하려고 노력해왔음
 - 이 과정에서 여러 가지 교훈을 배웠으며, 이를 공유하고자 함
 - 문제의 원인과 해결 방법을 설명할 것임
 
SQLite와 Rails의 문제점
- 기본적으로 SQLite를 사용한 Rails 애플리케이션은 바로 사용할 수 있는 상태가 아님
 - 약간의 조정과 미세 조정을 통해 성능 좋고 안정적인 애플리케이션을 만들 수 있음
 - Rails 8에서는 기본 설정만으로도 프로덕션 준비가 완료된 상태가 되도록 목표를 설정함
 
데모 애플리케이션 "Lorem News"
- "Lorem News"라는 데모 애플리케이션을 사용하여 문제와 해결책을 설명할 것임
 - 이 애플리케이션은 Hacker News의 클론으로, 사용자들이 게시물과 댓글을 작성할 수 있음
 
성능 테스트
- 
oha로드 테스트 CLI와 애플리케이션 내 벤치마킹 경로를 사용하여 성능을 테스트함 - 단일 요청과 동시 요청을 통해 성능을 측정함
 
주요 문제: SQLITE_BUSY 예외
- SQLite는 한 번에 하나의 쓰기 작업만 허용하기 위해 쓰기 잠금을 사용함
 - 여러 연결이 동시에 쓰기 잠금을 시도하면 
SQLITE_BUSY예외가 발생함 - 이 문제를 해결하기 위해 즉시 트랜잭션을 사용해야 함
 
즉시 트랜잭션
- 기본적으로 SQLite는 지연된 트랜잭션 모드를 사용함
 - 즉시 트랜잭션을 사용하면 쓰기 잠금을 즉시 시도하고 실패 시 재시도할 수 있음
 - 
sqlite3-rubygem을 사용하여 기본 트랜잭션 모드를 즉시 모드로 설정할 수 있음 
타임아웃 설정
- 
database.yml파일에서 타임아웃 설정을 통해SQLITE_BUSY예외를 줄일 수 있음 - SQLite의 
busy_timeout설정을 사용하여 쓰기 잠금을 재시도할 수 있음 
GVL(글로벌 VM 잠금) 문제
- 
sqlite3-rubygem은 SQLite의 C 코드를 호출할 때 GVL을 해제하지 않음 - 이는 동시성 성능을 저하시킴
 - 
busy_handler를 사용하여 GVL을 해제하고 성능을 개선할 수 있음 
busy_timeout 재구현
- 
busy_timeout을 재구현하여 모든 쿼리가 동일한 빈도로 재시도하도록 설정함 - 이는 오래된 쿼리가 타임아웃되지 않도록 함
 
성능 개선
- 성능을 개선하기 위해 다음과 같은 설정을 적용해야 함
- 즉시 트랜잭션 사용
 - 타임아웃 설정
 - 
busy_handler사용 - WAL(Write-Ahead Logging) 모드 사용
 - 읽기/쓰기 연결 풀 분리
 
 
GN⁺의 정리
- SQLite를 사용한 Rails 애플리케이션의 성능 문제와 해결책을 다룸
 - 즉시 트랜잭션, 타임아웃 설정, GVL 해제, WAL 모드 사용, 읽기/쓰기 연결 풀 분리 등의 방법을 통해 성능을 개선할 수 있음
 - 이 기사는 SQLite와 Rails를 사용하는 개발자들에게 매우 유용할 것임
 - 유사한 기능을 가진 다른 프로젝트로는 PostgreSQL과 MySQL을 추천함
 
Hacker News 의견
- 
Oldmoe의 Litestack 프로젝트 소개
- SQLIte와 Rails를 사용하는 사람들은 Oldmoe의 Litestack 프로젝트를 확인할 필요가 있음
 - Litestack은 SQLite의 강력함을 활용하여 웹 애플리케이션 데이터 인프라를 제공하는 Ruby gem임
 - SQL 데이터베이스, 빠른 캐시, 강력한 작업 큐, 신뢰할 수 있는 메시지 브로커, 전체 텍스트 검색 엔진, 메트릭스 플랫폼을 하나의 패키지로 제공함
 - 현재 프로젝트에서 사용 중이며 매우 만족스러움
 
 - 
상세한 기사 작성에 대한 감사
- SQLite 웹 애플리케이션을 확장하려는 사람들에게 유용한 정보임
 - Rails를 넘어 다른 프레임워크에서도 적용 가능함
 - 작가에게 감사함
 
 - 
SQLite 관련 작업을 하는 사람들에게 추천
- 사용하는 언어나 프레임워크와 상관없이 SQLite 관련 작업을 하는 사람들은 이 기사를 읽어야 함
 - 몇 년 전에는 직접 해결해야 했던 문제들을 다루고 있음
 - 작가에게 감사함
 
 - 
FOSS 분석 시스템에 대한 질문
- 설치가 쉬운 FOSS 분석 시스템을 만들고 있음
 - 이벤트 데이터를 별도의 SQLite 데이터베이스에 보내어 메인 앱의 데이터와 분리하려고 함
 - 초당 1000개 이상의 이벤트를 처리할 수 있는 확장성에 대한 우려가 있음
 - 서버 메모리에 이벤트를 저장하고 매초 한 번씩 일괄적으로 쓰는 방법을 고려 중임
 - SQLite의 많은 DB 쓰기 문제를 해결할 수 있는 합리적인 방법인지 의견을 구함
 
 - 
sqlite3-ruby gem의 GVL 문제
- sqlite3-ruby gem은 SQLite 호출 시 GVL을 해제하지 않음
 - 이는 대부분 합리적인 결정으로 보임
 - Python 확장에서는 다른 방식으로 설계되었을 가능성이 있음
 - extralite gem은 블로킹 중 GVL을 해제하며, 일반적으로 더 빠르고 동시성 문제도 없음
 
 - 
개인 웹서비스 설정
- 개인 웹서비스에서 사용하는 몇 가지 설정:
- 
PRAGMA journal_mode = WAL - 
PRAGMA busy_timeout = 5000 - 
PRAGMA synchronous = NORMAL - 
PRAGMA cache_size = 1000000000 - 
PRAGMA foreign_keys = true - 
PRAGMA temp_store = memory - 
BEGIN IMMEDIATE트랜잭션 사용 
 - 
 
 - 개인 웹서비스에서 사용하는 몇 가지 설정:
 - 
Django에 대한 질문
- 이 기사는 훌륭함
 - Django에 대한 유사한 솔루션이 있는지 궁금함
 - ArchiveBox는 Django를 통해 SQLite를 사용하며, Rails에서 언급된 문제를 자주 겪음
 - 앱의 다른 채널을 통해 모든 쓰기를 직렬화하지 않는 SQLite 레이어 솔루션이 있으면 좋겠음
 
 - 
busy_timeout기본 설정에 대한 의문- 매우 유익하고 잘 작성된 기사임
 - 기본 
busy_timeout메서드가 오래된 쿼리를 벌주는 지연을 가지는 이유가 궁금함 - 왜 이것이 기본 설정으로 의미가 있는지 궁금함
 
 - 
SQLite와 Rails 사용에 대한 의견
- SQLite와 Rails를 좋아하지만, 이는 MS Access를 프로덕션 환경에서 사용하는 것과 유사함
 
 - 
Rails 통합 문제 해결에 대한 감사
- 통합 문제를 해결하고 다른 사람들을 도와주는 것을 항상 기쁘게 생각함
 - 이러한 수정 사항이 기본 Rails 설정에 포함되기를 바람
 - Rails 앱을 운영하며, 몇 년 전 Postgres로 전환하여 매우 만족하고 있음
 - 여전히 대안이 있는 것은 좋으며, 다른 작업에 SQLite를 사용함