임베디드 레플리카
임베디드 레플리카 (Embedded Replicas)
Turso Cloud의 임베디드 레플리카는 데이터베이스를 애플리케이션 안에 직접 복제해요. 읽기는 로컬 파일에서 마이크로초 단위로 실행되고, 쓰기는 클라우드 프라이머리로 전송되었다가 레플리카에 다시 반영돼요. VM이나 VPS 배포, 그리고 안정적인 연결이 어려운 모바일 애플리케이션에서 특히 빛나요.
출처: 문서
본문
임베디드 레플리카(Embedded Replicas)는 Turso Cloud 데이터베이스의 로컬 읽기 레플리카를 유지해요: 읽기는 파일에서 로컬로 마이크로초 단위로 실행되고, 쓰기는 클라우드 프라이머리로 전송된 뒤 레플리카에 다시 반영돼요. 임베디드 레플리카는 프로덕션에서 완전히 지원돼요.
동기화가 필요한 새 프로젝트에는 Turso Sync를 권장해요. Sync는 Turso Database 엔진 기반으로 논리적 변경 데이터 캡처(change-data-capture)를 사용해서, 임베디드 레플리카의 페이지 수준 복제보다 대폭 적은 대역폭과 낮은 지연 시간으로 로컬 우선 쓰기와 명시적인 push() / pull()을 제공해요.
Turso Cloud의 임베디드 레플리카는 데이터베이스를 애플리케이션 안에 곧바로 복제할 수 있게 해 줘요. 안정적인 연결이 어려운 VM이나 VPS 배포, 모바일 애플리케이션에서 특히 유용해요. 로컬 데이터베이스에 끊김 없이 접근할 수 있거든요.
임베디드 레플리카는 로컬과 원격 데이터베이스 작업 사이를 매끄럽게 전환할 수 있게 해서, 같은 데이터베이스가 다양한 시나리오에 맞춰 적응해요. 로컬 복사본을 원격 데이터베이스와 동기화해 마이크로초 수준의 읽기를 실현해요.
동작 방식
- 로컬 파일을 메인 데이터베이스로 설정해요.
- 클라이언트 구성의
url매개변수예요.
- 클라이언트 구성의
- 동기화할 원격 데이터베이스를 설정해요.
- 클라이언트 구성의
syncUrl매개변수예요.
- 클라이언트 구성의
- 데이터베이스에서 읽어요:
- 읽기는 항상
url에 설정된 로컬 레플리카에서 제공돼요.
- 읽기는 항상
- 데이터베이스에 써요:
- 쓰기는 기본적으로
syncUrl에 설정된 원격 프라이머리 데이터베이스로 전송돼요. 로컬 파일에 먼저 기록되지 않아요. offline구성 옵션을true로 설정하면 로컬에 쓸 수도 있어요.- 읽기가 포함된 쓰기 트랜잭션도 원격 프라이머리 데이터베이스로 전송돼요.
- 쓰기가 성공하면 로컬 데이터베이스에 변경 사항이 자동으로 반영돼요(자신의 쓰기 읽기, 비활성화 가능).
- 쓰기는 기본적으로
주기적 동기화 (Periodic sync)
주기적 동기화 간격(syncInterval) 속성을 사용하면 임베디드 레플리카에 데이터를 자동으로 동기화할 수 있어요. 클라이언트를 인스턴스화할 때 syncInterval 매개변수를 전달하면 돼요:
import { createClient } from "@libsql/client";
const client = createClient({
url: "file:path/to/db-file.db",
authToken: "...",
syncUrl: "...",
syncInterval: 60,
offline: true, // 선택 사항: 오프라인 모드 활성화 (기본값: false)
});
자신의 쓰기 읽기 (Read your writes)
임베디드 레플리카는 read-your-writes 의미론도 보장해요. 실제로는 쓰기가 성공적으로 반환된 후, 그 쓰기를 시작한 레플리카는 sync()를 호출하지 않아도 항상 새 데이터를 즉시 볼 수 있다는 뜻이에요.
다른 레플리카는 sync()를 호출할 때 또는 주기적 동기화를 사용하는 경우 다음 동기화 주기에 새 데이터를 봐요.

저장 시 암호화 (Encryption at rest)
임베디드 레플리카는 libSQL 클라이언트 SDK 중 하나로 저장 시 암호화를 지원해요. 클라이언트를 인스턴스화할 때 encryptionKey 매개변수를 전달하면 돼요.
사용되는 암호화 키는 여러분이 직접 생성하고 관리해야 해요.
사용법
임베디드 레플리카를 사용하려면 syncUrl 매개변수로 클라이언트를 만들어야 해요. 이 매개변수는 클라이언트가 동기화할 원격 Turso Cloud 데이터베이스의 URL을 지정해요:
// TypeScript
import { createClient } from "@libsql/client";
const client = createClient({
url: "file:replica.db",
syncUrl: "libsql://...",
authToken: "...",
});
// Go
package main
import (
"database/sql"
"fmt"
"os"
"path/filepath"
"github.com/tursodatabase/go-libsql"
)
func main() {
dbName := "local.db"
primaryUrl := "libsql://[DATABASE].turso.io"
authToken := "..."
dir, err := os.MkdirTemp("", "libsql-*")
if err != nil {
fmt.Println("Error creating temporary directory:", err)
os.Exit(1)
}
defer os.RemoveAll(dir)
dbPath := filepath.Join(dir, dbName)
connector, err := libsql.NewEmbeddedReplicaConnector(dbPath, primaryUrl,
libsql.WithAuthToken(authToken),
)
if err != nil {
fmt.Println("Error creating connector:", err)
os.Exit(1)
}
defer connector.Close()
db := sql.OpenDB(connector)
defer db.Close()
}
// Rust
use libsql::{Builder};
let build = Builder::new_remote_replica("file:replica.db", "libsql://...", "...")
.build()
.await?;
let client = build.connect()?;
// PHP
use Libsql\Database;
$db = new Database(
path: 'replica.db',
url: getenv('TURSO_URL'),
authToken: getenv('TURSO_AUTH_TOKEN'),
syncInterval: 300 // 5분마다 동기화
);
$conn = $db->connect();
// Laravel
// config/database.php
return [
"default" => env("DB_CONNECTION", "libsql"),
"connections" => [
"libsql" => [
"driver" => "libsql",
"database" => database_path("database.db"),
"url" => env("TURSO_DATABASE_URL"),
"password" => env("TURSO_AUTH_TOKEN"),
"sync_interval" => env("TURSO_SYNC_INTERVAL", 300),
],
// ...
],
];
// .env
DB_CONNECTION=libsql
TURSO_DATABASE_URL=libsql://...
TURSO_AUTH_TOKEN=...
TURSO_SYNC_INTERVAL=300
원격 데이터베이스에서 로컬 레플리카로 변경 사항을 수동으로 동기화할 수 있어요:
// TypeScript
await client.sync();
// Go
if err := connector.Sync(); err != nil {
fmt.Println("Error syncing database:", err)
}
// Rust
client.sync().await?;
// PHP
$db->sync();
애플리케이션이 원격과 로컬 임베디드 레플리카를 동기화하고 싶을 때 백그라운드에서 .sync()를 호출하면 돼요. 예를 들어 5분마다, 또는 애플리케이션이 시작될 때마다 호출할 수 있어요.
알아 두어야 할 것들
- 임베디드 레플리카가 동기화 중일 때 로컬 데이터베이스를 열지 마세요. 데이터 손상으로 이어질 수 있어요.
- 파일시스템이 없는 서버리스 환경 같은 일부 환경에서는 임베디드 레플리카를 사용할 수 없어요.
- 예상보다 많은 프레임을 동기화할 수 있는 몇 가지 시나리오가 있어요.
- 내부 btree가 어떤 노드에서든 분할(split)되는 쓰기는 복제 로그에 많은 새 프레임을 기록하게 해요.
- 온디스크 WAL이 더러운(dirty) 상태로 남은 서버 재시작은 복제 로그를 재생성하고 추가 프레임을 동기화해요.
- 디스크의 로컬 파일을 제거하거나 무효화하면 임베디드 레플리카가 처음부터 다시 동기화할 수 있어요.
- 하나의 프레임은 4kB 데이터(디스크상 페이지 프레임 하나)예요. 그래서 1바이트 행을 써도 libsql이 쓰는 단위가 4kB이므로 항상 4kB 쓰기로 나타나요.
배포 가이드
- Turso + Fly — 임베디드 레플리카가 있는 JavaScript 프로젝트를 Fly.io에 배포
- Turso + Koyeb — 임베디드 레플리카가 있는 JavaScript/Rust 프로젝트를 Koyeb에 배포
- Turso + Railway — 임베디드 레플리카가 있는 JavaScript/Rust 프로젝트를 Railway에 배포
- Turso + Render — 임베디드 레플리카가 있는 JavaScript 프로젝트를 Render에 배포
- Turso + Linode by Akamai — 임베디드 레플리카가 있는 JavaScript/Rust 프로젝트를 Akamai에 배포
더 알아보기 (Learn more)
- Fly에서 임베디드 레플리카 — Fly.io 배포 가이드
- Koyeb에서 임베디드 레플리카 — Koyeb 배포 가이드
- Akamai에서 임베디드 레플리카 — Akamai 배포 가이드
- BYOK 암호화 (Encryption) — 암호화 키 생성과 관리
- Turso Sync — 새 프로젝트에 권장되는 동기화 방식