NewSQL = NoSQL + ACID

NewSQL = NoSQL + ACID
Մինչև վերջերս Odnoklassniki-ն SQL Server-ում պահում էր իրական ժամանակում մշակված մոտ 50 ՏԲ տվյալ։ Նման ծավալի համար գրեթե անհնար է ապահովել արագ և հուսալի և նույնիսկ տվյալների կենտրոնի խափանումներին հանդուրժող մուտք՝ օգտագործելով SQL DBMS: Սովորաբար, նման դեպքերում օգտագործվում է NoSQL պահեստներից մեկը, բայց ամեն ինչ չէ, որ կարող է փոխանցվել NoSQL. որոշ կազմակերպություններ պահանջում են ACID գործարքների երաշխիքներ:

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

Ինչպես է այն աշխատում և ինչ է տեղի ունեցել, կարդացեք կտրվածքի տակ:

Այսօր Odnoklassniki-ի ամսական լսարանը կազմում է ավելի քան 70 միլիոն եզակի այցելու։ Մենք Մենք առաջին հնգյակում ենք աշխարհի ամենամեծ սոցիալական ցանցերը և այն քսան կայքերի շարքում, որոնցում օգտատերերն ամենաշատ ժամանակն են անցկացնում: OK ենթակառուցվածքը մշակում է շատ մեծ բեռներ՝ ավելի քան մեկ միլիոն HTTP հարցում/վրկ մեկ ճակատում: Ավելի քան 8000 կտորից բաղկացած սերվերային նավատորմի մասերը տեղակայված են միմյանց մոտ՝ Մոսկվայի չորս տվյալների կենտրոններում, ինչը հնարավորություն է տալիս ապահովել ցանցի ուշացում 1 մվ-ից պակաս նրանց միջև:

Մենք Cassandra-ն օգտագործում ենք 2010 թվականից՝ սկսած 0.6 տարբերակից։ Այսօր գործում են մի քանի տասնյակ կլաստերներ։ Ամենաարագ կլաստերը վայրկյանում ավելի քան 4 միլիոն գործողություն է մշակում, իսկ ամենամեծը պահում է 260 ՏԲ:

Այնուամենայնիվ, սրանք բոլորը սովորական NoSQL կլաստերներ են, որոնք օգտագործվում են պահեստավորման համար թույլ համակարգված տվյալները։ Մենք ցանկանում էինք փոխարինել հիմնական հետևողական պահեստը՝ Microsoft SQL Server-ը, որն օգտագործվում էր Odnoklassniki-ի հիմնադրման օրվանից: Պահեստը բաղկացած էր ավելի քան 300 SQL Server Standard Edition մեքենաներից, որոնք պարունակում էին 50 ՏԲ տվյալներ՝ բիզնես սուբյեկտներ: Այս տվյալները փոփոխվում են որպես ACID գործարքների մաս և պահանջում են բարձր հետևողականություն.

Տվյալները SQL Server հանգույցներում բաշխելու համար մենք օգտագործեցինք ինչպես ուղղահայաց, այնպես էլ հորիզոնական բաժանում (շարդինգ): Պատմականորեն մենք օգտագործում էինք տվյալների փոխանակման պարզ սխեմա. յուրաքանչյուր կազմակերպություն կապված էր նշանի հետ՝ անձի ID-ի ֆունկցիան: Նույն նշանով սուբյեկտները տեղադրվել են նույն SQL սերվերի վրա: Վարպետ-դետալ հարաբերությունն իրականացվել է այնպես, որ հիմնական և երկրորդ գրառումների նշանները միշտ համընկնում են և գտնվում են նույն սերվերում: Սոցիալական ցանցում գրեթե բոլոր գրառումները ստեղծվում են օգտագործողի անունից, ինչը նշանակում է, որ մեկ ֆունկցիոնալ ենթահամակարգում օգտագործողի բոլոր տվյալները պահվում են մեկ սերվերի վրա: Այսինքն՝ բիզնես գործարքը գրեթե միշտ ներառում է աղյուսակներ մեկ SQL սերվերից, ինչը հնարավորություն է տալիս ապահովել տվյալների հետևողականությունը՝ օգտագործելով տեղական ACID գործարքները՝ առանց օգտագործման անհրաժեշտության։ դանդաղ և անվստահելի բաշխված ACID գործարքներ.

Sharding-ի և SQL-ի արագացման շնորհիվ.

  • Մենք չենք օգտագործում օտարերկրյա բանալիների սահմանափակումներ, քանի որ փոխանակման ժամանակ կազմակերպության ID-ն կարող է տեղակայվել մեկ այլ սերվերի վրա:
  • Մենք չենք օգտագործում պահված ընթացակարգեր և գործարկիչներ՝ DBMS պրոցեսորի վրա լրացուցիչ ծանրաբեռնվածության պատճառով:
  • Մենք չենք օգտագործում JOIN-ներ վերը նշված բոլորի և սկավառակից շատ պատահական ընթերցումների պատճառով:
  • Գործարքից դուրս մենք օգտագործում ենք Read Uncommitted մեկուսացման մակարդակը՝ փակուղիները նվազեցնելու համար:
  • Մենք կատարում ենք միայն կարճ գործարքներ (միջինում ավելի կարճ, քան 100 ms):
  • Մենք չենք օգտագործում բազմաշարք UPDATE և DELETE փակուղիների մեծ քանակի պատճառով. մենք միաժամանակ թարմացնում ենք միայն մեկ գրառում:
  • Մենք միշտ հարցումներ ենք կատարում միայն ինդեքսների վրա. աղյուսակի ամբողջական սկանավորման պլանով հարցումը մեզ համար նշանակում է տվյալների բազայի գերբեռնում և դրա ձախողման պատճառ:

Այս քայլերը թույլ տվեցին մեզ սեղմել SQL սերվերներից գրեթե առավելագույն կատարումը: Սակայն խնդիրներն ավելի ու ավելի շատ էին դառնում։ Եկեք նայենք նրանց:

SQL-ի հետ կապված խնդիրներ

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

Բայց հիմնական խնդիրն այն է

սխալների հանդուրժողականություն

Դասական SQL սերվերը սխալ հանդուրժողականություն ունի: Ենթադրենք, դուք ունեք տվյալների բազայի միայն մեկ սերվեր, և այն խափանում է երեք տարին մեկ անգամ: Այս ընթացքում կայքը չի աշխատում 20 րոպեով, ինչը ընդունելի է: Եթե ​​ունեք 64 սերվեր, ապա կայքը երեք շաբաթը մեկ խափանում է։ Իսկ եթե ունես 200 սերվեր, ուրեմն կայքը ամեն շաբաթ չի աշխատում։ Սա խնդիր է։

Ի՞նչ կարելի է անել SQL սերվերի սխալների հանդուրժողականությունը բարելավելու համար: Վիքիպեդիան մեզ հրավիրում է կառուցել բարձր հասանելի կլաստերորտեղ բաղադրիչներից որևէ մեկի խափանման դեպքում կա պահեստային:

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

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

Դրա համար մենք կարող էինք օգտագործել Multi-Master SQL Server-ում ներկառուցված կրկնօրինակում: Այս լուծումը շատ ավելի թանկ է ծրագրային ապահովման արժեքի պատճառով և տառապում է վերարտադրման հետ կապված հայտնի խնդիրներից՝ անկանխատեսելի գործարքների հետաձգումներ համաժամանակյա վերարտադրմամբ և կրկնօրինակումների կիրառման հետաձգում (և, որպես հետևանք, կորցրած փոփոխություններ) ասինխրոն կրկնօրինակմամբ: Ենթարկվողը կոնֆլիկտների ձեռքով լուծում այս տարբերակը մեզ համար լիովին անկիրառելի է դարձնում:

Այս բոլոր խնդիրները պահանջում էին արմատական ​​լուծում, և մենք սկսեցինք մանրամասն վերլուծել դրանք։ Այստեղ պետք է ծանոթանանք, թե հիմնականում ինչ է անում SQL Server-ը՝ գործարքները։

Պարզ գործարք

Դիտարկենք ամենապարզ գործարքը՝ կիրառական SQL ծրագրավորողի տեսանկյունից՝ ալբոմում լուսանկար ավելացնելը։ Ալբոմները և լուսանկարները պահվում են տարբեր ափսեներում: Ալբոմն ունի հանրային լուսանկարների հաշվիչ: Այնուհետև նման գործարքը բաժանվում է հետևյալ քայլերի.

  1. Մենք արգելափակում ենք ալբոմը բանալիով։
  2. Ստեղծեք գրառում լուսանկարների աղյուսակում:
  3. Եթե ​​լուսանկարն ունի հանրային կարգավիճակ, ապա ալբոմում ավելացրեք հանրային լուսանկարների հաշվիչ, թարմացրեք գրառումը և կատարեք գործարքը:

Կամ կեղծ կոդով.

TX.start("Albums", id);
Album album = albums.lock(id);
Photo photo = photos.create(…);

if (photo.status == PUBLIC ) {
    album.incPublicPhotosCount();
}
album.update();

TX.commit();

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

Գործարքն իրականացնելիս կարող է տեղի ունենալ մեկ այլ համակարգից նույն տվյալների միաժամանակյա փոփոխություն: Օրինակ, Antispam-ը կարող է որոշել, որ օգտատերը ինչ-որ կերպ կասկածելի է, և, հետևաբար, օգտատիրոջ բոլոր լուսանկարներն այլևս չպետք է լինեն հրապարակային, դրանք պետք է ուղարկվեն չափավորության, ինչը նշանակում է փոխել photo.status-ը որևէ այլ արժեքի և անջատել համապատասխան հաշվիչներ: Ակնհայտ է, որ եթե այս գործողությունը տեղի է ունենում առանց կիրառման ատոմականության երաշխիքների և մրցակցային փոփոխությունների մեկուսացման, ինչպես ACID, ապա արդյունքը չի լինի այն, ինչ անհրաժեշտ է՝ կա՛մ լուսանկարների հաշվիչը ցույց կտա սխալ արժեքը, կա՛մ ոչ բոլոր լուսանկարները կուղարկվեն չափավորության:

Նմանատիպ բազմաթիվ կոդեր, որոնք շահարկում են տարբեր բիզնես սուբյեկտներ մեկ գործարքի ընթացքում, գրվել են Odnoklassniki-ի ողջ գոյության ընթացքում: Հիմնվելով NoSQL-ից միգրացիայի փորձի վրա Վերջնական հետևողականություն Մենք գիտենք, որ ամենամեծ մարտահրավերը (և ժամանակի ներդրումը) գալիս է տվյալների հետևողականությունը պահպանելու համար կոդ մշակելուց: Հետևաբար, նոր պահեստավորման հիմնական պահանջը մենք համարեցինք կիրառական տրամաբանության համար իրական ACID գործարքների ապահովումը:

Այլ, ոչ պակաս կարևոր պահանջներն էին.

  • Եթե ​​տվյալների կենտրոնը ձախողվի, պետք է հասանելի լինեն և՛ կարդալը, և՛ գրելը նոր պահեստում:
  • Ընթացիկ զարգացման արագության պահպանում: Այսինքն՝ նոր պահեստի հետ աշխատելիս կոդի քանակը պետք է լինի մոտավորապես նույնը, պահեստում որևէ բան ավելացնելու, կոնֆլիկտների լուծման ալգորիթմներ մշակելու, երկրորդական ինդեքսների պահպանման և այլնի կարիք չկա։
  • Նոր պահեստավորման արագությունը պետք է բավականին բարձր լիներ, ինչպես տվյալների ընթերցման, այնպես էլ գործարքների մշակման ժամանակ, ինչը փաստորեն նշանակում էր, որ ակադեմիական խիստ, ունիվերսալ, բայց դանդաղ լուծումները, ինչպիսին, օրինակ, կիրառելի չէին: երկու փուլային պարտավորություններ.
  • Ինքնուրույն մասշտաբավորում:
  • Օգտագործելով սովորական էժան սերվերներ՝ առանց էկզոտիկ սարքավորումներ գնելու անհրաժեշտության:
  • Ընկերության մշակողների կողմից պահեստավորման զարգացման հնարավորությունը: Այսինքն՝ առաջնահերթությունը տրվել է սեփական կամ բաց կոդով լուծումներին, ցանկալի է՝ Java-ում։

Որոշումներ, որոշումներ

Վերլուծելով հնարավոր լուծումները՝ մենք հանգեցինք երկու հնարավոր ճարտարապետական ​​ընտրության.

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

Երկրորդ տարբերակն է՝ վերցնել պատրաստի NoSQL պահեստ՝ իրականացված մասշտաբով, ձախողման կլաստեր, կոնֆլիկտների լուծում և ինքնուրույն իրականացնել գործարքներ և SQL: Առաջին հայացքից նույնիսկ SQL-ի ներդրման խնդիրը, էլ չեմ խոսում ACID գործարքների մասին, կարծես խնդիր լինի, որը տարիներ կպահանջի։ Բայց հետո մենք հասկացանք, որ SQL գործառույթների հավաքածուն, որը մենք օգտագործում ենք գործնականում, նույնքան հեռու է ANSI SQL-ից Կասանդրա CQL հեռու ANSI SQL-ից: Ավելի մոտիկից նայելով CQL-ին, մենք հասկացանք, որ այն բավականին մոտ է մեզ անհրաժեշտին:

Կասանդրա և CQL

Այսպիսով, ի՞նչն է հետաքրքիր Կասանդրան, ի՞նչ հնարավորություններ ունի այն։

Նախ, այստեղ կարող եք ստեղծել աղյուսակներ, որոնք աջակցում են տվյալների տարբեր տեսակների, կարող եք կատարել SELECT կամ UPDATE հիմնական բանալիով:

CREATE TABLE photos (id bigint KEY, owner bigint,…);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET … WHERE id=?;

Կրկնօրինակների տվյալների հետևողականությունն ապահովելու համար Cassandra-ն օգտագործում է քվորումային մոտեցում. Ամենապարզ դեպքում դա նշանակում է, որ երբ նույն շարքի երեք կրկնօրինակները տեղադրվում են կլաստերի տարբեր հանգույցների վրա, գրումը համարվում է հաջող, եթե հանգույցների մեծ մասը (այսինքն՝ երեքից երկուսը) հաստատում են այս գրելու գործողության հաջողությունը։ . Շարքի տվյալները համարվում են համահունչ, եթե կարդալիս հանգույցների մեծամասնությունը հարցում է արվել և հաստատել դրանք: Այսպիսով, երեք կրկնօրինակներով, ամբողջական և ակնթարթային տվյալների հետևողականությունը երաշխավորված է, եթե մեկ հանգույց ձախողվի: Այս մոտեցումը մեզ թույլ տվեց իրականացնել ավելի հուսալի սխեմա. միշտ հարցումներ ուղարկեք բոլոր երեք կրկնօրինակներին՝ սպասելով պատասխանի երկու ամենաարագներից: Երրորդ կրկնօրինակի ուշ պատասխանն այս դեպքում անտեսվում է: Հանգույցը, որն ուշ է արձագանքում, կարող է լուրջ խնդիրներ ունենալ՝ արգելակներ, աղբի հավաքում JVM-ում, հիշողության ուղղակի վերականգնում Linux-ի միջուկում, ապարատային խափանում, ցանցից անջատում: Այնուամենայնիվ, դա որևէ կերպ չի ազդում հաճախորդի գործողությունների կամ տվյալների վրա:

Այն մոտեցումը, երբ մենք կապվում ենք երեք հանգույցների հետ և պատասխան ենք ստանում երկուսից, կոչվում է շահարկումներԼրացուցիչ կրկնօրինակների հարցումն ուղարկվում է նույնիսկ նախքան այն «ընկնելը»:

Cassandra-ի մեկ այլ առավելություն Batchlog-ն է՝ մեխանիզմ, որն ապահովում է, որ ձեր կատարած փոփոխությունների փաթեթը կամ ամբողջությամբ կիրառվի, կամ ընդհանրապես չկիրառվի: Սա թույլ է տալիս մեզ լուծել A ACID-ում` ատոմականությունը տուփից դուրս:

Կասանդրայում գործարքներին ամենամոտ բանը այսպես կոչված «թեթև գործարքներ«. Բայց դրանք հեռու են «իրական» ACID գործարքներից. իրականում սա անելու հնարավորություն է CAS միայն մեկ գրառումից ստացված տվյալների վրա՝ օգտագործելով կոնսենսուս՝ օգտագործելով ծանր քաշային Paxos արձանագրությունը: Հետեւաբար, նման գործարքների արագությունը ցածր է։

Այն, ինչ մեզ պակասում էր Կասանդրայում

Այսպիսով, մենք պետք է իրականացնեինք իրական ACID գործարքներ Կասանդրայում: Օգտագործելով այն, մենք կարող ենք հեշտությամբ կիրառել դասական DBMS-ի երկու այլ հարմար առանձնահատկություններ. հետևողական արագ ինդեքսներ, որոնք թույլ կտան մեզ տվյալների ընտրություն կատարել ոչ միայն հիմնական բանալիով, և միապաղաղ ավտոմատ աճող ID-ների կանոնավոր գեներատոր:

C* One

Այսպիսով ծնվեց նոր DBMS C* One, որը բաղկացած է երեք տեսակի սերվերային հանգույցներից.

  • Պահպանում – (գրեթե) ստանդարտ Cassandra սերվերներ, որոնք պատասխանատու են տեղական սկավառակների վրա տվյալների պահպանման համար: Տվյալների ծանրաբեռնվածության և ծավալի աճով, դրանց քանակը կարող է հեշտությամբ չափվել մինչև տասնյակ և հարյուրավոր:
  • Գործարքների համակարգողներ - ապահովում են գործարքների կատարումը.
  • Հաճախորդները կիրառական սերվերներ են, որոնք իրականացնում են բիզնես գործողություններ և նախաձեռնում են գործարքներ: Այդպիսի հաճախորդներ կարող են լինել հազարավոր։

NewSQL = NoSQL + ACID

Բոլոր տեսակի սերվերները ընդհանուր կլաստերի մի մասն են, օգտագործում են ներքին Cassandra հաղորդագրությունների արձանագրությունը միմյանց հետ շփվելու և բամբասանք կլաստերի տեղեկատվության փոխանակման համար: Heartbeat-ի միջոցով սերվերները սովորում են փոխադարձ խափանումների մասին, պահպանում են տվյալների միասնական սխեման՝ աղյուսակներ, դրանց կառուցվածքը և կրկնօրինակումը. բաժանման սխեմա, կլաստերային տոպոլոգիա և այլն:

Հաճախորդներ

NewSQL = NoSQL + ACID

Ստանդարտ դրայվերների փոխարեն օգտագործվում է Fat Client ռեժիմը: Նման հանգույցը չի պահում տվյալներ, բայց կարող է հանդես գալ որպես հարցումների կատարման համակարգող, այսինքն՝ Հաճախորդն ինքը հանդես է գալիս որպես իր հարցումների համակարգող. Սա ոչ միայն ավելի հուսալի և արագ է, քան ստանդարտ դրայվերը, որը պահանջում է հաղորդակցություն հեռավոր համակարգողի հետ, այլև թույլ է տալիս վերահսկել հարցումների փոխանցումը: Հաճախորդի վրա բացված գործարքից դուրս հարցումներն ուղարկվում են պահոցներ: Եթե ​​հաճախորդը բացել է գործարք, ապա գործարքի շրջանակներում բոլոր հարցումներն ուղարկվում են գործարքի համակարգողին:
NewSQL = NoSQL + ACID

C*One գործարքների համակարգող

Համակարգողը մի բան է, որը մենք իրականացրել ենք C*One-ի համար զրոյից: Այն պատասխանատու է գործարքների, կողպեքների և գործարքների կիրառման կարգի կառավարման համար:

Յուրաքանչյուր սպասարկվող գործարքի համար համակարգողը ստեղծում է ժամանակի դրոշմ. յուրաքանչյուր հաջորդ գործարք ավելի մեծ է, քան նախորդ գործարքը: Քանի որ Կասանդրայի կոնֆլիկտների լուծման համակարգը հիմնված է ժամանակային դրոշմանիշների վրա (երկու հակասական գրառումներից, վերջին ժամանակի դրոշմով մեկը համարվում է ընթացիկ), հակամարտությունը միշտ կլուծվի հօգուտ հաջորդ գործարքի: Այսպիսով մենք իրականացրեցինք Lamport ժամացույց - բաշխված համակարգում հակամարտությունները լուծելու էժան միջոց:

Փականներ

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

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

Քանի որ մեր դեպքում տվյալներն արդեն բաշխված են SQL-ի տեղական գործարքների խմբերի միջև, որոշվեց նշանակել տեղական գործարքների խմբեր համակարգողներին. մեկը համակարգողն իրականացնում է բոլոր գործարքները 0-ից 9-ը, երկրորդը՝ 10-ից 19-ի նշաններով, եւ այլն։ Արդյունքում, համակարգող ատյաններից յուրաքանչյուրը դառնում է գործարքի խմբի վարպետ:

Այնուհետև կողպեքները կարող են իրականացվել համակարգողի հիշողության մեջ սովորական HashMap-ի տեսքով:

Համակարգողի ձախողումներ

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

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

NewSQL = NoSQL + ACID

Ստանալով նմանատիպ տեղեկատվություն ուրիշներից որպես իրենց սրտի բաբախման հաղորդագրությունների մաս՝ յուրաքանչյուր համակարգող ինքն է որոշում, թե որ կլաստերային հանգույցներն են գործում և որոնք՝ ոչ՝ առաջնորդվելով քվորումի սկզբունքով. հաղորդագրությունների ստացում Y հանգույցից, այնուհետև, Y-ն աշխատում է: Եվ հակառակը, հենց որ մեծամասնությունը հայտնում է Y հանգույցից հաղորդագրություններ բացակայելու մասին, ապա Y-ն հրաժարվել է։ Հետաքրքիր է, որ եթե քվորումը տեղեկացնի X հանգույցին, որ այլևս հաղորդագրություններ չի ստանում դրանից, ապա X հանգույցն ինքն իրեն կհամարի ձախողված:

Սրտի բաբախման հաղորդագրություններն ուղարկվում են բարձր հաճախականությամբ, վայրկյանում մոտ 20 անգամ, 50 ms ժամանակահատվածով: Java-ում դժվար է երաշխավորել հավելվածի պատասխանը 50 ms-ի ընթացքում՝ աղբահանի պատճառով առաջացած դադարների համեմատելի երկարության պատճառով: Մենք կարողացանք հասնել այս արձագանքման ժամանակին, օգտագործելով G1 աղբահանիչը, որը թույլ է տալիս մեզ նշել թիրախ GC-ի դադարների տևողության համար: Այնուամենայնիվ, երբեմն, բավականին հազվադեպ, կոլեկցիոների դադարները գերազանցում են 50 ms, ինչը կարող է հանգեցնել սխալի սխալ հայտնաբերման: Որպեսզի դա տեղի չունենա, կոորդինատորը չի հայտնում հեռավոր հանգույցի ձախողման մասին, երբ անհետանում է նրանից ստացված սրտի բաբախման առաջին հաղորդագրությունը, միայն այն դեպքում, եթե մի քանիսը անընդմեջ անհետացել են: Ահա թե ինչպես մեզ հաջողվեց հայտնաբերել համակարգող հանգույցի ձախողումը 200 թ. ms.

Բայց դա բավարար չէ արագ հասկանալու համար, թե որ հանգույցն է դադարել գործել: Մենք պետք է ինչ-որ բան անենք այս հարցում:

Ամրագրում

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

NewSQL = NoSQL + ACID

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

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

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

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

Ինչպես է գործում գործարքը

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

NewSQL = NoSQL + ACID

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

NewSQL = NoSQL + ACID

Երբ հաճախորդը պահանջում է իր սեփական փոփոխված տվյալները որպես ակտիվ գործարքի մաս, համակարգողը գործում է հետևյալ կերպ.

  • եթե ID-ն արդեն գործարքի մեջ է, ապա տվյալները վերցվում են հիշողությունից.
  • եթե հիշողության մեջ չկա ID, ապա բացակայող տվյալները կարդացվում են պահեստային հանգույցներից՝ համակցված արդեն հիշողության մեջ եղածների հետ, և արդյունքը տրվում է հաճախորդին։

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

NewSQL = NoSQL + ACID

Երբ հաճախորդը ուղարկում է commit, վիճակը, որը գտնվում էր ծառայության հիշողության մեջ, պահպանվում է համակարգողի կողմից գրանցված փաթեթում և ուղարկվում է որպես գրանցված փաթեթ Cassandra պահեստ: Խանութներն անում են ամեն ինչ, որպեսզի համոզվեն, որ այս փաթեթը ատոմային (ամբողջությամբ) կիրառվի, և պատասխան է ուղարկում համակարգողին, որն ազատում է կողպեքները և հաճախորդին հաստատում գործարքի հաջողությունը:

NewSQL = NoSQL + ACID

Իսկ հետ վերադառնալու համար համակարգողին միայն անհրաժեշտ է ազատել գործարքի վիճակի զբաղեցրած հիշողությունը:

Վերոնշյալ բարելավումների արդյունքում մենք իրականացրեցինք ACID սկզբունքները.

  • Ատոմականություն. Սա երաշխիք է, որ ոչ մի գործարք մասամբ չի գրանցվի համակարգում, կա՛մ կավարտվի նրա բոլոր ենթագործողությունները, կա՛մ ոչ մեկը չի ավարտվի: Մենք հավատարիմ ենք այս սկզբունքին Cassandra-ում գրանցված խմբաքանակի միջոցով:
  • Հետևողականություն. Յուրաքանչյուր հաջող գործարք, ըստ սահմանման, գրանցում է միայն վավեր արդյունքներ: Եթե ​​գործարքը բացելուց և գործողությունների մի մասը կատարելուց հետո պարզվում է, որ արդյունքն անվավեր է, կատարվում է հետադարձ վերադարձ:
  • Մեկուսացում. Երբ գործարքն իրականացվում է, միաժամանակյա գործարքները չպետք է ազդեն դրա արդյունքի վրա: Մրցակցող գործարքները մեկուսացված են համակարգողի վրա հոռետեսական կողպեքների միջոցով: Գործարքից դուրս ընթերցումների դեպքում մեկուսացման սկզբունքը պահպանվում է Read Committed մակարդակում:
  • Կայունություն. Անկախ ցածր մակարդակներում առկա խնդիրներից՝ համակարգի անջատում, ապարատային խափանում, հաջողությամբ ավարտված գործարքի արդյունքում կատարված փոփոխությունները պետք է պահպանվեն, երբ գործառնությունները վերսկսվեն:

Ընթերցանություն ըստ ինդեքսների

Եկեք վերցնենք մի պարզ աղյուսակ.

CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
…)

Այն ունի ID (հիմնական բանալի), սեփականատեր և փոփոխման ամսաթիվ: Դուք պետք է շատ պարզ հարցում կատարեք. ընտրեք սեփականատիրոջ տվյալները «վերջին օրվա համար» փոփոխության ամսաթվով:

SELECT *
WHERE owner=?
AND modified>?

Որպեսզի նման հարցումն արագ մշակվի, դասական SQL DBMS-ում պետք է ինդեքս կառուցել ըստ սյունակների (սեփականատեր, փոփոխված): Մենք կարող ենք դա անել բավականին հեշտությամբ, քանի որ այժմ ունենք ACID երաշխիքներ:

Ցուցանիշները C*One-ում

Գոյություն ունի սկզբնաղբյուր աղյուսակ՝ լուսանկարներով, որոնցում գրանցման ID-ն հիմնական բանալին է:

NewSQL = NoSQL + ACID

Ցուցանիշի համար C*One-ը ստեղծում է նոր աղյուսակ, որը բնօրինակի պատճենն է: Բանալին նույնն է, ինչ ինդեքսի արտահայտությունը, և այն նաև ներառում է սկզբնաղբյուր աղյուսակից գրառման հիմնական բանալին.

NewSQL = NoSQL + ACID

Այժմ «վերջին օրվա սեփականատիրոջ» հարցումը կարող է վերագրվել որպես ընտրված մեկ այլ աղյուսակից.

SELECT * FROM i1_test
WHERE owner=?
AND modified>?

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

Օգտագործելով ACID-ը, մենք կարողացանք SQL-ի նման ինդեքսներ իրականացնել: Դրանք հետևողական են, մասշտաբային, արագ, բաղադրելի և ներկառուցված CQL հարցումների լեզվի մեջ: Ինդեքսներին աջակցելու համար հավելվածի կոդի փոփոխություններ չեն պահանջվում: Ամեն ինչ այնքան պարզ է, որքան SQL-ում: Եվ ամենակարևորը, ինդեքսները չեն ազդում սկզբնական գործարքների աղյուսակի փոփոխությունների կատարման արագության վրա:

Ինչ է պատահել

Մենք մշակեցինք C*One-ը երեք տարի առաջ և գործարկեցինք այն կոմերցիոն շահագործման մեջ:

Ի վերջո ի՞նչ ստացանք։ Եկեք սա գնահատենք՝ օգտագործելով լուսանկարների մշակման և պահպանման ենթահամակարգի օրինակը՝ սոցիալական ցանցի տվյալների կարևորագույն տեսակներից մեկը։ Խոսքը ոչ թե բուն լուսանկարների մարմինների, այլ բոլոր տեսակի մետատեղեկատվության մասին է։ Այժմ Odnoklassniki-ն ունի մոտ 20 միլիարդ նման գրառում, համակարգը մշակում է վայրկյանում 80 հազար ընթերցման հարցում, վայրկյանում մինչև 8 հազար ACID գործարք՝ կապված տվյալների փոփոխության հետ։

Երբ մենք օգտագործում էինք SQL կրկնօրինակման գործակիցով = 1 (բայց RAID 10-ում), լուսանկարի մետատեղեկատվությունը պահվում էր Microsoft SQL Server-ով աշխատող 32 մեքենաներից բաղկացած բարձր հասանելի կլաստերի վրա (գումարած 11 կրկնօրինակում): Պահուստային պատճենները պահելու համար հատկացվել է նաև 10 սերվեր։ Ընդհանուր 50 թանկարժեք մեքենա։ Միևնույն ժամանակ, համակարգը գործել է անվանական ծանրաբեռնվածությամբ, առանց պահուստի:

Նոր համակարգ տեղափոխվելուց հետո մենք ստացանք կրկնօրինակման գործակից = 3 - պատճենը յուրաքանչյուր տվյալների կենտրոնում: Համակարգը բաղկացած է 63 Cassandra պահեստավորման հանգույցներից և 6 համակարգող մեքենաներից՝ ընդհանուր 69 սերվերի համար: Բայց այս մեքենաները շատ ավելի էժան են, դրանց ընդհանուր արժեքը կազմում է SQL համակարգի արժեքի մոտ 30%-ը: Միաժամանակ բեռը պահվում է 30%-ի վրա։

C*One-ի ներդրմամբ ուշացումը նույնպես նվազել է. SQL-ում գրելու գործողությունը տևել է մոտ 4,5 ms: C*One-ում - մոտ 1,6 ms: Գործարքի տևողությունը միջինում 40 մվ-ից պակաս է, կատարումն ավարտվում է 2 մվ-ում, կարդալու և գրելու տևողությունը՝ միջինը 2 մվ: 99-րդ ցենտիլը՝ ընդամենը 3-3,1 ms, ընդմիջումների թիվը նվազել է 100 անգամ, այս ամենը պայմանավորված է շահարկումների լայն կիրառմամբ:

Մինչ այժմ, SQL Server հանգույցների մեծ մասը հեռացվել է շահագործումից, նոր արտադրանքները մշակվում են միայն C*One-ի միջոցով: Մենք հարմարեցրինք C*One-ը մեր ամպում աշխատելու համար մեկ ամպ, ինչը հնարավորություն տվեց արագացնել նոր կլաստերների տեղակայումը, պարզեցնել կոնֆիգուրացիան և ավտոմատացնել աշխատանքը։ Առանց սկզբնաղբյուրի, դա անելը շատ ավելի դժվար և ծանր կլիներ:

Այժմ մենք աշխատում ենք մեր մյուս պահեստային միջոցները ամպին փոխանցելու վրա, բայց դա բոլորովին այլ պատմություն է:

Source: www.habr.com

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