CobbleDB: AI-otsingu salvestusruumi uuesti ülesehitamine madalama latentsuse ja kulude nimel
Eraldatud arhitektuur eraldatud vastupidava oleku, partiidena värskenduste ja päringuaegse toomisega.
Tehisintellektipõhine otsing seab erinevad nõuded sellele, kuidas veebisisu tuleb töödelda, salvestada ja teenindada. Nende nõudmiste täitmiseks mastaabis oleme jõudluse parandamiseks ja kulude vähendamiseks ehitanud kogu pinu nullist üles.
Ehitasime oma roomamis-, indekseerimis- ja reastamisinfrastruktuuri, manusemudelid ning järeldusmootorid, et toetada tõhusat töötlemist ja kiiret teenindamist. Laiendame nüüd seda lähenemisviisi salvestusruumile, siduvale koekoele, kuhu töötlemine kirjutab ja kust teenindus loeb.
Hallatud andmebaasid, nagu DynamoDB, pakkusid usaldusväärset salvestusruumi, kuid meil oli piiratud kontroll selle üle, kuidas andmeid salvestati ja lugemisi teenindati, ning kasutusel põhinev hinnakujundus kasvas koos meie indeksi suuruse ja päringute mahuga. Eraldi sidus meie eelmine torustik dokumendi töötlemise otse teenindava andmebaasiga, mistõttu oli raske värskendusi reaalajas lugemistest sõltumatult hallata.
Uue sisemise kodeerimisagentide parve abiga ehitasime selle kihi uuesti üles CobbleDB, võti-väärtus-kuuma salvestusruumi ümber, mida toetavad Pillar vastupidava dokumendi oleku ja avaldamise jaoks ning Lorry partiidena värskenduste jaoks. Ümber kujundamine eraldab dokumendi töötlemise kuuma salvestusruumi sisselugemisest ja võimaldab meil teeninduse oma töövoo järgi häälestada. Tootmise enne-ja-pärast mõõtmised näitavad ligikaudu 5× madalamat partiina lugemise latentsust ning meie sisemine kulumudel hindab vähemalt 20% kokkuhoidu võrreldes DynamoDB-ga.
Salvestusinfrastruktuur tehisintellektipõhise otsingu jaoks
Klassikaline otsingupinu on üles ehitatud inimsoost lugeja, mitte keelemudeli jaoks. See erinevus muudab detailsustaset, millel süsteem peab veebisisu ette valmistama, salvestama ja teenindama.
Toore HTML-i mudelvalmiks sisuks muutmiseks puhastab meie töötlemistorustik iga lehekülje, jagab selle semantiliselt sidusateks lõikudeks, arvutab nende manused ning salvestab lõigud ja manused andmebaasi koos. Päringu ajal valib teenindustorustik päringu jaoks kõige asjakohasema teksti ja edastab selle mudelile.
Kaks erinevat töövoogu
Salvestuskiht peab seega toetama kahte erinevate nõudmistega töövoogu: töötlemistorustiku värskenduste sisselugemist ja madala latentsusega lugemiste teenindamist.
Kirjutamise poolel saabub uusi lehekülgi pidevalt, olemasolevad leheküljed muutuvad ning tükeldamismeetodite või manusemudelite muudatused võivad nõuda suure osa korpuse uuesti töötlemist. Salvestuskiht peab need värskendused vastupidavasse dokumendi olekusse integreerima, praeguseid versioone jälgima, õiged esitused allavoolu süsteemidele avaldama ja toetama suuri taastäiteid ilma kogu torustikku toorroomamisest alates kordamata.
Seevastu päringuaegsed lugemised nõuavad lehekülje võtmete partiisid ning toovad reastamiseks ja lehekülje valimiseks esile vastava lõike teksti ja manused. Need lugemised on lõpliku vastuse teel, mistõttu tuleb need kiiresti lõpule viia.
Need töökoormused nõuavad erinevaid disaine. Töötlemine saab kasu vastupidavatest järjekordadest ja võimalusest värskendusi tõhusalt edastada, tõrkeid uuesti proovida ja olemasolevad kirjed mastaapselt ajakohaseks tuua. Teenindus saab kasu eelarvutatud kirjetest, soojadest vahemäludest ja kiiretest partiidena lugemistest minimaalse päringuaegse tööga. Tihe seotus nende kahe vahel võib põhjustada taastamistööde ja suurte värskenduste konkureerimise latentsustundlike lugemistega.
Kus hallatud andmebaas jääb lühikeseks
DynamoDB pakkus meile kõrgkäideldavat salvestusruumi ilma hajutatud andmebaasi haldamise koormata. Spetsiaalne ettevalmistatud lehekülgede tabel sisaldas lõike ja manuseid päringuaegsete lugemiste jaoks, samas kui täielik lehekülje sisu ja metaandmed salvestati eraldi. Meie töökoormuse kasvades muutusid aga kolm piirangut oluliseks.
Esiteks nõuab kasutusel põhinev hinnakujundus tasu iga loetud või kirjutatud baidi eest. Üksainsa otsingu API päring sisaldab 100–120 võtit, mis vastavad lehekülgedele, mida peame hankima. Andmete toomise protsess jagab päringu 10–20 lehekülje võtmest koosnevateks väiksemateks partiideks, kusjuures üksuse keskmine suurus on umbes 50 KB. Nende kirjete korduv lugemine tarbis märkimisväärset mahtu, samas kui pidev roomamine ja tükeldamis- või manusemudelite muudatused tekitasid rohkem kirjutusi. Ökonoomika sõltus ka kirjete suurusest ja sagedusest, mitte ainult API päringute arvust.
Teiseks puudub hallatud teenusel paindlikkus, mida vajame jõudluse häälestamiseks. Meie vajatud toiming oli kitsas: antud lehekülje identifikaatorite partii, tagastage nende ettevalmistatud sisu kiiresti. Tahtsime kontrollida, milline masin hoiab partitsiooni, kui palju mälu on pühendatud selle vahemälule ja milline koopia käsitleb päringut. Need juhtelemendid on olulised, kuna vahemäluta lugemine, tsoonidevaheline hüpe või aeglane koopia võib kogu partii viivitada. DynamoDB haldab oma salvestusruumi ja koopiate käitumist API taga. Saime teenust konfigureerida, kuid me ei saanud selle sisemist paigutust, salvestusmootori vahemälu ega koopiate valimise poliitikat oma töökoormuse järgi häälestada.
Kolmandaks oli töötlemine seotud otse kuuma salvestusruumi kirjutamistega. Meie eelmine töötlemistorustik kirjutas iga ettevalmistatud lehekülje otse DynamoDB-sse. Seetõttu muutus suur ümbertöötlemistöö kuuma salvestusruumi üksikute värskenduste laineks ning töötlemine pidi arvestama kuuma salvestusruumi läbilaskevõime piirangute ja uuesti proovimise käitumisega. Me ei saanud käivitada MapReduce'i kogu andmebaasis 1–2 päevaga, et proovida uut tükeldamismeetodit, muuta oma manusemudelit või lisada uut välja. Puudus salvestatud lehekülje värskenduste sõltumatu voog, mida eraldi teenus oleks saanud partiidena koostada ja kuuma salvestusruumi omas tempos edastada.
Nende piirangute lahendamine nõudis enamat kui lihtsalt andmebaasi asendamist. Pidin eraldama vastupidava dokumendi oleku ja värskenduste edastamise päringuaegsest salvestusruumist ning seejärel optimeerima kuuma salvestusruumi spetsiaalselt kiirete partiidena lugemiste jaoks.
Eralda dokumendi olek, värskenduste edastamine ja teenindamine
Uus arhitektuur määrab iga vastutusala erinevale komponendile. Pillar säilitab vastupidava dokumendi oleku ja otsustab, mida avaldada. Lorry muudab need ekspordid partitsioonitud partiideks. CobbleDB loeb partiid sisse ja teenindab ettevalmistatud kirjeid lehekülje võtme järgi.
CobbleDB: häälestatav lugemistee
CobbleDB on meie kuum salvestusruum, mis on optimeeritud ettevalmistatud kirjete teenindamiseks päringu ajal. See on hajutatud võti-väärtus-salvestusruum: võtmed on lehekülje identifikaatorid (räsitud URL-id) ja väärtused on lehekülje töödeldud esitus (nende eelnevalt tükeldatud lõigud ja tükipõhised vektormanused).
Oluline muudatus on meie kontroll salvestuskonfiguratsiooni üle.
Andmed on partitsioonitud ja jagatud andmesõlmede vahel. See hajutatud vorming tagab, et andmebaas saab horisontaalselt skaleeruda, et mahutada tohutut töödeldud lehekülgede korpust. Igal partitsioonil on kolm koopiat kolmes erinevas sõlmes; kui üks koopia muutub kättesaamatuks, saavad teised lugemiste teenindamist jätkata.
Igale andmesõlmele määratakse partitsioonide alamhulka. Sõlm salvestab oma andmed RocksDB abil, mis on avatud lähtekoodiga manustatud võti-väärtus-salvestusmootor, mis sobib hästi lugemismahukate töökoormuste jaoks, mida toidab partiidena sissevõtmine.
Andmeid saab vahemälust teenindada mälust, samas kui vahemäluta lugemised kasutavad kohalikku NVMe salvestusruumi. See annab meile otsese viisi mälu ja ketta tasakaalu häälestamiseks vaadeldud töökoormuse jaoks, selle asemel et leppida hallatava teenuse sisemise vahemälu poliitikaga.
Olekuta päringuruuter räsib võtmed partitsioonideks ja suunab päringud sõlmedele paralleelselt. Arhitektuur sisaldab ka PostgreSQL-il põhinevat metaandmete teenust ja vastupidavat objektisalvestust.
See disain toetab lugemismustreid, mida meie töökoormus nõuab. Pärast seda, kui päring läbib otsingu ja järjestamise, et saada asjakohaste lehekülgede kandidaatide hulk, päritakse kuumalt salvestusruumilt hulgiviisiliselt nende lehekülgede sisu. Need lugemistaotlused saabuvad ruuterile ja suunatakse vastavasse andmesõlmesse. Ruuter seab võimalusel esikohale päringute saatmise samas saadavustsoonis asuvale sõlmele, et minimeerida tsoonidevahelist latentsust. Iga andmesõlm saab lehe sisu hankida MultiGeti abil, mis on RocksDB partiina lugemise API, mis on loodud mitme võtme üheaegseks hankimiseks madala latentsusega. Kui sõlm reageerib aeglaselt, saab süsteem päringu esitada ka teisele partitsiooni koopiale teises sõlmes, parandades sabalatentsust.
Samuti saame vältida selliste tavaliste funktsioonide rakendamist, mida meie töövoog ei vaja. Näiteks pakub enamik andmebaase järjepidevuse garantiisid ja tehingute tuge, kuid meie kuum salvestusruum ei vaja tehinguid ega sünkroniseeritud koopiaid. On vastuvõetav, et dokumendi kirjutamise ja selle lugemiseks kättesaadavaks muutmise vahele jääb lühike vahe, samuti on lubatud, et üks koopia loeb andmeid sisse kiiremini kui teine. Vajalike funktsioonide ärajätmine vähendab meie süsteemi üldkulusid ja maksumust.
Pillar ja Lorry: vastupidav kirjutustee
Eraldi salvestuskiht hoiab järge kõigel, mida me roomame ja töötleme, liites värskendused versioneeritud dokumendi olekusse ning avaldades vajalikud esitused CobbleDB-le ja otsinguindeksile. Lõime selleks otstarbeks oma dokumendi oleku ja avaldamise kihi Pillar.
Pillar on toetatud YTsaurus poolt. See salvestab lehekülje komponendid (nagu metaandmed, tükid ja manused) eraldi YTsauruse tabeliperedesse. Samuti jälgib see tükkide ja manuste versioone, võimaldades mitmel esitusel ilma üksteist üle kirjutamata eksisteerida, nii et aluseks olevad mudelid saavad muutuda. Kuna Pillar ja YTsaurus kasutavad odavat HDD-salvestusruumi, saame salvestada palju rohkem dokumente kui varem DynamoDB-s.
Pillar jälgib alamhulki ehk eeskirjadega määratletud lehekülgede rühmi, nagu värsked leheküljed või suure väärtusega leheküljed. Alamhulka kuulumine määrab, mitmed värskendused tuleb edasi anda allavoolu komponentidele, nagu CobbleDB. CobbleDB kasutab kallimat NVMe salvestusruumi, mistõttu ekspordime ainult neid dokumente, mida me tegelikult otsingutulemustes kasutada soovime. Kui lehekülje sisu värskendatakse või kui see lisatakse alamhulgale või eemaldatakse sellest, vastutab Pillar vastava eksporditöö järjekorda panemise eest.
YTsauruse aatomiaulsed tehingud hõlmavad olekut, ekspordi kavatsusi ja tarbitud sisendit, et tagada õigsus. Selleks, et tehing edukalt lõpule viia, peab süsteem värskendama vastupidavat olekut, märkima sisendi arvestatuks ja panema järjekorda kõik vajalikud ekspordid; kui tehing katkestatakse, ei tehta üheski kihis mingeid muudatusi.
CobbleDB eeldab, et värskendused koostatakse partiidesse vastavalt partitsioonile. Pillar ekspordid teisendatakse sellesse vormingusse olekuta teenuse abil, mida nimetame Lorryks. Selle ainsaks ülesandeks on lugeda ekspordikirjeid püsivast partitsiooniga joondatud järjekorrast, koondada need partitsioonipõhistesse partiifailidesse ja anda need CobbleDB-le.
Lorry ja Cobble'i vahel eraldab täiendav protokoll andmetasandi (S3) juhtimistasandist. Lorry kirjutab partii S3-sse kordumatu identifikaatori all ja registreerib partii Cobble'is. Cobble'i partitsiooni koopiad pärivad iseseisvalt partiid või juhtimistasandi API-d järgmise S3 partii sisselugemiseks ja rakendavad asünkroonselt partiivärskendusi kronoloogilises järjekorras. See tähendab, et aeglane või taastuv sõlm saab järele jõuda omas tempos, selle asemel et aeglustada ülejäänud süsteemi.
Uus tee eraldab vahetu töötlemise tehingu kuuma salvestusruumi sisselugemisest ning pakub taasesitatavat teed inkrementaalseteks värskendusteks ja hulgiuuesti ülesehitamiseks. See tööjaotus tagab, et vastupidava dokumendi oleku värskendused ei sega lugemistee latentsust.
Valideerimine
5x kiirem
Pärast kuuma salvestusruumi migreerimist langes partii lugemise mediaanlatentsus 31,4 ms-lt 5,60 ms-le. P90 langes 56,7 ms-lt 9,77 ms-le ja P99 langes 123 ms-lt 24,2 ms-le. Suhtarvud jäävad vahemikku 5,08× kuni 5,80× ning paranemist on näha nii tüüpiliste päringute kui ka sabapäringute puhul.
Need numbrid on tuletatud partiidena lugemistest, kus iga päring nõuab umbes 10–15 võtit. Kasuliku koorma üksuse keskmine suurus on 50 KB. Mõlemat süsteemi päriti umbes 200 tuhande rps-i juures, kuigi viisime läbi ka koormusteste kuni 500 tuhande rps-ini ilma halvenemiseta.
CobbleDB panuse isoleerimiseks hoiti kõiki teisi seadistuse aspekte muutumatuna. Siiski on see endiselt vaatluslik enne-ja-pärast võrdlus; süsteemid teenindasid reaalset tootlusliikluse liiklust erinevatel aegadel, mitte samu päringuid kontrollitud tingimustes. Seetõttu mõõtsime ka mõlema süsteemi jõudlust sünteetilisel võrdlustestil. Tootmises esinevate päringute lähendamiseks tegime päringuid mõlemale 10–15 võtmest koosnevate partiidega ja väärtustega vahemikus 100B kuni 100 KiB.
DynamoDB on selles kontekstis hädas, kuna selle hallatud lugemistee ei ole häälestatav sellise suurusega partiide lugemiseks. Seevastu CobbleDB on optimeeritud täpselt selleks olukorraks, kuna me haldame paigutust, vahemällu salvestamist ja koopiate juhtelemente. See rühmitab võtmed partitsiooni järgi, täidab lugemised paralleelselt partitsiooni koopiate vastu ja saab aeglasi lugemisi teiste koopiate suhtes maandada. Meie tulemused näitavad, et need disainivalikud tähendavad kiiremaid lugemisi tootmiskeskkonnas.
20% odavam
CobbleDB on samuti oluliselt odavam kui DynamoDB. Lisaks salvestusruumile võtab DynamoDB tasu ka iga loetud või kirjutatud baidi eest. Meie korpuse ja teenindava liikluse mastaabis muutuvad need kasutusel põhinevad tasud kogukulude oluliseks osaks. Pidevad värskendused tarbivad kirjutamisvõimsust, samas kui iga päringu jaoks hangitud ettevalmistatud lehekülgede partii tarbib lugemisvõimsust.
Arvutasime kulude kokkuhoiu salvestusruumi mahu, kirjutamisvõimsuse ühikute ja lugemisvõimsuse ühikute sisemiste hinnangute põhjal. Igal kohustustasemel on CobbleDB vähemalt 20% odavam kui DynamoDB. Tegelik kokkuhoid on tõenäoliselt isegi suurem, kuna need tulemused ei võta arvesse tõenäolist tihendamisest tulenevat varunduskokkuhoidu.
Kuidas tehisintellekti agentide parv aitas meil seda ehitada
CobbleDB ja seda ümbritseva infrastruktuuri ehitamine polnud teps mitte tühine ülesanne. Ainuüksi CobbleDB põhiandmebaas koosneb ligikaudu 40 000 Rusti reast ning migreerimine nõudis ka ulatuslikku tööd õigsuse ja tõrkekäitumise kontrollimiseks tootmismastaabis, CobbleDB integreerimiseks nii töötlemis- kui ka teenindusteedega ning elava liikluse turvaliseks üleviimiseks.
Kiirendasime seda pingutust sisemise süsteemi abil, mis käitab kodeerimisagentide parve. Süsteem on loodud olema ülivastupidav; see säilitab sessioonide vahel projekti eesmärgid, aktiivsed riskid, hoidla ajaloo ja varasemad otsused.
Määrasime CobbleDB projektile selliste ennetavate, alati sisselülitatud agentide kollektiivi. Nende esimene ülesanne oli luua täpne mudel juba pooleliolevast tööst. Nad auditeerisid projekti kanalit ja aktiivseid lõimi, ühendasid silmapaistvad üksused nende pull request'ide ja omanikega ning koostasid praeguse ülevaate süsteemi tervisest ja järgmistest toimingutest. Sealt edasi tegutsesid nad mitmes inseneritsükli osas:
- Vaatas üle koodi ja infrastruktuuri muudatused.
- Tõi esile blokaatorid, mida oli lihtne kahe silma vahele jätta, sealhulgas ebaturvalised taastamise eeldused, aegunud ehitusviited ja konfiguratsioonid, mis käitusajal ebaõnnestuksid.
- Ettevalmistatud sihipärased parandused, testid, seiremuudatused ja töödokumentatsioon.
- Jälgis CI-, ülevaatus- ja infrastruktuuripiiranguid, hoides samal ajal tootmistoimingud selgelt inimeste omanduses.
- Monitooritud kasutuselevõtud ning varundus- või taasteharjutused võrdlesid seejärel vaadeldud süsteemi olekut kasutuselevõtu edukuse kriteeriumidega.
- Säilitas projekti ülevaateid, et insenerid näeksid, mis on tarnitud, mis on endiselt blokeeritud ja kus on endiselt vaja inimeste hinnangut.
Insenerid määravad endiselt arhitektuuri, vaatasid üle olulised muudatused ja volitasid tootmistoiminguid. Agendid hoolitsesid suurema osa pidevast kontrollist ja nendest otsustest tulenevast järeltegevusest. See võimaldas väikesel meeskonnal projekti tõhusalt juhtida – põhilise CobbleDB infrastruktuuri ehitasid kaks iniminseneri ja sajad tehisintellekti agendid kahe kuuga.
Kokkuvõte
CobbleDB ei ole üldotstarbeline andmebaas; see on spetsiaalselt ehitatud meie konkreetse töökoormuse jaoks, mis koosneb ettevalmistatud leheküljekirjete korduvatest partiina lugemistest, mida toidab asünkroonne töötlemistorustik. Eraldades vastupidava oleku, värskenduste edastamise ja päringuaegse teenindamise, saame iga vastutusalat eraldi optimeerida, sundimata ühteandmebaasi liidest kõiki neid mahutama või surumata hooldustöid reaalajas päringute teele. Migreerimine CobbleDB-le parandas oluliselt nii mediaan- kui ka saba latentsust, vähendades samal ajal taristukulusid.
Kuna jätkame AI-omase infrastruktuuri arendamist ettevõttesiseselt, saame optimeerida jõudlust ja kulusid viisil, mis ei ole võimalik kolmandate osapoolte teostuste ja hinnakujundusmudelitega seotuna. Võimsad AI-agendid kallutavad kaalutluskaussi veelgi enam ise ehitamise kasuks ostmise asemel.
Plaanime CobbleDB peagi avatud lähtekoodiga teha, et teised tehisintellektipõhiseid otsingusüsteeme ehitavad meeskonnad saaksid kasu samast salvestuskihipist, mis muudab otsingu meie toodetes kiiremaks ja odavamaks.
Viide
@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}
}