Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Նախագիծը սկսել է իր պատմությունը բավականին վաղուց՝ 2000 թվականի սկզբին: Առաջին տարբերակները գրվել են Visual Basic 6-ում: Ժամանակի ընթացքում պարզ դարձավ, որ այս լեզվով զարգացումը դժվար կլինի ապագայում աջակցել, քանի որ IDE-ն իսկ լեզուն ինքնին թույլ են զարգացած: 2000-ականների վերջում որոշվեց անցնել ավելի խոստումնալից C#-ին։ Նոր տարբերակը գրվել է հինի վերանայմանը զուգահեռ, աստիճանաբար ավելի ու ավելի շատ կոդ է գրվել .NET-ում։ Backend-ը C#-ում ի սկզբանե կենտրոնացած էր ծառայությունների ճարտարապետության վրա, սակայն զարգացման ընթացքում օգտագործվել են ընդհանուր տրամաբանությամբ գրադարաններ, և ծառայությունները գործարկվել են մեկ գործընթացով: Արդյունքը եղավ մի ծրագիր, որը մենք անվանեցինք «ծառայության մոնոլիտ»:

Այս համակցության մի քանի առավելություններից մեկն այն էր, որ ծառայությունները միմյանց զանգահարեն արտաքին API-ի միջոցով: Հստակ նախադրյալներ կային ավելի ճիշտ ծառայության, իսկ ապագայում՝ միկրոսերվիսային ճարտարապետության անցնելու համար։

Քայքայման մեր աշխատանքները սկսել ենք մոտ 2015թ. Մենք դեռ չենք հասել իդեալական վիճակի. դեռևս կան մեծ նախագծի մասեր, որոնք դժվար թե կարելի է անվանել մոնոլիտներ, բայց դրանք էլ նման չեն միկրոսերվիսների։ Այնուամենայնիվ, առաջընթացը զգալի է։
Ես այդ մասին կխոսեմ հոդվածում:

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Պարունակություն

Առկա լուծման ճարտարապետությունը և խնդիրները


Սկզբում ճարտարապետությունն այսպիսի տեսք ուներ՝ UI-ն առանձին հավելված է, մոնոլիտ մասը գրված է Visual Basic 6-ում, .NET հավելվածը հարակից ծառայությունների մի ամբողջություն է, որն աշխատում է բավականին մեծ տվյալների բազայի հետ։

Նախորդ լուծման թերությունները

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

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

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

Ժամանակակից տեխնոլոգիաների ներդրումը դժվար է
Բոլոր ծրագրավորողներին ծանոթ խնդիր. կա ցանկություն նախագծում ներդնելու ժամանակակից տեխնոլոգիաներ, բայց հնարավորություն չկա։ Մեծ միաձույլ լուծումով ներկայիս գրադարանի ցանկացած թարմացում, էլ չեմ խոսում նորին անցնելու մասին, վերածվում է բավականին ոչ տրիվիալ գործի։ Երկար ժամանակ է պահանջվում թիմի ղեկավարին ապացուցելու համար, որ դա ավելի շատ բոնուսներ կբերի, քան իզուր նյարդեր։

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

Ակնկալիքներ միկրոսերվիսներից


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

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

Առանձին գործընթացներում ծառայությունների մեկուսացում. Իդեալում, ես ուզում էի այն մեկուսացնել բեռնարկղերում, բայց .NET Framework-ում գրված մեծ թվով ծառայություններ աշխատում են միայն Windows-ով: Այժմ հայտնվում են .NET Core-ի վրա հիմնված ծառայություններ, սակայն դրանք դեռ քիչ են:

Տեղակայման ճկունություն. Մենք կցանկանայինք համատեղել ծառայություններն այնպես, ինչպես դա մեզ անհրաժեշտ է, և ոչ թե ինչպես դա պարտադրում է օրենսգիրքը:

Նոր տեխնոլոգիաների կիրառում. Սա հետաքրքիր է ցանկացած ծրագրավորողի համար:

Անցումային խնդիրներ


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

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

Աշխատանքի մեկնարկի պահին պահեստն ուներ ավելի քան 500 նախագիծ և ավելի քան 700 հազար տող կոդ։ Սա բավականին մեծ որոշում է և երկրորդ խնդիրը. Պարզապես վերցնել ու բաժանել միկրոսերվիսների հնարավոր չէր։

Երրորդ խնդիր — անհրաժեշտ ենթակառուցվածքների բացակայություն. Փաստորեն, մենք ձեռքով պատճենում էինք աղբյուրի կոդը սերվերներին:

Ինչպես անցնել մոնոլիտից միկրոծառայությունների


Միկրոծառայությունների տրամադրում

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

Ի՞նչ մեթոդներ ենք օգտագործում միկրոսերվիսները մեկուսացնելու համար:

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

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

Հոսթինգի հետ հավաքումը Ծրագրի դասի կոդի ընդամենը մեկ տող է: Մենք Topshelf-ի հետ աշխատանքը թաքցրել ենք օժանդակ դասարանում:

namespace RBA.Services.Accounts.Host
{
   internal class Program
   {
      private static void Main(string[] args)
      {
        HostRunner<Accounts>.Run("RBA.Services.Accounts.Host");

       }
    }
}

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

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

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

Եթե ​​նայեք իրական օրինակին UI մասի կոդից, կարող եք տեսնել, որ այս լուծման մեծ մասը պարունակում է իրական բիզնես տրամաբանություն, որն օգտակար է այլ գործընթացներում, ոչ միայն UI ձևը կառուցելու համար:

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

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

Ծառայությունների բաժանումը մշակումից անքակտելիորեն կապված է սահմանափակ համատեքստ հասկացության հետ: Սա գաղափար է Domain Driven Design-ից: Դա նշանակում է տիրույթի մոդելի մի հատված, որտեղ մեկ լեզվի բոլոր տերմինները եզակիորեն սահմանված են: Որպես օրինակ նայենք ապահովագրության և օրինագծերի համատեքստին: Մենք ունենք մոնոլիտ հավելված, և ապահովագրության մեջ պետք է աշխատենք հաշվի հետ։ Մենք ակնկալում ենք, որ մշակողը կգտնի գոյություն ունեցող Հաշվի դասը մեկ այլ ժողովում, կանդրադառնա այն Ապահովագրության դասից, և մենք կունենանք աշխատանքային կոդ: Կպահպանվի DRY սկզբունքը, առաջադրանքը կկատարվի ավելի արագ՝ օգտագործելով գործող ծածկագիրը։

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

Այս սահմանափակ համատեքստերը միմյանցից առանձնացնելու և միկրոծառայությունների մոնոլիտ լուծումից տարանջատելու գործընթացը սկսելու համար մենք օգտագործեցինք այնպիսի մոտեցում, ինչպիսին է հավելվածի ներսում արտաքին API-ների ստեղծումը: Եթե ​​մենք իմանայինք, որ ինչ-որ մոդուլ պետք է դառնա միկրոսերվիս, ինչ-որ կերպ փոփոխված գործընթացի շրջանակներում, ապա արտաքին զանգերի միջոցով անմիջապես զանգեր արեցինք այն տրամաբանությանը, որը պատկանում է մեկ այլ սահմանափակ համատեքստին: Օրինակ, REST-ի կամ WCF-ի միջոցով:

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

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

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

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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Առաջին հերթին մենք ստեղծում ենք միկրոսերվիս՝ վերաշարադրելով կոդը։ Մենք բարելավում ենք որոշ ասպեկտներ, որոնցից գոհ չէինք: Մենք իրականացնում ենք նոր բիզնես պահանջներ հաճախորդի կողմից: Մենք ավելացնում ենք API Gateway UI-ի և backend-ի միջև կապին, որը կապահովի զանգերի վերահասցեավորում:

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Հաջողակ օդաչուի դեպքում մենք հասկանում ենք, որ նոր կոնֆիգուրացիան իսկապես գործունակ է, մենք կարող ենք հեռացնել հին մոնոլիտը հավասարումից և թողնել նոր կոնֆիգուրացիան հին լուծման փոխարեն:

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Ընդհանուր առմամբ, մենք օգտագործում ենք գրեթե բոլոր գոյություն ունեցող մեթոդները մոնոլիտի սկզբնական կոդը բաժանելու համար: Դրանք բոլորը թույլ են տալիս նվազեցնել հավելվածի մասերի չափը և դրանք թարգմանել նոր գրադարանների՝ դարձնելով ավելի լավ կոդ:

Տվյալների բազայի հետ աշխատելը


Տվյալների բազան կարելի է բաժանել ավելի վատ, քան սկզբնական կոդը, քանի որ այն պարունակում է ոչ միայն ընթացիկ սխեման, այլև կուտակված պատմական տվյալներ:

Մեր տվյալների բազան, ինչպես շատ ուրիշներ, ուներ ևս մեկ կարևոր թերություն՝ հսկայական չափսերը: Այս տվյալների բազան մշակվել է մոնոլիտի բարդ բիզնես տրամաբանության և տարբեր սահմանափակ համատեքստերի աղյուսակների միջև կուտակված հարաբերությունների համաձայն:

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

Օրենսգրքում սահմանափակ համատեքստերի նույն բաժանումն օգնում է մեզ տարանջատման հարցում: Սովորաբար դա մեզ բավականին լավ պատկերացում է տալիս այն մասին, թե ինչպես ենք մենք բաժանում տվյալները տվյալների բազայի մակարդակում: Մենք հասկանում ենք, թե որ աղյուսակները պատկանում են մի սահմանափակ համատեքստին, իսկ որոնք՝ մյուսին:

Մենք օգտագործեցինք տվյալների բազայի բաժանման երկու գլոբալ մեթոդ՝ գոյություն ունեցող աղյուսակների բաժանում և մշակման միջոցով բաժանում:

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

Մշակման բաժին է պետք, երբ բիզնես մոդելը մեծապես փոխվել է, և աղյուսակներն այլևս չեն բավարարում մեզ։

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

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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Ավելի ուշ մենք կհեռացնենք այս կապը, այսինքն՝ առանձին աղյուսակներից մոնոլիտ հավելվածից տվյալներ կարդալը նույնպես կտեղափոխվի API։

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Որպեսզի այս սխեման աշխատի, մեզ հավանաբար անցումային շրջան է պետք:

Այնուհետև կա երկու հնարավոր մոտեցում.

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

ԵրկրորդՄենք տվյալները բաժանում ենք ըստ որոշ բիզնես չափանիշների: Օրինակ՝ համակարգում ունեինք 5 ապրանք, որոնք պահվում էին հին տվյալների բազայում։ Մենք վեցերորդը տեղադրում ենք նոր բիզնես առաջադրանքի շրջանակներում՝ նոր տվյալների բազայում: Բայց մեզ անհրաժեշտ կլինի API Gateway, որը կհամաժամացնի այս տվյալները և ցույց կտա հաճախորդին, թե որտեղից և ինչից ստանալ:

Երկու մոտեցումներն էլ աշխատում են, ընտրեք՝ կախված իրավիճակից։

Այն բանից հետո, երբ մենք համոզված ենք, որ ամեն ինչ աշխատում է, մոնոլիտի այն հատվածը, որն աշխատում է տվյալների բազայի հին կառուցվածքների հետ, կարող է անջատվել:

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Վերջին քայլը տվյալների հին կառուցվածքների հեռացումն է:

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Աշխատեք սկզբնական կոդի հետ


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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Մեզ բախտ վիճակվեց ունենալ ենթակառուցվածքային գրադարաններ, որոնք կարող էին օգտագործվել առանձին:

Երբեմն առաջանում էր մի իրավիճակ, երբ որոշ ընդհանուր օբյեկտներ իրականում չէին պատկանում այս շերտին, այլ ենթակառուցվածքային գրադարաններ էին։ Սա լուծվեց անվանափոխությամբ։

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

Մենք ձևակերպել ենք մի քանի կանոններ կոդի բաժանման գործընթացի համար:

ԱռաջինՄենք այլևս չէինք ցանկանում կիսել բիզնես տրամաբանությունը ծառայությունների, գործունեության և հավելումների միջև: Մենք ցանկանում էինք միկրոսերվիսներում անկախացնել բիզնեսի տրամաբանությունը: Մյուս կողմից, միկրոծառայությունները իդեալականորեն համարվում են ծառայություններ, որոնք գոյություն ունեն ամբողջովին անկախ: Կարծում եմ, որ այս մոտեցումը ինչ-որ չափով վատնում է, և դրան հասնելը դժվար է, քանի որ, օրինակ, C#-ի ծառայությունները ամեն դեպքում միացված կլինեն ստանդարտ գրադարանով։ Մեր համակարգը գրված է C#-ով, մենք դեռ չենք օգտագործել այլ տեխնոլոգիաներ։ Ուստի մենք որոշեցինք, որ կարող ենք մեզ թույլ տալ օգտվել ընդհանուր տեխնիկական հավաքներից։ Գլխավորն այն է, որ դրանք չեն պարունակում բիզնես տրամաբանության բեկորներ։ Եթե ​​ձեր օգտագործած ORM-ի վրա հարմար փաթաթան ունեք, ապա այն ծառայությունից ծառայություն պատճենելը շատ թանկ արժե:

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

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

Այնուհետև մենք սկսեցինք անցնել առանձին պահեստներով մոդելի: Բիզնեսի տրամաբանությունն այլևս չի հոսում ծառայությունից ծառայություն, տիրույթներն իսկապես անկախացել են: Սահմանափակ համատեքստերն ավելի հստակ են աջակցվում: Ինչպե՞ս ենք մենք նորից օգտագործում ենթակառուցվածքի գրադարանները: Մենք դրանք առանձնացրինք առանձին պահեստի մեջ, այնուհետև դրեցինք Nuget փաթեթների մեջ, որոնք դրեցինք Artifactory: Ցանկացած փոփոխության դեպքում հավաքումը և հրապարակումը տեղի է ունենում ավտոմատ կերպով:

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

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

Ենթակառուցվածքային խնդիրներ


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

Ձեռքով տեղադրում միջավայրում

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

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Մենք օգտագործում ենք Atlassian-ը, Bitbucket-ը՝ սկզբնական կոդի պահպանման համար, իսկ Bamboo-ը՝ կառուցման համար: Մենք սիրում ենք Cake-ում գրել build scripts, քանի որ այն նույնն է, ինչ C#-ը: Պատրաստի փաթեթները գալիս են Artifactory, և Ansible-ը ավտոմատ կերպով հասնում է թեստային սերվերներին, որից հետո դրանք կարող են անմիջապես փորձարկվել։

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Առանձին հատումներ


Ժամանակին մոնոլիտի գաղափարներից մեկն էլ ընդհանուր անտառահատումներ ապահովելն էր: Մենք նաև պետք է հասկանայինք, թե ինչ անել առանձին տեղեկամատյանների հետ, որոնք գտնվում են սկավառակների վրա: Մեր տեղեկամատյանները գրված են տեքստային ֆայլերում: Մենք որոշեցինք օգտագործել ստանդարտ ELK կույտ: Մենք ուղղակիորեն պրովայդերների միջոցով չգրեցինք ELK-ին, այլ որոշեցինք, որ կփոփոխենք տեքստային տեղեկամատյանները և դրանց մեջ կգրենք հետքի ID-ն որպես նույնացուցիչ՝ ավելացնելով ծառայության անունը, որպեսզի այդ տեղեկամատյանները հետագայում վերլուծվեն:

Անցում մոնոլիտից միկրոծառայությունների. պատմություն և պրակտիկա

Օգտագործելով Filebeat-ը, մենք հնարավորություն ենք ստանում հավաքել մեր տեղեկամատյանները սերվերներից, այնուհետև վերափոխել դրանք, օգտագործել Kibana-ն՝ UI-ում հարցումներ ստեղծելու և տեսնելու, թե ինչպես է ընթացել զանգը ծառայությունների միջև: Trace ID-ն այս հարցում շատ է օգնում:

Փորձարկում և վրիպազերծում հարակից ծառայություններ


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

Կան սերվերներ, որոնք աշխատում են միայն ծառայությունների արտադրական տարբերակները: Այս սերվերները անհրաժեշտ են միջադեպերի դեպքում, առաքումը ստուգելու համար նախքան տեղակայումը և ներքին վերապատրաստման համար:

Մենք ավելացրել ենք ավտոմատացված փորձարկման գործընթաց՝ օգտագործելով հանրաճանաչ Specflow գրադարանը: Թեստերն ավտոմատ կերպով աշխատում են NUnit-ի միջոցով Ansible-ից տեղակայվելուց անմիջապես հետո: Եթե ​​առաջադրանքի ծածկույթը լիովին ավտոմատ է, ապա ձեռքով փորձարկման կարիք չկա: Թեև երբեմն լրացուցիչ ձեռքով փորձարկում դեռևս պահանջվում է: Մենք օգտագործում ենք պիտակներ Jira-ում, որոշելու համար, թե որ թեստերը պետք է կատարվեն կոնկրետ խնդրի համար:

Բացի այդ, ավելացել է բեռի փորձարկման անհրաժեշտությունը, նախկինում այն ​​իրականացվում էր միայն հազվադեպ դեպքերում: Մենք օգտագործում ենք JMeter-ը՝ թեստերը գործարկելու համար, InfluxDB-ը՝ դրանք պահելու համար, և Grafana-ը՝ գործընթացի գծապատկերներ ստեղծելու համար:

Ինչի՞ ենք հասել։


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

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

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

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

Ամփոփում

  • Միկրոծառայությունները լավ են հարմարվում բարդ համակարգերի քայքայման համար: Ընթացքում մենք սկսում ենք հասկանալ, թե ինչ կա մեր համակարգում, ինչ սահմանափակ ենթատեքստեր կան, որտեղ են դրանց սահմանները: Սա թույլ է տալիս ճիշտ բաշխել բարելավումները մոդուլների միջև և կանխել ծածկագրի շփոթությունը:
  • Միկրոծառայություններն ապահովում են կազմակերպչական առավելություններ: Նրանց մասին հաճախ խոսում են միայն որպես ճարտարապետություն, բայց ցանկացած ճարտարապետություն անհրաժեշտ է բիզնեսի կարիքները լուծելու համար, այլ ոչ թե ինքնուրույն։ Հետևաբար, կարելի է ասել, որ միկրոսերվիսները հարմար են փոքր թիմերում խնդիրներ լուծելու համար, հաշվի առնելով, որ Scrum-ը այժմ շատ տարածված է:
  • Բաժանումը կրկնվող գործընթաց է: Չի կարելի դիմում ընդունել ու ուղղակի բաժանել միկրոսերվիսների։ Ստացված արտադրանքը դժվար թե գործունակ լինի: Միկրոծառայություններ նվիրելիս ձեռնտու է վերաշարադրել գոյություն ունեցող ժառանգությունը, այսինքն՝ այն վերածել մեզ դուր եկած կոդի, որը ավելի լավ է բավարարում բիզնեսի կարիքները ֆունկցիոնալության և արագության առումով:

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

    Հ.Գ.Ավելի զգացմունքային պատմություն (և կարծես անձամբ քեզ համար) - ըստ ՈՒղեցույց.
    Ներկայացնում ենք զեկույցի ամբողջական տարբերակը.

Source: www.habr.com

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