Mga tampok ng pagdidisenyo ng modelo ng data para sa NoSQL

Pagpapakilala

Mga tampok ng pagdidisenyo ng modelo ng data para sa NoSQL "Kailangan mong tumakbo nang mabilis hangga't maaari upang manatili sa lugar,
at para makarating sa kung saan, kailangan mong tumakbo ng hindi bababa sa dalawang beses nang mas mabilis!”
(c) Alice in Wonderland

Ilang oras na ang nakalipas ay hinilingan akong magbigay ng lecture mga analyst ang aming kumpanya sa paksa ng pagdidisenyo ng mga modelo ng data, dahil nakaupo sa mga proyekto sa loob ng mahabang panahon (minsan sa loob ng ilang taon) nalilimutan namin ang mga nangyayari sa aming paligid sa mundo ng mga teknolohiyang IT. Sa aming kumpanya (nagkataon lang) maraming mga proyekto ang hindi gumagamit ng mga database ng NoSQL (hindi bababa sa ngayon), kaya sa aking panayam ay hiwalay akong nagbigay ng pansin sa kanila gamit ang halimbawa ng HBase at sinubukang i-orient ang presentasyon ng materyal sa mga iyon. na hindi kailanman gumamit ng mga ito ay nagtrabaho. Sa partikular, inilarawan ko ang ilan sa mga tampok ng disenyo ng modelo ng data gamit ang isang halimbawang nabasa ko ilang taon na ang nakararaan sa artikulong "Introduction to HB ase Schema Design" ni Amandeep Khurana. Kapag nagsusuri ng mga halimbawa, inihambing ko ang ilang mga opsyon para sa paglutas ng parehong problema upang mas maiparating ang mga pangunahing ideya sa madla.

Kamakailan lamang, "sa walang magawa," tinanong ko ang aking sarili ang tanong (ang mahabang katapusan ng linggo ng Mayo sa kuwarentenas ay partikular na kaaya-aya dito), magkano ang teoretikal na mga pagkalkula ay tumutugma sa pagsasanay? Sa totoo lang, ito ay kung paano ipinanganak ang ideya para sa artikulong ito. Ang isang developer na nagtatrabaho sa NoSQL sa loob ng ilang araw ay maaaring walang matutunang bago mula rito (at samakatuwid ay maaaring agad na laktawan ang kalahati ng artikulo). Ngunit para sa mga analystPara sa mga hindi pa nagtatrabaho nang malapit sa NoSQL, sa tingin ko ito ay magiging kapaki-pakinabang para sa pagkakaroon ng isang pangunahing pag-unawa sa mga tampok ng pagdidisenyo ng mga modelo ng data para sa HBase.

Halimbawa ng pagsusuri

Sa palagay ko, bago ka magsimulang gumamit ng mga database ng NoSQL, kailangan mong pag-isipang mabuti at timbangin ang mga kalamangan at kahinaan. Kadalasan ang problema ay malamang na malulutas gamit ang tradisyonal na mga relational na DBMS. Samakatuwid, mas mainam na huwag gumamit ng NoSQL nang walang makabuluhang dahilan. Kung nagpasya ka pa ring gumamit ng isang database ng NoSQL, dapat mong isaalang-alang na ang mga diskarte sa disenyo dito ay medyo naiiba. Lalo na ang ilan sa mga ito ay maaaring hindi pangkaraniwan para sa mga dati nang nakipag-ugnayan lamang sa mga relational na DBMS (ayon sa aking mga obserbasyon). Kaya, sa "relasyon" na mundo, kadalasan ay nagsisimula tayo sa pamamagitan ng pagmomodelo sa domain ng problema, at pagkatapos lamang, kung kinakailangan, i-denormalize ang modelo. Sa NoSQL tayo dapat agad na isaalang-alang ang mga inaasahang sitwasyon para sa pagtatrabaho sa data at sa una ay i-denormalize ang data. Bilang karagdagan, mayroong isang bilang ng iba pang mga pagkakaiba, na tatalakayin sa ibaba.

Isaalang-alang natin ang sumusunod na "synthetic" na problema, kung saan patuloy tayong gagana:

Kinakailangang magdisenyo ng istraktura ng imbakan para sa listahan ng mga kaibigan ng mga gumagamit ng ilang abstract na social network. Upang gawing simple, ipagpalagay namin na ang lahat ng aming mga koneksyon ay nakadirekta (tulad ng sa Instagram, hindi Linkedin). Ang istraktura ay dapat magpapahintulot sa iyo na epektibong:

  • Sagutin ang tanong kung ang user A ay nagbabasa ng user B (reading pattern)
  • Payagan ang pagdaragdag/pag-alis ng mga koneksyon kung sakaling magkaroon ng subscription/unsubscription ng user A mula sa user B (template ng pagbabago ng data)

Siyempre, maraming mga pagpipilian para sa paglutas ng problema. Sa isang regular na relational database, malamang na gagawa lang kami ng isang talahanayan ng mga relasyon (maaaring nai-type kung, halimbawa, kailangan naming mag-imbak ng isang grupo ng gumagamit: pamilya, trabaho, atbp., na kinabibilangan ng "kaibigan") na ito, at upang i-optimize ang bilis ng pag-access ay magdaragdag ng mga index/pagkahati. Malamang na ang huling talahanayan ay magiging ganito:

user_id
friend_id

Vasya
Petya

Vasya
Оля

pagkatapos nito, para sa kalinawan at mas mahusay na pag-unawa, magsasaad ako ng mga pangalan sa halip na mga ID

Sa kaso ng HBase, alam namin na:

  • ang mahusay na paghahanap na hindi nagreresulta sa isang buong pag-scan ng talahanayan ay posible eksklusibo sa pamamagitan ng susi
    • sa katunayan, iyon ang dahilan kung bakit ang pagsulat ng mga SQL query na pamilyar sa marami sa naturang mga database ay isang masamang ideya; technically, siyempre, maaari kang magpadala ng SQL query na may Joins at iba pang logic sa HBase mula sa parehong Impala, ngunit gaano ito magiging epektibo...

Samakatuwid, napipilitan kaming gamitin ang user ID bilang susi. At ang una kong naisip sa paksang "saan at paano mag-imbak ng mga ID ng mga kaibigan?" marahil isang ideya na iimbak ang mga ito sa mga hanay. Ang pinaka-halata at "walang muwang" na opsyon ay magiging ganito (tawagin natin ito Opsyon 1 (default)para sa karagdagang sanggunian):

RowKey
Mga Haligi

Vasya
1: Petya
2: Olya
3: Dasha

Petya
1: Masha
2: Vasya

Dito, ang bawat linya ay tumutugma sa isang gumagamit ng network. Ang mga column ay may mga pangalan: 1, 2, ... - ayon sa bilang ng mga kaibigan, at ang mga ID ng mga kaibigan ay naka-imbak sa mga column. Mahalagang tandaan na ang bawat row ay magkakaroon ng ibang bilang ng mga column. Sa halimbawa sa figure sa itaas, ang isang hilera ay may tatlong mga haligi (1, 2 at 3), at ang pangalawa ay may dalawa lamang (1 at 2) - dito kami mismo ay gumamit ng dalawang katangian ng HBase na wala sa mga relational database:

  • ang kakayahang dynamic na baguhin ang komposisyon ng mga column (magdagdag ng kaibigan -> magdagdag ng column, mag-alis ng kaibigan -> magtanggal ng column)
  • maaaring may iba't ibang komposisyon ng column ang iba't ibang row

Suriin natin ang aming istraktura para sa pagsunod sa mga kinakailangan ng gawain:

  • Pagbasa ng datos: upang maunawaan kung naka-subscribe si Vasya sa Olya, kakailanganin nating ibawas ang buong linya sa pamamagitan ng key RowKey = "Vasya" at pag-uri-uriin ang mga halaga ng hanay hanggang sa "makilala" namin si Olya sa kanila. O umulit sa mga halaga ng lahat ng mga hanay, "hindi matugunan" si Olya at ibalik ang sagot na Mali;
  • Pag-edit ng data: pagdaragdag ng kaibigan: para sa isang katulad na gawain kailangan din nating ibawas ang buong linya gamit ang key RowKey = “Vasya” para mabilang ang kabuuang bilang ng kanyang mga kaibigan. Kailangan namin ang kabuuang bilang ng mga kaibigan upang matukoy ang bilang ng column kung saan kailangan naming isulat ang ID ng bagong kaibigan.
  • Pagbabago ng data: pagtanggal ng kaibigan:
    • Kailangang ibawas ang buong linya sa pamamagitan ng key RowKey = “Vasya” at pag-uri-uriin ang mga column upang mahanap ang isa kung saan ang kaibigan na tatanggalin ay naitala;
    • Susunod, pagkatapos tanggalin ang isang kaibigan, kailangan nating "ilipat" ang lahat ng data sa isang hanay upang hindi makakuha ng "mga puwang" sa kanilang pag-numero.

Suriin natin ngayon kung gaano magiging produktibo ang mga algorithm na ito, na kakailanganin nating ipatupad sa panig ng "conditional application", gamit ang O-simbolismo. Tukuyin natin ang laki ng ating hypothetical social network bilang n. Kung gayon ang maximum na bilang ng mga kaibigan na maaaring magkaroon ng isang user ay (n-1). Maaari pa nating pabayaan ito (-1) para sa ating mga layunin, dahil sa loob ng balangkas ng paggamit ng mga simbolo ng O ito ay hindi mahalaga.

  • Pagbasa ng datos: ito ay kinakailangan upang ibawas ang buong linya at umulit sa lahat ng mga haligi nito sa limitasyon. Nangangahulugan ito na ang pinakamataas na pagtatantya ng mga gastos ay tinatayang O(n)
  • Pag-edit ng data: pagdaragdag ng kaibigan: upang matukoy ang bilang ng mga kaibigan, kailangan mong umulit sa lahat ng mga column ng row, at pagkatapos ay magpasok ng bagong column => O(n)
  • Pagbabago ng data: pagtanggal ng kaibigan:
    • Katulad ng pagdaragdag - kailangan mong dumaan sa lahat ng mga column sa limitasyon => O(n)
    • Pagkatapos alisin ang mga column, kailangan nating "ilipat" ang mga ito. Kung ipapatupad mo ang "head-on" na ito, sa limitasyon ay kakailanganin mo ng hanggang (n-1) na mga operasyon. Ngunit dito at higit pa sa praktikal na bahagi ay gagamit tayo ng ibang diskarte, na magpapatupad ng isang "pseudo-shift" para sa isang nakapirming bilang ng mga operasyon - iyon ay, ang patuloy na oras ay gugugol dito, anuman ang n. Ang pare-parehong oras na ito (O(2) upang maging eksakto) ay maaaring mapabayaan kumpara sa O(n). Ang diskarte ay inilalarawan sa figure sa ibaba: kinokopya lang namin ang data mula sa "huling" column sa isa kung saan gusto naming tanggalin ang data, at pagkatapos ay tanggalin ang huling column:
      Mga tampok ng pagdidisenyo ng modelo ng data para sa NoSQL

Sa kabuuan, sa lahat ng mga senaryo ay nakatanggap kami ng asymptotic computational complexity ng O(n).
Marahil ay napansin mo na na halos palaging kailangan nating basahin ang buong row mula sa database, at sa dalawang kaso sa tatlo, para lang dumaan sa lahat ng column at kalkulahin ang kabuuang bilang ng mga kaibigan. Samakatuwid, bilang isang pagtatangka sa pag-optimize, maaari kang magdagdag ng column na "count", na nag-iimbak ng kabuuang bilang ng mga kaibigan ng bawat user ng network. Sa kasong ito, hindi namin mababasa ang buong hilera upang kalkulahin ang kabuuang bilang ng mga kaibigan, ngunit basahin lamang ang isang column na "bilang". Ang pangunahing bagay ay huwag kalimutang i-update ang "bilang" kapag nagmamanipula ng data. yun. pagbutihin natin Opsyon 2 (bilang):

RowKey
Mga Haligi

Vasya
1: Petya
2: Olya
3: Dasha
bilang: 3

Petya
1: Masha
2: Vasya

bilang: 2

Kung ikukumpara sa unang pagpipilian:

  • Pagbasa ng datos: upang makakuha ng sagot sa tanong na "Nabasa ba ni Vasya si Olya?" walang nagbago => O(n)
  • Pag-edit ng data: pagdaragdag ng kaibigan: Pinasimple namin ang pagpasok ng isang bagong kaibigan, dahil ngayon hindi namin kailangang basahin ang buong linya at umulit sa mga haligi nito, ngunit maaari lamang makuha ang halaga ng haligi ng "bilang", atbp. agad na tukuyin ang numero ng hanay upang magpasok ng isang bagong kaibigan. Ito ay humahantong sa isang pagbawas sa computational complexity sa O(1)
  • Pagbabago ng data: pagtanggal ng kaibigan: Kapag nagde-delete ng isang kaibigan, maaari rin nating gamitin ang column na ito para bawasan ang bilang ng mga operasyon ng I/O kapag "inilipat" ang data sa isang cell sa kaliwa. Ngunit nananatili pa rin ang pangangailangang umulit sa mga hanay upang mahanap ang kailangang tanggalin, kaya => ​​O(n)
  • Sa kabilang banda, ngayon kapag nag-a-update ng data kailangan nating i-update ang column na "count" sa bawat oras, ngunit nangangailangan ito ng patuloy na oras, na maaaring mapabayaan sa loob ng balangkas ng mga O-simbolo

Sa pangkalahatan, ang opsyon 2 ay tila mas mahusay ng kaunti, ngunit ito ay mas katulad ng "ebolusyon sa halip na rebolusyon." Upang makagawa ng isang "rebolusyon" kakailanganin natin Opsyon 3 (col).
Baliktarin natin ang lahat: itatalaga natin user ID ng pangalan ng column! Ang isusulat sa mismong column ay hindi na mahalaga para sa amin, hayaan itong maging numero 1 (sa pangkalahatan, ang mga kapaki-pakinabang na bagay ay maaaring maimbak doon, halimbawa, ang grupong "pamilya/kaibigan/etc."). Maaaring sorpresa ng diskarteng ito ang hindi handa na "layman" na walang dating karanasan sa pagtatrabaho sa mga database ng NoSQL, ngunit tiyak na ang diskarteng ito ang nagbibigay-daan sa iyong gamitin ang potensyal ng HBase sa gawaing ito nang mas epektibo:

RowKey
Mga Haligi

Vasya
Petya: 1
Olya: 1
Dasha: 1

Petya
Masha: 1
Vasya: 1

Dito nakakakuha tayo ng ilang mga pakinabang nang sabay-sabay. Upang maunawaan ang mga ito, pag-aralan natin ang bagong istraktura at tantiyahin ang computational complexity:

  • Pagbasa ng datos: upang masagot ang tanong kung si Vasya ay naka-subscribe sa Olya, sapat na basahin ang isang haligi na "Olya": kung naroroon, kung gayon ang sagot ay Tama, kung hindi - Mali => O(1)
  • Pag-edit ng data: pagdaragdag ng kaibigan: Pagdaragdag ng kaibigan: magdagdag lang ng bagong column na “Friend ID” => O(1)
  • Pagbabago ng data: pagtanggal ng kaibigan: tanggalin lang ang column ng Friend ID => O(1)

Tulad ng nakikita mo, ang isang makabuluhang bentahe ng modelong ito ng imbakan ay na sa lahat ng mga senaryo na kailangan namin, kami ay nagpapatakbo gamit lamang ang isang column, pag-iwas sa pagbabasa ng buong row mula sa database at, bukod dito, pag-enumerate ng lahat ng mga column ng row na ito. Maaari tayong tumigil doon, ngunit...

Maaari kang maguluhan at pumunta nang kaunti sa landas ng pag-optimize ng pagganap at pagbabawas ng mga operasyon ng I/O kapag ina-access ang database. Paano kung direktang inimbak namin ang kumpletong impormasyon ng relasyon sa mismong row key? Ibig sabihin, gawing composite key ang key tulad ng userID.friendID? Sa kasong ito, hindi na natin kailangang basahin ang mga column ng linya (Opsyon 4(row)):

RowKey
Mga Haligi

Vasya.Petya
Petya: 1

Vasya.Olya
Olya: 1

Vasya.Dasha
Dasha: 1

Petya.Masha
Masha: 1

Petya.Vasya
Vasya: 1

Malinaw, ang pagtatasa ng lahat ng mga senaryo sa pagmamanipula ng data sa naturang istraktura, tulad ng sa nakaraang bersyon, ay magiging O(1). Ang pagkakaiba sa opsyon 3 ay nasa kahusayan lamang ng mga operasyon ng I/O sa database.

Well, ang huling "bow". Madaling makita na sa opsyon 4, ang row key ay magkakaroon ng variable na haba, na posibleng makaapekto sa performance (natatandaan namin na ang HBase ay nag-iimbak ng data bilang isang set ng mga byte at ang mga row sa mga talahanayan ay pinagsunod-sunod ayon sa key). Dagdag pa, mayroon kaming isang separator na maaaring kailangang pangasiwaan sa ilang mga sitwasyon. Upang maalis ang impluwensyang ito, maaari kang gumamit ng mga hash mula sa userID at friendID, at dahil ang parehong mga hash ay magkakaroon ng pare-parehong haba, maaari mo lamang pagsamahin ang mga ito, nang walang separator. Pagkatapos ang data sa talahanayan ay magiging ganito (Opsyon 5(hash)):

RowKey
Mga Haligi

dc084ef00e94aef49be885f9b01f51c01918fa783851db0dc1f72f83d33a5994
Petya: 1

dc084ef00e94aef49be885f9b01f51c0f06b7714b5ba522c3cf51328b66fe28a
Olya: 1

dc084ef00e94aef49be885f9b01f51c00d2c2e5d69df6b238754f650d56c896a
Dasha: 1

1918fa783851db0dc1f72f83d33a59949ee3309645bd2c0775899fca14f311e1
Masha: 1

1918fa783851db0dc1f72f83d33a5994dc084ef00e94aef49be885f9b01f51c0
Vasya: 1

Malinaw, ang pagiging kumplikado ng algorithm ng pagtatrabaho sa gayong istraktura sa mga sitwasyong isinasaalang-alang namin ay magiging pareho sa opsyon 4 - iyon ay, O(1).
Sa kabuuan, ibuod natin ang lahat ng aming mga pagtatantya ng computational complexity sa isang table:

Pagdaragdag ng kaibigan
Sinusuri ang isang kaibigan
Pag-alis ng kaibigan

Opsyon 1 (default)
O (n)
O (n)
O (n)

Opsyon 2 (bilang)
O (1)
O (n)
O (n)

Opsyon 3 (column)
O (1)
O (1)
O (1)

Opsyon 4 (hilera)
O (1)
O (1)
O (1)

Opsyon 5 (hash)
O (1)
O (1)
O (1)

Tulad ng nakikita mo, ang mga pagpipilian 3-5 ay tila ang pinaka-kanais-nais at ayon sa teorya ay tinitiyak ang pagpapatupad ng lahat ng kinakailangang mga sitwasyon sa pagmamanipula ng data sa patuloy na oras. Sa mga kondisyon ng aming gawain, walang tahasang kinakailangan upang makakuha ng isang listahan ng lahat ng mga kaibigan ng gumagamit, ngunit sa mga tunay na aktibidad ng proyekto, makabubuti para sa amin, bilang mahusay na mga analyst, na "maasahan" na ang ganoong gawain ay maaaring lumitaw at "magkalat ng dayami." Samakatuwid, ang aking mga pakikiramay ay nasa panig ng opsyon 3. Ngunit malamang na sa isang tunay na proyekto ang kahilingang ito ay maaaring nalutas na sa pamamagitan ng iba pang paraan, samakatuwid, nang walang pangkalahatang pananaw sa buong problema, mas mabuting huwag gawin panghuling konklusyon.

Paghahanda ng eksperimento

Gusto kong subukan ang mga teoretikal na argumento sa itaas sa pagsasanay - ito ang layunin ng ideya na lumitaw sa mahabang katapusan ng linggo. Upang gawin ito, kinakailangan upang suriin ang bilis ng pagpapatakbo ng aming "kondisyon na aplikasyon" sa lahat ng inilarawan na mga senaryo para sa paggamit ng database, pati na rin ang pagtaas sa oras na ito sa pagtaas ng laki ng social network (n). Ang target na parameter na interesado sa amin at na susukatin namin sa panahon ng eksperimento ay ang oras na ginugol ng "conditional application" upang magsagawa ng isang "operasyon ng negosyo." Sa pamamagitan ng "transaksyon sa negosyo" ang ibig naming sabihin ay isa sa mga sumusunod:

  • Pagdaragdag ng isang bagong kaibigan
  • Sinusuri kung ang User A ay kaibigan ng User B
  • Pag-alis ng isang kaibigan

Kaya, isinasaalang-alang ang mga kinakailangan na nakabalangkas sa paunang pahayag, ang senaryo ng pag-verify ay lumalabas tulad ng sumusunod:

  • Pag-record ng data. Random na bumuo ng isang paunang network ng laki n. Upang mas mapalapit sa "tunay na mundo", ang bilang ng mga kaibigan na mayroon ang bawat user ay isa ring random na variable. Sukatin ang oras kung kailan isinusulat ng aming "kondisyon na aplikasyon" ang lahat ng nabuong data sa HBase. Pagkatapos ay hatiin ang resultang oras sa kabuuang bilang ng mga idinagdag na kaibigan - ito ay kung paano namin makuha ang average na oras para sa isang "operasyon ng negosyo"
  • Pagbasa ng datos. Para sa bawat user, gumawa ng listahan ng "mga personalidad" kung saan kailangan mong makakuha ng sagot kung ang user ay naka-subscribe sa kanila o hindi. Ang haba ng listahan = humigit-kumulang sa bilang ng mga kaibigan ng gumagamit, at para sa kalahati ng mga naka-check na kaibigan ang sagot ay dapat na "Oo", at para sa iba pang kalahati - "Hindi". Isinasagawa ang pagsusuri sa isang pagkakasunud-sunod na ang mga sagot na "Oo" at "Hindi" ay kahalili (iyon ay, sa bawat pangalawang kaso kailangan nating dumaan sa lahat ng mga hanay ng linya para sa mga pagpipilian 1 at 2). Ang kabuuang oras ng screening ay hinati sa bilang ng mga kaibigan na nasubok upang makuha ang average na oras ng screening bawat paksa.
  • Pagtanggal ng Data. Alisin ang lahat ng mga kaibigan mula sa user. Bukod dito, random ang pagkakasunud-sunod ng pagtanggal (iyon ay, "i-shuffle" namin ang orihinal na listahang ginamit upang itala ang data). Ang kabuuang oras ng pagsusuri ay hinati sa bilang ng mga kaibigang inalis upang makuha ang average na oras sa bawat tseke.

Ang mga senaryo ay kailangang patakbuhin para sa bawat isa sa 5 pagpipilian sa modelo ng data at para sa iba't ibang laki ng social network upang makita kung paano nagbabago ang oras habang ito ay lumalaki. Sa loob ng isang n, ang mga koneksyon sa network at ang listahan ng mga user na susuriin ay dapat, siyempre, ay pareho para sa lahat ng 5 mga pagpipilian.
Para sa mas mahusay na pag-unawa, nasa ibaba ang isang halimbawa ng nabuong data para sa n= 5. Ang nakasulat na "generator" ay gumagawa ng tatlong ID na diksyunaryo bilang output:

  • ang una ay para sa pagpasok
  • ang pangalawa ay para sa pagsuri
  • pangatlo - para sa pagtanggal

{0: [1], 1: [4, 5, 3, 2, 1], 2: [1, 2], 3: [2, 4, 1, 5, 3], 4: [2, 1]} # всего 15 друзей

{0: [1, 10800], 1: [5, 10800, 2, 10801, 4, 10802], 2: [1, 10800], 3: [3, 10800, 1, 10801, 5, 10802], 4: [2, 10800]} # всего 18 проверяемых субъектов

{0: [1], 1: [1, 3, 2, 5, 4], 2: [1, 2], 3: [4, 1, 2, 3, 5], 4: [1, 2]} # всего 15 друзей

Gaya ng nakikita mo, lahat ng ID na higit sa 10 sa diksyunaryo para sa pagsuri ay tiyak na magbibigay ng sagot na Mali. Ang pagpasok, pagsuri at pagtanggal ng "mga kaibigan" ay isinasagawa nang eksakto sa pagkakasunud-sunod na tinukoy sa diksyunaryo.

Ang eksperimento ay isinagawa sa isang laptop na tumatakbo sa Windows 10, kung saan ang HBase ay tumatakbo sa isang Docker container, at ang Python na may Jupyter Notebook ay tumatakbo sa isa pa. Ang Docker ay inilaan ng 2 CPU core at 2 GB ng RAM. Ang lahat ng lohika, parehong ang pagtulad ng "conditional application" at ang "piping" para sa pagbuo ng data ng pagsubok at pagsukat ng oras, ay isinulat sa Python. Ang aklatan ay ginamit upang gumana sa HBase happybase, upang kalkulahin ang mga hash (MD5) para sa opsyon 5 - hashlib

Isinasaalang-alang ang kapangyarihan sa pag-compute ng isang partikular na laptop, isang paglulunsad para sa n = 10, 30, … ay pinili nang eksperimento. 170 – kapag ang kabuuang oras ng pagpapatakbo ng buong ikot ng pagsubok (lahat ng mga senaryo para sa lahat ng opsyon para sa lahat n) ay higit pa o hindi gaanong makatwiran at akma sa isang tea party (sa average na 15 minuto).

Narito ito ay kinakailangan upang gumawa ng isang puna na sa eksperimentong ito ay hindi namin pangunahing sinusuri ang ganap na mga bilang ng pagganap. Kahit na ang isang kamag-anak na paghahambing ng magkaibang dalawang opsyon ay maaaring hindi ganap na tama. Ngayon kami ay interesado sa likas na katangian ng pagbabago sa oras depende sa n, dahil isinasaalang-alang ang pagsasaayos sa itaas ng "test stand", napakahirap makakuha ng mga pagtatantya ng oras na "na-clear" ng impluwensya ng random at iba pang mga kadahilanan ( at hindi naitakda ang ganoong gawain).

Resulta ng eksperimento

Ang unang pagsubok ay kung paano nagbabago ang oras na ginugol sa pagpuno sa listahan ng mga kaibigan. Ang resulta ay nasa graph sa ibaba.
Mga tampok ng pagdidisenyo ng modelo ng data para sa NoSQL
Ang mga opsyon 3-5, gaya ng inaasahan, ay nagpapakita ng halos pare-parehong oras ng "transaksyon sa negosyo", na hindi nakadepende sa paglaki ng laki ng network at isang hindi matukoy na pagkakaiba sa pagganap.
Ang Opsyon 2 ay nagpapakita rin ng pare-pareho, ngunit bahagyang mas masahol na pagganap, halos eksaktong 2 beses na nauugnay sa mga opsyon 3-5. At hindi ito magalak, dahil nauugnay ito sa teorya - sa bersyong ito ang bilang ng mga operasyon ng I/O papunta/mula sa HBase ay eksaktong 2 beses na mas malaki. Maaari itong magsilbi bilang hindi direktang katibayan na ang aming test bench, sa prinsipyo, ay nagbibigay ng mahusay na katumpakan.
Ang Opsyon 1 din, gaya ng inaasahan, ay lumalabas na pinakamabagal at nagpapakita ng linear na pagtaas sa oras na ginugol sa pagdaragdag ng isa't isa sa laki ng network.
Tingnan natin ngayon ang mga resulta ng ikalawang pagsubok.
Mga tampok ng pagdidisenyo ng modelo ng data para sa NoSQL
Ang mga opsyon 3-5 ay muling kumilos tulad ng inaasahan - pare-pareho ang oras, independiyente sa laki ng network. Ang mga opsyon 1 at 2 ay nagpapakita ng isang linear na pagtaas sa oras habang tumataas ang laki ng network at katulad na pagganap. Bukod dito, ang opsyon 2 ay lumalabas na medyo mabagal - tila dahil sa pangangailangang i-proofread at iproseso ang karagdagang column na "bilang", na nagiging mas kapansin-pansin habang lumalaki ang n. Ngunit pigilin ko pa rin ang paggawa ng anumang mga konklusyon, dahil ang katumpakan ng paghahambing na ito ay medyo mababa. Bilang karagdagan, ang mga ratio na ito (kung aling opsyon, 1 o 2, ang mas mabilis) ay nagbago mula sa run hanggang run (habang pinapanatili ang likas na katangian ng pag-asa at "pumupunta sa leeg at leeg").

Well, ang huling graph ay ang resulta ng pagsubok sa pag-alis.

Mga tampok ng pagdidisenyo ng modelo ng data para sa NoSQL

Muli, walang mga sorpresa dito. Ang mga opsyon 3-5 ay nagsasagawa ng pag-alis sa palagiang oras.
Bukod dito, kawili-wili, ang mga opsyon 4 at 5, hindi tulad ng mga nakaraang senaryo, ay nagpapakita ng kapansin-pansing bahagyang mas masahol na pagganap kaysa sa opsyon 3. Tila, ang operasyon ng pagtanggal ng hilera ay mas mahal kaysa sa operasyon ng pagtanggal ng column, na sa pangkalahatan ay lohikal.

Ang mga opsyon 1 at 2, gaya ng inaasahan, ay nagpapakita ng linear na pagtaas ng oras. Kasabay nito, ang opsyon 2 ay patuloy na mas mabagal kaysa sa opsyon 1 - dahil sa karagdagang operasyon ng I/O upang “panatilihin” ang column ng bilang.

Pangkalahatang konklusyon ng eksperimento:

  • Ang mga opsyon 3-5 ay nagpapakita ng higit na kahusayan habang sinasamantala nila ang HBase; Bukod dito, ang kanilang pagganap ay naiiba sa bawat isa sa pamamagitan ng isang pare-pareho at hindi nakasalalay sa laki ng network.
  • Ang pagkakaiba sa pagitan ng mga opsyon 4 at 5 ay hindi naitala. Ngunit hindi ito nangangahulugan na ang opsyon 5 ay hindi dapat gamitin. Malamang na ang pang-eksperimentong senaryo na ginamit, na isinasaalang-alang ang mga katangian ng pagganap ng test bench, ay hindi pinahintulutan itong matukoy.
  • Ang likas na katangian ng pagtaas sa oras na kinakailangan upang maisagawa ang "mga pagpapatakbo ng negosyo" na may data sa pangkalahatan ay nakumpirma ang dating nakuha na mga teoretikal na kalkulasyon para sa lahat ng mga opsyon.

Epilogo

Ang mga magaspang na eksperimento na isinagawa ay hindi dapat kunin bilang ganap na katotohanan. Mayroong maraming mga kadahilanan na hindi isinasaalang-alang at binaluktot ang mga resulta (ang mga pagbabagong ito ay lalo na nakikita sa mga graph na may maliit na laki ng network). Halimbawa, ang bilis ng pag-iimpok, na ginagamit ng happybase, ang dami at paraan ng pagpapatupad ng lohika na isinulat ko sa Python (hindi ko maangkin na ang code ay isinulat nang mahusay at epektibong ginamit ang mga kakayahan ng lahat ng mga bahagi), marahil ang mga feature ng HBase caching, background activity ng Windows 10 sa aking laptop, atbp. Sa pangkalahatan, maaari nating ipagpalagay na ang lahat ng teoretikal na kalkulasyon ay eksperimento na nagpakita ng kanilang bisa. Well, o hindi bababa sa hindi posible na pabulaanan ang mga ito sa gayong "head-on attack".

Sa konklusyon, mga rekomendasyon para sa lahat na nagsisimula pa lang magdisenyo ng mga modelo ng data sa HBase: abstract mula sa nakaraang karanasan sa pagtatrabaho sa mga relational database at tandaan ang "mga utos":

  • Kapag nagdidisenyo, nagpapatuloy kami mula sa gawain at mga pattern ng pagmamanipula ng data, at hindi mula sa modelo ng domain
  • Mahusay na pag-access (nang walang buong pag-scan ng talahanayan) – sa pamamagitan lamang ng key
  • Denormalisasyon
  • Maaaring maglaman ng iba't ibang column ang iba't ibang row
  • Dynamic na komposisyon ng mga nagsasalita

Pinagmulan: www.habr.com

Magdagdag ng komento