3P by GN⁺ | ★ favorite | 댓글 1개
  • 데이터 저장소 선택은 전체 스택에 영향을 주며, 많은 웹앱은 MySQL이나 Postgres 대신 SQLite로 성능·복잡도·비용의 균형을 더 단순하게 맞출 수 있음
  • 전체 데이터베이스가 단일 파일에 들어가 애플리케이션에 임베드되므로, 앱과 DB 사이 네트워크 지연이 사라지고 n+1 문제 부담도 크게 줄어듦
  • 다중 인스턴스에서는 SQLite 파일을 직접 분산할 수 없지만, LiteFSTurso 같은 도구가 복제와 지연 없는 읽기 문제를 보완함
  • 최대 Exabyte 규모 데이터베이스를 다룰 수 있고, 개발·테스트 환경에서는 포트 충돌이나 별도 DB 서비스 없이 테스트마다 독립 DB 파일을 만들기 쉬움
  • 다만 subscriptions, 외부 클라이언트 직접 접속, Postgres용 플러그인, enum 지원이 필요한 실시간·시계열·타입 강제 요구에는 맞지 않을 수 있음

SQLite가 단순한 선택지가 되는 이유

  • 데이터 저장소 선택은 애플리케이션 전체 스택에 큰 영향을 줌
  • MySQL과 Postgres는 좋은 기본 선택지지만, 많은 웹앱에서는 SQLite가 운영과 개발 흐름을 크게 단순화할 수 있음
  • SQLite는 SQL 기반 데이터베이스이며, 전체 데이터베이스가 하나의 파일에 들어감
  • 과거에는 단순한 사용 사례용 데이터베이스로 여겨졌지만, 최근 개발과 관심이 늘면서 더 고급 사용 사례에도 쓸 수 있는 선택지가 됨

0 지연 시간과 n+1 문제 완화

  • SQLite가 디스크의 단일 파일이라는 점은 0 지연 시간이라는 큰 장점을 만듦
  • 앱과 데이터베이스 사이 네트워크 왕복이 없기 때문에 n+1 문제 부담이 크게 줄어듦
  • 개발자는 쿼리 수를 줄이는 데 과도한 시간을 쓰지 않아도 되고, 무리한 쿼리 최적화로 생기는 비효율도 줄일 수 있음
  • 앱과 DB 사이 거리를 신중히 다루지 않으면 애플리케이션 성능에 기본 지연이 생김
    • 앱-DB 지연은 수십 밀리초, 때로는 수백 밀리초로 측정될 수 있음
    • 이 경우 어떤 최적화를 해도 최신 데이터를 포함한 페이지 로딩은 그 지연 시간보다 빨라지기 어려움

관리할 서비스가 하나 줄어드는 효과

  • SQLite는 애플리케이션에 임베드된 일부로 실행되므로 별도 관리 대상 서비스가 하나 줄어듦
  • 자체 웹사이트를 Postgres에서 SQLite로 이전한 주요 동기도 관리해야 할 서비스가 줄어드는 점이었음
  • SQLite 파일을 애플리케이션의 다른 데이터와 같은 볼륨에 두면 바로 사용할 수 있음
  • 이 방식은 복잡도비용을 함께 낮춤
  • 인스턴스 수와 복제 고려사항이 늘어날수록 이런 단순화 효과가 더 커짐

다중 인스턴스에서의 복제 선택지

  • SQLite는 디스크 파일이므로 그 자체를 직접 분산할 수는 없음
  • 다중 인스턴스가 필요한 애플리케이션에서는 LiteFS 같은 도구를 사용할 수 있음
    • LiteFS는 SQLite 데이터베이스를 투명하게 복제하는 분산 파일 시스템
    • 애플리케이션은 로컬 디스크 SQLite DB를 쓰는 것처럼 실행되지만, 뒤에서는 DB가 클러스터의 모든 노드에 복제됨
    • 데이터베이스를 애플리케이션 바로 옆, 엣지에서 실행할 수 있음
    • LiteFS는 어디서나 실행 가능함
  • LiteFS는 읽기 복제본 일관성 문제를 다루는 내장 지원도 제공함
  • 여러 인스턴스에서 앱을 실행해야 한다면 이런 보완 도구가 필요함
  • Turso도 SQLite를 내부에서 사용하며, 지연 없는 읽기를 위한 embedded replicas 개념을 제공함

데이터베이스 크기와 대용량 레코드

개발과 테스트에서 편해지는 부분

  • Postgres 같은 별도 DB를 개발 환경에서 띄우려면 docker compose를 정기적으로 실행하는 워크플로가 필요할 수 있음
  • 여러 앱을 동시에 실행하면 데이터베이스와 포트 충돌이 생길 수 있지만, SQLite는 파일 하나라 이런 문제가 사실상 없음
  • 같은 앱의 여러 인스턴스를 동시에 실행해도 큰 문제가 없음
  • 새 Postgres 데이터베이스를 시작하는 일은 비교적 손이 많이 가지만, SQLite는 파일을 만들고 프로덕션 마이그레이션과 시드를 실행하면 됨
  • 테스트에서도 같은 장점이 이어짐
    • DB 설정이 복잡하면 ORM 수준에서 DB를 목 처리하는 방법을 찾게 됨
    • 테스트 중 DB 실행·연결과 격리 문제를 피하는 데 시간이 들어감
    • SQLite는 테스트마다 자체 DB 파일을 둘 수 있음
    • 약간의 코드로 DB 생성과 연결만 처리하면 전체 데이터베이스를 대상으로 테스트를 실행할 수 있음
    • 다른 데이터베이스도 가능하지만 SQLite만큼 쉽고 효율적이지 않음

SQLite가 맞지 않을 수 있는 경우

  • SQLite에는 분명한 단점도 있음
  • subscriptions를 지원하지 않아 특정 실시간 사용 사례에서는 제한이 될 수 있음
    • 다만 데이터베이스 subscriptions를 실시간 사용 사례에 쓰지 말아야 할 이유도 많음
    • 실시간 사용 사례 확장은 상당히 어려우며, 애플리케이션에서는 Partykit이 그 부분을 맡도록 할 수 있음
  • SQLite가 디스크 파일이라는 점 때문에 외부 클라이언트에서 직접 연결하는 것은 사실상 불가능함
    • Fly.io에서는 프로덕션 서버에서 prisma studio를 실행하고 이를 프록시해 로컬에서 접근하는 방식이 쉬움
    • 다른 앱에서 연결해야 한다면 필요한 데이터에 대해 호스트 앱에 HTTP 엔드포인트를 만들어야 함
    • 관련 개선은 LiteFS 이슈에 연결되어 있음
  • SQLite는 Postgres용 TimescaleDB 같은 플러그인을 지원하지 않음
    • SQLite로 시계열 데이터를 다루는 것은 가능함
    • 시계열 데이터 용도로 SQLite를 쓰는 것은 권장하기 어려울 수 있음
  • SQLite는 enum을 지원하지 않아 문자열을 사용해야 함
    • 주요 단점은 클라이언트 타입에서 특정 컬럼 값이 정해진 문자열 집합 안에만 있다는 점을 보장하기 어렵다는 것임
    • Prisma client extensions를 쓰면 클라이언트와 타입 수준에서 이런 강제를 처리하는 것이 가능함

결론

  • 대부분의 독자는 SQLite를 사용할 수 있고, 실제로 사용하는 편이 적절할 수 있음
  • 기술 선택에는 여러 작동 가능한 해법이 있으므로 결정은 단순하지 않음
  • 성능, 단순화, 비용 이점 때문에 SQLite를 진지하게 검토할 가치가 있음
  • 자체 애플리케이션과 EpicWeb.dev 워크숍에서도 SQLite를 사용함

댓글과 토론

Hacker News 의견들
  • VPS 하나에서 돌아가는 앱이라면 괜찮고 꽤 말이 됨
    하지만 인스턴스를 여러 개 띄우는 앱이라면 글에서 제안하는 방식은 복잡도가 너무 커짐
    그 복잡도를 관리하느니 RDS 같은 관리형 데이터베이스를 띄우는 편이 더 낫고, 직접 호스팅하더라도 MySQL/Postgres 클러스터를 운영하는 게 글에서 말한 선택지보다 훨씬 단순해 보임
    더 핵심적으로는 MySQL/Postgres 복제는 이미 지루할 정도로 검증됐고, 작은 규모에서는 놀랄 일이 거의 없음

    • 맞음. SQLite는 VM 같은 곳에서 단일 인스턴스로 돌릴 때 훌륭하지만, 호스트 간 마이그레이션이나 파일시스템 기반 백업을 해결하려면 지저분해짐
      LiteFS가 도움이 되긴 해도, 관리형 네트워크 데이터베이스보다 나은지는 의문임
      최근 5년 정도 내가 관여한 운영 워크로드는 대부분 컨테이너화된 앱이 상태를 데이터베이스/캐시/블롭 저장소로 넘기는 구조였거나, 그 방향을 지향했음
      로컬 개발에서는 SQLite의 장점을 얻고 운영에서는 파일을 다루지 않아도 되도록, 로컬 파일 하나를 쓰다가 운영에서는 네트워크 데이터베이스를 쓰는 내장형 Postgres 라이브러리/바이너리가 있으면 좋겠음
    • 데이터베이스 클러스터 운영이 쉽거나, 글쓴이가 설명한 것보다 쉽다는 뉘앙스인데 실제로 다중 노드 RDBMS 운영은 정말 어려움
      예전 직장에서 수백 개의 MySQL 3노드 그룹을 설계하고 관리했는데, MySQL은 장애 조치 중 데이터 손실을 막으려면 이해해야 할 설정이 많음
      semi sync, sync bin log, trx commit flush 같은 것들이 있고, MySQL과 PostgreSQL 모두 장애 조치를 자체적으로 처리하는 내장 메커니즘이 없음
      결국 주변에 별도 소프트웨어 스택을 두거나 직접 만든 무언가가 필요함
      글쓴이 주장에 동의한다는 뜻은 아니고, 너무 쉽게 묘사된다는 뜻임
    • 왜 인스턴스가 여러 개 필요함? 지금은 서버 한 대에 400코어와 RAM 8TB도 가능함
      밈 같은 기능을 만지작거리는 걸 좋아하지만, 그 이상을 쓰는 회사가 세상에 그렇게 많지는 않을 것 같음
    • SQLite에 대한 흥분은 LAMP 스택 피로감에서 오는 것 같음
      모든 Wordpress 사이트는 SQLite로도 충분히 만들 수 있었고 보안도 더 나았을 수 있음
      다만 그 이상으로 가면 인증과 ALTER TABLE을 갖춘 진짜 RDBMS가 필요해짐
    • LiteFS Cloud 같은 걸 쓰면 실제로 꽤 쉬움
      https://fly.io/docs/litefs/
  • SQLite는 마이그레이션에 쓰기 쉽지 않음. 많은 ALTER TABLE 옵션을 지원하지 않아서 [1], 예를 들어 컬럼을 수정하는 대신 새 테이블을 만들어야 함
    또한 외래 키는 기본적으로 무시되며, 연결 후 명시적으로 켜야 함
    컬럼 타입도 검사하지 않아서 숫자 컬럼에 문자열을 쉽게 넣을 수 있음
    애플리케이션 서버를 여러 대 쓰는 것도 허용하지 않으니, 작고 단순한 사이트에만 적합함
    [1] https://www.sqlite.org/lang_altertable.html

  • 사람들이 정말 PostgreSQL이나 MySQL을 띄우는 데 어려움을 겪는 건지 모르겠음. 이게 진짜 개발/DevOps/운영 장벽인가?
    문제라는 것 자체가 이상하게 느껴짐
    SQLite도 쓰지만, 우리 회사의 관리 웹 포털용 데이터베이스는 아님

    • HN의 유행 파도에 그냥 몸을 맡기면 됨 :)
      SQLite 열풍은 모든 것을 기본적으로 ‘웹 스케일’로 만들던 습관에서 벗어나, 우리가 설계하는 대부분의 시스템에는 그게 필요 없다는 깨달음으로 돌아오는 정당한 진자 운동처럼 봄
      반면 litefs 같은 새 기술을 섞어서 대안의 근본적 한계를 덮기 시작하면, 그 선택이 제정신인지 의심하게 됨
      드라이버, 망치, 렌치가 있는데 렌치를 고른 뒤 ‘서비스형 드라이버 어댑터’로 감싸지는 말자는 느낌임
    • “그냥 postgres를 시작하면 된다”는 가능하지만, 지금보다 훨씬 더 어렵게 되어 있음
      보통 postgres 명령을 실행하면 되지만 불필요한 장애물이 많음
      그냥 postgres를 호출하고 싶어도 먼저 initdb를 호출해야 함. DB 디렉터리가 없으면 다른 서버들, 예를 들어 consul처럼 자동으로 해주면 안 되는 이유를 모르겠음
      호출 방식에 따라 “initdb: invalid locale settings; check LANG and LC_* environment variables” 같은 오류를 만나기 쉬움. 간단한 UTF-8 기본값이 왜 없는지 모르겠음
      Postgres는 root로 실행되기를 거부하고, 이건 코드에 하드코딩되어 우회도 안 됨. 컨테이너나 VM 안에서 Postgres만 돌리는 상황에서 root로 “그냥 시작”할 수 없고, CI에서 취소 시 안정적으로 종료하려고 unshare 아래에서 돌리기도 좋지 않음
      다른 소프트웨어는 root 실행 자체를 거부하지 않으니 이 제약은 제거돼야 함. 이런 사고방식은 정말 27년 전 것임
      빠른 테스트나 CI를 위한 인메모리 Postgres도 시작할 수 없음. 그런 기능이 아예 없음
      모두 고칠 수 있는 것들이지만, 현재는 “postgres를 그냥 실행하면 된다, 단 A/B/C/D 같은 임의 조건에서는 안 된다”가 되어버림
    • 동의함. SQLite는 단순한 용도에 훌륭하지만, 이 글은 PostgreSQL 실행이 불가능할 정도로 어렵고 웹 서버에서 100ms 떨어진 서버에서만 가능하다는 식으로 다룸
      단순한 앱이라면 같은 서버에서 Postgres를 돌리고 설정에서 적절히 크기를 맞추면 됨
      정말 어렵지 않고 이미 잘 닦인 길임
      단일 테넌트 앱이 임베디드 장치 같은 곳에서 돌아간다면 SQLite는 훌륭함
      그런데 “이 글을 읽는 대부분”이 SQLite를 써야 한다는 결론은 매우 이상함
      독자층이 실제 운영 웹사이트보다 작거나 장난감 같은 웹사이트를 만드는 쪽이라는 뜻인가 싶음
    • 예전 직장에서 그런 사용 사례가 하나 있었음. 온프레미스의 물리/가상 서버에 설치되는 관리 소프트웨어였고 조금 구식이었음
      전체 설치는 PHP, Apache, MySQL을 세팅한 뒤 앱 자체를 설치하고, 셸 스크립트로 된 마이그레이션도 돌려야 했음
      이걸 Go 바이너리와 SQLite로 바꿨고, 패키지나 파일만 설치한 뒤 시작하면 나머지는 알아서 처리되게 했음
      SQLite는 내가 통제하지 못하거나 직접 세팅해야 하는 시스템에 훌륭하지만, 웹서버에는 아닐 수 있음
      흔한 사용 사례는 앱의 내부 저장소처럼 다른 앱과 공유하거나 분산할 필요가 없는 경우임
      그런 경우 MySQL이나 Postgres를 설치·설정·실행하고 싶지 않음
    • 맞음. SQLite를 쓸 수 있는 제약 조건이라면 로컬 PostgreSQL 인스턴스도 돌릴 수 있으니, 서비스 디스커버리나 복잡한 인증 흐름 등이 필요 없어져 오히려 더 쉬울 수 있음
      SQLite는 훌륭하고, 적절한 곳에서는 반드시 써야 함
      다만 PostgresQL/SQL Server 같은 것을 일반적으로 대체하는 게 적절하다는 주장은 이해하기 어려움
  • “디스크에 있으니 지연 시간이 0”이라고 하는 건 기술적 정직성 관점에서 거슬림

    • SQLite의 아이디어는 알겠지만, MySQL/Postgres도 많은 것을 메모리에 저장하므로 디스크 접근이 필요 없을 수 있음
      데이터가 아니더라도 인덱스는 메모리에 상주함
      우리에게는 Java와 Lucene 인덱스 파일시스템 기반 데이터베이스를 쓰는 오래된 웹 도구가 있는데, 솔직히 다루기 고통스러움
      https://lucene.apache.org/
    • LAN이나 인터넷 너머에 있는 것과 비교하면 지연 시간이 한 자릿수 이상 줄어드니, 인터넷 관점에서는 0에 가까움
    • 특히 그걸 N+1 문제의 해결책이라고 내세우면 더 그렇음
    • 짜증 날 정도로 거의 맞는 말이긴 함
      로컬 디스크에 있기 때문에 결국 프로세스 내부 RAM에 캐시되고, 그건 여전히 지연 시간 0은 아니지만 네트워크 스택 너머 데이터베이스와 통신하는 것에 비하면 훨씬 낮음
      그래서 거의, 아주 약간은 받아들일 수 있을 것 같기도 함
    • 비교 대상은 네트워크 데이터베이스임
      그 맥락에서는 로컬 디스크가 대부분의 사용 사례에서 사실상 지연 시간이 0에 가까움
      또한 SQLite는 인메모리로도 실행 가능함
      프로세스가 오래 살아 있고 DB를 RAM에 유지한다면 지연 시간은 더 0에 가까워짐
  • Kent는 풀스택 개발계의 HN판 Steve Gibson 같음 (https://news.ycombinator.com/item?id=37999197#38001051)
    https://news.ycombinator.com/item?id=35903878#35915789
    “Kent는 덜 경험 많은 동료들에게 완전히 무시하라고 말하고 싶어졌던 유일한 블로거임”

    • 확증 편향이 있는 사람들이 예상 밖의 견해를 만나고도 설명해내지 못할 때 무슨 일이 벌어지는지 보는 건 흥미로움
      결국 할 수 있는 건 무시하고, 다른 사람들에게도 그것이 존재하지 않는 척하라고 요구하는 것뿐임
  • 데이터베이스가 수십 ms, 심지어 수백 ms 떨어져 있는 게 흔하다고 말하는 건 좋게 봐도 무지함
    성능을 신경 쓴다면 데이터베이스 쿼리마다 미국을 가로지르지 않음
    솔직히 이런 글은 소셜 존재감을 부풀리기 위해 쓰인 것 같고, 기술 독자에게는 아무것도 주지 않음

  • SQL Server, MySQL, Postgres 대신 SQLite를 쓸 수 있는 경우는 있음. 결국 문제를 어떻게 판단하느냐에 달림
    개인적으로는 SQLite를 두 가지 경우에만 썼음

    1. 개발 중. 제대로 된 MySQL/SQLServer/Postgres를 만들기 전에 무언가를 빠르게 모으는 간단한 방법으로 씀
    2. 클라이언트 소프트웨어. 일부 클라이언트 소프트웨어는 임시 데이터 저장소가 필요하고 SQLite가 잘 맞음
      이런 DB는 복잡하지 않고 테이블도 5개 남짓이며, REST API를 통해 메시지 큐로 보내는 큐 시스템에 가까움
      “success” 응답을 받으면 SQLite에서 제거되는 단순하고 괜찮은 시스템임
      그 외 이유도 몇 가지 있을 수 있음
      하지만 그 이상으로는, 우리가 만든 웹 포털이나 CMS처럼 여러 요청이 동시에 데이터베이스와 대화할 수 있는 중간 규모 DB에 SQLite 파일을 쓰는 건 자신 없을 것 같음
      그래서 중앙화된 관계형 데이터베이스를 쓰는 게 맞음
      특히 MySQL과 Postgres는 같은 시스템이든 전용 서버든 설치가 그렇게 어렵지 않음
      SQLite를 부정적으로 보는 건 아님. 오히려 SQLite에 들어간 작업과 노력은 정말 좋아함
      데이터를 직접 작성하거나 디렉터리 안에 수많은 “레코드” 파일을 두는 대신 파일 하나에 담는 접근은 훌륭함
    • 동시성 수준이 낮고 실시간 복제가 필요 없는 대부분의 것에는 쓸 수 있다고 봄
      SQLite용 복제 “해법”도 있지만, 그 순간 단순함이 사라지고 Postgres를 쓰는 편이 나아짐
  • SQLite는 훌륭한 도구지만, 만들어지지 않은 상황에 억지로 끼워 넣는 건 그만했으면 함
    현재 또는 미래에 두 대 이상의 머신으로 확장될 웹 앱 배포 근처에는 맞지 않음
    일단 분산 시스템이 되고 재해 복구 시나리오의 복잡도가 생기면, 그런 용도로 만들어진 도구를 써야 함
    PG/MySQL을 고르면 크게 틀릴 일이 없지만, 장애로 알려진 회사의 VC 과대광고가 붙은 복제 파일시스템을 쓰면 크게 잘못될 수 있음

    • 모두가 12-factor를 최신 유행으로 받아들이기 전으로 다시 돌아가는 느낌도 듦
      SQLite는 분명 쓸 곳이 있지만, 수평 확장, 고가용성, 별도 워커 프로세스가 필요할 수 있는 시스템에는 맞지 않음
      SQLite 몇 개를 덕트테이프로 묶을 수는 있지만 그러면 이런 걸 다뤄야 함
      “LiteFS only allows a single node to be the primary at any given time. The primary node is the only one that can write data to the database. The other nodes are called replicas and they provide a read-only copy.”
      차라리 별도 DB 서버를 세팅하는 게 낫고 덜 번거로움
      MySQL/Postgres를 수직 확장 이상으로 키워야 하는 시점이면, 해줄 사람에게 돈을 낼 여력도 있을 가능성이 큼
    • JavaScript 몇백 줄로 오프라인이고 종단 간 암호화되며 SQLite가 뒷받침하는 완전한 분산 시스템을 만드는 사람들을 봤음
      서버는 동기화용 과장된 캐시 시스템으로만 씀
      논리 시계와 충돌 없는 복제 데이터 타입 같은 난해한 요소가 있지만, 클라이언트-서버 아키텍처보다 훨씬 더 분산적이고 전부 SQLite로 뒷받침됨
    • 조건을 달면 두 대 이상의 머신에 걸칠 수는 있음. WAL 모드를 켜면 안 되고 쓰기 노드는 하나뿐이어야 함
      성능이 어떤지는 제대로 살펴본 적 없고, 모든 접근이 명시적으로 SQLITE3_OPEN_READONLY를 통해 이뤄지는 게 가장 좋을 것 같음
    • 실제로 두 대 이상의 머신에 걸쳐야 하는 웹 앱 비율이 얼마나 될까? 0.1%쯤?
  • 프로젝트에서 Pocketbase[0]를 쓰고 있는데 정말 추천할 만함
    SQLite DB 위에 만들어졌고 실시간 발행/구독 기능도 있음
    JS SDK도 CRUD에 쓰기와 설정이 엄청 쉬움
    사이드 프로젝트와 일부 중간 규모 작업에서는 SQLite/Pocketbase가 매우 다루기 쉬웠음
    [0] https://pocketbase.io

  • 가능한 전략 중 하나는 고객마다 디렉터리/파일 하나, 즉 SQLite 파일 하나를 두는 것임
    그러면 사용자가 로그인할 때 먼저 어떤 데이터베이스에 연결해야 하는지 찾아야 함
    또는 사용자 ID/사용자명에서 어떻게든 유도할 수도 있음
    모든 고객 DB를 단일 디렉터리/디스크에 두고 계속 S3로 “lite streaming”하는 방식임
    각 사용자가 격리되어 있으니 자기 DB에만 쓰게 됨
    하지만 마이그레이션은 고통스러움. 각 DB에 따로 배포해야 함
    장점 하나는 사용자가 언제든 자신의 데이터를 가져갈 수 있게 해줄 수 있다는 것임. 그냥 파일 하나임
    [0]. https://litestream.io/

    • 아니면 그냥 그들의 데이터를 데이터베이스의 행 하나로 만들면 됨
      SQLite 테이블 컬럼에는 엄청난 양을 저장할 수 있음