Retaj aplikaĵoj nun estas uzataj ĉie, kaj inter ĉiuj transportprotokoloj, HTTP okupas la plej grandan parton. Kiam vi studas la nuancojn de disvolvo de TTT-aplikoj, plej multaj homoj tre malmulte atentas la operaciumon, kie ĉi tiuj aplikoj efektive funkcias. La disiĝo de evoluo (Dev) kaj operacioj (Ops) nur plimalbonigis la situacion. Sed kun la kresko de DevOps-kulturo, programistoj iĝas respondecaj pri rulado de siaj aplikoj en la nubo, do estas tre utile ke ili plene koniĝu kun la backend de la operaciumo. Ĉi tio estas precipe utila se vi provas deploji sistemon por miloj aŭ dekoj da miloj da samtempaj konektoj.
La limigoj en retservoj estas tre similaj al tiuj en aliaj aplikoj. Ĉu temas pri ŝarĝbalanciloj aŭ datumbazaj serviloj, ĉiuj ĉi tiuj aplikoj havas similajn problemojn en alt-efikeca medio. Kompreni ĉi tiujn fundamentajn limigojn kaj kiel venki ilin ĝenerale helpos vin taksi la rendimenton kaj skaleblon de viaj TTT-aplikoj.
Mi skribas ĉi tiun serion de artikoloj responde al demandoj de junaj programistoj, kiuj volas fariĝi bone informitaj sistemaj arkitektoj. Estas neeble klare kompreni Linuksajn aplikaĵajn optimumigajn teknikojn sen plonĝi en la bazaĵojn pri kiel ili funkcias ĉe la mastruma sistemo. Kvankam ekzistas multaj specoj de aplikoj, en ĉi tiu serio mi volas esplori ret-bazitajn aplikojn prefere ol labortablaj aplikoj kiel retumilo aŭ tekstredaktilo. Ĉi tiu materialo estas destinita por programistoj kaj arkitektoj, kiuj volas kompreni kiel funkcias Linuksaj aŭ Uniksaj programoj kaj kiel strukturi ilin por alta rendimento.
Linukso estas servila ĉambro operaciumo, kaj plej ofte viaj aplikaĵoj funkcias per ĉi tiu OS. Kvankam mi diras "Linukso", plejofte vi povas sekure supozi, ke mi celas ĉiujn Unikso-similajn operaciumojn ĝenerale. Tamen mi ne testis la akompanan kodon en aliaj sistemoj. Do, se vi interesiĝas pri FreeBSD aŭ OpenBSD, viaj rezultoj povas varii. Kiam mi provas ion specifan Linukson, mi atentigas ĝin.
Dum vi povas uzi ĉi tiun scion por konstrui app de nulo kaj ĝi estos perfekte optimumigita, estas plej bone ne fari tion. Se vi skribas novan retservilon en C aŭ C++ por la komerca aplikaĵo de via organizo, ĉi tio eble estos via lasta tago en la laboro. Tamen, koni la strukturon de ĉi tiuj aplikoj helpos elekti ekzistantajn programojn. Vi povos kompari procez-bazitajn sistemojn kun faden-bazitaj sistemoj same kiel okazaĵ-bazitaj. Vi komprenos kaj aprezos kial Nginx funkcias pli bone ol Apache httpd, kial Tornado-bazita Python-apliko povas servi pli da uzantoj kompare kun Django-bazita Python-apliko.
ZeroHTTPd: Lerna Ilo
NuloHTTPd estas retservilo, kiun mi skribis de nulo en C kiel instruilo. Ĝi ne havas eksterajn dependecojn, inkluzive de aliro al Redis. Ni prizorgas niajn proprajn Redis-procedojn. Vidu sube por pliaj detaloj.
Kvankam ni povus longe diskuti teorion, estas nenio pli bona ol skribi kodon, ruli ĝin kaj kompari ĉiujn servilajn arkitekturojn unu kun la alia. Ĉi tiu estas la plej evidenta metodo. Tial, ni skribos simplan ZeroHTTPd retservilon uzante ĉiun modelon: procez-bazita, faden-bazita kaj evento-bazita. Ni kontrolu ĉiun el ĉi tiuj serviloj kaj vidu kiel ili funkcias kompare unu kun la alia. ZeroHTTPd estas efektivigita en ununura C-dosiero. La okazaĵ-bazita servilo inkluzivas uthash, bonega hashtabelefektivigo kiu venas en ununura kapdosiero. En aliaj kazoj, ne ekzistas dependecoj, por ne malfaciligi la projekton.
Estas multaj komentoj en la kodo por helpi vin kompreni. Estante simpla retservilo en kelkaj linioj de kodo, ZeroHTTPd ankaŭ estas minimuma kadro por reto-disvolviĝo. Ĝi havas limigitan funkciecon, sed kapablas servi statikajn dosierojn kaj tre simplajn "dinamikajn" paĝojn. Mi devas diri, ke ZeroHTTPd estas bona por lerni kiel krei alt-efikecajn Linuksajn aplikojn. Ĝenerale, plej multaj retservoj atendas petojn, kontrolas ilin kaj prilaboras ilin. Ĝuste ĉi tio faros ZeroHTTPd. Ĉi tio estas ilo por lernado, ne produktado. Ĝi ne estas bonega pri erartraktado kaj verŝajne ne fanfaronas pri plej bonaj sekurecaj praktikoj (ho jes, mi uzis strcpy) aŭ la lertajn lertaĵojn de la lingvo C. Sed mi esperas, ke ĝi bone plenumas sian laboron.
ZeroHTTPd hejmpaĝo. Ĝi povas eligi malsamajn dosiertipojn inkluzive de bildoj
Apliko de Gastlibro
Modernaj TTT-aplikoj kutime ne estas limigitaj al senmovaj dosieroj. Ili havas kompleksajn interagojn kun diversaj datumbazoj, kaŝmemoroj, ktp. Do ni kreos simplan TTT-aplikaĵon nomitan "Gastolibro", kie vizitantoj lasas enskribojn sub siaj nomoj. La gastlibroj konservas enskribojn forlasitajn pli frue. Estas ankaŭ vizitanto nombrilo ĉe la malsupro de la paĝo.
Reta aplikaĵo "Gastolibro" ZeroHTTPd
La enskriboj de vizitlibroj kaj gastolibroj estas konservitaj en Redis. Por komunikadoj kun Redis, propraj proceduroj estas efektivigitaj; ili ne dependas de la ekstera biblioteko. Mi ne estas granda ŝatanto pri lanĉi hejman kodon kiam ekzistas publike disponeblaj kaj bone testitaj solvoj. Sed la celo de ZeroHTTPd estas studi Linuksan agadon kaj aliron al eksteraj servoj, dum servi HTTP-petojn havas gravan efikecon. Ni devas plene kontroli komunikadojn kun Redis en ĉiu el niaj servilaj arkitekturoj. En iuj arkitekturoj ni uzas blokantajn vokojn, en aliaj ni uzas okazaĵ-bazitajn procedurojn. Uzado de ekstera klienta biblioteko de Redis ne provizos ĉi tiun kontrolon. Aldone, nia malgranda Redis-kliento nur plenumas kelkajn funkciojn (akiri, agordi kaj pligrandigi ŝlosilon; akiri kaj aldoni al tabelo). Krome, la protokolo Redis estas ege eleganta kaj simpla. Vi eĉ ne bezonas speciale instrui ĝin. La fakto mem, ke la protokolo faras la tutan laboron en ĉirkaŭ cent linioj de kodo montras kiom bone pripensita ĝi estas.
La sekva figuro montras kion la aplikaĵo faras kiam la kliento (retumilo) petas /guestbookURL.
Kiel funkcias la gastlibro-aplikaĵo
Kiam gastlibropaĝo devas esti elsendita, estas unu alvoko al la dosiersistemo por legi la ŝablonon en memoron kaj tri retvokoj al Redis. La ŝablona dosiero enhavas la plej grandan parton de la HTML-enhavo por la paĝo en la supra ekrankopio. Estas ankaŭ specialaj anstataŭiloj por la dinamika parto de la enhavo: afiŝoj kaj vizitanto nombrilo. Ni ricevas ilin de Redis, enigas ilin en la paĝon kaj provizas la klienton kun plene formita enhavo. La tria voko al Redis povas esti evitita ĉar Redis resendas la novan ŝlosilvaloron kiam pliigita. Tamen, por nia servilo, kiu havas nesinkronan okazaĵ-bazitan arkitekturon, multaj retaj vokoj estas bona testo por lernado. Do ni forĵetas la revenan valoron de Redis de la nombro da vizitantoj kaj pridemandas ĝin per aparta voko.
Servilaj arkitekturoj ZeroHTTPd
Ni konstruas sep versiojn de ZeroHTTPd kun la sama funkcieco sed malsamaj arkitekturoj:
Ripetema
Fork-servilo (unu infanprocezo per peto)
Antaŭforkservilo (antaŭforkiĝo de procezoj)
Servilo kun ekzekutfadenoj (unu fadeno per peto)
Servilo kun antaŭfadena kreado
Bazita sur arkitekturo poll()
Bazita sur arkitekturo epoll
Ni mezuras la rendimenton de ĉiu arkitekturo ŝarĝante la servilon per HTTP-petoj. Sed kiam oni komparas tre paralelajn arkitekturojn, la nombro da demandoj pliiĝas. Ni testas tri fojojn kaj kalkulas la mezumon.
Testa metodiko
ZeroHTTPd-ŝarĝa testado aranĝo
Gravas, ke dum provoj, ĉiuj komponantoj ne funkcias per la sama maŝino. En ĉi tiu kazo, la OS altiras aldonan planadon superkoste ĉar komponentoj konkuras por CPU. Mezuri la operaciumon superkoste de ĉiu el la elektitaj servilaj arkitekturoj estas unu el la plej gravaj celoj de ĉi tiu ekzerco. Aldoni pli da variabloj fariĝos damaĝa al la procezo. Tial, la agordo en la supra bildo funkcias plej bone.
Kion faras ĉiu el ĉi tiuj serviloj?
load.unixism.net: Ĉi tie ni kuras ab, Apache Benchmark ilo. Ĝi generas la ŝarĝon necesan por testi niajn servilaj arkitekturoj.
nginx.unixism.net: Kelkfoje ni volas ruli pli ol unu ekzemplon de servila programo. Por fari tion, la Nginx-servilo kun la taŭgaj agordoj funkcias kiel ŝarĝbalancilo venanta ab al niaj servilaj procezoj.
zerohttpd.unixism.net: Ĉi tie ni rulas niajn servilprogramojn sur sep malsamaj arkitekturoj, unuope.
redis.unixism.net: Ĉi tiu servilo kuras la Redis-demonon, kie estas stokitaj gastlibroj kaj vizit-nombriloj.
Ĉiuj serviloj funkcias per la sama procesoro-kerno. La ideo estas taksi la maksimuman rendimenton de ĉiu arkitekturo. Ĉar ĉiuj servilaj programoj estas testitaj sur la sama aparataro, ĉi tio estas bazlinio por komparo. Mia testa aranĝo konsistas el virtualaj serviloj luitaj de Digital Ocean.
Kion ni mezuras?
Vi povas mezuri malsamajn indikilojn. Ni taksas la agadon de ĉiu arkitekturo en difinita agordo ŝarĝante la servilojn per petoj je malsamaj niveloj de paraleleco: la ŝarĝo kreskas de 20 ĝis 15 samtempaj uzantoj.
Testrezultoj
La sekva diagramo montras la agadon de serviloj sur malsamaj arkitekturoj je malsamaj niveloj de paraleleco. La y-akso estas la nombro da petoj je sekundo, la x-akso estas paralelaj ligoj.
El la grafikaĵo kaj tabelo videblas, ke super 8000 samtempaj petoj restas al ni nur du ludantoj: antaŭforko kaj epoll. Ĉar la ŝarĝo pliiĝas, enket-bazita servilo funkcias pli malbone ol fluanta. La faden-antaŭ-krea arkitekturo estas inda konkuranto por epoll, atesto pri kiom bone la Linukso-kerno planas grandajn nombrojn da fadenoj.
Fontkodo ZeroHTTPd
Fontkodo ZeroHTTPd tie. Estas aparta dosierujo por ĉiu arkitekturo.
Krom sep dosierujoj por ĉiuj arkitekturoj, estas du pliaj en la plej alta dosierujo: publika kaj ŝablonoj. La unua enhavas la dosieron index.html kaj la bildon de la unua ekrankopio. Vi povas meti aliajn dosierojn kaj dosierujojn tie, kaj ZeroHTTPd devus servi tiujn senmovajn dosierojn sen problemoj. Se la vojo en la retumilo kongruas kun la vojo en la publika dosierujo, tiam ZeroHTTPd serĉas la index.html dosieron en ĉi tiu dosierujo. La enhavo por la gastlibro estas generita dinamike. Ĝi nur havas ĉefpaĝon, kaj ĝia enhavo baziĝas sur la dosiero 'templates/guestbook/index.html'. ZeroHTTPd facile aldonas dinamikajn paĝojn por etendo. La ideo estas, ke uzantoj povas aldoni ŝablonojn al ĉi tiu dosierujo kaj etendi ZeroHTTPd laŭbezone.
Por konstrui ĉiujn sep servilojn, rulu make all de la plej alta dosierujo - kaj ĉiuj konstruaĵoj aperos en ĉi tiu dosierujo. Efektiveblaj dosieroj serĉas la publikajn kaj ŝablonojn dosierujojn en la dosierujo el kiu ili estas lanĉitaj.
Linukso API
Vi ne bezonas bone koni la Linuksan API por kompreni la informojn en ĉi tiu artikola serio. Tamen mi rekomendas legi pli pri ĉi tiu temo; ekzistas multaj referencresursoj en la Interreto. Kvankam ni tuŝos plurajn kategoriojn de Linukso-API-oj, nia fokuso estos ĉefe pri procezoj, fadenoj, eventoj kaj la reto-stako. Krom libroj kaj artikoloj pri la Linukso API, mi ankaŭ rekomendas legi manaon por sistemvokoj kaj bibliotekfunkcioj uzataj.
Efikeco kaj Skalebleco
Unu noto pri rendimento kaj skaleblo. Teorie, ne ekzistas rilato inter ili. Vi povas havi retservon, kiu funkcias tre bone, kun responda tempo de kelkaj milisekundoj, sed ĝi tute ne skalas. Same, povas ekzisti malbone funkcianta TTT-apliko, kiu bezonas kelkajn sekundojn por respondi, sed ĝi grimpas je dekoj por trakti dekojn da miloj da samtempaj uzantoj. Tamen, la kombinaĵo de alta rendimento kaj skaleblo estas tre potenca kombinaĵo. Alt-efikecaj aplikoj ĝenerale uzas resursojn ŝpareme kaj tiel efike servas pli da samtempaj uzantoj sur la servilo, reduktante kostojn.
CPU kaj I/O-taskoj
Fine, en komputado estas ĉiam du eblaj specoj de taskoj: por I/O kaj CPU. Ricevi petojn tra la Interreto (reto I/O), servado de dosieroj (reto kaj disko I/O), komuniki kun la datumbazo (reto kaj disko I/O) estas ĉiuj I/O-agadoj. Iuj datumbazdemandoj povas esti iom CPU-intensaj (ordigado, averaĝe miliono da rezultoj, ktp.). La plej multaj TTT-aplikoj estas limigitaj per la maksimuma ebla I/O, kaj la procesoro malofte estas uzita ĉe plena kapacito. Kiam vi vidas, ke iu I/O-tasko uzas multe da CPU, ĝi plej verŝajne estas signo de malbona aplika arkitekturo. Ĉi tio povas signifi, ke CPU-resursoj estas malŝparitaj en proceza administrado kaj kuntekstŝanĝo - kaj tio ne estas tute utila. Se vi faras ion kiel pritraktadon de bildoj, konvertiĝon de sondosieroj aŭ maŝinlernadon, tiam la aplikaĵo postulas potencajn CPU-resursojn. Sed por plej multaj aplikoj ĉi tio ne estas la kazo.