CobbleDB: Reconstruint l'emmagatzematge de cerca d'IA per a menor latència i cost
Una arquitectura desacomplçada amb estat durador separat, actualitzacions per lots i recuperació en el moment de la consulta.
La cerca nativa d'IA imposa diferents requisits sobre com s'ha de processar, emmagatzemar i servir el contingut web. Per satisfer aquestes demandes a escala, hem estat reconstruint tota la pila des de zero per millorar el rendiment i reduir el cost.
Hem construït la nostra pròpia infraestructura de rastreig, indexació i classificació, models d'incrustació i motors d'inferència per impulsar un processament eficient i un servei ràpid. Ara estem estenent aquest enfocament a l'emmagatzematge, el teixit connectiu on el processament escriu i des d'on el servei llegeix les lectures.
Les bases de dades gestionades com DynamoDB proporcionaven un emmagatzematge fiable, però teníem un control limitat sobre com s'emmagatzemaven les dades i es servien les lectures, i els preus basats en l'ús creixien amb la nostra mida d'índex i volum de consultes. Per separat, la nostra canonada anterior acoblava el processament de documents directament a la base de dades de servei, cosa que dificultava la gestió de les actualitzacions independentment de les lectures en directe.
Amb l'ajuda d'un nou eixam d'agents de codificació interns, hem reconstruït aquesta capa al voltant de CobbleDB, un magatzem calent clau-valor, amb el suport de Pillar per a l'estat i la publicació de documents duradors, i Lorry per a actualitzacions per lots. El redisseny separa el processament de documents de la ingestió de l'emmagatzematge calent i ens permet ajustar el servei a la nostra càrrega de treball. Les mesures de producció d'abans i després mostren una latència de lectura per lots aproximadament 5× menor, i el nostre model de cost intern estima un estalvi d'almenys un 20% en relació amb DynamoDB.
Infraestructura d'emmagatzematge per a la cerca nativa d'IA
Una pila de cerca clàssica està dissenyada per a un lector humà, no per a un model de llenguatge. Aquesta diferència canvia la granularitat a la qual el sistema necessita preparar, emmagatzemar i servir contingut web.
Per convertir HTML en brut en contingut apte per a models, la nostra canonada de processament neteja cada pàgina, la divideix en passatges semànticament coherents, calcula les seves incrustacions i emmagatzema els passatges i les incrustacions junts a la base de dades. En el moment de la consulta, la canonada de servei selecciona el text més rellevant per a la consulta i el passa al model.
Dos fluxos de treball diferents
Per tant, la capa d'emmagatzematge ha de suportar dos fluxos de treball amb diferents exigències: ingerir actualitzacions de la canonada de processament i servir lectures de baixa latència.
Pel costat de l'escriptura, les noves pàgines arriben contínuament, les pàgines existents canvien i els canvis en els mètodes de fragmentació o els models d'incrustació poden requerir el reprocessament de grans porcions del corpus. La capa d'emmagatzematge ha d'incorporar aquestes actualitzacions a l'estat durador del document, fer un seguiment de les versions actuals, publicar les representacions adequades als sistemes aigües avall (downstream) i admetre grans càrregues retroactives (backfills) sense repetir tota la canonada a partir del rastreig en brut.
En canvi, les lectures en el moment de la consulta sol·liciten lots de claus de pàgina i recuperen el text del passatge corresponent i les incrustacions per a la classificació (ranking) i la selecció de passatges. Aquestes lectures es troben al camí cap a la resposta final, de manera que s'han de completar ràpidament.
Aquestes càrregues de treball requereixen dissenys diferents. El processament es beneficia de les cues duradores i de la capacitat de lliurar actualitzacions de manera eficient, reintentar fallades i posar al dia els registres existents a escala. El servei es beneficia de registres precalculats, memòria cau calenta (warm caches) i lectures ràpides per lots amb un mínim treball en el moment de la consulta. Un acoblament estret entre tots dos pot fer que el treball de recuperació i les grans actualitzacions competeixin amb les lectures sensibles a la latència.
On es queden curtes les bases de dades gestionades
DynamoDB ens va proporcionar un emmagatzematge altament disponible sense la càrrega d'operar una base de dades distribuïda. Una taula dedicada de pàgines preparades contenia passatges i incrustacions (embeddings) per a lectures en el moment de la consulta, mentre que el contingut complet de la pàgina i les metadades s'emmagatzemaven per separat. Tanmateix, a mesura que la nostra càrrega de treball va créixer, tres restriccions van esdevenir importants.
Segon, el model de preus basat en l'ús cobra cada byte llegit o escrit. Una sola sol·licitud de l'API de cerca conté 100-120 claus corresponents a les pàgines que hem de recuperar. El procés de recuperació de dades divideix una sol·licitud en lots més petits de 10-20 claus de pàgina amb una mida mitjana d'element d'uns 50 KB. Llegir repetidament aquests registres consumia una capacitat substancial, mentre que els rastrejos continus i els canvis en els mètodes de fragmentació o models d'incrustació generaven més escriptures. L'economia també depenia de la mida i la freqüència dels registres, no només del nombre de cridades a l'API.
Segon, el servei gestionat manca de la flexibilitat que necessitem per ajustar el rendiment. L'operació que necessitàvem era concreta: donat un lot d'identificadors de pàgina, retornar el seu contingut preparat ràpidament. Volíem control sobre quina màquina allotjava una partició, quanta memòria es dedicava a la seva memòria cau i quina rèplica gestionava una sol·licitud. Aquests controls importen perquè una lectura no emmagatzemada a cau, un salt entre zones o una rèplica lenta poden endarrerir tot el lot. DynamoDB gestiona el seu propi emmagatzematge i el comportament de les rèpliques darrere de l'API. Podíem configurar el servei, però no podíem ajustar la seva ubicació interna, les memòries cau del motor d'emmagatzematge o la política de selecció de rèpliques al voltant de la nostra càrrega de treball.
Tercer, el processament estava lligat directament a les escriptures de l'emmagatzematge calent. La nostra canonada de processament anterior escrivia cada pàgina preparada directament a DynamoDB. Per tant, un gran treball de reprocessament es convertia en una onada d'actualitzacions individuals de l'emmagatzematge calent, i el processament havia de sintonitzar-se amb els límits de rendiment i el comportament de reintent de l'emmagatzematge calent. No podíem executar MapReduce a tota la base de dades en 1-2 dies per provar un nou mètode de fragmentació (chunking), canviar el nostre model d'incrustació o afegir un nou camp. No hi havia cap flux independent d'actualitzacions de pàgines desades que un servei separat pogués agrupar (batch) i lliurar a l'emmagatzematge calent al seu propi ritme.
Abordar aquestes restriccions requeria més que substituir la base de dades. Havíem de separar l'estat durador del document i el lliurament d'actualitzacions de l'emmagatzematge en el moment de la consulta, i després optimitzar l'emmagatzematge calent específicament per a lectures ràpides per lots.
Separar l'estat del document, el lliurament d'actualitzacions i el servei
La nova arquitectura assigna cada responsabilitat a un component diferent. Pillar manté un estat de document durador i decideix què s'ha de publicar. Lorry converteix aquestes exportacions en lots particionats. CobbleDB ingereix els lots i serveix registres preparats per clau de pàgina.
CobbleDB: el camí de lectura ajustable
CobbleDB és el nostre emmagatzematge calent optimitzat per servir registres preparats en el moment de la consulta. És una magatzem clau-valor distribuït: les claus són identificadors de pàgina (URL amb hash) i els valors són la representació processada de la pàgina (els seus passatges prefragmentats i incrustacions vectorials per fragment).
El canvi important és el nostre control sobre la configuració de l'emmagatzematge.
Les dades es particionen i es divideixen entre nodes de dades. Aquest format distribuït garanteix que la base de dades pugui escalar horitzontalment per allotjar un corpus enorme de pàgines processades. Cada partició té tres rèpliques en tres nodes diferents; si una còpia no està disponible, les altres poden continuar servint lectures.
A cada node de dades se li assigna un subconjunt de les particions. El node emmagatzema les seves dades utilitzant RocksDB, un motor d'emmagatzematge clau-valor incrustat i de codi obert molt adequat per a càrregues de treball amb moltes lectures alimentades per la ingestió per lots.
Les dades de la memòria cau es poden servir des de la memòria, mentre que les lectures no incloses a la memòria cau utilitzen emmagatzematge NVMe local. Això ens ofereix una manera directa d'ajustar l'equilibri entre memòria i disc per a la càrrega de treball observada, en lloc d'acceptar la política de memòria cau interna d'un servei gestionat.
Un router de consultes sense estat aplica hash a les claus per repartir-les en particions i envia les sol·licituds als nodes en paral·lel. L'arquitectura també inclou un servei de metadades basat en PostgreSQL i emmagatzematge d'objectes durador.
Aquest disseny admet els patrons de lectura que exigeix la nostra càrrega de treball. Després que una consulta passi per la recuperació i la classificació per obtenir un conjunt de candidats de pàgines rellevants, l'emmagatzematge calent es consulta de manera massiva per obtenir el contingut d'aquestes pàgines. Aquestes sol·licituds de lectura arriben al gestor d'encrutament (router) i s'envien a un node de dades corresponent. El router prioritza l'enviament de sol·licituds a un node de la mateixa zona de disponibilitat per minimitzar la latència entre zones, si és possible. Cada node de dades pot recuperar el contingut de la pàgina utilitzant MultiGet, una API de lectura per lots de RocksDB dissenyada per recuperar múltiples claus simultàniament amb una baixa latència. Si un node triga a respondre, el sistema també pot consultar una altra rèplica de partició en un node diferent, millorant la latència dels casos extrems (tail latency).
També podem evitar implementar característiques comunes que el nostre flux de treball no requereix. Per exemple, la majoria de bases de dades ofereixen garanties de consistència i suport de transaccions, però el nostre emmagatzematge calent no requereix transaccions ni rèpliques sincronitzades. És acceptable que hi hagi un petit interval entre el moment en què s'escriu un document i el moment en què està disponible per a les lectures, i també està bé que una rèplica ingereixi dades més ràpidament que una altra. Ometre característiques que no necessitem redueix la sobrecàrrega (overhead) i el cost del nostre sistema.
Pillar i Lorry: el camí d'escriptura durador
Una capa d'emmagatzematge separada fa un seguiment de tot el que rastreguem i processem, fusionant les actualitzacions en un estat de document versionat i publicant les representacions necessàries a CobbleDB i a l'índex de cerca. Hem creat Pillar, la nostra capa d'estat de documents i publicació, amb aquest propòsit.
Pillar funciona amb el suport de YTsaurus. Emmagatzema components de pàgines (com ara metadades, fragments i incrustacions) en famílies de taules de YTsaurus separades. També fa un seguiment de les versions dels fragments i incrustacions, permetent que múltiples representacions coexisteixin sense sobreescriure' les unes a les altre perquè els models subjacents puguin canviar. Com que Pillar i YTsaurus utilitzen emmagatzematge HDD barat, podem emmagatzemar molts més documents dels que emmagatzemàvem anteriorment a DynamoDB.
Pillar fa un seguiment de subconjunts, o grups de pàgines definits per política, com ara pàgines fresques o pàgines d'alt valor. La pertinença al subconjunt determina quines actualitzacions s'han de passar als components aigües avall com CobbleDB. CobbleDB utilitza un emmagatzematge NVMe més car, de manera que només exportem els documents que realment voleu utilitzar en els resultats de cerca. Quan s'actualitza el contingut d'una pàgina, o si s'afegeix o s'elimina d'un subconjunt, Pillar s'encarrega de posar a la cua el treball d'exportació corresponent.
Les transaccions atòmiques de YTsaurus cobreixen l'estat, les intencions d'exportació i l'entrada consumida per garantir la correcció. Perquè una transacció es completi amb èxit, el sistema ha d'actualitzar l'estat durador, marcar l'entrada com a comptabilitzada i posar a la cua totes les exportacions requerides; si la transacció s'avorta, no es fa cap canvi a cap capa.
CobbleDB espera que les actualitzacions s'agrupin per lots segons la partició. Les exportacions de Pillar es converteixen en aquest format mitjançant un servei sense estat (stateless) que anomenem Lorry. La seva única feina és llegir registres d'exportació d'una cua persistent alineada amb particions, acumular-los en fitxers per lots per partició i lliurar-los a CobbleDB.
Entre Lorry i Cobble, un protocol addicional separa el pla de dades (S3) del pla de control. Lorry escriu el lot a S3 sota un identificador únic i registra el lot dins de Cobble. Les rèpliques de partició de Cobble consulten de manera independent l'API del pla de control o de lot per obtenir el proper lot S3 a ingerir i apliquen de manera asíncrona les actualitzacions per lots en ordre cronològic. Això significa que un node lent o en recuperació pot posar-se al dia al seu propi ritme, en lloc de alentir la resta del sistema.
El nou camí separa la transacció de processament immediat de la ingestió de l'emmagatzematge calent i proporciona un camí reproduïble per a actualitzacions incrementals i reconstruccions massives. Aquesta divisió del treball garanteix que les actualitzacions de l'estat durador del document no interfereixin amb la latència del camí de lectura.
Validació
5x més ràpid
Després de migrar l'emmagatzematge calent (hot store), la latència mitjana de lectura per lots va baixar de 31,4 ms a 5,60 ms. El p90 va baixar de 56,7 ms a 9,77 ms, i el p99 va baixar de 123 ms a 24,2 ms. Les proporcions oscil·len entre 5,08× i 5,80×, amb millores tant en les sol·licituds típiques com en els casos extrems (tail).
Aquests números es deriven de lectures per lots, on cada consulta sol·licita aproximadament 10-15 claus. La mida mitjana dels elements de càrrega útil (payload) és de 50 KB. Es va consultar a tots dos sistemes a unes 200k rps, tot i que també vam executar proves de càrrega de fins a 500k rps sense cap degradació.
Per aïllar la contribució de CobbleDB, tots els altres aspectes de la configuració es van mantenir constant. Tanmateix, continua sent una comparació observacional d'abans i després; els sistemes van servir tràfic de producció en directe en moments diferents en lloc de les mateixes sol·licituds sota condicions controlades. Per tant, també vam mesurar el rendiment d'ambdós sistemes en un punt de referència (benchmark) sintètic. Per aproximar les sol·licituds observades en producció, vam consultar ambdues amb lots de 10-15 claus i valors que anaven de 100B a 100 KiB.
DynamoDB té dificultats en aquest context perquè el seu camí de lectura gestionat no es pot ajustar per a lectures per lots d'aquesta mida. En canvi, CobbleDB està optimitzat exactament per a aquest entorn, ja que gestionem la ubicació, la memòria cau i els controls de les rèpliques. Agrupa les claus per partició, executa lectures en paral·lel contra les rèpliques de partició i pot protegir les lectures lentes contra altres rèpliques. Els nostres resultats demostren que aquestes opcions de disseny es tradueixen en lectures més ràpides en un entorn de producció.
20% més barat
CobbleDB també és significativament més barat que DynamoDB. A més de l'emmagatzematge, DynamoDB també cobra cada byte llegit o escrit. A l'escala del nostre corpus i del tràfic de servei, aquests càrrecs basats en l'ús es converteixen en una part substancial del cost total. Les actualitzacions contínues consumeixen capacitat d'escriptura, mentre que cada lot de pàgines preparades recuperades per a una consulta consumeix capacitat de lectura.
Hem calculat l'estalvi de costos basant-nos en estimacions internes de la mida de l'emmagatzematge, unitats de capacitat d'escriptura i unitats de capacitat de lectura. A tots els nivells de compromís, CobbleDB és almenys un 20% més barat que DynamoDB. L'estalvi real probablement sigui encara més gran, ja que aquests resultats no tenen en compte el possible estalvi en còpies de seguretat derivat de la compressió.
Com un eixam d'agents d'IA ens va ajudar a construir-ho
Construir CobbleDB i la infraestructura del seu entorn no va ser gens trivial. Només la base de dades principal de CobbleDB té aproximadament 40.000 línies de Rust, i la migració també va requerir un treball extensiu per verificar la correcció i el comportament davant fallides a escala de producció, integrar CobbleDB amb les rutes de processament i servei, i fer la transició del tràfic en directe de manera segura.
Hem accelerat aquest esforç utilitzant un sistema intern que opera un eixam d'agents de codificació. El sistema està dissenyat per ser altament persistent; reté els objectius del projecte, els riscs actius, l'historial del repositori i les decisions prèvies a través de cada Sessió.
Vam assignar un col·lectiu d'aquests agents proactius i sempre actius al projecte CobbleDB. La seva primera tasca va ser construir un model precís del treball que ja estava en marxa. Van auditar el fil del projecte i els fils actius, van connectar els elements pendents amb els seus pull requests i propietaris, i van produir un informe actual de la salut del sistema i les properes accions. A partir d'aquí, van operar a través de diverses parts del cicle d'enginyeria:
- S'han revisat els canvis de codi i d'infraestructura.
- S'han tret a la llum elements de bloqueig fàcils d'obviar, incloent-hi suposicions de restauració no segures, referències de compilació obsoletes i configuracions que fallarien en temps d'execució.
- S'han preparat correccions focalitzades, proves, canvis de monitorització i documentació operacional.
- S'ha fet un seguiment de la integració contínua (CI), la revisió i les portes d'infraestructura, mantenint alhora les accions de producció sota responsabilitat explícitament humana.
- Desplegaments (rollouts) monitoritzats i exercicis de còpia de seguretat o restauració, comparant llavors l'estat del sistema observat amb els criteris d'èxit del desplegament.
- S'han mantingut els informes de projecte perquè els enginyers poguessin veure què s'havia enviat a producció, què continuava bloquejat i on encara es requeria criteri humà.
Els enginyers encara defineixen l'arquitectura, revisen els canvis conseqüents i autoritzen les operacions de producció. Els agents s'encarreguen de gran part de la inspecció contínua i el seguiment entre aquestes decisions. Això va permetre a un equip petit impulsar el projecte de manera eficient: la infraestructura central de CobbleDB va ser construïda per dos enginyers humans i centenars d'agents d'IA en dos mesos.
Conclusió
CobbleDB no és una base de dades d'ús general; està construïda expressament per a la nostra càrrega de treball específica de lectures repetides per lots de registres de pàgines preparades, alimentades per una canonada (pipeline) de processament asíncron. En separar l'estat durador, el lliurament d'actualitzacions i el servei en el moment de la consulta, podem optimitzar cada responsabilitat de manera independent sense obligar una sola interfície de base de dades a adaptar-les totes ni empènyer el treball de manteniment al camí de consulta en directe. Migrar a CobbleDB va millorar significativament tant la latència mitjana com la dels casos extrems (tail latency), alhora que va reduir els costos d'infraestructura.
A mesura que continuem desenvolupant infraestructura nativa d'IA de manera interna, podem optimitzar el rendiment i el cost de maneres que no són possibles quan estem lligats a implementacions i models de preus de tercers. Els agents d'IA potents desvien el càlcul encara més a favor de construir en lloc de comprar.
Tenim previst publicar CobbleDB com a codi obert aviat, de manera que altres equips que construeixin sistemes de cerca natius d'IA puguin beneficiar-se de la mateixa capa d'emmagatzematge que fa que la cerca sigui més ràpida i barata dins dels nostres productes.
Citació
@online{perplexity2026Cobbledb,
author = {{Perplexity} and Alexandr Yarats and Marco Montagna and Aleksei Bykov and Alexey Gusev and Ali Abdullaev and Amir Mokhammed-Ali and Andrey Zosimov and Denis Kremko and Gleb Vishnevsky and Micah Zirn and Phi Hoang and Claire Beamer and Jeremy Yang and Jerry Ma and Denis Yarats},
title = {{CobbleDB: Rebuilding AI search storage for lower latency and cost}},
date = {2026-09-14},
url = {https://www.perplexity.ai/hub/blog/cobbledb}
}