Մինչև վերջերս 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 ծրագրավորողի տեսանկյունից՝ ալբոմում լուսանկար ավելացնելը։ Ալբոմները և լուսանկարները պահվում են տարբեր ափսեներում: Ալբոմն ունի հանրային լուսանկարների հաշվիչ: Այնուհետև նման գործարքը բաժանվում է հետևյալ քայլերի.
Մենք արգելափակում ենք ալբոմը բանալիով։
Ստեղծեք գրառում լուսանկարների աղյուսակում:
Եթե լուսանկարն ունի հանրային կարգավիճակ, ապա ալբոմում ավելացրեք հանրային լուսանկարների հաշվիչ, թարմացրեք գրառումը և կատարեք գործարքը:
Կամ կեղծ կոդով.
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 սերվերներ, որոնք պատասխանատու են տեղական սկավառակների վրա տվյալների պահպանման համար: Տվյալների ծանրաբեռնվածության և ծավալի աճով, դրանց քանակը կարող է հեշտությամբ չափվել մինչև տասնյակ և հարյուրավոր:
Գործարքների համակարգողներ - ապահովում են գործարքների կատարումը.
Հաճախորդները կիրառական սերվերներ են, որոնք իրականացնում են բիզնես գործողություններ և նախաձեռնում են գործարքներ: Այդպիսի հաճախորդներ կարող են լինել հազարավոր։
Բոլոր տեսակի սերվերները ընդհանուր կլաստերի մի մասն են, օգտագործում են ներքին Cassandra հաղորդագրությունների արձանագրությունը միմյանց հետ շփվելու և բամբասանք կլաստերի տեղեկատվության փոխանակման համար: Heartbeat-ի միջոցով սերվերները սովորում են փոխադարձ խափանումների մասին, պահպանում են տվյալների միասնական սխեման՝ աղյուսակներ, դրանց կառուցվածքը և կրկնօրինակումը. բաժանման սխեմա, կլաստերային տոպոլոգիա և այլն:
Հաճախորդներ
Ստանդարտ դրայվերների փոխարեն օգտագործվում է Fat Client ռեժիմը: Նման հանգույցը չի պահում տվյալներ, բայց կարող է հանդես գալ որպես հարցումների կատարման համակարգող, այսինքն՝ Հաճախորդն ինքը հանդես է գալիս որպես իր հարցումների համակարգող. Սա ոչ միայն ավելի հուսալի և արագ է, քան ստանդարտ դրայվերը, որը պահանջում է հաղորդակցություն հեռավոր համակարգողի հետ, այլև թույլ է տալիս վերահսկել հարցումների փոխանցումը: Հաճախորդի վրա բացված գործարքից դուրս հարցումներն ուղարկվում են պահոցներ: Եթե հաճախորդը բացել է գործարք, ապա գործարքի շրջանակներում բոլոր հարցումներն ուղարկվում են գործարքի համակարգողին:
C*One գործարքների համակարգող
Համակարգողը մի բան է, որը մենք իրականացրել ենք C*One-ի համար զրոյից: Այն պատասխանատու է գործարքների, կողպեքների և գործարքների կիրառման կարգի կառավարման համար:
Յուրաքանչյուր սպասարկվող գործարքի համար համակարգողը ստեղծում է ժամանակի դրոշմ. յուրաքանչյուր հաջորդ գործարք ավելի մեծ է, քան նախորդ գործարքը: Քանի որ Կասանդրայի կոնֆլիկտների լուծման համակարգը հիմնված է ժամանակային դրոշմանիշների վրա (երկու հակասական գրառումներից, վերջին ժամանակի դրոշմով մեկը համարվում է ընթացիկ), հակամարտությունը միշտ կլուծվի հօգուտ հաջորդ գործարքի: Այսպիսով մենք իրականացրեցինք Lamport ժամացույց - բաշխված համակարգում հակամարտությունները լուծելու էժան միջոց:
Փականներ
Մեկուսացում ապահովելու համար մենք որոշեցինք օգտագործել ամենապարզ մեթոդը՝ հոռետեսական կողպեքներ, որոնք հիմնված են ռեկորդի առաջնային բանալիի վրա։ Այլ կերպ ասած, գործարքի ժամանակ գրառումը պետք է նախ կողպվի, միայն դրանից հետո կարդալ, փոփոխել և պահպանել: Միայն հաջող կատարումից հետո կարող է բացվել գրառումը, որպեսզի մրցակցող գործարքները կարողանան օգտագործել այն:
Նման կողպման իրականացումը պարզ է ոչ բաշխված միջավայրում: Բաշխված համակարգում կա երկու հիմնական տարբերակ՝ կա՛մ իրականացնել բաշխված կողպում կլաստերի վրա, կա՛մ բաշխել գործարքները, որպեսզի նույն գրառումը պարունակող գործարքները միշտ սպասարկվեն նույն համակարգողի կողմից:
Քանի որ մեր դեպքում տվյալներն արդեն բաշխված են SQL-ի տեղական գործարքների խմբերի միջև, որոշվեց նշանակել տեղական գործարքների խմբեր համակարգողներին. մեկը համակարգողն իրականացնում է բոլոր գործարքները 0-ից 9-ը, երկրորդը՝ 10-ից 19-ի նշաններով, եւ այլն։ Արդյունքում, համակարգող ատյաններից յուրաքանչյուրը դառնում է գործարքի խմբի վարպետ:
Այնուհետև կողպեքները կարող են իրականացվել համակարգողի հիշողության մեջ սովորական HashMap-ի տեսքով:
Համակարգողի ձախողումներ
Քանի որ համակարգողներից մեկը բացառապես սպասարկում է գործարքների խումբ, շատ կարևոր է արագ որոշել դրա ձախողման փաստը, որպեսզի գործարքի կատարման երկրորդ փորձը ավարտվի: Սա արագ և հուսալի դարձնելու համար մենք օգտագործեցինք լիարժեք միացված քվորումի սրտի զարկերի արձանագրություն.
Յուրաքանչյուր տվյալների կենտրոն ունի առնվազն երկու համակարգող հանգույց: Պարբերաբար, յուրաքանչյուր համակարգող ուղարկում է սրտի բաբախման հաղորդագրություն մյուս համակարգողներին և տեղեկացնում նրանց իր գործունեության մասին, ինչպես նաև վերջին անգամ կլաստերի որ համակարգողներից է ստացել սրտի զարկերի հաղորդագրությունները:
Ստանալով նմանատիպ տեղեկատվություն ուրիշներից որպես իրենց սրտի բաբախման հաղորդագրությունների մաս՝ յուրաքանչյուր համակարգող ինքն է որոշում, թե որ կլաստերային հանգույցներն են գործում և որոնք՝ ոչ՝ առաջնորդվելով քվորումի սկզբունքով. հաղորդագրությունների ստացում Y հանգույցից, այնուհետև, Y-ն աշխատում է: Եվ հակառակը, հենց որ մեծամասնությունը հայտնում է Y հանգույցից հաղորդագրություններ բացակայելու մասին, ապա Y-ն հրաժարվել է։ Հետաքրքիր է, որ եթե քվորումը տեղեկացնի X հանգույցին, որ այլևս հաղորդագրություններ չի ստանում դրանից, ապա X հանգույցն ինքն իրեն կհամարի ձախողված:
Սրտի բաբախման հաղորդագրություններն ուղարկվում են բարձր հաճախականությամբ, վայրկյանում մոտ 20 անգամ, 50 ms ժամանակահատվածով: Java-ում դժվար է երաշխավորել հավելվածի պատասխանը 50 ms-ի ընթացքում՝ աղբահանի պատճառով առաջացած դադարների համեմատելի երկարության պատճառով: Մենք կարողացանք հասնել այս արձագանքման ժամանակին, օգտագործելով G1 աղբահանիչը, որը թույլ է տալիս մեզ նշել թիրախ GC-ի դադարների տևողության համար: Այնուամենայնիվ, երբեմն, բավականին հազվադեպ, կոլեկցիոների դադարները գերազանցում են 50 ms, ինչը կարող է հանգեցնել սխալի սխալ հայտնաբերման: Որպեսզի դա տեղի չունենա, կոորդինատորը չի հայտնում հեռավոր հանգույցի ձախողման մասին, երբ անհետանում է նրանից ստացված սրտի բաբախման առաջին հաղորդագրությունը, միայն այն դեպքում, եթե մի քանիսը անընդմեջ անհետացել են: Ահա թե ինչպես մեզ հաջողվեց հայտնաբերել համակարգող հանգույցի ձախողումը 200 թ. ms.
Բայց դա բավարար չէ արագ հասկանալու համար, թե որ հանգույցն է դադարել գործել: Մենք պետք է ինչ-որ բան անենք այս հարցում:
Ամրագրում
Դասական սխեման ներառում է վարպետի ձախողման դեպքում նոր ընտրությունների մեկնարկը՝ օգտագործելով դրանցից մեկը նորաձեւհամընդհանուր ալգորիթմներ. Այնուամենայնիվ, նման ալգորիթմները հայտնի խնդիրներ ունեն ժամանակի մերձեցման և բուն ընտրական գործընթացի երկարության հետ: Մենք կարողացանք խուսափել նման լրացուցիչ ուշացումներից՝ օգտագործելով համակարգողի փոխարինման սխեման ամբողջությամբ միացված ցանցում.
Ենթադրենք, որ ուզում ենք գործարք կատարել 50-րդ խմբում: Եկեք նախօրոք որոշենք փոխարինման սխեման, այսինքն՝ հիմնական համակարգողի ձախողման դեպքում որ հանգույցները կիրականացնեն գործարքներ 50-րդ խմբում: Մեր նպատակն է պահպանել համակարգի ֆունկցիոնալությունը տվյալների կենտրոնի խափանման դեպքում: Եկեք որոշենք, որ առաջին պահուստը կլինի հանգույց այլ տվյալների կենտրոնից, իսկ երկրորդ պահուստը կլինի հանգույց երրորդից: Այս սխեման ընտրվում է մեկ անգամ և չի փոխվում այնքան ժամանակ, քանի դեռ կլաստերի տոպոլոգիան չի փոխվել, այսինքն՝ մինչև նոր հանգույցներ մտնել դրան (ինչը շատ հազվադեպ է պատահում)։ Նոր ակտիվ վարպետի ընտրության կարգը, եթե հինը ձախողվի, միշտ կլինի հետևյալը. առաջին ռեզերվը կդառնա ակտիվ վարպետ, իսկ եթե դադարել է գործել, երկրորդ ռեզերվը կդառնա ակտիվ վարպետ:
Այս սխեման ավելի հուսալի է, քան ունիվերսալ ալգորիթմը, քանի որ նոր վարպետը ակտիվացնելու համար բավական է որոշել հինի ձախողումը:
Բայց ինչպե՞ս կհասկանան հաճախորդները, թե որ վարպետն է այժմ աշխատում: Անհնար է հազարավոր հաճախորդների տեղեկատվություն ուղարկել 50 ms-ում: Հնարավոր է իրավիճակ, երբ հաճախորդը հարցում է ուղարկում գործարք բացելու համար՝ դեռ չիմանալով, որ այս վարպետն այլևս չի գործում, և հարցումը կլրանա: Որպեսզի դա տեղի չունենա, հաճախորդները սպեկուլյատիվ կերպով գործարք բացելու հարցում են ուղարկում խմբի վարպետին և նրա երկու պահուստներին միանգամից, բայց միայն նա, ով տվյալ պահին գործող վարպետն է, կպատասխանի այս խնդրանքին: Հաճախորդը գործարքի շրջանակներում բոլոր հետագա շփումները կկատարի միայն ակտիվ վարպետի հետ:
Պահուստային վարպետները իրենցը չհանդիսացող գործարքների վերաբերյալ ստացված հարցումները տեղադրում են չծնված գործարքների հերթում, որտեղ դրանք պահվում են որոշ ժամանակով: Եթե ակտիվ վարպետը մահանում է, ապա նոր վարպետը մշակում է իր հերթից գործարքները բացելու հարցումները և պատասխանում է հաճախորդին: Եթե հաճախորդն արդեն բացել է գործարք հին վարպետի հետ, ապա երկրորդ պատասխանն անտեսվում է (և, ակնհայտորեն, նման գործարքը չի ավարտվի և կկրկնվի հաճախորդի կողմից):
Ինչպես է գործում գործարքը
Ենթադրենք, հաճախորդը հարցում է ուղարկել համակարգողին՝ այսինչ հիմնական բանալիով այս կամ այն անձի համար գործարք բացելու համար: Համակարգողը կողպում է այս էությունը և տեղադրում հիշողության կողպեքի աղյուսակում: Անհրաժեշտության դեպքում համակարգողը կարդում է այս նյութը պահեստից և ստացված տվյալները պահում է գործարքի վիճակում համակարգողի հիշողության մեջ:
Երբ հաճախորդը ցանկանում է փոխել տվյալները գործարքի մեջ, նա հարցում է ուղարկում համակարգողին՝ կազմակերպությունը փոփոխելու համար, և համակարգողը նոր տվյալները տեղադրում է գործարքի կարգավիճակի աղյուսակում՝ հիշողության մեջ: Սա ավարտում է ձայնագրությունը. ոչ մի ձայնագրություն չի արվում պահեստում:
Երբ հաճախորդը պահանջում է իր սեփական փոփոխված տվյալները որպես ակտիվ գործարքի մաս, համակարգողը գործում է հետևյալ կերպ.
եթե ID-ն արդեն գործարքի մեջ է, ապա տվյալները վերցվում են հիշողությունից.
եթե հիշողության մեջ չկա ID, ապա բացակայող տվյալները կարդացվում են պահեստային հանգույցներից՝ համակցված արդեն հիշողության մեջ եղածների հետ, և արդյունքը տրվում է հաճախորդին։
Այսպիսով, հաճախորդը կարող է կարդալ իր փոփոխությունները, բայց մյուս հաճախորդները չեն տեսնում այդ փոփոխությունները, քանի որ դրանք պահվում են միայն համակարգողի հիշողության մեջ, դրանք դեռ չկան Cassandra հանգույցներում:
Երբ հաճախորդը ուղարկում է commit, վիճակը, որը գտնվում էր ծառայության հիշողության մեջ, պահպանվում է համակարգողի կողմից գրանցված փաթեթում և ուղարկվում է որպես գրանցված փաթեթ Cassandra պահեստ: Խանութներն անում են ամեն ինչ, որպեսզի համոզվեն, որ այս փաթեթը ատոմային (ամբողջությամբ) կիրառվի, և պատասխան է ուղարկում համակարգողին, որն ազատում է կողպեքները և հաճախորդին հաստատում գործարքի հաջողությունը:
Իսկ հետ վերադառնալու համար համակարգողին միայն անհրաժեշտ է ազատել գործարքի վիճակի զբաղեցրած հիշողությունը:
Վերոնշյալ բարելավումների արդյունքում մենք իրականացրեցինք ACID սկզբունքները.
Ատոմականություն. Սա երաշխիք է, որ ոչ մի գործարք մասամբ չի գրանցվի համակարգում, կա՛մ կավարտվի նրա բոլոր ենթագործողությունները, կա՛մ ոչ մեկը չի ավարտվի: Մենք հավատարիմ ենք այս սկզբունքին Cassandra-ում գրանցված խմբաքանակի միջոցով:
Հետևողականություն. Յուրաքանչյուր հաջող գործարք, ըստ սահմանման, գրանցում է միայն վավեր արդյունքներ: Եթե գործարքը բացելուց և գործողությունների մի մասը կատարելուց հետո պարզվում է, որ արդյունքն անվավեր է, կատարվում է հետադարձ վերադարձ:
Մեկուսացում. Երբ գործարքն իրականացվում է, միաժամանակյա գործարքները չպետք է ազդեն դրա արդյունքի վրա: Մրցակցող գործարքները մեկուսացված են համակարգողի վրա հոռետեսական կողպեքների միջոցով: Գործարքից դուրս ընթերցումների դեպքում մեկուսացման սկզբունքը պահպանվում է Read Committed մակարդակում:
Կայունություն. Անկախ ցածր մակարդակներում առկա խնդիրներից՝ համակարգի անջատում, ապարատային խափանում, հաջողությամբ ավարտված գործարքի արդյունքում կատարված փոփոխությունները պետք է պահպանվեն, երբ գործառնությունները վերսկսվեն:
Այն ունի ID (հիմնական բանալի), սեփականատեր և փոփոխման ամսաթիվ: Դուք պետք է շատ պարզ հարցում կատարեք. ընտրեք սեփականատիրոջ տվյալները «վերջին օրվա համար» փոփոխության ամսաթվով:
SELECT *
WHERE owner=?
AND modified>?
Որպեսզի նման հարցումն արագ մշակվի, դասական SQL DBMS-ում պետք է ինդեքս կառուցել ըստ սյունակների (սեփականատեր, փոփոխված): Մենք կարող ենք դա անել բավականին հեշտությամբ, քանի որ այժմ ունենք ACID երաշխիքներ:
Ցուցանիշները C*One-ում
Գոյություն ունի սկզբնաղբյուր աղյուսակ՝ լուսանկարներով, որոնցում գրանցման ID-ն հիմնական բանալին է:
Ցուցանիշի համար C*One-ը ստեղծում է նոր աղյուսակ, որը բնօրինակի պատճենն է: Բանալին նույնն է, ինչ ինդեքսի արտահայտությունը, և այն նաև ներառում է սկզբնաղբյուր աղյուսակից գրառման հիմնական բանալին.
Այժմ «վերջին օրվա սեփականատիրոջ» հարցումը կարող է վերագրվել որպես ընտրված մեկ այլ աղյուսակից.
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-ը մեր ամպում աշխատելու համար մեկ ամպ, ինչը հնարավորություն տվեց արագացնել նոր կլաստերների տեղակայումը, պարզեցնել կոնֆիգուրացիան և ավտոմատացնել աշխատանքը։ Առանց սկզբնաղբյուրի, դա անելը շատ ավելի դժվար և ծանր կլիներ:
Այժմ մենք աշխատում ենք մեր մյուս պահեստային միջոցները ամպին փոխանցելու վրա, բայց դա բոլորովին այլ պատմություն է: