CobbleDB: AI meklēšanas krātuves pārbūve zemākai aiztures un izmaksām
Atsaistīta arhitektūra ar atdalītu noturīgu stāvokli, pakešu atjauninājumiem un vaicājuma laika izgūšanu.
Mākslīgā intelekta vietējā meklēšana izvirza dažādas prasības tam, kā tīmekļa saturs ir jāapstrādā, jāglabā un jāapkalpo. Lai apmierinātu šīs prasības mērogā, mēs esam no jauna pārbūvējuši visu stektu no nulles, lai uzlabotu veiktspēju un samazinātu izmaksas.
Mēs izveidojām savu pašu apkopošanas, indeksēšanas un ranžēšanas infrastruktūru, iegulšanas modeļus un inferences dzinenus, lai nodrošinātu efektīvu apstrādi un ātru apkalpošanu. Tagad mēs paplašinām šo pieeju uz krātuvi — savienojošo audu, kurā apstrāde raksta un no kuras apkalpošana lasa.
Pārvaldītas datu bāzes, piemēram, DynamoDB, nodrošināja uzticamu krātuvi, taču mums bija ierobežota kontrole pār to, kā dati tiek glabāti un lasījumi apkalpoti, un uz lietošanu balstīta Cenu noteikšanaauga līdz ar mūsu indeksa izmēru un vaicājumu apjomu. Atsevišķi mūsu iepriekšējais konveijers savienoja dokumentu apstrādi tieši ar apkalpošanas datu bāzi, apgrūtinot atjauninājumu pārvaldību neatkarīgi no tiešajiem lasījumiem.
Ar jauna iekšējā kodēšanas aģentu bara palīdzību mēs pārbūvējām šo slāni ap CobbleDB — atslēgu-vērtību karsto krātuvi, ko atbalsta Pillar noturīgam dokumenta stāvoklim un publicēšanai, un Lorry pakešu atjauninājumiem. Pārbūve atdala dokumentu apstrādi no karstās krātuves ielādes un ļauj mums pielāgot apkalpošanu mūsu darba slodzei. Ražošanas pirms-un-pēc mērījumi uzrāda aptuveni 5× zemāku pakešu lasīšanas aizturi, un mūsu iekšējais izmaksu modelis lēš vismaz 20% ietaupījumu salīdzinājumā ar DynamoDB.
Krātuves infrastruktūra mākslīgā intelekta vietējai meklēšanai
Klasiska meklēšanas steka ir izveidota cilvēka lasītājam, nevis valodas modelim. Šī atšķirība maina granularitāti, kādā sistēmai ir jāsagatavo, jāglabā un jāapkalpo tīmekļa saturs.
Lai pārvērstu neapstrādātu HTML modelim gatavā saturā, mūsu apstrādes konveijers notīra katru lapu, sadala to semantiski saskaņotos fragmentos, aprēķina to iegulumus un glabā fragmentus un iegulumus kopā datu bāzē. Vaicājuma laikā apkalpošanas konveijers atlasa vaicājumam visatbilstošāko tekstu un nodod to modelim.
Divas atšķirīgas darbplūsma
Tāpēc krātuves slānim ir jāatbalsta divas darbplūsma ar dažādām prasībām: atjauninājumu ielāde no apstrādes konveijera un zemas aiztures lasījumu apkalpošana.
Rakstīšanas pusē nepārtraukti pienāk jaunas lapas, esošās lapas mainās, un izmaiņas fragmentēšanas metodēs vai iegulšanas modeļos var prasīt lielu korpusa daļu atkārtotu apstrādi. Krātuves slānim ir jāiekļauj šie atjauninājumi noturīgā dokumenta stāvoklī, jāseko līdzi pašreizējām versijām, jāpublicē pareizie attēlojumi uz pakārtotajām sistēmām un jāatbalsta liela datu aizpilde, neatkārtojot visu konveijeru no neapstrādātas apkopošanas.
Turpretī vaicājuma laika lasījumi pieprasa lapu atslēgu paketes un izgūst atbilstošo fragmentu tekstu un iegulumus ranžēšanai un fragmentu atlasei. Šie lasījumi atrodas ceļā uz galīgo atbildi, tāpēc tiem jābūt pabeigtiem ātri.
Šīm darba slodzēm ir nepieciešams dažāds dizains. Apstrāde gūst labumu no noturīgām rindām un spējas efektīvi piegādāt atjauninājumus, atkārtot neizdevušos mēģinājumus un atjaunināt esošos ierakstus mērogā. Apkalpošana gūst labumu no iepriekš aprēķinātiem ierakstiem, siltām kešatmiņām un ātrām pakešu lasīšanām ar minimālu darbu vaicājuma laikā. Stingra savienošana starp abām var izraisīt to, ka atkopšanas darbs un lieli atjauninājumi konkurē ar aiztures ziņā jutīgiem lasījumiem.
Kur pārvaldītā datu bāze kļūst par īsu
DynamoDB nodrošināja mums augstas pieejamības krātuvi bez apgrūtinājuma darbināt izplatītu datu bāzi. Īpaši sagatavotu lapu tabulā tika glabāti fragmenti un iegulumi vaicājuma laika lasījumiem, savukārt pilns lapas saturs un metadati tika glabāti atsevišķi. Tomēr, augot mūsu darba slodzei, kļuva svarīgi trīs ierobežojumi.
Pirmkārt, uz izmantošanu balstītā cenu noteikšana iekasē maksu par katru nolasīto vai ierakstīto baitu. Viens Search API pieprasījums satur 100–120 atslēgas, kas atbilst lapām, kuras mums nepieciešams iegūt. Datu izgūšanas process sadala pieprasījumu mazākās 10–20 lapu atslēgu paketēs, un vidējais vienības lielums ir aptuveni 50 KB. Atkārtota šo ierakstu lasīšana patērēja ievērojamu jaudu, savukārt nepārtraukta apkopošana un izmaiņas fragmentēšanas vai iegulšanas modeļos ģenerēja vairāk rakstīšanas darbību. Ekonomiskais pamatojums bija atkarīgs arī no ierakstu lieluma un biežuma, ne tikai no API izsaukumu skaita.
Otrkārt, pārvaldītajam pakalpojumam trūkst elastības, kas mums nepieciešama veiktspējas regulēšanai. Mums nepieciešamā darbība bija šaura: ņemot lapas identifikatoru paketi, ātri atgriezt to sagatavoto saturu. Mēs gribējām kontroli pār to, kura mašīna tur partīciju, cik daudz atmiņas ir veltīts tās kešatmiņai un kura kopija apstrādā pieprasījumu. Šīs vadīklas ir svarīgas, jo lasījums bez kešatmiņas, starpzonu lēciens vai lēna kopija var aizkavēt visu paketi. DynamoDB pārvalda savu krātuvi un kopiju uzvedību aiz API. Mēs varējām konfigurēt pakalpojumu, bet mēs nevarējām pielāgot tā iekšējo izvietojumu, krātuves dzinēja kešatmiņas vai kopijas atlases politiku ap mūsu darba slodzi.
Treškārt, apstrāde bija tieši saistīta ar karstās krātuves rakstīšanu. Mūsu iepriekšējais apstrādes konveijers ierakstīja katru sagatavoto lapu tieši DynamoDB. Tāpēc liels pārstrādes darbs kļuva par atsevišķu karsto krātuvju atjauninājumu vilni, un apstrādei bija jāpielāgojas karstās krātuvesCaurlaidības limits un atkārtoti mēģinājumu uzvedībai. Mēs nevarējām palaist MapReduce visā datu bāzē 1–2 dienu laikā, lai izmēģinātu jaunu fragmentēšanas metodi, mainītu mūsu iegulšanas modeli vai pievienotu jaunu lauku. Nebija neatkarīgas saglabāto lapu atjauninājumu plūsmas, ko atsevišķs pakalpojums varētu sagrupēt un piegādāt karstajai krātuvei tās pašu tempā.
Šo ierobežojumu risināšana prasīja vairāk nekā tikai datu bāzes nomaiņu. Mums bija jāatdala noturīgais dokumenta stāvoklis un atjauninājumu piegāde no vaicājuma laika krātuves, pēc tam optimizējot karsto krātuvi speciāli ātrām pakešu lasīšanām.
Atdalīts dokumenta stāvoklis, atjauninājumu piegāde un apkalpošana
Jaunā arhitektūra piešķir katru atbildību citam komponentam. Pillar uztur noturīgu dokumenta stāvokli un izlemj, ko publicēt. Lorry pārvērš šos eksportus partīciju paketēs. CobbleDB ielādē paketes un apkalpo sagatavotos ierakstus pēc lapas atslēgas.
CobbleDB: regulējamais lasīšanas ceļš
CobbleDB ir mūsu karstā krātuve, kas optimizēta sagatavotu ierakstu apkalpošanai vaicājuma laikā. Tā ir izplatīta atslēgu-vērtību krātuve: atslēgas ir lapu identifikatori (jaucēti URL), un vērtības ir lapas apstrādātais attēlojums (to iepriekš sadalītie fragmenti un katra fragmenta vektora iegulumi).
Svarīgas izmaiņas ir mūsu kontrole pār krātuves konfigurāciju.
Dati ir sadalīti un sadalīti starp datu mezgliem. Šis izplatītais formāts nodrošina, ka datu bāze var mērogot horizontāli, lai ietilpinātu milzīgu apstrādāto lapu korpusu. Katrai partīcijai ir trīs kopijas trīs dažādos mezglos; ja viena kopija kļūst nepieejama, pārējās var turpināt apkalpot lasījumus.
Katram datu mezglam ir piešķirta daļa no partīcijām. Mezgls glabā savus datus, izmantojot RocksDB — atvērtā koda iegulto atslēgu-vērtību krātuves dzineni, kas ir labi piemērots lielai lasīšanas slodzei, ko nodrošina pakešu ielāde.
Kešatmiņā saglabātos datus var apkalpot no atmiņas, savukārt lasījumi bez kešatmiņas izmanto vietējo NVMe krātuvi. Tas mums nodrošina tiešu veidu, kā pielāgot atmiņas un diska attiecību novērotajai darba slodzei, nevis pieņemt pārvaldītā pakalpojuma iekšējo kešatmiņas politiku.
Bezvalsts vaicājumu maršrutētājs jauc atslēgas uz partīcijām un paralēli virza pieprasījumus uz mezgliem. Arī arhitektūrā ietilpst PostgreSQL metadatu pakalpojums un noturīga objekta krātuve.
Šis dizains atbalsta lasīšanas modeļus, ko pieprasa mūsu darba slodze. Pēc tam, kad vaicājums iziet cauri izgūšanai un ranžēšanai, lai iegūtu atbilstošu lapu kandidātu kopu, karstajai krātuvei tiek vaicāts vairumā par šo lapu saturu. Šie lasīšanas pieprasījumi nonāk maršrutētājā un tiek novirzīti uz atbilstošo datu mezglu. Maršrutētājs prioritāri nosūta pieprasījumus uz mezglu tajā pašā pieejamības zonā, lai pēc iespējas samazinātu starpzonu aizturi. Katrs datu mezgls var ielādēt lapas saturu, izmantojot MultiGet — RocksDB pakešu lasīšanas API, kas paredzēts vairāku atslēgu vienlaicīgai ielādei ar zemu aizturi. Ja mezgls reaģē lēni, sistēma var arī vaicāt citu partīcijas kopiju citā mezglā, uzlabojot astes aizturi.
Mēs varam arī izvairīties no tādu kopīgu funkciju ieviešanas, kuras mūsu darbplūsma neprasa. Piemēram, lielākā daļa datu bāzu piedāvā konsekvences garantijas un darījumu atbalstu, bet mūsu karstajai krātuvei nav nepieciešami darījumi vai sinhronizētas kopijas. Ir pieļaujama īsa pauze starp brīdi, kad dokuments tiek ierakstīts, un brīdi, kad tas ir pieejams lasīšanai, un ir arī normāli, ja viena kopija ielādē datus ātrāk nekā cita. Tādu funkciju izlaišana, kas mums nav nepieciešamas, samazina mūsu sistēmas pieskaitāmās izmaksas un izmaksas.
Pillar un Lorry: noturīgais rakstīšanas ceļš
Atsevišķs krātuves slānis seko līdzi visam, ko mēs apkopojam un apstrādājam, apvienojot atjauninājumus versijotā dokumenta stāvoklī un publicējot nepieciešamos attēlojumus CobbleDB un meklēšanas indeksā. Šim nolūkam mēs izveidojām Pillar — mūsu dokumentu stāvokļa un publicēšanas slāni.
Pillar pamatā ir YTsaurus. Tas glabā lapas komponentus (piemēram, metadatus, fragmentus un iegulumus) atsevišķās YTsaurus tabulu saimēs. Tas arī seko līdzi fragmentu un iegulumu versijām, ļaujot vairākiem attēlojumiem pastāvēt kopā, nepārrakstot viens otru, lai pamatā esošie modeļi varētu mainīties. Tā kā Pillar un YTsaurus izmanto lētu HDD krātuvi, mēs varam uzglabāt daudz vairāk dokumentu nekā iepriekš glabājām DynamoDB.
Pillar seko līdzi apakškopām vai politikas definētām lapu grupām, piemēram, svaigām lapām vai augstas vērtības lapām. Apakškopas dalība nosaka, kuri atjauninājumi ir jāpārsūta uz pakārtotajiem komponentiem, piemēram, CobbleDB. CobbleDB izmanto dārgāku NVMe krātuvi, tāpēc mēs eksportējam tikai tos dokumentus, kurus patiešām vēlamies izmantot meklēšanas rezultātos. Kad lapas saturs tiek atjaunināts vai ja tā tiek pievienota vai noņemta no apakškopas, Pillar ir atbildīgs par atbilstošo eksporta darbu ievietošanu rindā.
Atomārie YTsaurus darījumi aptver stāvokli, eksporta nolūkus un patērēto ievadi, lai nodrošinātu pareizību. Lai darījums veiksmīgi noslēgtos, sistēmai ir jāatjaunina noturīgais stāvoklis, jāatzīmē ievade kā uzskaitīta un jāievieto rindā visi nepieciešamie eksporti; ja darījums tiek pārtraukts, nevienā slānī netiek veiktas nekādas izmaiņas.
CobbleDB paredz, ka atjauninājumi ir jāsagrupē atbilstoši partīcijai. Pillar eksportus konvertē uz šo formātu bezvalsts pakalpojums, ko saucam par Lorry. Tā vienīgais uzdevums ir lasīt eksporta ierakstus no pastāvīgas partīcijai pielāgotas rindas, uzkrāt tos katras partīcijas pakešu failos un nodot tos CobbleDB.
Starp Lorry un Cobble papildu protokols atdala datu plakni (S3) no vadības plaknes. Lorry ieraksta paketi S3 ar unikālu identifikatoru un reģistrē paketi Cobble. Cobble partīciju kopijas neatkarīgi pieprasa paketi vai vadības plaknes API nākamo S3 paketi ielādei un asinhroni lieto pakešu atjauninājumus hronoloģiskā secībā. Tas nozīmē, ka lēns vai atgūstrošs mezgls var panākt nokavēto savā tempā, nevis palēnināt pārējo sistēmu.
Jaunais ceļš atdala tūlītējas apstrādes darījumu no karstās krātuves datu ielādes un nodrošina atkārtojamu ceļu inkrementāliem atjauninājumiem un masu pārbūvēm. Šis darba dalījums nodrošina, ka atjauninājumi noturīgā dokumenta stāvoklī netraucē lasīšanas ceļa aizturei.
Validācija
5x ātrāka
Pēc karstās krātuves migrācijas mediānas pakešu lasīšanas aizture samazinājās no 31,4 ms līdz 5,60 ms. P90 samazinājās no 56,7 ms līdz 9,77 ms, un p99 samazinājās no 123 ms līdz 24,2 ms. Attiecības svārstās no 5,08× līdz 5,80× ar uzlabojumiem gan tipiskajos pieprasījumos, gan galos.
Šie skaitļi ir iegūti no pakešu lasījumiem, kur katrs vaicājums pieprasa aptuveni 10–15 atslēgas. Vidējais datu vienības izmērs ir 50KB. Abām sistēmām tika nosūtīti vaicājumi ar aptuveni 200k rps, lai gan mēs veicām arī slodzes testus līdz 500k rps bez degradācijas.
Lai izolētu CobbleDB ieguldījumu, visi pārējie iestatījuma aspekti tika saglabāti nemainīgi. Tomēr šī joprojām ir novērojoša pirms-un-pēc salīdzināšana; sistēmas apkalpoja reālo ražošanas datplūsmu dažādos laikos, nevis vienus un tos pašus pieprasījumus kontrolētos apstākļos. Tāpēc mēs izmērījām arī abu sistēmu veiktspēju sintētiskā etalonā. Lai tuvinātos ražošanā novērotajiem pieprasījumiem, mēs vaicājām abām sistēmām ar 10–15 atslēgu paketēm un vērtībām no 100B līdz 100 KiB.
DynamoDB šajā kontekstā saskaras ar grūtībām, jo tās pārvaldīto lasīšanas ceļu nevar pielāgot šāda izmēra pakešu lasīšanai. Pretstatā tam CobbleDB ir optimizēta tieši šim iestatījumam, jo mēs pārvaldām izvietojumu, kešatmiņu un kopiju vadīklas. Tā grupē atslēgas pēc partīcijas, izpilda lasījumus paralēli pret partīciju kopijām un var ierobežot lēnos lasījumus pret citām kopijām. Mūsu rezultāti parāda, ka šīs dizaina izvēles nozīmē ātrākus lasījumus ražošanas vidē.
Par 20% lētāka
CobbleDB ir arī ievērojami lētāka nekā DynamoDB. Papildus krātuvei DynamoDB iekasē maksu arī par katru nolasīto vai ierakstīto baitu. Mūsu korpusa un apkalpošanas datplūsmas mērogā šīs uz lietošanu balstītās maksas kļūst par būtisku kopējo izmaksu daļu. Nepārtraukti atjauninājumi patērē rakstīšanas jaudu, savukārt katra vaicājumam ielādētā sagatavoto lapu pakete patērē lasīšanas jaudu.
Mēs aprēķinājām izmaksu ietaupījumu, pamatojoties uz iekšējiem aprēķiniem par krātuves lielumu, rakstīšanas jaudas vienībām un lasīšanas jaudas vienībām. Katrā saistību līmenī CobbleDB ir vismaz par 20% lētāka nekā DynamoDB. Reālie ietaupījumi, visticamāk, ir pat lielāki, jo šie rezultāti neņem vērā iespējamos dublēšanas ietaupījumus no saspiešanas.
Kā mākslīgā intelekta aģentu bars palīdz mums to izveidot
CobbleDB un apkārtējās infrastruktūras izveide nebija vienkārša. Tikai CobbleDB pamata datu bāze ir aptuveni 40 000 Rust rindu, un migrācija prasa arī plašu darbu, lai pārbaudītu pareizību un kļūmju uzvedību ražošanas mērogā, integrētu CobbleDB gan ar apstrādes, gan apkalpošanas ceļiem un droši pāreja uz reālo datplūsmu.
Mēs paātrinājām šo centienu, izmantojot iekšēju sistēmu, kas darbina kodēšanas aģentu baru. Sistēma ir izstrādāta tā, lai tā būtu ļoti noturīga; tā saglabā projekta mērķus, aktīvos riskus, repozitorija vēsturi un iepriekšējos lēmumus starp sesijām.
Mēs piešķirām šādu proaktīvu, vienmēr ieslēgtu aģentu kopumu CobbleDB projektam. Viņu pirmais uzdevums bija izveidot precīzu modeli par darbu, kas jau tiek veikts. Viņi pārbaudīja projekta pavediens un aktīvos pavedienus, savienoja neatrisinātos vienumus ar to pull request un īpašniekiem, kā arī sagatavoja aktuālu sistēmas veselības un nākamo darbību pārskatu. No turienes viņi darbojās vairākās inženierijas cilpas daļās:
- Pārskatīts kods un infrastruktūras izmaiņas.
- Tika izcelti bloķētāji, kurus bija viegli nepamanīt, tostarp nedroši atjaunošanas pieņēmumi, novecojušas būvēšanas references un konfigurācijas, kas izgāztos izpildes laikā.
- Sagatavoti mērķtiecīgi labojumi, testi, uzraudzības izmaiņas un operacionālā dokumentācija.
- Tika sekots līdzi CI, pārskatīšanas un infrastruktūras vārtiem, vienlaikus saglabājot ražošanas darbības nepārprotami cilvēka pārvaldītām.
- Uzraudzītas ieviešanas un dublēšanas vai atjaunošanas vingrinājumi, pēc tam salīdzinot novēroto sistēmas stāvokli ar ieviešanas panākumu kritērijiem.
- Tika uzturēti projekta pārskati, lai inženieri varētu redzēt, kas ir nosūtīts, kas palicis bloķēts un kur joprojām ir nepieciešams cilvēka spriedums.
Inženieri joprojām iestatīja arhitektūru, pārskatīja būtiskas izmaiņas un pilnvaroja ražošanas darbības. Aģenti apstrādāja lielāko daļu nepārtrauktās pārbaudes un izpildes starp šiem lēmumiem. Tas ļāva nelielai komandai efektīvi virzīt projektu — pamata CobbleDB infrastruktūru divos mēnešos uzbūvēja divi cilvēku inženieri un simtiem AI aģentu.
Secinājums
CobbleDB nav vispārējas nozīmes datu bāze; tā ir īpaši izveidota mūsu specifiskajai darba slodzei, kas sastāv no sagatavotu lapu ierakstu atkārtotām pakešu lasīšanām, ko nodrošina asinhronas apstrādes konveijers. Atdalot noturīgo stāvokli, atjauninājumu piegādi un vaicājuma laika apkalpošanu, mēs varam neatkarīgi optimizēt katru atbildības jomu, nepiespiežot vienu datu bāzes saskarni tās visas pielāgot vai uzspiežot uzturēšanas darbus uz tiešā vaicājuma ceļa. Migrēšana uz CobbleDB būtiski uzlaboja gan mediānas, gan astes aizturi, vienlaikus samazinot infrastruktūras izmaksas.
Tā kā mēs turpinām iekštelpās izstrādāt mākslīgā intelekta vietējo infrastruktūru, mēs varam optimizēt veiktspēju un izmaksas veidos, kas nav iespējami, kad esam piesaistīti trešo pušu ieviešanai un cenu noteikšanas modeļiem. Jaudīgi mākslīgā intelekta aģenti maina aprēķinus vēl vairāk par labu būvēšanai, nevis pirkšanai.
Mēs plānojam drīzumā padarīt CobbleDB par atvērtā koda risinājumu, lai citas komandas, kas veido mākslīgā intelekta vietējās meklēšanas sistēmas, varētu gūt labumu no tā paša krātuves slāņa, kas padara meklēšanu ātrāku un lētāku mūsu produktos.
Citāts
@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}
}