Hyrje
«Duhet të vraposh me të gjitha forcat vetëm për të qëndruar në vend,
në mënyrë që të arrish diku, duhet të vraposh të paktën dy herë më shpejt!»
(s) Aliça nĂ« Vendin e Ăudirave
Disa kohë më parë, më kërkuan të mbaja një ligjëratë për analistët e kompanisë sonë mbi projektimin e modeleve të dhënash, sepse duke qëndruar për një kohë të gjatë në projekte (ndonjëherë për disa vite) ne humbasim nga vëmendja atë që ndodh përreth në botën e teknologjive IT. Në kompaninë tonë (është njësoj) në shumë projekte nuk përdoren bazat e të dhënave NoSQL (të paktën deri tani), prandaj në ligjëratën time u dedikova veçanërisht atyre në shembullin e HBase dhe përpiqesha të orientoj materialin për ata që nuk kanë punuar kurrë me to. Në veçanti, ilustrova disa veçori të projektimit të modelit të dhënave mbi një shembull që kam lexuar disa vite më parë . Duke shqyrtuar shembujt, krahasova disa mundësi zgjidhjeje për të njëjtën detyrë, për të sjellë më mirë idetë kryesore te dëgjuesit.
Së fundmi, «për shkak të mungesës së gjërave për të bërë», fillova të mendoj (fundjavat e gjata të majit në karantinë e nxisin këtë veçanërisht), sa do të përputhen konkluzionet teorike me praktiken? Në thelb, kështu lindi ideja e këtij artikulli. Një zhvillues që ka disa vite përvojë me NoSQL, ndoshta nuk do të nxjerrë diçka të re nga ajo (dhe prandaj mund të kalojë menjëherë disa etapa të artikullit). Por për analistët, që ende nuk kanë punuar ngushtë me NoSQL, mendoj se do të jetë e dobishme për të marrë konceptet bazë mbi veçoritë e projektimit të modeleve të dhënash për HBase.
Analiza e shembullit
Sipas mendimit tim, para se të filloni të përdorni bazat e të dhënave NoSQL, është e rëndësishme të mendoni mirë dhe të peshojnë "për" dhe "kundër". Shpesh, problemin mund ta zgjidhni edhe me sistemet tradicionale të menaxhimit të të dhënave relacionale. Prandaj, është më mirë të shmangni përdorimin e NoSQL pa arsye të forta. Nëse gjithsesi vendosni të përdorni një bazë të dhënash NoSQL, duhet të keni parasysh se qasjet në dizajn janë paksa të ndryshme. Sidomos, disa prej tyre mund të duken të panjohura për ata që deri tani kanë punuar vetëm me sistemet relacionale të menaxhimit të të dhënave (sipas vëzhgimeve të mia). Në "botën relacionale", zakonisht fillojmë me modelimin e fushës së aplikimit dhe më pas, kur nevojitet, realizojmë denormalizimin e modelit. Ndërsa në NoSQL ne duhet menjëherë të marrim parasysh skenarët e parashikuar të punës me të dhënat dhe fillimisht të denormalizojmë të dhënat. Për më tepër, ka disa dallime të tjera, për të cilat do të shkruhet më poshtë.
Le të shqyrtojmë detyrën e mëposhtme "sintetike", me të cilën do të punojmë më tej:
Duhet të dizajnojmë një strukturë për ruajtjen e listës së miqve të përdoruesve të një rrjeti social abstrakt. Për thjeshtësim, do të supozojmë se të gjitha lidhjet janë të drejtuara (si në Instagram, dhe jo si në Linkedin). Strukturë duhet të lejojë që të:
- Përgjigjemi pyetjes, a e lexon përdoruesi A përdoruesin B (shkema e leximit)
- Të lejojmë shtimin/zhbllokimin e lidhjeve në rastin e ndjekjes/ndaljes së përdoruesit A nga përdoruesi B (shkema e ndryshimit të të dhënave)
Natyrisht, ka shumë mundësi për zgjidhjen e problemit. Në një bazë të dhënash relacionale normale, ne do të bënim një tabelë lidhjesh (ndoshta të tipizuar, nëse, për shembull, ka nevojë për të ruajtur grupin e përdoruesve: familja, puna, etj., në të cilin hyn ky "miku"), dhe për të optimizuar shpejtësinë e aksesit do të shtonim indekse/particionim. Për më tepër, tabela përfundimtare do të dukej ndoshta kështu:
user_id
friend_id
Vasja
Petja
Vasja
Olja
këtu dhe më pas për sqarje dhe kuptim më të mirë në vend të ID do të përcaktoj emrat
Në rastin e HBase e dimë se:
- kërkimi efektiv, i cili nuk çon në një skanim të plotë të tabelës, është i mundshëm përshtatshëm vetëm sipas çelësit
- Prandaj, tĂ« shkruash SQL kĂ«rkesa tĂ« njohura pĂ«r shumĂ« njerĂ«z me baza tĂ« tilla Ă«shtĂ« njĂ« ide e keqe; teknikisht, sigurisht, mund tĂ« dĂ«rgosh njĂ« kĂ«rkesĂ« SQL me Join dhe logjikĂ« tjetĂ«r nĂ« HBase nga Impala, por sa e efektshme do tĂ« jetĂ« kjoâŠ
Prandaj, ID e përdoruesit ne jemi të detyruar ta përdorim si çelës. Një mendim i parë për temën "ku dhe si të ruajmë ID e miqve?" mund të jetë ideja e ruajtjes së tyre në kolona. Ky variant më i dukshëm dhe "naiv" do të dukej kështu (ta quajmë) Varianti 1 (default), për t'u referuar më pas):
RowKey
Kolonat
Vasja
1: Petja
2: Olya
3: Dasha
Petja
1: Masha
2: Vasya
KĂ«tu, çdo rresht i pĂ«rkon njĂ« pĂ«rdoruesi tĂ« vet nĂ« rrjet. Kolonat kanĂ« emra: 1, 2, ... - sipas numrit tĂ« miqve, dhe nĂ« kolonat ruhen ID e miqve. ĂshtĂ« e rĂ«ndĂ«sishme tĂ« theksohet se çdo rresht do tĂ« ketĂ« njĂ« numĂ«r tĂ« ndryshĂ«m kolonash. NĂ« shembullin nĂ« figurĂ«n mĂ« sipĂ«r, njĂ« rresht ka tre kolona (1, 2 dhe 3), ndĂ«rsa i dyti ka vetĂ«m dy (1 dhe 2) - kĂ«tu ne kemi shfrytĂ«zuar dy vetitĂ« e HBase, tĂ« cilat nuk i ka databaza relacional:
- mundësinë për të ndryshuar përbërjen e kolonave dinamikisht (shto mikun -> shto kolonën, hiq mikun -> hiq kolonën)
- për rreshta të ndryshëm, përbërja e kolonave mund të jetë e ndryshme
Le të verifikojmë strukturën tonë në përputhje me kërkesat e detyrës:
- Leximi i të dhënave: për të kuptuar nëse Vasya është i regjistruar tek Olya, na nevojitet të lexojmë të gjithë rreshtin me çelësin RowKey = "Vasya" dhe të kalojmë përmes vlerave të kolonave, derisa të "takojmë" Olya në to. Ose të kalojmë përmes të gjitha vlerave të kolonave, "të mos takojmë" Olya dhe të kthejmë përgjigjen False;
- Ndryshimi i të dhënave: shtimi i mikut: për një detyrë të tillë na nevojitet gjithashtu të lexojmë të gjithë rreshtin me çelësin RowKey = "Vasya", për të llogaritur numrin total të miqve të tij. Ky numër total miqsh është i nevojshëm për të përcaktuar numrin e kolonës ku duhet të shkruhet ID i mikut të ri.
- Ndryshimi i të dhënave: heqja e mikut:
- Duhet të lexojmë të gjithë rreshtin me çelësin RowKey = "Vasya" dhe të kalojmë përmes kolonave për të gjetur atë, ku është regjistruar miku që po hiqet;
- Më pas, pas heqjes së mikut, ne duhet të "zhvendosim" të dhënat e gjitha një kolonë, në mënyrë që të mos marrim "ndarje" në numërimin e tyre.
Tani le të vlerësojmë se sa efikas do të jenë algoritmet që na nevojiten për të zbatuar në anën e "aplikacionit të kushteve", duke përdorur Le të shohim madhësinë e rrjetit tonë hipotetik shoqëror si n. Atëherë numri maksimal i miqve për një përdorues mund të jetë (n-1). Këtë (-1) ne mund ta injorojmë për qëllimet tona, pasi në kuadër të përdorimit të simbolikës O, ajo është e parëndësishme.
- Leximi i të dhënave: nevojitet të lexojmë të gjithë rreshtin dhe të shqyrtojmë në kufijtë të gjitha kolonat e tij. Kështu, vlerësimi i sipërm i kostove do të jetë afërsisht O(n)
- Ndryshimi i të dhënave: shtimi i mikut: për të përcaktuar numrin e miqve, ne duhet të shqyrtojmë të gjitha kolonat e rreshtit, pas së cilës do të insertojmë një kolonë të re => O(n)
- Ndryshimi i të dhënave: heqja e mikut:
- Po ashtu si nĂ« rastin e shtimit â kĂ«rkohet qĂ« nĂ« kufijtĂ« tĂ« shqyrtojmĂ« tĂ« gjitha kolonat => O(n)
- Pas fshirjes sĂ« kolonave, na duhen "skaj" ato. NĂ«se e realizojmĂ« kĂ«tĂ« "drejt" do tĂ« nevojiteshin deri nĂ« (n-1) operacione. Por kĂ«tu dhe mĂ« tej nĂ« pjesĂ«n praktike do tĂ« aplikojmĂ« njĂ« qasje tjetĂ«r, e cila do tĂ« realizojĂ« "pseudoskaj" pĂ«rmes njĂ« numri tĂ« fiksuar operacionesh â do tĂ« thotĂ« se do tĂ« shpenzohet njĂ« kohĂ« konstante pavarĂ«sisht n. Kjo kohĂ« konstante (nĂ«se jemi tĂ« saktĂ«, O(2)) nĂ« krahasim me O(n) mund tĂ« injorohet. Qasja ilustrohet nĂ« figurĂ«n mĂ« poshtĂ«: ne thjesht kopjojmĂ« tĂ« dhĂ«nat nga kolonat "e fundit" nĂ« atĂ« nga e cila duam tĂ« fshijmĂ« tĂ« dhĂ«nat, pas sĂ« cilĂ«s fshijmĂ« kolonĂ«n mĂ« tĂ« fundit:

Së fundmi, në të gjitha skenaret ne kemi marrë kompleksitetin asimptotik të llogaritjes O(n).
Mbase tashmë e keni vënë re se ne kemi pothuajse gjithmonë nevojë të lexojmë të gjithë rreshtin nga baza, veçanërisht në dy nga tre rastet vetëm për të shqyrtuar të gjitha kolonat dhe për të llogaritur numrin total të miqve. Prandaj, si një përpjekje optimizimi mund të shtojmë një kolonë "count", ku ruhet numri total i miqve për secilin përdorues në rrjet. Në këtë rast, ne mund të mos lexojmë të gjithë rreshtin për të llogaritur numrin e përgjithshëm të miqve, por të lexojmë vetëm një kolonë "count". E rëndësishme është të mos harrojmë të përditësojmë "count" gjatë manipulimeve me të dhënat. Kështu, arrijmë një përmirësim Opsioni 2 (count):
RowKey
Kolonat
Vasja
1: Petja
2: Olya
3: Dasha
count: 3
Petja
1: Masha
2: Vasya
count: 2
Në krahasim me opsionin e parë:
- Leximi i të dhënave: për të marrë përgjigjen për pyetjen "A e lexon Vasja Olën?" nuk ka ndryshuar asgjë => O(n)
- Ndryshimi i të dhënave: shtimi i mikut: E kemi thjeshtuar shtimin e një miku të ri, pasi tani nuk na nevojitet të lexojmë të toda rreshtin dhe të kalojmë kolonat e tij, por mund të marrim vetëm vlerën e kolonës «count» dhe kështu të përcaktojmë menjëherë numrin e kolonës për të shtuar mikun e ri. Kjo çon në uljen e kompleksitetit të llogaritjes në O(1)
- Ndryshimi i të dhënave: heqja e mikut: Gjatë fshirjes së një miku, gjithashtu mund ta përdorim këtë kolonek, për të ulur numrin e operacioneve të hyrjes dhe daljeve kur «shkarkojmë» të dhënat një hap majtas. Por nevoja për të kaluar nëpër kolonat për të gjetur atë që duhet fshirë mbetet, prandaj => O(n)
- Nga ana tjetër, tani gjatë përditësimit të të dhënave, na duhet të përditësojmë çdo herë edhe kolonën «count», por për këtë nevojitet një kohë konstante, të cilën në kuadër të simbolikës O mund ta injorojmë
Në përgjithësi, opsioni 2 duket pak më optimal, por kjo është më shumë «evolucioni në vend të revolucionit». Për të realizuar një «revolucion» na nevojitet Opsioni 3 (col).
Ta kthejmĂ« gjithçka «pĂ«rmbys»: tĂ« caktojmĂ« emrin e kolonĂ«s identifikues tĂ« pĂ«rdoruesit! ĂfarĂ« do tĂ« regjistrohet nĂ« vetĂ« kolonĂ«n â pĂ«r ne nuk ka rĂ«ndĂ«si, le tĂ« jetĂ« numri 1 (nĂ« tĂ« vĂ«rtetĂ«, nga tĂ« dhĂ«nat e dobishme aty mund tĂ« ruhet, pĂ«r shembull, grupi «familje/mik/etj.». Ky qasje mund tĂ« befasojĂ« njĂ« «pĂ«rfitues» tĂ« papĂ«rgatitur, i cili deri tani nuk ka pasur pĂ«rvojĂ« pune me bazat NoSQL, por pikĂ«risht kjo i lejon tĂ« shfrytĂ«zojĂ« potencialin e HBase nĂ« kĂ«tĂ« detyrĂ« mĂ« efikase:
RowKey
Kolonat
Vasja
Petja: 1
Olja: 1
Dasha: 1
Petja
Masha: 1
Vasia: 1
Këtu ne marrim menjëherë disa avantazhe. Për t'i kuptuar ato, le të analizojmë strukturën e re dhe të vlerësojmë kompleksitetin e llogaritjes:
- Leximi i tĂ« dhĂ«nave: pĂ«r tĂ« pĂ«rgjigjur pyetjes, nĂ«se Vasia Ă«shtĂ« regjistruar me OljĂ«n, mjafton tĂ« lexojmĂ« njĂ« kolonĂ« «Olja»: nĂ«se ajo Ă«shtĂ« atje, pĂ«rgjigja Ă«shtĂ« True, nĂ«se jo â False => O(1)
- Ndryshimi i të dhënave: shtimi i mikut: Shtimi i një miku: mjafton të shtojmë një kolonë të re «ID miku» => O(1)
- Ndryshimi i të dhënave: heqja e mikut: mjafton të fshijmë kolonën «ID miku» => O(1)
Siç e shohim, njĂ« pĂ«rparĂ«si e madhe e kĂ«saj modeli tĂ« ruajtjes Ă«shtĂ« se nĂ« tĂ« gjitha skenarĂ«t e nevojshĂ«m operojmĂ« vetĂ«m me njĂ« kolonĂ«, duke shmangur leximin e tĂ« dhĂ«nave nga e gjithĂ« rreshti dhe sidomos kalimin nĂ« tĂ« gjitha kolonat e kĂ«tij rreshti. KĂ«tu mund tĂ« ndalojmĂ«, porâŠ
Mund tĂ« shqetĂ«sohemi dhe tĂ« shkojmĂ« edhe mĂ« tej nĂ« rrugĂ«n e optimizimit tĂ« performancĂ«s dhe reduktimit tĂ« operacioneve tĂ« hyrjes-dalinjes kur i drejtohemi bazĂ«s. ĂfarĂ« ndodh nĂ«se ruajmĂ« informacionin e plotĂ« tĂ« lidhjes drejtpĂ«rdrejt nĂ« çelĂ«sin e rreshtit? DomethĂ«nĂ«, ta bĂ«jmĂ« çelĂ«sin tĂ« pĂ«rbĂ«rĂ« nga userID.friendID? NĂ« kĂ«tĂ« rast, madje nuk na nevojitet tĂ« lexojmĂ« kolonat e rreshtit.Opsioni 4 (rreshti)):
RowKey
Kolonat
Vasja.Petja
Petja: 1
Vasja.Olja
Olja: 1
Vasja.Dasha
Dasha: 1
Petja.Masha
Masha: 1
Petja.Vasja
Vasia: 1
ĂshtĂ« e qartĂ« se vlerĂ«simi i tĂ« gjithĂ« skenarĂ«ve tĂ« manipulimit tĂ« tĂ« dhĂ«nave nĂ« kĂ«tĂ« strukturĂ«, ashtu si nĂ« opsionin e mĂ«parshĂ«m, do tĂ« jetĂ« O(1). Ndryshimi me opsionin 3 do tĂ« jetĂ« thjesht nĂ« efikasitetin e operacioneve tĂ« hyrjes-dalinjes nĂ« DB.
Dhe, pĂ«rfundimisht, njĂ« "kalim i fundit". ĂshtĂ« e lehtĂ« tĂ« vĂ«resh se nĂ« opsionin 4 çelĂ«si i rreshtit do tĂ« ketĂ« njĂ« gjatĂ«si tĂ« ndryshueshme, qĂ« ndoshta mund tĂ« ndikojĂ« nĂ« performancĂ« (kĂ«tu kujtojmĂ« se HBase ruan tĂ« dhĂ«nat si njĂ« grup bajtesh dhe rreshtat nĂ« tabela janĂ« tĂ« renditur sipas çelĂ«sit). Plus, kemi njĂ« ndarĂ«s, i cili nĂ« disa skenarĂ« mund tĂ« kĂ«rkojĂ« trajtim. PĂ«r tĂ« eliminuar kĂ«tĂ« ndikim, mund tĂ« pĂ«rdorim hash-e nga userID dhe friendID, dhe pasi tĂ« dy hash-et do tĂ« kenĂ« gjatĂ«si fikse, mund thjesht t'i konkatenujmĂ« ato, pa ndarĂ«s. AtĂ«herĂ« tĂ« dhĂ«nat nĂ« tavolinĂ« do tĂ« duken kĂ«shtu (Opsioni 5 (hash)):
RowKey
Kolonat
dc084ef00e94aef49be885f9b01f51c01918fa783851db0dc1f72f83d33a5994
Petja: 1
dc084ef00e94aef49be885f9b01f51c0f06b7714b5ba522c3cf51328b66fe28a
Olja: 1
dc084ef00e94aef49be885f9b01f51c00d2c2e5d69df6b238754f650d56c896a
Dasha: 1
1918fa783851db0dc1f72f83d33a59949ee3309645bd2c0775899fca14f311e1
Masha: 1
1918fa783851db0dc1f72f83d33a5994dc084ef00e94aef49be885f9b01f51c0
Vasia: 1
ĂshtĂ« e qartĂ« se kompleksiteti algoritmik i punĂ«s me njĂ« strukturĂ« tĂ« tillĂ« pĂ«r skenarĂ«t qĂ« po shqyrtojmĂ« do tĂ« jetĂ« i njĂ«jtĂ« me opsionin 4 â dmth O(1).
Pra, do ta përmbledhim të gjithë vlerësimin tonë të kompleksitetit të llogaritjeve në një tabelë:
Shtimi i një miku
Kontrollimi i mikut
Fshirja e mikut
Varianti 1 (default)
O(n)
O(n)
O(n)
Opsioni 2 (count)
O(1)
O(n)
O(n)
Opsioni 3 (kolona)
O(1)
O(1)
O(1)
Opsioni 4 (rreshti)
O(1)
O(1)
O(1)
Opsioni 5 (hash)
O(1)
O(1)
O(1)
Siç duket, opsionet 3-5 duken më të preferuara dhe teorikisht sigurojnë përmbushjen e të gjitha skenarëve të nevojshme për manipulimin e të dhënave në një kohë konstante. Në kushtet e detyrës tonë nuk ka kërkesa të qarta për të marrë një listë të të gjitha miqve të përdoruesit, por në aktivitetin tonë të projektit, si analistë të mirë, do të ishte e mençur të "parashikojmë" se një detyrë e tillë mund të lindë dhe ta "përgatitim" vetveten. Prandaj, preferencat e mia janë për opsionin 3. Por është krejtësisht e mundur që në një projekt të vërtetë kjo kërkesë të jetë zgjidhur me mjete të tjera, prandaj pa një vizion të plotë të detyrës, nuk duhet të nxjerrim përfundime të përfundshme.
Përgatitja e eksperimentit
DĂ«shirojmĂ« t'i verifikojmĂ« kĂ«to mendime teorike nĂ« praktikĂ« â kjo ishte qĂ«llimi qĂ« lindi gjatĂ« fundjavĂ«s sĂ« gjatĂ«. PĂ«r kĂ«tĂ«, Ă«shtĂ« e nevojshme tĂ« vlerĂ«sojmĂ« shpejtĂ«sinĂ« e punĂ«s sĂ« "aplikacionit tonĂ« tĂ« kushtuar" nĂ« tĂ« gjitha skenarĂ«t e pĂ«rshkruar pĂ«r pĂ«rdorimin e databazĂ«s, si dhe rritjen e kĂ«tij koha me rritjen e madhĂ«sisĂ« sĂ« rrjetit social (n). Parametri i synuar qĂ« na intereson dhe qĂ« do tĂ« masim gjatĂ« eksperimentit, Ă«shtĂ« koha e shpenzuar nga "aplikacioni i kushtuar" pĂ«r tĂ« kryer njĂ« "operacion biznesi". Me "operacion biznesi" kuptojmĂ« njĂ« nga sa vijon:
- Shtimi i një miku të ri
- Kontrollimi i shtyrjes nëse përdoruesi A është mik i përdoruesit B
- Fshirja e një miku
Prandaj, duke pasur parasysh kërkesat e shtruara në fillim, skenari i kontrollit shfaqet si vijon:
- Shkruaj tĂ« dhĂ«nat. TĂ« gjenerohet rastĂ«sisht njĂ« rrjet fillestar me madhĂ«sinĂ« n. PĂ«r njĂ« afĂ«rsi mĂ« tĂ« madhe me "botĂ«n reale", numri i miqve tĂ« çdo pĂ«rdoruesi Ă«shtĂ« gjithashtu njĂ« vlerĂ« rastĂ«sore. TĂ« masim kohĂ«n gjatĂ« sĂ« cilĂ«s "aplikacioni ynĂ« i kushtuar" do tĂ« shkrijĂ« tĂ« gjitha tĂ« dhĂ«nat e gjeneruara nĂ« HBase. MĂ« pas, tĂ« ndajmĂ« kohĂ«n e marrĂ« me numrin total tĂ« miqve tĂ« shtuar â ashtu do tĂ« marrim kohĂ«n mesatare pĂ«r njĂ« "operacion biznesi".
- Leximi i tĂ« dhĂ«nave. PĂ«r çdo pĂ«rdorues, pĂ«rgatitni njĂ« listĂ« "identitetesh" pĂ«r tĂ« cilat duhet tĂ« kontrolloni nĂ«se pĂ«rdoruesi Ă«shtĂ« ndjekĂ«s i tyre apo jo. GjatĂ«sia e listĂ«s Ă«shtĂ« afĂ«rsisht sa numri i miqve tĂ« pĂ«rdoruesit, ku pĂ«r gjysmĂ«n e miqve tĂ« kontrolluar, pĂ«rgjigja duhet tĂ« jetĂ« "Po", ndĂ«rsa pĂ«r gjysmĂ«n tjetĂ«r â "Jo". Kontrolli bĂ«het nĂ« njĂ« renditje tĂ« tillĂ« qĂ« pĂ«rgjigjet "Po" dhe "Jo" tĂ« alternohen (dmth. nĂ« çdo rast tĂ« dytĂ« na duhet tĂ« kontrollojmĂ« tĂ« gjitha kolonat e rreshtit pĂ«r variantet 1 dhe 2). Koha e pĂ«rgjithshme e kontrollit mĂ« pas ndahet me numrin e miqve tĂ« kontrolluar pĂ«r tĂ« marrĂ« kohĂ«n mesatare pĂ«r kontrollin e njĂ« subjekti.
- Fshirja e të dhënave. Fshihni të gjithë miqtë e përdoruesit. Renditja e fshirjes është rastësore (dmth. "përzierim" i listës fillestare që është përdorur për regjistrimin e të dhënave). Koha e përgjithshme e kontrollit më pas ndahet me numrin e miqve të fshirë për të marrë kohën mesatare për një kontroll.
Skenarët duhet të kalohen për çdo një nga 5 variantet e modeleve të të dhënave dhe për madhësi të ndryshme të rrjetit social, për të parë se si ndryshon koha me rritjen e tij. Brenda një n lidhjeje në rrjet dhe lista e përdoruesve për kontroll duhet të jetë, natyrisht, e njëjtë për të gjithë 5 variantet.
Për një kuptim më të mirë, më poshtë po sjell një shembull të të dhënave të gjeneruara për n= 5. "Generatori" i shkruar jep si rezultat tre fjalorë ID-sh:
- i pari â pĂ«r futjen
- i dyti â pĂ«r kontrollin
- i tretĂ« â pĂ«r fshirjen
{0: [1], 1: [4, 5, 3, 2, 1], 2: [1, 2], 3: [2, 4, 1, 5, 3], 4: [2, 1]} # gjithsej 15 miq
{0: [1, 10800], 1: [5, 10800, 2, 10801, 4, 10802], 2: [1, 10800], 3: [3, 10800, 1, 10801, 5, 10802], 4: [2, 10800]} # gjithsej 18 subjekte të kontrolluara
{0: [1], 1: [1, 3, 2, 5, 4], 2: [1, 2], 3: [4, 1, 2, 3, 5], 4: [1, 2]} # gjithsej 15 miq
Siç mund të vëreni, të gjitha ID, të mëdha se 10 000 në fjalorin për kontroll, janë ato që me siguri do të japin përgjigje False. Futja, kontrolli dhe fshirja e "miqve" bëhen pikërisht në rendin e specifikuar në fjalor.
Eksperimenti u zhvillua nĂ« njĂ« laptop me sistemin Windows 10, ku nĂ« njĂ« konteiner Docker ishte e vendosur njĂ« bazĂ« HBase, ndĂ«rsa nĂ« konteinerin tjetĂ«r â Python me Jupyter Notebook. Docker-it i ishin dhĂ«nĂ« 2 bĂ«rthama CPU dhe 2 GB pĂ«rmemorie. E gjithĂ« logjika, si simuluar e funksionit tĂ« "aplikacionit tĂ« mundshĂ«m", ashtu edhe "mbĂ«shtetje" pĂ«r gjenerimin e tĂ« dhĂ«nave testuese dhe regjistrimin e kohĂ«s ishin shkruar nĂ« Python. PĂ«r punĂ« me HBase u pĂ«rdor biblioteka , pĂ«r llogaritjen e hash-Ă«ve (MD5) pĂ«r variantin 5 â hashlib
Duke marrĂ« parasysh fuqinĂ« computing tĂ« laptopit tĂ« caktuar, pĂ«rvojĂ« eksperimentale u zgjodh tĂ« fillojĂ« pĂ«r n = 10, 30, âŠ. 170 â kur koha totale e funksionimit tĂ« ciklit tĂ« plotĂ« tĂ« testimit (tĂ« gjitha skenarĂ«t pĂ«r tĂ« gjitha variantet pĂ«r tĂ« gjithĂ« n) ishte akoma mĂ« shumĂ« ose mĂ« pak e arsyeshme dhe pĂ«rfshihej brenda kohĂ«s njĂ« çaji (nĂ« mesatare 15 minuta).
Këtu është e nevojshme të bëhet një shënim, se në këtë eksperiment ne vlerësojmë kryesisht jo shifrat absolute të performancës. Edhe krahasimi relativ i dy varianteve të ndryshme mund të mos jetë plotësisht korrekt. Aktualisht, na intereson natyra e ndryshimit të kohës në varësi të n, pasi duke marrë parasysh konfigurimin e mësipërm të "testit të qendrës" është shumë e vështirë të merret një vlerësim kohor, "i pastruar" nga ndikimet rastësore dhe faktorë të tjerë (dhe asnjëherë nuk është vendosur një qëllim të tillë).
Rezultati i eksperimentit
Testi i parĂ« â si ndryshon koha e kaluar pĂ«r mbushjen e listĂ«s sĂ« miqve. Rezultati â nĂ« grafikĂ«n mĂ« poshtĂ«.

Variantet 3-5 pritet të tregojnë praktikisht një kohë konstante të "veprës afariste", e cila nuk varet nga rritja e madhësisë së rrjetit dhe diferenca e pamundshme në performancë.
Varianti 2 gjithashtu tregon një performancë konstante, por pak më të dobët, dhe në mënyrë të përafërt dyfish në krahasim me variantet 3-5. Dhe kjo nuk mund të mos gëzojë, pasi përputhet me teorinë - në këtë variant numri i operacioneve të hyrjes-daljes në/nga HBase është pikërisht dyfish më i madh. Kjo mund të shërbejë si një dëshmi indirekte se qendra jonë testuese në parim siguron një saktësi të mirë.
Varianti 1 gjithashtu është siç pritej më i ngadalshëm dhe tregon një rritje lineare të kohës së kaluar për shtimin e një miku në varësi të madhësisë së rrjetit.
Tani le të shikojmë rezultatet e testit të dytë.

Opsionet 3-5 pĂ«rsĂ«ri veprojnĂ« siç pritej â kohĂ« konstante, e cila nuk varet nga madhĂ«sia e rrjetit. Opsionet 1 dhe 2 tregojnĂ« njĂ« rritje lineare tĂ« kohĂ«s me rritjen e madhĂ«sisĂ« sĂ« rrjetit dhe njĂ« performancĂ« tĂ« ngjashme. NĂ« veçanti, opsioni 2 rezulton pak mĂ« i ngadalshĂ«m â duket se pĂ«r shkak tĂ« nevojĂ«s pĂ«r tĂ« lexuar dhe trajtuar njĂ« kolonĂ« shtesĂ« "count", e cila bĂ«het mĂ« e dukshme me rritjen e n. MegjithatĂ«, do tĂ« pĂ«rmbahem nga çdo pĂ«rfundim, pasi saktĂ«sia e kĂ«tij krahasimi Ă«shtĂ« relativisht e ulĂ«t. PĂ«r mĂ« tepĂ«r, kĂ«to raporte (cilat opsione, 1 apo 2, janĂ« mĂ« tĂ« shpejta) ndryshonin nga njĂ« ekzekutim nĂ« tjetrin (ndĂ«rsa ruanin karakterin e varĂ«sisĂ« dhe "shkonin krahas")
Dhe grafiku i fundit â rezultati i testit tĂ« fshirjes.

Këtu përsëri pa surpriza. Opsionet 3-5 realizojnë fshirjen në kohë konstante.
Dhe, çka është interesante, opsionet 4 dhe 5, ndryshe nga skenarët e mëparshëm, tregojnë një performancë disi më të ulët se opsioni 3. Dukshëm, operacioni i fshirjes së një rreshti është më i shtrenjtë se operacioni i fshirjes së një kolone, që në përgjithësi është logjike.
Opsionet 1 dhe 2, siç pritej, tregojnĂ« njĂ« rritje lineare tĂ« kohĂ«s. NĂ« kĂ«tĂ« rast, opsioni 2 vazhdimisht Ă«shtĂ« mĂ« i ngadaltĂ« se opsioni 1 â pĂ«r shkak tĂ« operacionit shtesĂ« tĂ« hyrjes dhe daljes pĂ«r "mirĂ«mbajtjen" e kolonĂ«s count.
Përfundimet e përgjithshme të eksperimentit:
- Opsionet 3-5 demonstrojnë një efikasitet më të lartë, pasi ato shfrytëzojnë avantazhet e HBase; ndërsa performanca e tyre ndryshon njëra me tjetrën me një konstant dhe nuk varet nga madhësia e rrjetit.
- Diferenca midis opsioneve 4 dhe 5 nuk është regjistruar. Por kjo nuk do të thotë se opsioni 5 nuk duhet përdorur. Ka shumë mundësi që skenari i përdorur në eksperiment, duke marrë parasysh TTX e vendit të provës, nuk e mundësoi të zbulohej.
- Natyra e rritjes së kohës së nevojshme për të realizuar "operacionet biznesore" me të dhëna, në përgjithësi konfirmoi përfundimet teorike të mëparshme për të gjitha opsionet.
Epilogu
Eksperimet e bëra nuk duhet të merren si e vërtetë absolute. Ekzistojnë shumë faktorë që nuk janë marrë parasysh dhe që kanë sjellë disa devijime në rezultatet (veçanërisht këto fluktuacione duken qartë në grafikë kur dimensioni i rrjetit është i vogël). Për shembull, shpejtësia e Thrift-it, i cili përdoret nga Happybase, volume dhe mënyra e zbatimit të logjikës që kam shkruar në Python (nuk pretendoj se kodi është shkruar në mënyrë optimale dhe që përdor maksimumin e mundësive të të gjithë komponenteve), mundësisht karakteristikat e caching-ut të HBase, aktiviteti në sfond i Windows 10 në laptopin tim etj. Në përgjithësi, mund të mendohet se të gjitha përllogaritjet teorike e kanë dëshmuar vlerën e tyre eksperimentale. Ose të paktën nuk ka qenë e mundur të hedhim poshtë këto përllogaritje me një goditje të tillë të drejtpërdrejtë.
NĂ« pĂ«rfundim â rekomandime pĂ«r tĂ« gjithĂ« ata qĂ« sapo po fillojnĂ« tĂ« projektojnĂ« modele tĂ« dhĂ«nash nĂ« HBase: abstrahohuni nga pĂ«rvoja e mĂ«parshme me bazat e tĂ« dhĂ«nave relacionale dhe mbani mend "shqiponjat":
- Kur projektojmë, fillojmë nga detyra dhe modelet e manipulimit me të dhënat, dhe jo nga modeli i fushës së subjektit.
- Qasje efikase (pa skanim të plotë të tabelës) - vetëm përmes çelësit.
- Denormalizimi.
- Rreshta të ndryshëm mund të përmbajnë kolona të ndryshme.
- Përbërje dinamike e koloneve.
Burimi: habr.com

