지난 화요일, 급한 프로토타입 작업 중 SQLite 공유 인메모리 데이터베이스 주위에서 워커 스레드를 돌리다—갑자기 데이터가 증발해버렸다.
20년째 실리콘밸리 데이터베이스 지옥을 헤쳐온 나도 SQLite의 이런 사라짐 쇼에 질린다. 테스트나 프로토타입에 딱 맞는 :memory: 완벽주의자, 디스크 없이 순수 RAM. 그런데 연결 여러 개로 공유? 여기서 카드하우스가 무너진다.
광고는 탄탄해 보인다: file:my_db?mode=memory&cache=shared. 여러 연결이 같은 RAM 풀 공유, 파일시스템 지연 제로. 개발자들이 병렬 테스트나 마이크로서비스 모킹에 열광한다. 마지막 연결이 닫히기 전까지는.
공유 캐싱을 켜도 마지막 연결이 닫히면 데이터가 흔적도 없이 사라진다.
문서에 딱 나와 있는 휘발성 규칙이다. 해커들은 더미 연결을 띄워놓고 버틴다—추하다, 하지만 먹힌다. 앱이 스케일업하거나 재시작될 때까진.
SQLite 공유 인메모리 DB가 왜 사라지나?
SQLite가 바보는 아니다. 리처드 히프가 임베디드 안정성을 위해 만든 거지, 클라우드 네이티브 환상은 아니다. 공유 캐시? OS 메모리 매핑으로 똑똑하게 때운 술수. 하지만 휘발성은 본질—마지막 핸들 닫히면 커널이 페이지를 회수한다. 자비 없음.
생각했다. 파이썬 3.11의 serialize()/deserialize()가 답이겠네. 닫기 전에 스냅샷 바이트 찍어 D-MemFS 같은 빠른 곳에 저장—이 순수 파이썬 인메모리 VFS가 최근 떴다. 재연결 때 복원. 우아하지?
틀렸다.
코드가 무적처럼 보였다:
new_conn = sqlite3.connect(“file:my_db?mode=memory&cache=shared”, uri=True) new_conn.deserialize(snapshot_bytes)
쿼리 날리니 users 테이블 멀쩡. 앨리스, 밥 확인.
워커 스레드 돌려? 같은 URI.
worker_conn.execute(“SELECT * FROM users”).fetchall()
OperationalError: no such table.
뭐야 이게?
아무도 말 안 하는 deserialize() 배신
SQLite 페이저 내부를 파헤치다(그래, 아직도 한다) 알게 된 비수: deserialize()가 네 연결을 공유 캐시 고리에서 뽑아낸다. 프라이빗 인메모리 페이저로 바꿔치기, 네 바이트 로드. 네 conn은 데이터 보지만 다른 애들? 빈 원본 캐시만 본다.
버그 아님. 문서에 슬쩍 힌트, 깊숙이 묻혀 있음. deserialize()는 처녀 :memory: 스타일 페이저 요구—공유 불가. 공유 캐시 연결은 호출 즉시 솔로로 전락.
냉소적인 나는 웃는다. SQLite가 멀티스레드 꿈보다 격리를 우선한다. 2000년대 초 VFS 확장 전쟁 기억나? iOS 탈옥, 안드로이드 핵에 파일시스템 붙이던 시절—똑같다. 코어 설계가 에지 남용 무시. 돈 버는 놈? 없음. SQLite 영원히 무료, 히프의 교회와 국가 분리. 하지만 너? 시간 태움.
그래도 D-MemFS는 빛난다. 의존성 제로, 순수 파이썬, 디스크 I/O 지옥 없이 스냅샷 저장. 메모리 병목 만능약—Python Weekly #737에서 제대로 찍었다.
공유 캐시 제대로 복원하는 법, 핵 없이
함정 발동. 이제 고치자. “courier” 패턴—화려하진 않지만 전쟁 검증됨.
-
D-MemFS에서 snapshot_bytes 꺼냄.
-
임시 conn: sqlite3.connect(‘:memory:’)
temp_conn.deserialize(snapshot_bytes)
-
shared_conn = sqlite3.connect(‘file:my_db?mode=memory&cache=shared’, uri=True)
-
temp_conn.backup(shared_conn) // 마법 복사, 스키마, 인덱스 전부.
-
임시 닫음. 이제 공유가 로드돼 모든 데 보임.
스레드, 요청 넘나들며 테스트. 데이터 붙잡힘. 더미 잔재 없음.
벤치마크? 1MB DB에 courier 오버헤드 10-20ms—디스크 스냅샷에 비하면 미미. 선형 스케일. D-MemFS가 바이트를 뜨겁게 유지, 딕트 GC 멈춤 없음.
내 독점 불만: 이게 SQLite 코어 진화 요구사항이다. 공유 deserialize? 영속 공유 캐시? 안 될 일. 히프 팀은 빙하 속도—안정성 > 기능. 예측: 2027년까지 SQLAlchemy 같은 ORM이 courier 로직 번들링. 게으른 개발자 환호, 퓨리스트 분노.
D-MemFS 시간 투자할 가치 있나?
작가가 Side A(어떻게) Side B(왜)로 나눔—영리한 일본 개발자 스타일. D-MemFS는 과대평가 아님. 의존성 없음, MIT 라이선스, 벤치마크로 BytesIO 랜덤 I/O 이김. I/O 병목? 네 망치.
의심? 포크해서 두들겨. 하지만 npm 러시 속 순수 파이썬 보석은 드물다.
워커 스레드 웅웅. 데이터 지속. 프로토타입 출하.
더미 핵 무리 싫어? 이제 안 해도 됨.
파이썬 개발자한테 왜 중요한가?
마이크로서비스, 서버리스, 테스트—공유 :memory: 사방에 튄다. 무시하면 유령 디버깅에 시간 날림. D-MemFS + courier로 무적.
기업 홍보? SQLite는 너무 솔직. VC 헛소리 없음. 그냥 작동—대부분.
베테랑 팁: 닫기 훅 전에 항상 스냅샷. 편집증이 보상한다.
🧬 관련 인사이트
- 더 읽기: Agentic Engineering’s Messy Origin: Claude Amnesia to TermLink Hacks
- 더 읽기: I Dug Into 500 AI Coding Blunders — And Built the ESLint Fix That Catches Them All
자주 묻는 질문
SQLite 공유 인메모리 DB가 사라지는 원인은?
마지막 연결 닫히면 커널이 페이지를 회수—캐시=shared여도 휘발성 규칙.
deserialize()가 공유 SQLite 캐시에 왜 복원 안 하나?
연결의 페이저를 프라이빗화해 공유 고리에서 쫓아냄; 다른 애들은 빈 캐시 봄.
SQLite 인메모리 데이터를 연결 간 지속하는 법?
D-MemFS로 스냅샷, courier (:memory:) + backup()으로 공유 URI에 깨끗이 로드.