mirror of
https://github.com/zoo-apps/papers.git
synced 2026-10-30 14:56:54 +00:00
100 lines
2.9 KiB
TeX
100 lines
2.9 KiB
TeX
\section{Specification}
|
|
|
|
|
|
\subsection{Replicate Configuration}
|
|
|
|
\begin{lstlisting}[language=yaml,caption={replicate-config ConfigMap}]
|
|
dbs:
|
|
- path: /app/data/data.db
|
|
replicas:
|
|
- type: s3
|
|
bucket: zoo-data
|
|
path: ${POD_NAME}
|
|
endpoint: ${LITESTREAM_S3_ENDPOINT}
|
|
region: sfo3
|
|
force-path-style: true
|
|
sync-interval: 1s
|
|
snapshot-interval: 1h
|
|
\end{lstlisting}
|
|
|
|
\begin{itemize}
|
|
\item \texttt{sync-interval: 1s} --- WAL frames shipped every
|
|
second, achieving $\leq 1$\,s RPO.
|
|
\item \texttt{snapshot-interval: 1h} --- Full snapshot every hour
|
|
bounds restore time (restore replays at most 1 hour of WAL).
|
|
\item \texttt{force-path-style: true} --- Required for
|
|
DigitalOcean Spaces and MinIO.
|
|
\end{itemize}
|
|
|
|
\subsection{Encryption}
|
|
|
|
WAL segments and snapshots are encrypted at rest using
|
|
\texttt{hanzoai/age} with per-environment X25519 key pairs:
|
|
|
|
\begin{lstlisting}[language=yaml,caption={Encryption configuration}]
|
|
dbs:
|
|
- path: /app/data/data.db
|
|
replicas:
|
|
- type: s3
|
|
bucket: zoo-data
|
|
path: ${POD_NAME}
|
|
encryption:
|
|
type: age
|
|
key: ${AGE_SECRET_KEY}
|
|
\end{lstlisting}
|
|
|
|
Key management:
|
|
\begin{itemize}
|
|
\item Encryption keys stored in Zoo KMS (K-Chain) or
|
|
Kubernetes secrets (bootstrapping).
|
|
\item One key pair per environment (devnet, testnet, mainnet).
|
|
\item Key rotation: generate new pair, re-snapshot with new key,
|
|
update secret. Old WAL segments remain readable with old key
|
|
until next snapshot.
|
|
\end{itemize}
|
|
|
|
\subsection{Service Applicability}
|
|
|
|
\begin{table}[h]
|
|
\centering
|
|
\caption{Zoo services and replication targets}
|
|
\begin{tabular}{@{}llll@{}}
|
|
\toprule
|
|
Service & Kind & Data & Replicate \\
|
|
\midrule
|
|
zoo-bridge & Deployment & SQLite (future) & Yes \\
|
|
zoo-gateway & CRD (ZooGateway) & Stateless & No \\
|
|
zoo-explorer & Deployment & PostgreSQL & No \\
|
|
zoo-chain & StatefulSet & Node data (PVC) & No\footnotemark \\
|
|
zoo-operator & Deployment & Stateless & No \\
|
|
sql & StatefulSet & PostgreSQL & No \\
|
|
kv & StatefulSet & Valkey & No \\
|
|
ingress & Deployment & Stateless & No \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
\footnotetext{Chain node data replication uses PVC snapshots and
|
|
chain sync, not WAL streaming. Replicate is for SQLite only.}
|
|
|
|
As services migrate from PostgreSQL to Base/SQLite, they gain
|
|
replicate sidecars with zero code changes --- only a K8s patch.
|
|
|
|
\subsection{Recovery Guarantees}
|
|
|
|
\begin{description}
|
|
\item[RPO $\leq 1$\,s] WAL frames synced every second.
|
|
In the worst case, the last second of writes is lost.
|
|
|
|
\item[RTO $\approx$ seconds] Init container restores latest
|
|
snapshot ($\leq 1$ hour old) plus WAL replay. Typical
|
|
restore: 2--5 seconds for databases under 1\,GB.
|
|
|
|
\item[Durability] S3 provides 11 nines of durability.
|
|
Snapshots are LZ4-compressed and optionally age-encrypted.
|
|
|
|
\item[Consistency] SQLite WAL mode guarantees atomic commits.
|
|
Replicate ships complete WAL frames, preserving transaction
|
|
boundaries.
|
|
\end{description}
|
|
|