Ավելի շատ մշակողներ պետք է իմանան սա տվյալների բազաների մասին

Նշում. թարգմ.Ջաանա Դողանը Google-ի փորձառու ինժեներ է, ով ներկայումս աշխատում է Go-ում գրված ընկերության արտադրական ծառայությունների տեսանելիության վրա: Այս հոդվածում, որը մեծ ժողովրդականություն է ձեռք բերել անգլիախոս լսարանի շրջանում, նա 17 կետերում հավաքել է կարևոր տեխնիկական մանրամասներ DBMS-ների (և երբեմն ընդհանրապես բաշխված համակարգերի) վերաբերյալ, որոնք օգտակար են մեծ/պահանջկոտ հավելվածների մշակողների համար:

Ավելի շատ մշակողներ պետք է իմանան սա տվյալների բազաների մասին

Համակարգչային համակարգերի ճնշող մեծամասնությունը հետևում է իրենց վիճակին և, համապատասխանաբար, պահանջում է տվյալների պահպանման որոշակի համակարգ: Ես երկար ժամանակ կուտակել եմ գիտելիքներ տվյալների բազաների մասին՝ ճանապարհին կատարելով դիզայնի սխալներ, որոնք հանգեցրել են տվյալների կորստի և անջատումների: Համակարգերում, որոնք մշակում են մեծ ծավալի տեղեկատվություն, տվյալների բազաները գտնվում են համակարգի ճարտարապետության հիմքում և գործում են որպես հիմնական տարր օպտիմալ լուծում ընտրելու համար: Չնայած այն հանգամանքին, որ մեծ ուշադրություն է դարձվում տվյալների բազայի աշխատանքին, այն խնդիրները, որոնք հավելվածների մշակողները փորձում են կանխատեսել, հաճախ սառցաբեկորի գագաթն են: Այս հոդվածների շարքում ես կիսվում եմ որոշ գաղափարներով, որոնք օգտակար կլինեն այս ոլորտում ոչ մասնագիտացած ծրագրավորողների համար:

  1. Դուք հաջողակ եք, եթե 99,999% դեպքերում ցանցը խնդիրներ չի առաջացնում:
  2. ԹԹՈՒՆ նշանակում է շատ տարբեր բաներ:
  3. Յուրաքանչյուր շտեմարան ունի հետևողականության և մեկուսացման ապահովման իր մեխանիզմները:
  4. Լավատեսական արգելափակումը օգնության է հասնում, երբ դժվար է պահպանել սովորականը։
  5. Բացի կեղտոտ ընթերցումից և տվյալների կորստից, կան նաև այլ անոմալիաներ:
  6. Տվյալների բազան և օգտագործողը միշտ չէ, որ համաձայնվում են գործողությունների ընթացքի վերաբերյալ:
  7. Հավելվածի մակարդակի համօգտագործումը կարող է տեղափոխվել հավելվածից դուրս:
  8. Ինքնաբարձրացումը կարող է վտանգավոր լինել:
  9. Հնացած տվյալները կարող են օգտակար լինել և կողպման կարիք չունենալ:
  10. Խեղաթյուրումները բնորոշ են ժամանակի ցանկացած աղբյուրի։
  11. Ուշացումը շատ իմաստներ ունի.
  12. Կատարման պահանջները պետք է գնահատվեն կոնկրետ գործարքի համար:
  13. Ներդրված գործարքները կարող են վտանգավոր լինել:
  14. Գործարքները չպետք է կապված լինեն կիրառման վիճակի հետ:
  15. Հարցումների պլանավորողները կարող են ձեզ շատ բան ասել տվյալների բազաների մասին:
  16. Առցանց միգրացիան դժվար է, բայց հնարավոր:
  17. Տվյալների բազայի զգալի աճը ենթադրում է անկանխատեսելիության աճ:

Ես կցանկանայի շնորհակալություն հայտնել Էմմանուել Օդեկեին, Ռեյն Հենրիխսին և մյուսներին այս հոդվածի ավելի վաղ տարբերակի վերաբերյալ իրենց կարծիքի համար:

Դուք հաջողակ եք, եթե 99,999% դեպքերում ցանցը խնդիրներ չի առաջացնում:

Հարցը մնում է այն մասին, թե որքանով են հուսալի ժամանակակից ցանցային տեխնոլոգիաները և որքան հաճախ են համակարգերը խափանում ցանցի խափանումների պատճառով: Այս հարցի վերաբերյալ տեղեկատվությունը սակավ է, և հետազոտություններում հաճախ գերակշռում են մասնագիտացված ցանցեր, սարքավորումներ և անձնակազմ ունեցող խոշոր կազմակերպությունները:

Spanner-ի (Google-ի համաշխարհային բաշխված տվյալների բազա) 99,999% հասանելիության մակարդակով Google-ը պնդում է, որ միայն 7,6% խնդիրները կապված են ցանցի հետ։ Միևնույն ժամանակ, ընկերությունն իր մասնագիտացված ցանցն անվանում է բարձր հասանելիության «հիմնական հենասյուն»։ Ուսումնասիրել Բեյլիս և Քինգսբերի, որն անցկացվել է 2014 թվականին, մարտահրավեր է նետում «թյուր պատկերացումներ բաշխված հաշվարկների վերաբերյալ», որը Պիտեր Դոյչը ձեւակերպել է 1994թ. Արդյո՞ք ցանցը իսկապես հուսալի է:

Համապարփակ հետազոտություն հսկա ընկերություններից դուրս, որն իրականացվել է ավելի լայն ինտերնետի համար, պարզապես գոյություն չունի: Չկան նաև բավարար տվյալներ հիմնական խաղացողներից այն մասին, թե իրենց հաճախորդների խնդիրների քանի տոկոսն է կապված ցանցի հետ: Մենք քաջատեղյակ ենք խոշոր ամպային պրովայդերների ցանցի խափանումների մասին, որոնք կարող են մի քանի ժամով հեռացնել ինտերնետի մի ամբողջ հատվածը, պարզապես այն պատճառով, որ դրանք բարձրակարգ իրադարձություններ են, որոնք ազդում են մեծ թվով մարդկանց և ընկերությունների վրա: Ցանցի անջատումները կարող են խնդիրներ առաջացնել շատ ավելի դեպքերում, նույնիսկ եթե այդ դեպքերից ոչ բոլորն են ուշադրության կենտրոնում: Ամպային ծառայությունների հաճախորդները նույնպես ոչինչ չգիտեն խնդիրների պատճառների մասին։ Եթե ​​կա ձախողում, գրեթե անհնար է այն վերագրել ծառայության մատակարարի կողմից ցանցային սխալին: Նրանց համար երրորդ կողմի ծառայությունները սև արկղեր են: Անհնար է գնահատել ազդեցությունը առանց խոշոր ծառայություններ մատուցող լինելու:

Հաշվի առնելով, թե ինչ են հայտնում խոշոր խաղացողները իրենց համակարգերի մասին, կարելի է վստահորեն ասել, որ հաջողակ եք, եթե ցանցային դժվարությունները հաշվի են առնում հնարավոր խափանումների միայն փոքր տոկոսը: Ցանցային հաղորդակցությունները դեռևս տառապում են այնպիսի առօրյա բաներից, ինչպիսիք են ապարատային խափանումները, տոպոլոգիայի փոփոխությունները, վարչական կազմաձևերի փոփոխությունները և էլեկտրաէներգիայի անջատումները: Վերջերս զարմացա, երբ իմացա, որ ավելացվել է հնարավոր խնդիրների ցանկը շնաձկների խայթոցները (այո, ճիշտ եք լսել):

ԹԹՈՒՆ նշանակում է շատ տարբեր բաներ

ACID հապավումը նշանակում է ատոմականություն, հետևողականություն, մեկուսացում, հուսալիություն: Գործարքների այս հատկությունները նպատակ ունեն ապահովելու դրանց վավերականությունը խափանումների, սխալների, ապարատային խափանումների և այլնի դեպքում: Առանց ACID-ի կամ նմանատիպ սխեմաների, հավելվածների մշակողների համար դժվար կլինի տարբերակել, թե ինչի համար են նրանք պատասխանատու և ինչի համար է պատասխանատու տվյալների բազան: Հարաբերական գործարքային տվյալների բազաների մեծ մասը փորձում է համապատասխանել ACID-ին, սակայն NoSQL-ի նման նոր մոտեցումները հիմք են տվել բազմաթիվ տվյալների բազաների՝ առանց ACID գործարքների, քանի որ դրանց ներդրումը թանկ է:

Երբ ես առաջին անգամ մտա արդյունաբերություն, մեր տեխնիկական առաջատարը խոսում էր այն մասին, թե որքանով է տեղին ACID հայեցակարգը: Արդարության համար նշենք, որ ACID-ը համարվում է ավելի շուտ կոպիտ նկարագրություն, քան կատարման խիստ ստանդարտ: Այսօր ես այն հիմնականում օգտակար եմ համարում, քանի որ այն բարձրացնում է հարցերի կոնկրետ կատեգորիա (և առաջարկում է մի շարք հնարավոր լուծումներ):

Ամեն DBMS չէ, որ համապատասխանում է ACID-ին. Միևնույն ժամանակ, ACID-ին աջակցող տվյալների բազայի իրականացումները տարբեր կերպ են հասկանում պահանջների շարքը: Պատճառներից մեկը, թե ինչու է ACID-ի ներդրումը կարկատանային է, պայմանավորված է բազմաթիվ փոխզիջումներով, որոնք պետք է արվեն ACID-ի պահանջները կյանքի կոչելու համար: Ստեղծողները կարող են իրենց տվյալների բազաները ներկայացնել որպես ACID-ին համապատասխան, սակայն եզրային դեպքերի մեկնաբանությունը կարող է կտրուկ տարբերվել, ինչպես նաև «անհավանական» իրադարձությունների հետ աշխատելու մեխանիզմը: Առնվազն, ծրագրավորողները կարող են բարձր մակարդակի ըմբռնում ձեռք բերել բազային ներդրման բարդությունների մասին՝ իրենց հատուկ վարքագծի և դիզայնի փոխզիջումների պատշաճ ըմբռնման համար:

Բանավեճը այն մասին, թե արդյոք MongoDB-ը համապատասխանում է ACID-ի պահանջներին, շարունակվում է նույնիսկ 4-րդ տարբերակի թողարկումից հետո: MongoDB-ն երկար ժամանակ չի աջակցվում ծառահատումներ, թեև լռելյայն տվյալների վրա դրված էր սկավառակի վրա ոչ ավելի, քան 60 վայրկյանը մեկ անգամ: Պատկերացրեք հետևյալ սցենարը. հավելվածը տեղադրում է երկու գրություն (w1 և w2): MongoDB-ն հաջողությամբ պահպանում է w1-ը, սակայն w2-ը կորչում է ապարատային անսարքության պատճառով:

Ավելի շատ մշակողներ պետք է իմանան սա տվյալների բազաների մասին
Սցենարը պատկերող դիագրամ: MongoDB-ն խափանում է, նախքան այն կարող է տվյալներ գրել սկավառակի վրա

Սկավառակին միանալը թանկ գործընթաց է: Խուսափելով հաճախակի պարտավորություններից՝ մշակողները բարելավում են ձայնագրման կատարումը՝ ի հաշիվ հուսալիության: MongoDB-ն ներկայումս աջակցում է գրանցամատյանում, սակայն կեղտոտ գրառումները դեռ կարող են ազդել տվյալների ամբողջականության վրա, քանի որ տեղեկամատյանները լռելյայնորեն գրանցվում են յուրաքանչյուր 100 մվ-ում: Այսինքն՝ լոգերի և դրանցում ներկայացված փոփոխությունների դեպքում դեռ հնարավոր է նմանատիպ սցենար, թեև ռիսկը շատ ավելի ցածր է։

Յուրաքանչյուր տվյալների բազա ունի իր հետևողականության և մեկուսացման մեխանիզմները

ACID-ի պահանջներից, հետևողականությունն ու մեկուսացումը պարծենում են տարբեր իրականացումների ամենամեծ քանակից, քանի որ փոխզիջումների շրջանակն ավելի լայն է: Պետք է ասել, որ հետևողականությունը և մեկուսացումը բավականին թանկ գործառույթներ են։ Նրանք պահանջում են համակարգում և մեծացնում մրցակցությունը տվյալների հետևողականության համար: Խնդրի բարդությունը զգալիորեն մեծանում է, երբ անհրաժեշտ է տվյալների բազան հորիզոնական մասշտաբավորել բազմաթիվ տվյալների կենտրոններում (հատկապես, եթե դրանք գտնվում են տարբեր աշխարհագրական տարածաշրջաններում): Հետևողականության բարձր մակարդակի հասնելը շատ դժվար է, քանի որ այն նաև նվազեցնում է հասանելիությունը և մեծացնում ցանցի հատվածավորումը: Այս երեւույթի ավելի ընդհանուր բացատրության համար խորհուրդ եմ տալիս անդրադառնալ CAP թեորեմ. Հարկ է նաև նշել, որ հավելվածները կարող են հաղթահարել փոքր քանակությամբ անհամապատասխանություններ, և ծրագրավորողները կարող են բավական լավ հասկանալ խնդրի նրբությունները, որպեսզի հավելվածում լրացուցիչ տրամաբանություն մտցնեն անհամապատասխանությունը կարգավորելու համար՝ առանց այն լուծելու համար մեծապես հենվելու տվյալների բազայի վրա:

DBMS-ները հաճախ ապահովում են մեկուսացման տարբեր մակարդակներ: Հավելվածի մշակողները կարող են ընտրել ամենաարդյունավետը՝ ելնելով իրենց նախասիրություններից: Ցածր մեկուսացումը թույլ է տալիս բարձրացնել արագությունը, բայց նաև մեծացնում է տվյալների մրցավազքի ռիսկը: Բարձր մեկուսացումը նվազեցնում է այս հավանականությունը, բայց դանդաղեցնում է աշխատանքը և կարող է հանգեցնել մրցակցության, ինչը կհանգեցնի բազայի այնպիսի արգելակների, որ սկսվեն խափանումները:

Ավելի շատ մշակողներ պետք է իմանան սա տվյալների բազաների մասին
Գոյություն ունեցող համաժամանակյա մոդելների և նրանց միջև հարաբերությունների վերանայում

SQL ստանդարտը սահմանում է միայն չորս մեկուսացման մակարդակ, թեև տեսականորեն և պրակտիկայում կան շատ ավելին: Jepson.io առաջարկում է գոյություն ունեցող համաժամանակյա մոդելների հիանալի ակնարկ: Օրինակ, Google Spanner-ը երաշխավորում է արտաքին սերիալիզացիան ժամացույցի համաժամացման միջոցով, և չնայած սա ավելի խիստ մեկուսացման շերտ է, այն սահմանված չէ ստանդարտ մեկուսացման շերտերում:

SQL ստանդարտը նշում է մեկուսացման հետևյալ մակարդակները.

  • Սերիալիզացվող (Ամենախիստ և թանկ). Հերթական կատարումը նշանակում է, որ յուրաքանչյուր հաջորդ գործարքը սկսվում է միայն նախորդի ավարտից հետո: Հարկ է նշել, որ մակարդակը Սերիալիզացվող հաճախ իրականացվում է որպես այսպես կոչված snapshot-ի մեկուսացում (օրինակ, Oracle-ում) մեկնաբանման տարբերությունների պատճառով, թեև snapshot-ի մեկուսացումն ինքնին ներկայացված չէ SQL ստանդարտում:
  • Կրկնվող ընթերցումներԸնթացիկ գործարքի չգրանցված գրառումները հասանելի են ընթացիկ գործարքի համար, սակայն այլ գործարքների արդյունքում կատարված փոփոխությունները (օրինակ՝ նոր տողերը) տեսանելի չէ.
  • Կարդացեք հավատարիմԳործարքների համար անհասանելի տվյալներ չկան: Այս դեպքում գործարքները կարող են տեսնել միայն պարտավորված տվյալները, և ֆանտոմային ընթերցումներ կարող են տեղի ունենալ: Եթե ​​գործարքը զետեղում և կատարում է նոր տողեր, ընթացիկ գործարքը կկարողանա տեսնել դրանք, երբ հարցման ենթարկվի:
  • Կարդացեք առանց պարտավորությունների (նվազագույն խիստ և թանկ մակարդակ). Կեղտոտ ընթերցումները թույլատրվում են, գործարքները կարող են տեսնել այլ գործարքների կողմից կատարված չհաստատված փոփոխությունները: Գործնականում այս մակարդակը կարող է օգտակար լինել կոպիտ գնահատումների համար, ինչպիսիք են հարցումները COUNT(*) սեղանին.

Մակարդակ Սերիալիզացվող նվազագույնի է հասցնում տվյալների մրցավազքի ռիսկը, մինչդեռ այն ամենաթանկն է իրագործման համար և հանգեցնում է համակարգի ամենաբարձր մրցակցային բեռի: Մեկուսացման այլ մակարդակները ավելի հեշտ են իրականացնել, բայց մեծացնում են տվյալների մրցավազքի հավանականությունը: Որոշ DBMS-ներ թույլ են տալիս սահմանել հատուկ մեկուսացման մակարդակ, մյուսներն ունեն ուժեղ նախապատվություններ և ոչ բոլոր մակարդակներն են աջակցվում:

Մեկուսացման մակարդակների աջակցությունը հաճախ գովազդվում է տվյալ DBMS-ում, բայց միայն դրա վարքագծի մանրակրկիտ ուսումնասիրությունը կարող է բացահայտել, թե իրականում ինչ է տեղի ունենում:

Ավելի շատ մշակողներ պետք է իմանան սա տվյալների բազաների մասին
Տարբեր DBMS-ների համար մեկուսացման տարբեր մակարդակներում համաժամանակյա անոմալիաների վերանայում

Մարտին Կլեպմանն իր նախագծում ճգնավոր Համեմատում է մեկուսացման տարբեր մակարդակները, խոսում է համաժամանակյա անոմալիաների մասին և արդյոք տվյալների բազան կարող է հավատարիմ մնալ մեկուսացման որոշակի մակարդակին: Kleppmann-ի հետազոտությունը ցույց է տալիս, թե տվյալների բազայի մշակողները որքան տարբեր են մտածում մեկուսացման մակարդակների մասին:

Լավատեսական արգելափակումը օգնության է հասնում, երբ դժվար է պահպանել սովորականը։

Արգելափակումը կարող է շատ թանկ արժենալ ոչ միայն այն պատճառով, որ այն մեծացնում է մրցակցությունը տվյալների բազայում, այլ նաև այն պատճառով, որ պահանջում է հավելվածի սերվերներից անընդհատ միանալ տվյալների բազային: Ցանցի սեգմենտավորումը կարող է սրել բացառիկ արգելափակման իրավիճակները և հանգեցնել փակուղիների, որոնք դժվար է հայտնաբերել և լուծել: Այն դեպքերում, երբ բացառիկ կողպումը հարմար չէ, լավատեսական կողպումն օգնում է:

Լավատեսական փական մեթոդ է, երբ տողը կարդալիս հաշվի է առնվում դրա տարբերակը, ստուգման գումարը կամ վերջին փոփոխության ժամանակը: Սա թույլ է տալիս համոզվել, որ մուտքագրումը փոխելուց առաջ ատոմային տարբերակի փոփոխություն չկա.

UPDATE products
SET name = 'Telegraph receiver', version = 2
WHERE id = 1 AND version = 1

Այս դեպքում աղյուսակի թարմացում products չի իրականացվի, եթե մեկ այլ գործողություն նախկինում փոփոխություններ է կատարել այս շարքում: Եթե ​​այս տողում այլ գործողություններ չեն կատարվել, ապա մեկ տողի փոփոխությունը տեղի կունենա, և կարելի է ասել, որ թարմացումը հաջող է եղել:

Բացի կեղտոտ ընթերցումից և տվյալների կորստից, կան նաև այլ անոմալիաներ

Երբ խոսքը վերաբերում է տվյալների հետևողականությանը, ուշադրությունը կենտրոնանում է մրցավազքի պայմանների հնարավորության վրա, որոնք կարող են հանգեցնել կեղտոտ ընթերցումների և տվյալների կորստի: Այնուամենայնիվ, տվյալների անոմալիաները չեն դադարում դրանով:

Նման անոմալիաների օրինակներից է գրանցման աղավաղումը (գրել շեղեր). Խեղաթյուրումները դժվար է հայտնաբերել, քանի որ դրանք սովորաբար ակտիվորեն չեն փնտրում: Դրանք պայմանավորված են ոչ թե կեղտոտ ընթերցմամբ կամ տվյալների կորստով, այլ տվյալների վրա դրված տրամաբանական սահմանափակումների խախտմամբ:

Օրինակ, եկեք դիտարկենք մոնիտորինգի մի ծրագիր, որը պահանջում է, որ մեկ օպերատոր միշտ հսկիչ լինի.

BEGIN tx1;                      BEGIN tx2;
SELECT COUNT(*)
FROM operators
WHERE oncall = true;
0                               SELECT COUNT(*)
                                FROM operators
                                WHERE oncall = TRUE;
                                0
UPDATE operators                UPDATE operators
SET oncall = TRUE               SET oncall = TRUE
WHERE userId = 4;               WHERE userId = 2;
COMMIT tx1;                     COMMIT tx2;

Վերոնշյալ իրավիճակում կոռուպցիայի ռեկորդային ցուցանիշ կառաջանա, եթե երկու գործարքները հաջողությամբ իրականացվեն: Թեև չկար կեղտոտ ընթերցումներ կամ տվյալների կորուստ, տվյալների ամբողջականությունը վտանգված էր. այժմ երկու հոգի միաժամանակ հերթապահ են համարվում:

Սերիալիզացվող մեկուսացումը, սխեմայի ձևավորումը կամ տվյալների բազայի սահմանափակումները կարող են օգնել վերացնել գրելու կոռուպցիան: Մշակողները պետք է կարողանան բացահայտել նման անոմալիաները արտադրության ընթացքում խուսափելու համար: Միևնույն ժամանակ, ձայնագրման աղավաղումները չափազանց դժվար է փնտրել կոդի բազայում: Հատկապես խոշոր համակարգերում, երբ զարգացման տարբեր թիմեր պատասխանատու են նույն աղյուսակների վրա հիմնված գործառույթների իրականացման համար և համաձայն չեն տվյալների հասանելիության առանձնահատկությունների հետ:

Տվյալների բազան և օգտատերը միշտ չէ, որ պայմանավորվում են, թե ինչ անել

Տվյալների բազաների հիմնական առանձնահատկություններից մեկը կատարման կարգի երաշխիքն է, սակայն այս հրամանն ինքնին կարող է թափանցիկ չլինել ծրագրաշարի մշակողի համար: Տվյալների շտեմարանները գործարքներն իրականացնում են իրենց ստացման հաջորդականությամբ, այլ ոչ թե ծրագրավորողների նախատեսած կարգով: Գործարքների կարգը դժվար է կանխատեսել, հատկապես բարձր բեռնված զուգահեռ համակարգերում:

Մշակման ընթացքում, հատկապես չարգելափակող գրադարանների հետ աշխատելիս, վատ ոճը և ցածր ընթեռնելիությունը կարող են պատճառ դառնալ, որ օգտատերերը հավատան, որ գործարքները կատարվում են հաջորդաբար, մինչդեռ իրականում դրանք կարող են ցանկացած կարգով հայտնվել տվյալների բազա:

Առաջին հայացքից ստորև բերված ծրագրում T1-ը և T2-ը կոչվում են հաջորդաբար, բայց եթե այդ գործառույթները չեն արգելափակում և անմիջապես վերադարձնում են արդյունքը ձևով. խոստում, ապա զանգերի հերթականությունը կորոշվի տվյալների բազա մուտք գործելու պահերով.

result1 = T1() // իրական արդյունքները խոստումներ են
արդյունք 2 = T2 ()

Եթե ​​պահանջվում է ատոմականություն (այսինքն՝ կամ բոլոր գործողությունները պետք է ավարտվեն կամ ընդհատվեն) և հաջորդականությունը, ապա T1 և T2 գործողությունները պետք է կատարվեն մեկ գործարքի շրջանակներում:

Հավելվածի մակարդակի համօգտագործումը կարող է տեղափոխվել հավելվածից դուրս

Sharding-ը տվյալների բազայի հորիզոնական բաժանման մեթոդ է: Որոշ տվյալների բազաներ կարող են ավտոմատ կերպով բաժանել տվյալները հորիզոնական, իսկ մյուսները չեն կարող կամ այնքան էլ լավ չեն դրանում: Երբ տվյալների ճարտարապետները/մշակողները կարողանում են ճշգրիտ կանխատեսել, թե ինչպես են մուտք գործելու տվյալներ, նրանք կարող են ստեղծել հորիզոնական միջնորմներ օգտագործողի տարածքում՝ այս աշխատանքը տվյալների շտեմարան պատվիրակելու փոխարեն: Այս գործընթացը կոչվում է «հավելվածի մակարդակի փոխանակում» (հավելվածի մակարդակի փոխանակում).

Ցավոք սրտի, այս անունը հաճախ թյուր պատկերացում է ստեղծում, որ sharding-ը ապրում է հավելվածների ծառայություններում: Փաստորեն, այն կարող է իրականացվել որպես առանձին շերտ տվյալների բազայի դիմաց: Կախված տվյալների աճից և սխեմայի կրկնություններից՝ փոխանակման պահանջները կարող են բավականին բարդ դառնալ: Որոշ ռազմավարություններ կարող են օգուտ քաղել առանց հավելվածի սերվերների վերաբաշխման կրկնելու կարողությունից:

Ավելի շատ մշակողներ պետք է իմանան սա տվյալների բազաների մասին
Ճարտարապետության օրինակ, որտեղ հավելվածի սերվերները բաժանված են փոխանակման ծառայությունից

Տարբերակումը առանձին ծառայության մեջ տեղափոխելը ընդլայնում է փոխանակման տարբեր ռազմավարություններ օգտագործելու հնարավորությունը՝ առանց հավելվածների վերատեղակայման անհրաժեշտության: Vitess կիրառական մակարդակում նման համօգտագործման համակարգի օրինակ է: Vitess-ն ապահովում է MySQL-ի հորիզոնական հղկում և թույլ է տալիս հաճախորդներին միանալ դրան MySQL արձանագրության միջոցով: Համակարգը տվյալները բաժանում է տարբեր MySQL հանգույցների, որոնք միմյանց մասին ոչինչ չգիտեն:

Ինքնաբարձրացումը կարող է վտանգավոր լինել

AUTOINCREMENT-ը հիմնական բանալիներ ստեղծելու սովորական միջոց է: Հաճախ լինում են դեպքեր, երբ տվյալների բազաները օգտագործվում են որպես ID գեներատորներ, և տվյալների բազան պարունակում է աղյուսակներ, որոնք նախատեսված են նույնացուցիչներ ստեղծելու համար: Կան մի քանի պատճառ, թե ինչու առաջնային բանալիներ ստեղծելը, օգտագործելով ավտոմատ աճը, հեռու է իդեալական լինելուց.

  • Բաշխված տվյալների բազայում ավտոմատ ավելացումը լուրջ խնդիր է: ID-ն ստեղծելու համար անհրաժեշտ է գլոբալ կողպեք: Փոխարենը, դուք կարող եք ստեղծել UUID. սա չի պահանջում տվյալների բազայի տարբեր հանգույցների միջև փոխազդեցություն: Կողպեքների հետ ավտոմատ ավելացումը կարող է հանգեցնել վեճի և զգալիորեն նվազեցնել ներդիրների աշխատանքը բաշխված իրավիճակներում: Որոշ DBMS-ներ (օրինակ՝ MySQL) կարող են պահանջել հատուկ կոնֆիգուրացիա և ավելի ուշադիր ուշադրություն՝ Master-Master Replication-ը ճիշտ կազմակերպելու համար: Եվ կարգավորելիս հեշտ է սխալներ թույլ տալ, ինչը կհանգեցնի ձայնագրման ձախողումների:
  • Որոշ տվյալների բազաներ ունեն բաժանման ալգորիթմներ՝ հիմնված առաջնային բանալիների վրա: Անընդհատ ID-ները կարող են հանգեցնել անկանխատեսելի թեժ կետերի և որոշ միջնապատերի բեռի ավելացման, մինչդեռ մյուսները մնում են անգործուն:
  • Առաջնային բանալին տվյալների բազայում տող մուտք գործելու ամենաարագ ճանապարհն է: Գրառումները նույնականացնելու ավելի լավ եղանակներով, հաջորդական ID-ները կարող են աղյուսակների ամենակարևոր սյունակը վերածել անիմաստ արժեքներով լցված անօգուտ սյունակի: Հետևաբար, հնարավորության դեպքում, խնդրում ենք ընտրել գլոբալ եզակի և բնական առաջնային բանալի (օրինակ՝ օգտվողի անուն):

Մոտեցման վերաբերյալ որոշում կայացնելուց առաջ հաշվի առեք ID-ների և UUID-ների ավտոմատ ավելացման ազդեցությունը ինդեքսավորման, բաժանման և բաժանման վրա:

Հնացած տվյալները կարող են օգտակար լինել և չպահանջել կողպում

Multiversion Concurrency Control (MVCC) իրականացնում է հետևողականության պահանջներից շատերը, որոնք համառոտ քննարկվել են վերևում: Որոշ տվյալների բազաներ (օրինակ՝ Postgres, Spanner) օգտագործում են MVCC՝ «սնուցելու» գործարքները snapshot-ներով՝ տվյալների բազայի ավելի հին տարբերակներով: Snapshot գործարքները կարող են նաև սերիականացվել՝ հետևողականություն ապահովելու համար: Հին լուսանկարից կարդալիս կարդացվում են հնացած տվյալները:

Թեթևակի հնացած տվյալների ընթերցումը կարող է օգտակար լինել, օրինակ՝ տվյալների հիման վրա վերլուծություններ ստեղծելիս կամ մոտավոր համախառն արժեքները հաշվարկելիս:

Հնացած տվյալների հետ աշխատելու առաջին առավելությունը ցածր ուշացումն է (հատկապես, եթե տվյալների բազան բաշխված է տարբեր աշխարհագրություններով): Երկրորդն այն է, որ միայն կարդալու գործարքներն առանց կողպման են: Սա զգալի առավելություն է այն հավելվածների համար, որոնք շատ են կարդում, քանի դեռ նրանք կարող են կառավարել հնացած տվյալները:

Ավելի շատ մշակողներ պետք է իմանան սա տվյալների բազաների մասին
Հավելվածի սերվերը կարդում է տեղական կրկնօրինակի տվյալները, որոնք 5 վայրկյան հնացած են, նույնիսկ եթե վերջին տարբերակը հասանելի է Խաղաղ օվկիանոսի մյուս կողմում:

DBMS-ները ավտոմատ կերպով մաքրում են հին տարբերակները և, որոշ դեպքերում, թույլ են տալիս դա անել ըստ պահանջի: Օրինակ, Postgres-ը թույլ է տալիս օգտվողներին անել VACUUM խնդրանքով, ինչպես նաև պարբերաբար ավտոմատ կերպով կատարում է այս գործողությունը: Spanner-ն աշխատում է աղբահանող՝ մեկ ժամից ավելի հին լուսանկարներից ազատվելու համար:

Ժամանակի ցանկացած աղբյուր ենթակա է խեղաթյուրման

Համակարգչային գիտության մեջ ամենալավ պահված գաղտնիքն այն է, որ բոլոր ժամանակային API-ները ստում են: Փաստորեն, մեր մեքենաները չգիտեն ճշգրիտ ընթացիկ ժամանակը: Համակարգիչները պարունակում են քվարց բյուրեղներ, որոնք առաջացնում են թրթռումներ, որոնք օգտագործվում են ժամանակ պահելու համար: Այնուամենայնիվ, դրանք բավականաչափ ճշգրիտ չեն և կարող են ճշգրիտ ժամանակից առաջ/հետ մնալ: Հերթափոխը կարող է հասնել օրական 20 վայրկյանի: Հետևաբար, մեր համակարգիչների ժամանակը պետք է պարբերաբար համաժամանակացվի ցանցայինի հետ:

NTP սերվերները օգտագործվում են համաժամացման համար, սակայն համաժամացման գործընթացն ինքնին ենթակա է ցանցային ուշացումների: Նույնիսկ նույն տվյալների կենտրոնում NTP սերվերի հետ համաժամացումը որոշ ժամանակ է պահանջում: Հասկանալի է, որ հանրային NTP սերվերի հետ աշխատելը կարող է հանգեցնել էլ ավելի մեծ աղավաղման:

Ատոմային ժամացույցները և դրանց GPS-ի նմանակները ավելի լավն են ընթացիկ ժամանակը որոշելու համար, բայց դրանք թանկ են և պահանջում են բարդ կարգավորում, ուստի դրանք չեն կարող տեղադրվել յուրաքանչյուր մեքենայի վրա: Դրա պատճառով տվյալների կենտրոնները օգտագործում են աստիճանավոր մոտեցում: Ատոմային և/կամ GPS ժամացույցները ցույց են տալիս ճշգրիտ ժամանակը, որից հետո այն հեռարձակվում է այլ մեքենաների վրա երկրորդական սերվերների միջոցով: Սա նշանակում է, որ յուրաքանչյուր մեքենա կունենա որոշակի փոխհատուցում ճշգրիտ ժամանակից:

Իրավիճակը բարդանում է նրանով, որ հավելվածները և տվյալների բազաները հաճախ տեղակայված են տարբեր մեքենաների վրա (եթե ոչ տարբեր տվյալների կենտրոններում): Այսպիսով, ժամանակը կտարբերվի ոչ միայն տարբեր մեքենաների վրա բաշխված DB հանգույցների վրա: Այն նաև տարբեր կլինի հավելվածի սերվերում:

Google TrueTime-ը բոլորովին այլ մոտեցում է ցուցաբերում: Մարդկանց մեծամասնությունը կարծում է, որ Google-ի առաջընթացն այս ուղղությամբ բացատրվում է ատոմային և GPS ժամացույցների սովորական անցումով, բայց սա մեծ պատկերի միայն մի մասն է: Ահա թե ինչպես է աշխատում TrueTime-ը.

  • TrueTime-ն օգտագործում է երկու տարբեր աղբյուրներ՝ GPS և ատոմային ժամացույցներ: Այս ժամացույցներն ունեն ոչ փոխկապակցված ձախողման ռեժիմներ: [Տես էջ 5 մանրամասների համար այստեղ - մոտ. թարգմ.), ուստի դրանց համատեղ օգտագործումը մեծացնում է հուսալիությունը։
  • TrueTime-ն ունի անսովոր API: Այն վերադարձնում է ժամանակը որպես ինտերվալ՝ չափման սխալով և դրա մեջ ներկառուցված անորոշությամբ: Ժամանակի իրական պահը գտնվում է միջակայքի վերին և ստորին սահմանների միջև: Spanner-ը՝ Google-ի բաշխված տվյալների բազան, պարզապես սպասում է, մինչև ապահով լինի ասել, որ ընթացիկ ժամանակը դուրս է տիրույթից: Այս մեթոդը որոշակի ուշացում է մտցնում համակարգում, հատկապես, եթե վարպետների վրա անորոշությունը բարձր է, բայց ապահովում է կոռեկտություն նույնիսկ գլոբալ բաշխված իրավիճակում:

Ավելի շատ մշակողներ պետք է իմանան սա տվյալների բազաների մասին
Spanner բաղադրիչներն օգտագործում են TrueTime, որտեղ TT.now()-ը վերադարձնում է ինտերվալը, հետևաբար, Spanner-ը պարզապես քնում է մինչև այն կետը, որտեղ կարող է վստահ լինել, որ ընթացիկ ժամանակը անցել է որոշակի կետ:

Ընթացիկ ժամանակի որոշման կրճատված ճշգրտությունը նշանակում է Spanner-ի գործողությունների տևողության ավելացում և կատարողականի նվազում: Ահա թե ինչու է կարևոր պահպանել հնարավոր առավելագույն ճշգրտությունը, թեև անհնար է ձեռք բերել լիովին ճշգրիտ ժամացույց:

Ուշացումը շատ իմաստներ ունի

Եթե ​​մի տասնյակ փորձագետների հարցնեք, թե ինչ է ուշացումը, հավանաբար տարբեր պատասխաններ կստանաք։ DBMS-ում ուշացումը հաճախ կոչվում է «տվյալների բազայի ուշացում» և տարբերվում է հաճախորդի կողմից ընկալվողից: Փաստն այն է, որ հաճախորդը դիտում է ցանցի ուշացման և տվյալների բազայի հետաձգման գումարը: Լատենտության տեսակը մեկուսացնելու ունակությունը կարևոր է աճող խնդիրների վրիպազերծման ժամանակ: Չափումներ հավաքելիս և ցուցադրելիս միշտ փորձեք հետևել երկու տեսակին էլ:

Կատարման պահանջները պետք է գնահատվեն կոնկրետ գործարքի համար

Երբեմն DBMS-ի կատարողական բնութագրերը և դրա սահմանափակումները սահմանվում են գրելու/ընթերցվելու թողունակության և հետաձգման առումով: Սա ապահովում է համակարգի հիմնական պարամետրերի ընդհանուր ակնարկ, սակայն նոր DBMS-ի կատարողականը գնահատելիս շատ ավելի համապարփակ մոտեցում է կարևորագույն գործողությունների առանձին գնահատումը (յուրաքանչյուր հարցման և/կամ գործարքի համար): Օրինակներ.

  • Գրեք թողունակությունը և հետաձգումը X աղյուսակում (50 միլիոն տողով) նոր տող տեղադրելիս համապատասխան աղյուսակներում նշված սահմանափակումներով և տողերի լրացմամբ:
  • Որոշակի օգտվողի ընկերների ընկերների ցուցադրման հետաձգում, երբ ընկերների միջին թիվը 500 է:
  • Օգտատերերի պատմությունից 100 լավագույն գրառումները ստանալու հետաձգման հետաձգում, երբ օգտատերը ժամում X գրառումներով հետևում է 500 այլ օգտատերերի:

Գնահատումը և փորձարկումը կարող են ներառել նման կարևոր դեպքեր, քանի դեռ չեք վստահել, որ տվյալների բազան համապատասխանում է կատարողականի պահանջներին: Նմանատիպ գործնական կանոնը նաև հաշվի է առնում այս տարանջատումը հապաղման ցուցանիշները հավաքելիս և SLO-ները որոշելիս:

Տեղյակ եղեք բարձր կարդինալության մասին յուրաքանչյուր գործողության համար չափումներ հավաքելիս: Օգտագործեք տեղեկամատյաններ, իրադարձությունների հավաքագրում կամ բաշխված հետագծում՝ վրիպազերծման մեծ հզորության տվյալներ ստանալու համար: Հոդվածում «Ցանկանու՞մ եք վրիպազերծել ուշացումը:» Դուք կարող եք ծանոթանալ հետաձգման կարգաբերման մեթոդոլոգիաներին:

Ներդրված գործարքները կարող են վտանգավոր լինել

Ոչ բոլոր DBMS-ներն են աջակցում ներկառուցված գործարքներին, բայց երբ դրանք աջակցում են, այդպիսի գործարքները կարող են հանգեցնել անսպասելի սխալների, որոնք միշտ չէ, որ հեշտ է հայտնաբերել (այսինքն՝ ակնհայտ պետք է լինի, որ ինչ-որ անոմալիա կա):

Դուք կարող եք խուսափել ներդրված գործարքների օգտագործումից՝ օգտագործելով հաճախորդների գրադարանները, որոնք կարող են հայտնաբերել և շրջանցել դրանք: Եթե ​​ներկառուցված գործարքներից հնարավոր չէ հրաժարվել, հատուկ զգույշ եղեք դրանց իրականացման ժամանակ, որպեսզի խուսափեք անսպասելի իրավիճակներից, երբ ավարտված գործարքները պատահաբար ընդհատվում են ներկառուցված գործարքների պատճառով:

Տարբեր շերտերում գործարքների ամփոփումը կարող է հանգեցնել անսպասելի ներդիր գործարքների, իսկ կոդերի ընթեռնելիության տեսանկյունից դա կարող է դժվարացնել հեղինակի մտադրությունները հասկանալը: Նայեք հետևյալ ծրագրին.

with newTransaction():
   Accounts.create("609-543-222")
   with newTransaction():
       Accounts.create("775-988-322")
       throw Rollback();

Ո՞րն է լինելու վերը նշված ծածկագրի արդյունքը: Արդյո՞ք այն հետ կվերցնի երկու գործարքները, թե՞ պարզապես ներքինը: Ի՞նչ է պատահում, եթե մենք ապավինենք գրադարանների մի քանի շերտերին, որոնք ներառում են մեզ համար գործարքների ստեղծումը: Կկարողանա՞նք բացահայտել և բարելավել նման դեպքերը։

Պատկերացրեք տվյալների շերտը մի քանի գործողություններով (օրինակ. newAccount) արդեն իսկ իրականացվել է սեփական գործարքներում: Ի՞նչ կլինի, եթե դրանք գործարկեք որպես ավելի բարձր մակարդակի բիզնես տրամաբանության մի մաս, որը գործում է իր իսկ գործարքի շրջանակներում: Ինչպիսի՞ն կլիներ մեկուսացումը և հետևողականությունը այս դեպքում։

function newAccount(id string) {
  with newTransaction():
      Accounts.create(id)
}

Նման անվերջ հարցերի պատասխանները փնտրելու փոխարեն ավելի լավ է խուսափել ներդիր գործարքներից։ Ի վերջո, ձեր տվյալների շերտը կարող է հեշտությամբ կատարել բարձր մակարդակի գործողություններ՝ առանց սեփական գործարքներ ստեղծելու: Բացի այդ, բիզնես տրամաբանությունն ինքնին ընդունակ է գործարք սկսել, դրա վրա գործողություններ կատարել, գործարք կատարել կամ ընդհատել:

function newAccount(id string) {
   Accounts.create(id)
}
// In main application:
with newTransaction():
   // Read some data from database for configuration.
   // Generate an ID from the ID service.
   Accounts.create(id)
   Uploads.create(id) // create upload queue for the user.

Գործարքները չպետք է կապված լինեն կիրառման վիճակի հետ

Երբեմն գայթակղիչ է օգտագործել հավելվածի վիճակը գործարքներում՝ որոշակի արժեքներ փոխելու կամ հարցումների պարամետրերը կսմթելու համար: Քննարկվող կարևորագույն նրբերանգը կիրառման ճիշտ շրջանակն է: Հաճախորդները հաճախ վերսկսում են գործարքները, երբ առկա են ցանցային խնդիրներ: Եթե ​​գործարքն այնուհետև կախված է մի վիճակից, որը փոխվում է որևէ այլ գործընթացի միջոցով, այն կարող է ընտրել սխալ արժեքը՝ կախված տվյալների մրցավազքի հնարավորությունից: Գործարքները պետք է հաշվի առնեն հավելվածում տվյալների մրցավազքի պայմանների ռիսկը:

var seq int64
with newTransaction():
    newSeq := atomic.Increment(&seq)
    Entries.query(newSeq)
    // Other operations...

Վերոնշյալ գործարքը կավելացնի հաջորդականության համարը ամեն անգամ, երբ այն կատարվում է, անկախ վերջնական արդյունքից: Եթե ​​կատարումը ձախողվի ցանցի խնդիրների պատճառով, հարցումը կկատարվի այլ հաջորդական համարով, երբ նորից փորձեք:

Հարցումների պլանավորողները կարող են ձեզ շատ բան պատմել տվյալների բազայի մասին

Հարցման պլանավորողները որոշում են, թե ինչպես է հարցումը կատարվելու տվյալների բազայում: Նրանք նաև վերլուծում են հարցումները և օպտիմալացնում դրանք նախքան դրանք ուղարկելը: Պլանավորողները կարող են միայն որոշ հնարավոր գնահատականներ տրամադրել՝ հիմնվելով իրենց տրամադրության տակ եղած ազդանշանների վրա: Օրինակ, ո՞րն է որոնման լավագույն մեթոդը հետևյալ հարցման համար:

SELECT * FROM articles where author = "rakyll" order by title;

Արդյունքները կարելի է ստանալ երկու եղանակով.

  • Սեղանի ամբողջական սկանավորումԴուք կարող եք դիտել աղյուսակի յուրաքանչյուր գրառում և հոդվածներ վերադարձնել համապատասխան հեղինակի անունով, այնուհետև պատվիրել դրանք:
  • Ինդեքսային սկանավորումԴուք կարող եք օգտագործել ինդեքսը՝ համապատասխան ID-ներ գտնելու, այդ տողերը ստանալու և այնուհետև դրանք պատվիրելու համար:

Հարցման պլանավորողի խնդիրն է որոշել, թե որ ռազմավարությունն է լավագույնը: Արժե հաշվի առնել, որ հարցումների պլանավորողները միայն սահմանափակ կանխատեսման հնարավորություններ ունեն: Սա կարող է հանգեցնել վատ որոշումների: DBA-ները կամ մշակողները կարող են դրանք օգտագործել՝ թերակատարվող հարցումները ախտորոշելու և ճշգրտելու համար: DBMS-ի նոր տարբերակները կարող են կարգավորել հարցումների պլանավորողները, և ինքնաախտորոշումը կարող է օգնել տվյալների բազան թարմացնելիս, եթե նոր տարբերակը հանգեցնի կատարողականի խնդիրների: Դանդաղ հարցումների տեղեկամատյանները, հետաձգման խնդիրների մասին հաշվետվությունները կամ կատարման ժամանակի վիճակագրությունը կարող են օգնել բացահայտելու օպտիմալացման կարիք ունեցող հարցումները:

Հարցման պլանավորողի կողմից ներկայացված որոշ չափումներ կարող են ենթարկվել աղմուկի (հատկապես ուշացման կամ պրոցեսորի ժամանակը գնահատելիս): Ժամանակացույցների լավ հավելումը կատարման ուղին հետագծելու և հետևելու գործիքներն են: Նրանք թույլ են տալիս ախտորոշել նման խնդիրները (ավաղ, ոչ բոլոր DBMS-ներն են տալիս նման գործիքներ):

Առցանց միգրացիան դժվար է, բայց հնարավոր

Առցանց միգրացիան, կենդանի միգրացիան կամ իրական ժամանակի միգրացիան նշանակում է մի տվյալների բազայից մյուսը տեղափոխել առանց ժամանակի կամ տվյալների կոռուպցիայի: Կենդանի միգրացիան ավելի հեշտ է իրականացնել, եթե անցումը տեղի է ունենում նույն DBMS/շարժիչում: Իրավիճակն ավելի է բարդանում, երբ անհրաժեշտ է անցնել նոր DBMS՝ տարբեր կատարողականի և սխեմայի պահանջներով:

Կան առցանց միգրացիայի տարբեր մոդելներ: Ահա դրանցից մեկը.

  • Միացնել կրկնակի մուտքագրումը երկու տվյալների բազայում: Նոր տվյալների բազան այս փուլում չունի բոլոր տվյալները, այլ ընդունում է միայն վերջին տվյալները։ Երբ համոզվեք դրանում, կարող եք անցնել հաջորդ քայլին:
  • Միացնել ընթերցումը երկու տվյալների բազաներից:
  • Կազմաձևեք համակարգը այնպես, որ կարդալն ու գրելը հիմնականում կատարվեն նոր տվյալների բազայում:
  • Դադարեցրեք գրել հին տվյալների բազայում՝ շարունակելով կարդալ տվյալները: Այս փուլում նոր տվյալների բազան դեռ զուրկ է որոշ տվյալներից։ Դրանք պետք է պատճենվեն հին տվյալների բազայից:
  • Հին տվյալների բազան միայն կարդալու է: Բացակայող տվյալները պատճենեք հին տվյալների բազայից նորը: Միգրացիայի ավարտից հետո անցեք ուղիները դեպի նոր տվյալների բազա, դադարեցրեք հինը և ջնջեք այն համակարգից:

Լրացուցիչ տեղեկությունների համար խորհուրդ եմ տալիս կապ հաստատել Հոդված, որը մանրամասնում է Stripe-ի միգրացիոն ռազմավարությունը՝ հիմնված այս մոդելի վրա։

Տվյալների բազայի զգալի աճը ենթադրում է անկանխատեսելիության աճ

Տվյալների բազայի աճը հանգեցնում է անկանխատեսելի խնդիրների՝ կապված դրա մասշտաբների հետ: Որքան ավելի շատ գիտենք տվյալների բազայի ներքին կառուցվածքի մասին, այնքան ավելի լավ կարող ենք կանխատեսել, թե ինչպես է այն մասշտաբավորվելու: Այնուամենայնիվ, որոշ պահեր դեռևս անհնար է կանխատեսել։
Քանի որ բազան մեծանում է, տվյալների ծավալի և ցանցի թողունակության պահանջների վերաբերյալ նախկին ենթադրություններն ու ակնկալիքները կարող են հնացած դառնալ: Սա այն դեպքում, երբ հարց է ծագում նախագծման հիմնական վերանորոգման, լայնածավալ գործառնական բարելավումների, տեղակայման վերանայման կամ այլ DBMS-ներ տեղափոխման մասին՝ հնարավոր խնդիրներից խուսափելու համար:

Բայց մի կարծեք, որ առկա տվյալների բազայի ներքին կառուցվածքի գերազանց իմացությունը միակ բանն է, որ անհրաժեշտ է։ Նոր կշեռքներն իրենց հետ կբերեն նոր անհայտներ։ Անկանխատեսելի ցավի կետերը, տվյալների անհավասար բաշխումը, անսպասելի թողունակությունը և ապարատային խնդիրները, անընդհատ աճող երթևեկությունը և ցանցի նոր հատվածները կստիպեն ձեզ վերանայել ձեր տվյալների բազայի մոտեցումը, տվյալների մոդելը, տեղակայման մոդելը և տվյալների բազայի չափը:

...

Այն ժամանակ, երբ ես սկսեցի մտածել այս հոդվածը հրապարակելու մասին, իմ սկզբնական ցուցակում արդեն կար ևս հինգ կետ: Հետո եկավ ահռելի թիվ նոր գաղափարներ այն մասին, թե ուրիշ ինչ կարելի է լուսաբանել: Ուստի հոդվածում անդրադառնում են առավելագույն ուշադրություն պահանջող ամենաքիչ ակնհայտ խնդիրներին։ Սակայն դա չի նշանակում, որ թեման սպառվել է, և ես այլևս չեմ վերադառնա դրան իմ հետագա նյութերում և փոփոխություններ չեմ անելու ընթացիկի մեջ։

PS

Կարդացեք նաև մեր բլոգում.

Source: www.habr.com

Добавить комментарий