The Search Stack That Nearly Broke Us — Until We Did This

Ang Paghahanap sa Pag -scale ay hindi lamang tungkol sa pagdaragdag ng mas malaking server – kung minsan kailangan mo ng tamang mga tool.
Noong una naming inilunsad ang Finlight.me, ang aming real-time na pinansiyal na balita sa API, ang mga postgres full-text na paghahanap ay higit pa sa sapat. Ito ay mabilis, madaling i -set up, at magkasya perpektong sa aming simpleng maagang arkitektura. Ngunit habang lumalaki ang bilang ng mga artikulo at naging mas kumplikado ang mga kahilingan sa paghahanap, nagsimulang lumitaw ang mga bitak. Sa artikulong ito, ibabahagi ko kung paano kami lumipat mula sa Postgres hanggang OpenSearch, ang mga hamon na kinakaharap namin, at kung bakit ang pagpapanatili ng mga postgres bilang aming mapagkukunan ng katotohanan ay naging isa sa aming pinakamahusay na mga pagpapasya.
Nagsimula ang lahat sa isang simpleng pag-setup ng full-text sa loob ng mga postgres na nagtrabaho nang nakakagulat nang maayos-hanggang sa hindi ito ginawa.
Unang Arkitektura: Postgres full-text paghahanap
Sa mga unang araw, ginamit namin ang built-in na full-text na paghahanap ng Postgres 'na mga query sa artikulo. Ang mga pamagat at nilalaman ay pinagsama sa isang solong tsvector
patlang, na nagpapahintulot sa amin na maghanap nang mahusay nang hindi nababahala tungkol sa casing, suffix, o order ng keyword – mga limitasyon na pangunahing %query%
Ang mga paghahanap ay hihirapan. Ang mga papasok na query sa paghahanap ay na -convert din sa mga vectors, at ang Postgres ay gumawa ng isang matatag na trabaho sa pagraranggo at pagbabalik ng mga kaugnay na resulta. Para sa isang habang, ang pag -setup na ito ay hawakan ang aming mga pangangailangan sa mabilis na mga oras ng pagtugon at minimal na overhead. Ito ay simple, isinama, at nagtrabaho nang maayos sa tabi ng natitirang bahagi ng aming ingestion at imbakan system.
Ngunit habang nagsimulang lumaki ang dami ng artikulo at naging mas kumplikado ang mga query ng gumagamit, sinimulan naming mapansin ang mga bitak na bumubuo sa ilalim ng ibabaw.
Mga puntos ng sakit na may scaling postgres
Sa una, ang pag-post ng buong-text na paghahanap ay hawakan nang maayos ang aming lumalagong dataset. Ngunit habang ang bilang ng artikulo ay umakyat sa daan -daang libo, ang pagganap ng paghahanap ay nagsimulang kapansin -pansin na nagpapabagal. Ang pangunahing isyu ay hindi lamang ang full-text na paghahanap mismo-ito ay kung paano pinagsama ng mga gumagamit ang mga free-text query na may karagdagang mga filter tulad ng pag-publish ng mga saklaw ng petsa, mga tiyak na mapagkukunan, o mga patlang ng metadata. Malakas ang mga postgres sa pag -index ng mga indibidwal na patlang, at nito GIN
Pinabilis ng index ang buong-text na paghahanap. Gayunpaman, mabilis kaming tumakbo sa isang mahirap na limitasyon: hindi pinapayagan ng mga postgres ang pagsasama a GIN
index na may regular B-Tree
Index sa isang composite index. Nangangahulugan ito na hindi namin mai -optimize ang parehong mga uri ng mga query nang sabay -sabay, na pinilit ang database na pumili ng alinman sa isang suboptimal na plano o bumalik sa sunud -sunod na mga pag -scan – pareho sa mga ito ay naging masakit na mabagal habang lumalaki ang dataset.
Index Management Nightmare: Opsyonal na mga parameter at lumalagong pagiging kumplikado
Ang kakayahang umangkop ng aming API-na nagpapahintulot sa mga gumagamit na pagsamahin ang anumang subset ng mga filter tulad ng pag-publish ng petsa, mapagkukunan, paghahanap ng libreng-text at higit pa-ipinakilala ang isa pang layer ng mga hamon sa pag-scale. Dahil opsyonal ang bawat parameter ng paghahanap, nahaharap kami sa isang pagsabog ng combinatorial ng mga posibleng pattern ng query. Upang mapanatili ang katanggap -tanggap na pagganap, kailangan naming lumikha ng iba't ibang mga index upang suportahan ang pinaka -karaniwang mga kumbinasyon ng mga parameter. Sa bawat oras na nagdagdag kami ng isang bagong mahahanap na patlang, kinakailangan nito ang pagdidisenyo ng mga bagong index, pagsusuri ng mga plano sa query na may EXPLAIN ANALYZE
at mano -mano ang pagpapatunay ng pagganap. Ang patuloy na pag -tune ng index na ito ay naging nakakapagod at hindi matatag. Mas masahol pa, sa kabila ng lahat ng pagsisikap, ang pangunahing limitasyon ay nanatili: hindi pa rin namin mahusay na ma-optimize ang buong-text na paghahanap na sinamahan ng mga filter ng metadata sa isang solong query.
Ang pagbagsak ng pagination at pagiging mabagal ng gumagamit
Habang ang mga volume ng artikulo ay patuloy na lumalaki, isa pang pagganap ng bottleneck ang lumitaw: pagination. Inilantad ng aming API a page
Parameter na direkta na naka -mapa sa SQL OFFSET
pag -uugali sa likod ng mga eksena. Habang nagtrabaho ito ng maayos sa mga mababang offset, mabilis na lumala ang pagganap habang hiniling ng mga gumagamit ang mas malalim na mga pahina. Lalo na, ang mismong tampok na dapat gumawa ng mga paghahanap nang mas mabilis – pagbabalik lamang ng isang maliit na hiwa ng mga resulta – natapos ang paggawa ng mga bagay na mas mabagal. Ang bawat hined na kahilingan ay pinilit na mga postgres na i -scan, mabilang, at laktawan ang libu -libong mga hilera bago ito masimulan ang pagbabalik ng mga resulta, muling pagkerculate ng malalaking bahagi ng plano ng query sa bawat oras. Ang mga query na dating kinuha sa ilalim ng pangalawang lobo sa sampu -sampung segundo. Sa puntong iyon, hindi na ito isang problema sa imprastraktura – ito ay naging isang pagkabigo sa karanasan ng gumagamit. Napagtanto namin na kahit na ang isang mahusay na nakatutok na pag-setup ng postgres ay hindi sapat upang suportahan ang mabilis, nababaluktot na paghahanap sa scale na lumalaki kami.
Bakit pinili namin ang OpenSearch
Malinaw na kailangan namin ng isang system na itinayo partikular para sa paghahanap-isang bagay na na-optimize para sa mga free-text query, pag-filter, at mabilis na pagination sa scale. Ang pagkakaroon ng nagtrabaho sa Elasticsearch sa mga nakaraang proyekto ng freelance, pamilyar na kami sa mga lakas ng nakalaang mga search engine: baligtad na mga index, mahusay na mga algorithm ng pagmamarka, at malakas na kakayahang umangkop sa query. Napagpasyahan naming mag-ampon ng OpenSearch, ang tinidor na hinimok ng komunidad ng Elasticsearch, kapwa para sa malakas na mga kakayahan sa teknikal at mas kanais-nais na modelo ng paglilisensya.
Kasabay nito, gumawa kami ng isang mahalagang desisyon sa arkitektura: upang paghiwalayin ang landas ng pagsulat mula sa landas na nabasa. Ang mga postgres ay mananatiling aming solong mapagkukunan ng katotohanan para sa mga ingested at naproseso na mga artikulo, tinitiyak ang integridad ng data at pagkakapare -pareho. Ang OpenSearch ay magsisilbing layer na na-optimize na nabasa, na naghahatid ng mabilis at nababaluktot na paghahanap nang hindi labis na labis ang aming ingestion pipeline. Pinayagan kaming gumamit ng pinakamahusay na tool para sa bawat kinakailangan-isang maaasahang, relational, normalized database para sa pag-iimbak at ingestion, at isang mataas na pagganap na search engine para sa pagtatanong-sa halip na subukang pilitin ang isang sistema na gawin ang lahat.
Phase ng Pagsubok: Simula ng Maliit at Mabilis na Pag -aaral
Bago ganap na gumawa ng paggawa, pinagsama namin ang OpenSearch sa isang minimal-resource na pag-setup ng pagsubok: isang solong-node na kumpol na may limitadong RAM, na inilaan para sa pagsusuri at pag-tune. Sa kapaligiran na ito, mabilis kaming nakatagpo ng mga pag -uugali na nagpahiwatig sa mga pangangailangan ng scaling ng system. Sa paglipas ng panahon, napansin namin ang nawawalang mga index at pinanghihinang pagganap ng paghahanap – ang mga sintomas na malamang na sanhi ng mga kaganapan sa presyon ng memorya at mga kaganapan sa pag -iwas sa mapagkukunan sa panig ng pagho -host. Malayo sa pagiging isang pag-iingat, ang mga maagang pagsubok na ito ay napatunayan ang isang mahalagang aralin: Habang maihatid ng OpenSearch ang pagganap na kailangan namin, hiniling nito ang mga mapagkukunan na grade-production na gawin ito nang maaasahan. Pinapayagan kami ng Pagsubok sa Lean na mag -tune ng mga mapa ng index, patunayan ang pagganap ng query, at kapasidad ng plano batay sa totoong pag -uugali. Pinatibay din nito ang aming pagpipilian sa arkitektura upang mapanatili ang mga post
Pag -scale ng OpenSearch para sa paggawa
Gamit ang mga pananaw mula sa aming yugto ng pagsubok, lumipat kami sa isang pag-deploy ng grade-OpenSearch na may mga mapagkukunan na kinakailangan upang tumugma sa aming paglaki. Nagdagdag kami ng maraming mga node sa kumpol, inilalaan ng sapat na RAM, at nakatutok sa mga mapa ng index upang mai -optimize ang parehong pagsulat at pagganap ng query. Sa bagong pag -setup, ang mga oras ng pagtugon sa paghahanap ay bumaba nang malaki – kahit na ang mga kumplikadong mga query na may malalim na pagination ay nagbalik ng mga resulta sa millisecond sa halip na mga segundo.
Ang pangkalahatang daloy ng data ay umusbong din: Matapos ang mga artikulo ay dumaan sa aming real-time na artikulo sa pagproseso ng pipeline-kung saan sila ay nakolekta, pinayaman, at nasuri-agad silang pinapakain sa OpenSearch para sa mabilis na pagkuha. Ang mga Postgres ay nananatiling nag-iisang mapagkukunan ng katotohanan, ang pag-iimbak ng lahat ng hilaw at naproseso na data na maaasahan, habang ang OpenSearch ay kumikilos bilang nabasa na na-optimize na layer na nakatutok para sa pagganap ng paghahanap.
Ipinakilala rin namin ang regular na pag -snapshotting ng mga indensearch indeks, tinitiyak na kahit na lumago ang base ng artikulo, maaari kaming mabawi nang mabilis mula sa mga pagkabigo o muling itayo ang mga index nang walang downtime. Ang pagpapagamot ng OpenSearch bilang isang advanced na cache sa halip na ang pangunahing database ay nagbigay sa amin ng kakayahang umangkop: maaari naming magbago ng mga scheme ng paghahanap, muling itayo ang mga index, o ayusin ang mga mappings nang hindi inilalagay ang panganib sa integridad ng data. Sa paglipas ng panahon, habang tumaas ang trapiko at pinalawak ang aming dataset, ang bagong arkitektura ay patuloy na gumanap nang maaasahan sa ilalim ng pag -load.
Arkitektura ngayon: nababanat, real-time na paghahanap
Ngayon, malinis ang aming system na naghihiwalay sa mga responsibilidad sa pagitan ng ingestion, imbakan, at pagkuha. Ang mga postgres ay patuloy na kumikilos bilang nag -iisang mapagkukunan ng katotohanan, maaasahan na iniimbak ang lahat ng mga hilaw at naproseso na data ng artikulo sa isang normalized na istruktura ng relational. Ang mga artikulo ay dumadaloy sa aming real-time na artikulo sa pagproseso ng pipeline-kung saan sila ay na-scrap, pinayaman, at nasuri-bago pinapakain sa OpenSearch para sa na-optimize na pagganap ng paghahanap. Hinahawak ng OpenSearch ang lahat ng mga query sa paghahanap na nakaharap sa gumagamit, na nagpapahintulot sa amin na maghatid ng mabilis, nababaluktot na mga resulta kahit sa ilalim ng mataas na pag-load. Ang regular na pag-snapshotting, maalalahanin na pamamahala ng index, at isang paglawak ng multi-node na matiyak na ang aming imprastraktura sa paghahanap ay nananatiling nababanat at nasusukat habang lumalaki ang aming set ng data. Sa pamamagitan ng pag -decoup ng pagsulat at basahin ang mga panig ng arkitektura at pagpili ng pinakamahusay na tool para sa bawat pangangailangan, nagtayo kami ng isang sistema na mabilis, maaasahan, at handa na para sa patuloy na paglaki.
Mga Aralin na Natutunan: Payo para sa mga Tagabuo
- Simulan ang simple, ngunit ang disenyo na may sukat sa isip. Ang mga postgres full-text na paghahanap ay nagsilbi sa amin nang maayos-ngunit ang kakayahang umangkop sa disenyo na ginawa ng paglipat na posible sa ibang pagkakataon nang walang pangunahing sakit.
- Paghiwalayin ang basahin at isulat ang mga landas nang maaga pa sa praktikal. Sinusubukang gumawa ng isang solong database hawakan ang lahat ay nagiging mas mahirap na mas mahirap habang lumalaki ang pagiging kumplikado.
- Gumamit ng tamang tool para sa trabaho. Ang isang relational database ay higit sa pag -iimbak at pagkakapare -pareho; Ang isang search engine ay higit sa nababaluktot na pagkuha at pagraranggo.
- Huwag maliitin ang opsyonal na pagiging kumplikado ng query. Ang pagsuporta sa nababaluktot na mga filter ng API ay simple hanggang sa kailangan mong i -index ang bawat posibleng kumbinasyon.
- Pagsubok ng Lean, Scale Smart. Ang maagang pagsubok na may kaunting mga mapagkukunan ay nagturo sa amin kung ano ang talagang kailangan ng produksyon-grade OpenSearch-at maiwasan ang mga magastos na sorpresa.
- Panatilihin ang isang maaasahang mapagkukunan ng katotohanan. Ang pagkakaroon ng mga postgres sa likod ng OpenSearch ay nagpapahintulot sa amin na muling itayo, pagalingin, at palawakin ang aming imprastraktura sa paghahanap nang walang panganib na integridad ng data ng pangunahing.
Kung nagtatayo ka ng mga scalable API o nagtatrabaho sa mga malalaking datasets sa paghahanap, gusto kong marinig kung paano ka papalapit sa mga katulad na hamon. Huwag mag -atubiling ibahagi ang iyong mga saloobin o karanasan sa mga komento!