La setmana passada vaig esborrar la meva base de dades de producció. La meva instància de treball [Neotoma](https://neotoma.io) va passar de 6.174 observacions i 3.862 entitats a 84 observacions i 67 entitats en una comanda. Mesos de contactes, tasques, converses, notes de comentaris, transaccions i regles permanents: desaparegut.

El vaig recuperar. La base de dades final té 6.296 observacions i 3.951 entitats que abasten cinc setmanes d'activitat. La recuperació va durar aproximadament una hora. Aquesta publicació tracta sobre com va passar, per què va ser possible la recuperació i què va revelar l'experiència sobre la construcció d'un sistema de memòria en el qual realment podeu confiar.

## Què va passar

Estava treballant a la Neotoma CLI, provant un flux de treball de desenvolupament. Vaig executar una seqüència d'ordres que restableixen l'estat de la base de dades i la van reiniciar. La intenció era esborrar les dades de prova d'un entorn de desenvolupament. L'objectiu era la base de dades de producció.

L'error va ser mundà. Vaig executar `neotoma reset` mentre `NEOTOMA_ENV` estava configurat en producció. Vaig pensar que m'orientava a dev. Quan em vaig adonar, la base de dades activa tenia 84 observacions noves del procés de reinicialització i res més.

## Trobar les còpies de seguretat

El primer que vaig fer va ser buscar tots els fitxers Neotoma SQLite a la meva màquina. Vaig trobar deu còpies repartides per directoris de còpia de seguretat, carpetes de dades i artefactes de recuperació amb marca de temps d'una trucada de tancament anterior a principis de març.

| Fitxer font | Observacions | Entitats | Última activitat |
|---|---|---|---|
| `neotoma.prod.db.db` | 6.174 | 3.862 | 9 de març |
| `neotoma.prod 2.db` | 4.406 | 3.073 | 10 de març |
| Objectiu en directe (post-esborrat) | 84 | 67 | 11 de març |
| `neotoma.prod.db.recovered-*` | 4.381 | 3.059 | 3 de març |
| `còpies de seguretat de dades/còpia de dades/` | 4.158 | 2.955 | 2 de març |
| Diverses còpies antigues | 3.100 a 3.931 | 2.558 a 2.806 | 17 de febrer al 27 de febrer |

Les còpies de seguretat existien perquè havia estat copiant manualment el fitxer de la base de dades a intervals irregulars. No és un sistema de còpia de seguretat formal, només ordres `cp` ocasionals quan recordava o em sentia nerviós. Una d'aquestes còpies, `neotoma.prod.db.db`, ​​va contenir gairebé tot fins al 9 de març. Una segona còpia, `neotoma.prod 2.db`, ​​tenia dades fins al 10 de març que la primera còpia es va perdre.

Entre aquests dos fitxers i les 84 observacions supervivents a la base de dades en directe, tenia prou material per reconstruir la línia de temps completa.

## Com va funcionar la fusió

Neotoma té una comanda incorporada `merge-db` per combinar bases de dades SQLite. El procés:

1. Feu una còpia de seguretat de tots els fitxers implicats (tant les fonts com la destinació) en un directori amb marca de temps. Cap intent de recuperació hauria de posar en perill els originals.
2. Atureu el servidor Neotoma en execució per evitar escriptures concurrents.
3. Realitzeu la fusió en sec per veure quins conflictes existeixen.
4. Executeu la fusió amb `--mode keep-target`, que insereix files de la font que falten l'objectiu i conserva la versió de l'objectiu de qualsevol fila que comparteixen ambdues bases de dades.
5. Repetiu per a la segona font.
6. Verificar l'observació i el recompte d'entitats.
7. Reinicieu el servidor.

La fusió principal va portar 6.174 observacions de la còpia de seguretat més gran. La fusió secundària n'ha afegit aproximadament 100 més des de la finestra del 10 de març. El recompte final: 6.296 observacions, 3.951 entitats, activitat que va del 9 de febrer a l'11 de març.

Després de reiniciar, vaig provar les entitats a través del Neotoma MCP per confirmar que tot era accessible. Contactes, tasques, converses, registres de comentaris: tots presents i estructurats correctament.

## Per què va ser possible aquesta recuperació

La recuperació va funcionar a causa de tres propietats de l'arquitectura de Neotoma.

**Les observacions són la font de la veritat.** Neotoma no emmagatzema entitats sobreescriure una fila quan alguna cosa canvia. Cada fet entra al sistema com una observació immutable: "El correu electrònic d'Alice és alice@example.com, observat el 3 de març des de Gmail". L'estat de l'entitat es calcula a partir del conjunt complet d'observacions. El registre d'observació només es pot afegir.

Això significa que una còpia de seguretat de la base de dades és una instantània completa de tots els fets que el sistema ha vist mai, no només de l'últim estat. Quan vaig fusionar la còpia de seguretat a la base de dades en directe, no estava restaurant "l'últim estat conegut de cada entitat". Estava reproduint tota la història.

**Les instantànies d'entitat es deriven, no primàries.** Després de combinar les observacions, Neotoma torna a calcular les instantànies d'entitat a partir del registre d'observació. La instantània de cada entitat és determinista: donades les mateixes observacions, sempre s'obté el mateix estat de l'entitat. És per això que l'ordre de combinació inclou un pas de recàlcul de la instantània. Un cop fetes les observacions, les entitats es reconstrueixen correctament.

**Fusió de clau primària amb detecció de conflictes.** L'ordre `merge-db` recorre totes les taules, insereix files que existeixen a la font però no a la destinació i gestiona els conflictes per clau primària. En el mode "mantenir l'objectiu", la versió de l'objectiu guanya en qualsevol col·lisió. El mode d'execució en sec mostra exactament què s'inserirà i què entrarà en conflicte abans de comprometre's. Vaig executar execucions en sec per a les dues fusions i vaig revisar els informes de conflictes abans d'executar-los.

Aquestes tres propietats juntes fan que la base de dades s'autocura d'una manera que les còpies de seguretat tradicionals a nivell de fila no ho són. No cal que us preocupeu per quina còpia de seguretat té "la versió correcta" d'una entitat. Combina les observacions, tornes a calcular i cau l'estat correcte.

## El que vaig aprendre

L'experiència va reforçar algunes coses.

**Les còpies de seguretat informals són millors que no fer còpies de seguretat.** El meu hàbit de copiar ocasionalment el fitxer de la base de dades m'ha estalviat mesos de feina. Però les còpies manuals ocasionals no són un sistema. Deixen buits. Si hagués esborrat la base de dades el 7 de març en comptes de l'11 de març, hauria perdut les dades del 28 de febrer al 7 de març perquè cap còpia cobria aquesta finestra completament. Ara estic configurant còpies de seguretat diàries automatitzades amb Time Machine al meu Mac.

**L'error de la bandera d'env és un clàssic.** Tots els sistemes que funcionen en entorns de desenvolupament i producció comporta aquest risc. La mitigació són sol·licituds de confirmació d'operacions destructives, sol·licituds de terminal codificades per colors o credencials separades per entorn. Després d'aquest incident, vaig afegir una confirmació forçada a "neotoma reset" sempre que detecta un entorn de producció. La bandera `-y` s'ignora per a prod. Veu "Reinicialització de Neotoma (PRODUCCIÓ)" i un avís abans que passi res.

**L'arquitectura d'origen d'esdeveniments val la pena en la recuperació.** Si Neotoma emmagatzemés entitats sobreescriure les files al seu lloc, l'esborrat de la base de dades seria un esdeveniment de pèrdua de dades sense un camí de recuperació net. Com que les observacions són immutables i l'estat de l'entitat es deriva, la recuperació és una operació de fusió i recàlcul. El registre d'observació és la veritat del terreny. Tota la resta es pot reconstruir a partir d'ell.

**Vaig provar les eines que estava construint.** Vaig escriure l'ordre `merge-db` fa mesos per a un cas d'ús diferent: combinar dades d'usuaris que executen diverses instàncies de Neotoma. Mai m'esperava utilitzar-lo amb les meves pròpies dades de producció. Però com que l'eina existia i gestionava la resolució de conflictes i el càlcul de les instantànies, la recuperació va ser mecànica més que estressant.

## Les vostres dades haurien de sobreviure als vostres errors

Aquest incident va exposar els buits que Neotoma hauria de tancar perquè els usuaris mai hagin de fer el que vaig fer manualment.

**Instantànies automàtiques.** Neotoma hauria de capturar la base de dades segons una programació i abans de qualsevol operació destructiva. Un conjunt rotatiu de còpies marcades de temps, conservades durant 30 dies. Si executeu un restabliment del producte per error, la instantània prèvia al restabliment és allà mateix. La recuperació no hauria de dependre de si us heu recordat d'executar `cp` aquella setmana.

**Detecció d'anomalies.** No és normal una caiguda sobtada de milers d'observacions a gairebé zero. Neotoma podria detectar aquest patró i confirmar abans de comprometre's. Una simple heurística, "aquesta operació eliminaria més del 90% de les observacions, confirmeu?" hauria impedit la meva neteja per complet.

**Recuperació impulsada per agents.** Com que els agents són l'UX principal de Neotoma, la recuperació també hauria de funcionar mitjançant agents. Li dius al teu agent "la meva base de dades sembla incorrecta, crec que he perdut dades". L'agent verifica els recomptes d'observacions, troba les instantànies disponibles, compara els intervals de dates i us guia per la fusió mitjançant l'MCP. No es requereix espeleologia CLI.

**Sincronització remota.** Les còpies de seguretat locals protegeixen contra sobreescritures accidentals però no contra errors de disc. Neotoma hauria d'admetre la sincronització del registre d'observació amb una ubicació remota: un cub de núvol, una segona màquina o un servidor autoallotjat. Com que les observacions només s'afegeixen, el model de sincronització és senzill. Envia noves observacions al comandament remot. Reconstrueix l'estat de l'entitat a cada extrem.

La mateixa arquitectura que va fer possible aquesta recuperació fa que aquestes funcions siguin senzilles de construir. Les observacions només adjuntes, l'estat derivat i el càlcul determinista no són només propietats de recuperació. Són la base per a la còpia de seguretat, la sincronització i l'autocuració com a garanties de primera classe.

## Els números

| mètrica | Abans de netejar | Després de netejar | Després de la recuperació |
|---|---|---|---|
| Observacions | 6.174 | 84 | 6.296 |
| Entitats | 3.862 | 67 | 3.951 |
| Interval de dates | Del 9 de febrer al 9 de març | 10 de març a 11 de març | 9 de febrer a 11 de març |

El recompte final és superior al recompte previ a l'esborrat perquè la combinació combinava observacions de les tres fonts: els dos fitxers de còpia de seguretat i les dades posteriors a l'esborrat. Algunes observacions que només existien a la còpia de seguretat del 10 de març o només a la base de dades en directe no estaven a la còpia de seguretat més gran original.

Si el vostre sistema de memòria utilitza un estat mutable, l'esborrat és permanent. Si utilitza un registre d'observació només per adjuntar amb un estat de l'entitat derivat, una neteja és una fusió per evitar la recuperació completa. Aquesta diferència importa quan les dades són els vostres contactes, els vostres compromisos, el vostre historial amb els agents durant centenars de sessions.

Neotoma és [codi obert a GitHub](https://github.com/neotoma-app/neotoma). Si voleu una capa de memòria on les vostres dades puguin sobreviure als vostres pitjors errors, [proveu-ho](https://neotoma.io/install).