Bu yazıda üzərində işlədiyim layihənin böyük monolitdən mikroservislər dəstinə çevrilməsindən danışacağam.
Layihə öz tarixinə kifayət qədər uzun müddət əvvəl, 2000-ci ilin əvvəlində başlamışdır. İlk versiyalar Visual Basic 6-da yazılmışdır. Zaman keçdikcə aydın oldu ki, bu dildə inkişafı gələcəkdə dəstəkləmək çətin olacaq, çünki IDE və dilin özü zəif inkişaf edir. 2000-ci illərin sonlarında daha perspektivli C#-a keçmək qərara alındı. Yeni versiya köhnənin təftişi ilə paralel olaraq yazılmışdır, getdikcə daha çox kod .NET-də idi. C#-da backend əvvəlcə xidmət arxitekturasına yönəlmişdi, lakin inkişaf zamanı məntiqi olan ümumi kitabxanalardan istifadə edildi və xidmətlər vahid prosesdə işə salındı. Nəticə “xidmət monolit” adlandırdığımız bir tətbiq oldu.
Belə bir paketin bir neçə üstünlüklərindən biri xidmətlərin xarici API vasitəsilə bir-birinə zəng etmək imkanı idi. Daha düzgün xidmətə, gələcəkdə isə mikroservis arxitekturasına keçid üçün aydın ilkin şərtlər var idi.
Təxminən 2015-ci ildə parçalanma işlərimizə başladıq. Biz hələ ideal vəziyyətə çatmamışıq – böyük layihənin elə hissələri var ki, onları çətin ki, monolit adlandırmaq olar, lakin onlar da mikroservislərə bənzəmir. Bununla belə, irəliləyiş əhəmiyyətlidir.
Bu barədə məqalədə danışacağam.

Məzmun
Memarlıq və mövcud həll problemləri
Əvvəlcə arxitektura belə görünürdü: UI - ayrıca proqram, monolit hissəsi Visual Basic 6-da yazılmışdır, .NET tətbiqi kifayət qədər böyük verilənlər bazası ilə işləyən əlaqəli xidmətlər toplusu idi.
Əvvəlki həllin çatışmazlıqları
Tək uğursuzluq nöqtəsi
Tək bir uğursuzluq nöqtəmiz var idi: .NET tətbiqi bir prosesdə işləyirdi. Modullardan hər hansı biri uğursuz olarsa, bütün proqram uğursuz oldu və yenidən işə salınmalı oldu. Fərqli istifadəçilər üçün çoxlu sayda prosesi avtomatlaşdırdığımız üçün onlardan birində nasazlıq olduğu üçün onların hamısı bir müddət işləyə bilmədi. Proqram xətası ilə artıqlıq da kömək etmədi.
Təkmilləşdirmə növbəsi
Bu çatışmazlıq daha çox təşkilati xarakter daşıyır. Tətbiqimizdə çoxlu müştəri var və onların hamısı bunu mümkün qədər tez tamamlamaq istəyir. Əvvəllər bunu paralel etmək mümkün deyildi və bütün müştərilər növbədə dayanırdılar. Bu proses biznes üçün neqativə səbəb oldu, çünki onlar işlərinin dəyərli olduğunu sübut etməli idilər. Və inkişaf qrupu bu növbəni təşkil etmək üçün vaxt sərf etdi. Bu, çox vaxt və səy tələb etdi və nəticədə məhsul istədiyimiz qədər tez dəyişə bilmədi.
Resurslardan suboptimal istifadə
Xidmətləri bir prosesdə yerləşdirərkən, biz həmişə konfiqurasiyanı serverdən serverə tamamilə köçürürdük. Resursları israf etməmək və yerləşdirmə sxemimizə daha çevik nəzarət etmək üçün ən çox yüklənmiş xidmətləri ayrıca ayırmaq istədik.
Müasir texnologiyaların tətbiqi çətindir
Bütün tərtibatçılara tanış olan problem: layihəyə müasir texnologiyalar tətbiq etmək istəyi var, lakin heç bir yol yoxdur. Böyük bir monolit həll ilə, mövcud kitabxananın hər hansı bir yeniləməsi, yenisinə keçidi qeyd etməmək, olduqca qeyri-trivial bir işə çevrilir. Komanda rəhbərinə bunun boşa çıxan əsəblərdən daha çox bonus gətirəcəyini sübut etmək çox vaxt aparır.
Dəyişikliklərin verilməsində çətinlik
Bu, ən ciddi problem idi - iki aydan bir buraxılışlar verirdik.
Tərtibatçıların sınaqlarına və səylərinə baxmayaraq, hər buraxılış bank üçün əsl fəlakətə çevrildi. Biznes həftənin əvvəlində bəzi funksionallığın onun üçün işləməyəcəyini başa düşdü. Və tərtibatçılar başa düşdülər ki, onları bir həftə ciddi hadisələr gözləyir.
Hər kəsin vəziyyəti dəyişmək arzusu var idi.
Mikroservislərdən gözləntilər
Hazır olduqda komponentlərin buraxılması. Məhlulun parçalanması və müxtəlif proseslərin ayrılması yolu ilə komponentlərin hazır olduqları kimi buraxılması.
Kiçik məhsul qrupları. Bu vacibdir, çünki köhnə monolit üzərində işləyən böyük komandanı idarə etmək çətin idi. Belə bir komanda ciddi bir prosesə uyğun işləməyə məcbur idi, lakin onlar daha çox yaradıcılıq və müstəqillik istəyirdilər. Bunu yalnız kiçik komandalar ödəyə bilərdi.
Ayrı-ayrı proseslərdə xidmətlərin təcrid edilməsi. İdeal olaraq, onu konteynerlərdə təcrid etmək istərdim, amma .NET Framework-də yazılmış çox sayda xidmət yalnız altında işləyir Windows.NET Core əsaslı xidmətlər artıq ortaya çıxır, lakin hələ də onlardan azdır.
Yerləşdirmə çevikliyi. Mən xidmətləri kodun məcbur etdiyi şəkildə deyil, bizə lazım olan şəkildə birləşdirmək istərdim.
Yeni texnologiyalardan istifadə. Bu, hər bir proqramçı üçün maraqlıdır.
Keçid məsələləri
Təbii ki, monolitin mikroservislərə bölünməsi asan olsaydı, bu barədə konfranslarda danışmağa, məqalələr yazmağa ehtiyac qalmazdı. Bu prosesdə çoxlu tələlər var, bizə mane olan əsasları təsvir edəcəyəm.
İlk problem əksər monolitlər üçün xarakterikdir: iş məntiqi əlaqəsi. Monolit yazarkən əlavə kod yazmamaq üçün siniflərimizi təkrar istifadə etmək istəyirik. Mikroservislərə keçərkən bu, problemə çevrilir: bütün kodlar kifayət qədər sıx bağlıdır və xidmətləri ayırmaq çətindir.
İşə başlayan zaman depoda 500-dən çox layihə və 700 mindən çox kod sətirləri var idi. Bu kifayət qədər böyük bir həlldir. ikinci problem. Sadəcə götürüb mikroservislərə bölmək mümkün deyildi.
Üçüncü problem - Lazımi infrastrukturun olmaması. Əslində, mənbə kodunun serverlərə əl ilə kopyalanması ilə məşğul idik.
Monolitdən mikroservislərə necə keçmək olar
Mikroxidmətlərin ayrılması
Birincisi, biz dərhal özümüz üçün müəyyən etdik ki, mikroxidmətlərin ayrılması iterativ bir prosesdir. Bizdən həmişə paralel olaraq biznes tapşırıqlarını hazırlamaq tələb olunub. Bunu texniki cəhətdən necə həyata keçirəcəyimiz artıq bizim problemimizdir. Ona görə də biz iterativ prosesə hazırlaşdıq. Böyük bir tətbiqiniz varsa və ilkin olaraq yenidən yazılmağa hazır deyilsə, o, fərqli işləməyəcək.
Mikroservisləri təcrid etmək üçün hansı üsullardan istifadə edirik?
ПÐμÑ € Ð²Ñ <й Ñ Ð¿Ð¾Ñ Ð¾Ð ± - mövcud modulları xidmət kimi çıxarmaq. Bu baxımdan bizim bəxtimiz gətirdi: artıq WCF protokolu ilə işləyən rəsmiləşdirilmiş xidmətlər var idi. Onlar ayrı-ayrı məclislərə ayrıldılar. Onları ayrı-ayrılıqda daşıdıq, hər quruluşa kiçik bir başlatma əlavə etdik. Tətbiqi həm xidmət, həm də konsol kimi işlətməyə imkan verən gözəl Topshelf kitabxanasından istifadə etməklə yazılmışdır. Bu, sazlama üçün faydalıdır, çünki həlldə əlavə layihələr tələb olunmur.
Xidmətlər ümumi yığıncaqlardan istifadə etdikləri və ümumi məlumat bazası ilə işlədikləri üçün biznes məntiqi ilə əlaqələndirilirdi. Onları ən təmiz formada mikroservislər adlandırmaq çətin idi. Ancaq biz bu xidmətləri ayrı-ayrılıqda, müxtəlif proseslərdə verə bilərdik. Bu, artıq onların bir-birinə təsirini azaltmağa, paralel inkişaf və bir uğursuzluq nöqtəsi ilə problemi azaltmağa imkan verdi.
Host məclisi Proqram sinfində yalnız bir kod sətridir. Topshelf ilə işi köməkçi sinifdə gizlətdik.
namespace RBA.Services.Accounts.Host
{
internal class Program
{
private static void Main(string[] args)
{
HostRunner<Accounts>.Run("RBA.Services.Accounts.Host");
}
}
}
Mikroservisləri təcrid etməyin ikinci yolu: onları yeni problemləri həll etmək üçün yaradın. Eyni zamanda monolit böyüməzsə, bu, artıq əladır, yəni düzgün istiqamətdə hərəkət edirik. Yeni problemləri həll etmək üçün ayrıca xidmətlər yaratmağa çalışdıq. Əgər belə bir imkan olsaydı, biz onların məlumat modelini, ayrıca verilənlər bazasını tamamilə idarə edən daha çox “kanonik” xidmətlər yaratdıq.
Biz, bir çoxları kimi, autentifikasiya və avtorizasiya xidmətlərindən başladıq. Bunun üçün mükəmməldirlər. Onlar müstəqildirlər, bir qayda olaraq, ayrıca məlumat modelinə malikdirlər. Onlar özləri monolit ilə qarşılıqlı əlaqədə deyil, yalnız bəzi problemləri həll etmək üçün onlara istinad edir. Bu xidmətlərdə siz yeni arxitekturaya keçidə başlaya, onlarda infrastrukturu sazlaya, şəbəkə kitabxanaları ilə bağlı bəzi yanaşmaları sınaya və s. Təşkilatımızda autentifikasiya xidməti göstərə bilməyən komanda yoxdur.
Mikroservisləri təcrid etməyin üçüncü yoluistifadə etdiyimiz , bir az bizə xasdır. Bu, UI qatından biznes məntiqinin çıxarılmasıdır. Bizim əsas UI tətbiqimiz masaüstüdür, o, backend kimi C# dilində yazılmışdır. Tərtibatçılar vaxtaşırı səhvlərə yol verdilər və UI-də arxa hissədə mövcud olmalı və yenidən istifadə edilməli olan məntiq hissələrini çıxardılar.
UI hissəsinin kodundan real nümunəyə baxsanız, görə bilərsiniz ki, bu həllin əksəriyyətində yalnız UI forması yaratmaq üçün deyil, digər proseslərdə də faydalı olan real biznes məntiqi var.

Əsl UI məntiqi yalnız son bir neçə sətirdir. Biz onu serverə köçürdük ki, yenidən istifadə olunsun və bununla da UI-ni azaldıb düzgün arxitekturaya nail olduq.
Dördüncüsü, mikroservisləri təcrid etməyin ən vacib yolumonoliti azaltmağa imkan verən , emal ilə mövcud xidmətlərin çıxarılmasıdır. Mövcud modulları olduğu kimi çıxardıqda, tərtibatçılar həmişə nəticəni bəyənmirlər və funksionallıq yaradılandan bəri iş prosesi köhnələ bilər. Refaktorinq vasitəsilə biz yeni iş prosesini dəstəkləyə bilərik, çünki biznes tələbləri daim dəyişir. Mənbə kodunu təkmilləşdirə, məlum qüsurları aradan qaldıra, daha yaxşı məlumat modeli yarada bilərik. Qazanılmalı çoxlu faydalar var.
Yenidən işləmə ilə xidmətlərin ayrılması məhdud kontekst anlayışı ilə birlikdə gedir. Bu, domen yönümlü dizayndan bir konsepsiyadır. Bu, bir dilin bütün şərtlərinin unikal şəkildə müəyyən edildiyi domen modelinin bölməsi deməkdir. Nümunə olaraq sığorta və veksellərin kontekstini nəzərdən keçirək. Monolit tətbiqimiz var və sığortada hesabla işləmək lazımdır. Tərtibatçıdan başqa bir məclisdə mövcud Hesab sinifini tapmasını, Sığorta sinfindən ona istinad etməsini gözləyirik və biz iş kodu alacağıq. DRY prinsipinə əməl olunacaq, mövcud koddan istifadə etməklə tapşırıq daha tez yerinə yetiriləcək.
Nəticədə hesab və sığorta kontekstlərinin bir-birinə bağlı olduğu ortaya çıxır. Yeni tələblər ortaya çıxdıqca, bu əlaqələr inkişafa mane olacaq və onsuz da mürəkkəb olan biznes məntiqinə mürəkkəblik əlavə edəcək. Bu problemi həll etmək üçün koddakı kontekstlər arasındakı sərhədləri tapmaq və onların pozuntularını aradan qaldırmaq lazımdır. Məsələn, sığortalar kontekstində Mərkəzi Bankdakı hesabın 20 rəqəmli nömrəsinin və hesabın açılma tarixinin kifayət etməsi tamamilə mümkündür.
Bu məhdud kontekstləri bir-birindən ayırmaq və monolit həlldən mikroservislərin çıxarılması prosesinə başlamaq üçün tətbiq daxilində xarici API yaratmaq kimi bir yanaşmadan istifadə etdik. Əgər bilsəydik ki, hansısa modul mikroservisə çevrilməli, hansısa yolla proses daxilində dəyişməlidir, onda dərhal xarici zənglər vasitəsilə başqa məhdud kontekstə aid məntiqə zənglər etdik. Məsələn, REST və ya WCF vasitəsilə.
Paylanmış əməliyyatlar tələb edən koddan qaçmayacağımıza özümüz üçün qəti qərar verdik. Bizim vəziyyətimizdə bu qaydaya riayət etmək olduqca asan oldu. İndiyə qədər biz sərt paylanmış əməliyyatlara həqiqətən ehtiyac duyulduğunda belə hallarla qarşılaşmamışıq - modullar arasında yekun uyğunluq kifayət qədərdir.
Konkret bir nümunəyə nəzər salaq. Bizdə orkestr anlayışı var - "tətbiq"in mahiyyətini emal edən boru kəməri. O, növbə ilə müştəri, hesab və bank kartı yaradır. Müştəri və hesab uğurla yaradılıbsa, lakin kartın yaradılması uğursuz olarsa, proqram "uğurlu" statusuna keçmir və "kart yaradılmadı" statusunda qalır. Gələcəkdə fon fəaliyyəti onu götürəcək və bitirəcək. Sistem bir müddətdir ki, uyğunsuzluq vəziyyətindədir, lakin biz ümumilikdə bundan razıyıq.
Məlumatların bir hissəsini ardıcıl olaraq saxlamaq lazım olduğu bir vəziyyət yaranarsa, biz bunu bir prosesdə emal etmək üçün çox güman ki, xidmətin genişləndirilməsinə gedəcəyik.
Mikroxidmətin ayrılması nümunəsinə nəzər salın. Onu istehsala gətirmək necə nisbətən təhlükəsiz ola bilər? Bu nümunədə sistemin ayrıca bir hissəsi var - əmək haqqı xidməti modulu, kod bölmələrindən birini mikroservis etmək istəyirik.

İlk olaraq kodu yenidən yazaraq mikroservis yaradırıq. Bizə uyğun gəlməyən bəzi məqamları təkmilləşdiririk. Biz müştərinin yeni biznes tələblərini həyata keçiririk. Zəngin yönləndirilməsini təmin edəcək UI və API Gateway backend arasında paketə əlavə edirik.

Sonra bu konfiqurasiyanı işə salırıq, lakin pilot vəziyyətdədir. İstifadəçilərimizin əksəriyyəti hələ də köhnə biznes prosesləri ilə işləyir. Yeni istifadəçilər üçün biz bu prosesdə artıq olmayan monolit tətbiqin yeni versiyasını hazırlayırıq. Əslində, pilot şəklində işləyən bir dəstə monolit və mikroservisimiz var.

Uğurlu pilotla biz başa düşürük ki, yeni konfiqurasiya həqiqətən işləyir, biz köhnə monoliti tənlikdən çıxara və köhnə həllin yerinə yeni konfiqurasiyanı buraxa bilərik.

Ümumilikdə, monolitin mənbə kodunu ayırmaq üçün demək olar ki, bütün mövcud üsullardan istifadə edirik. Onların hamısı bizə tətbiqin hissələrinin ölçüsünü azaltmağa və onları daha yaxşı mənbə kodu edərək yeni kitabxanalara tərcümə etməyə imkan verir.
Verilənlər bazası ilə işləmək
Verilənlər bazası mənbə kodundan daha pis ayrılmağa borc verir, çünki o, təkcə cari sxemi deyil, həm də yığılmış tarixi məlumatları ehtiva edir.
Bizim verilənlər bazamız, bir çoxları kimi, daha bir vacib çatışmazlığa malik idi - onun böyük ölçüsü. Bu verilənlər bazası monolitin mürəkkəb biznes məntiqinə uyğun olaraq tərtib edilmişdir və müxtəlif məhdud kontekstlərin cədvəlləri arasında əlaqələr yığılmışdır.
Bizim vəziyyətimizdə bütün çətinliklərin (böyük verilənlər bazası, çoxlu əlaqələr, bəzən cədvəllər arasında anlaşılmaz sərhədlər) üstündə bir çox böyük layihələrdə baş verən bir problem var idi: paylaşılan verilənlər bazası modelindən istifadə. Məlumatlar görünüşlər vasitəsilə, replikasiya vasitəsilə cədvəllərdən götürülüb və bu təkrarlamanın lazım olduğu digər sistemlərə göndərilib. Nəticədə, cədvəlləri ayrı bir sxemə köçürə bilmədik, çünki onlar fəal şəkildə istifadə olunurdu.
Bölmədə koddakı məhdud kontekstlərə bölünmənin özü bizə kömək edir. Bu, adətən verilənlər bazası səviyyəsində məlumatları necə parçaladığımız barədə bizə yaxşı fikir verir. Hansı cədvəllərin bir məhdud konteksə, hansı digərinə aid olduğunu başa düşürük.
Biz verilənlər bazasını bölmək üçün iki qlobal üsul tətbiq etdik: mövcud cədvəlləri bölmək və emal ilə bölmək.
Məlumat strukturu yaxşı olarsa, biznes tələblərinə cavab verirsə və hər kəs bundan razıdırsa, mövcud cədvəllərin ayrılması yaxşı təcrübədir. Bu halda, mövcud cədvəlləri ayrıca sxemə ayıra bilərik.
Biznes modeli çox dəyişdikdə və cədvəllər artıq bizi heç qane etmirsə, emallı bir filial lazımdır.
Mövcud cədvəllərin ayrılması. Nəyi ayıracağımızı müəyyən etməliyik. Bu bilik olmadan heç nə işləməyəcək və kodda məhdud kontekstlərin ayrılması burada bizə kömək edəcək. Bir qayda olaraq, mənbə kodundakı kontekstlərin sərhədlərini başa düşə bilsəniz, hansı cədvəllərin ayrılması üçün siyahıya daxil edilməli olduğu aydın olur.
Təsəvvür edin ki, iki monolit modulun eyni verilənlər bazası ilə qarşılıqlı əlaqədə olduğu bir həllimiz var. Yalnız bir modulun ayrılmış cədvəllər bölməsi ilə qarşılıqlı əlaqədə olduğundan, digərinin isə API vasitəsilə onunla qarşılıqlı əlaqədə olduğundan əmin olmalıyıq. Başlamaq üçün API vasitəsilə yalnız qeydin aparılması kifayətdir. Bu, mikroservislərin müstəqilliyindən danışa bilməmiz üçün zəruri şərtdir. Böyük bir problem olmadığı müddətcə oxunmuş bağlantılar qala bilər.

Növbəti addım olaraq, biz artıq ayrıla bilən cədvəllərlə işləyən kod bölməsini emallı və ya işlənmədən ayrıca mikroservisə ayıra və ayrıca prosesdə, konteynerdə işləyə bilərik. Bu, monolit verilənlər bazasına və onunla birbaşa əlaqəsi olmayan cədvəllərə qoşulan ayrıca bir xidmət olacaqdır. Monolit hələ də oxumaq üçün ayrılan hissə ilə qarşılıqlı əlaqədədir.

Daha sonra biz bu əlaqəni aradan qaldıracağıq, yəni ayrılmış cədvəllərdən monolit tətbiq məlumatlarının oxunmasını da API-yə köçürəcəyik.

Sonra, ümumi verilənlər bazasından yalnız yeni mikroservisin işlədiyi cədvəlləri seçirik. Cədvəlləri ayrı bir sxemə və ya hətta ayrıca fiziki verilənlər bazasına köçürə bilərik. Mikroservis və monolit verilənlər bazası arasında oxumaq üçün əlaqə qalır, lakin narahat olmaq üçün heç bir şey yoxdur, bu konfiqurasiyada o, uzun müddət yaşaya bilər.

Son addım bütün bağlantıları tamamilə silməkdir. Bu halda, əsas verilənlər bazasından məlumatları köçürməyimiz lazım ola bilər. Bəzən biz xarici sistemlərdən təkrarlanan bəzi məlumat və ya qovluqları bir neçə verilənlər bazasında təkrar istifadə etmək istəyirik. Bizdə vaxtaşırı belə olur.

Emal şöbəsi. Bu üsul birinciyə çox bənzəyir, yalnız tərsinə gedir. Dərhal yeni verilənlər bazamız və API vasitəsilə monolitlə qarşılıqlı əlaqədə olan yeni mikroservisimiz var. Lakin bu, gələcəkdə silmək istədiyimiz verilənlər bazası cədvəlləri toplusunu tərk edir. Artıq ehtiyacımız olmayacaq, yeni modeldə əvəz etmişik.

Bu sxemin işləməsi üçün çox güman ki, keçid dövrünə ehtiyacımız olacaq.
Sonra, iki mümkün yanaşma var.
Ilk: biz yeni və köhnə verilənlər bazalarındakı bütün məlumatları təkrarlayırıq. Bu halda, məlumat ehtiyatımız var, sinxronizasiya ilə bağlı problemlər ola bilər. Amma sonra iki fərqli müştəri götürə bilərik. Biri yeni versiya ilə, digəri köhnə ilə işləyəcək.
Ikinci: bəzi biznes atributuna görə məlumatların ayrılması. Məsələn, bizim sistemdə köhnə verilənlər bazasında saxlanılan 5 məhsulumuz var idi. Altıncısı, yeni iş tapşırığı çərçivəsində biz yeni verilənlər bazasına yerləşdiririk. Ancaq bizə bu məlumatları sinxronlaşdıran və müştəriyə harada və nəyi götürəcəyini göstərən API Gateway lazımdır.
Hər iki yanaşma işləyir, vəziyyətdən asılı olaraq seçin.
Hər şeyin işlədiyinə əmin olduqdan sonra, köhnə verilənlər bazası strukturları ilə işləyən monolitin hissəsi deaktiv edilə bilər.

Son addım köhnə məlumat strukturlarını silməkdir.

Yekun olaraq deyə bilərik ki, verilənlər bazası ilə bağlı problemlərimiz var: mənbə kodu ilə müqayisədə onunla işləmək çətindir, onu ayırmaq daha çətindir, lakin bunu etmək olar və etmək lazımdır. Bunu kifayət qədər təhlükəsiz etməyə imkan verən bəzi yollar tapdıq, lakin verilənlərlə səhv etmək mənbə kodundan daha asandır.
Mənbə kodu ilə işləmək
Monolit layihəni təhlil etməyə başlayanda mənbə kodu diaqramı belə görünürdü.

Şərti olaraq üç təbəqəyə bölmək olar. Bu, işləmə modulları, plaginlər, xidmətlər və fərdi fəaliyyətlər təbəqəsidir. Əslində bunlar monolitik bir həll daxilində giriş nöqtələri idi. Hamısı Ümumi təbəqə ilə sıx şəkildə bağlandı. Xidmətlər və bir çox əlaqələr arasında paylaşılan iş məntiqi var idi. Hər bir xidmət və plagin ölçüsündən və tərtibatçıların vicdanından asılı olaraq 10 və ya daha çox ümumi yığıncaqdan istifadə edirdi.
Bəxtimiz gətirdi, ayrıca istifadə edilə bilən infrastruktur kitabxanalarımız var idi.
Bəzən elə bir vəziyyət yaranırdı ki, bəzi Ümumi obyektlər əslində bu təbəqəyə aid deyil, infrastruktur kitabxanaları idi. Bu, adının dəyişdirilməsi ilə həll edildi.
Məhdud kontekstlər ən böyük narahatlıq idi. Belə oldu ki, 3-4 kontekst bir Ümumi məclisdə qarışdırılıb və eyni biznes funksiyaları çərçivəsində bir-birindən istifadə edilib. Onun harada və hansı sərhədlər boyunca bölünə biləcəyini və mənbə kodu birləşmələrinə bu ayırmanın xəritələşdirilməsi ilə bundan sonra nə edəcəyini anlamaq lazım idi.
Biz kodun bölünməsi prosesi üçün bir neçə qayda tərtib etdik.
Ilk: Biz artıq xidmətlər, fəaliyyətlər və plaginlər arasında biznes məntiqini bölüşmək istəmirdik. Biz mikroservislər daxilində biznes məntiqini müstəqil etmək istədik. Digər tərəfdən, mikroservislər, ideal olaraq, tamamilə müstəqil mövcud olan xidmətlər kimi qəbul edilir. Düşünürəm ki, bu yanaşma bir qədər israfçılıqdır və nail olmaq çətindir, çünki məsələn, C# xidmətləri hər halda standart kitabxana ilə birləşdiriləcək. Sistemimiz C# dilində yazılmışdır, digər texnologiyalardan hələ istifadə olunmayıb. Buna görə də, ümumi texniki qurğulardan istifadə etməyə imkanımız olduğuna qərar verdik. Əsas odur ki, onlarda biznes məntiqinin heç bir fraqmenti yoxdur. İstifadə etdiyiniz ORM ətrafında gözəl sarğı varsa, onu xidmətdən xidmətə köçürmək çox baha başa gəlir.
Komandamız domen yönümlü dizaynın pərəstişkarıdır, ona görə də soğan arxitekturası bizim üçün çox uyğun idi. Xidmətlərimizdə əsas məlumat girişi təbəqəsi deyil, yalnız biznes məntiqini ehtiva edən və infrastruktura keçidlərdən məhrum olan domen məntiqi ilə bir montaj idi. Eyni zamanda, çərçivələrlə əlaqəli problemləri həll etmək üçün müstəqil olaraq domen birləşməsini təkmilləşdirə bilərik.
Bu mərhələdə ilk ciddi problemlə qarşılaşdıq. Xidmət bir domen yığıncağına istinad etməli idi, məntiqi müstəqil etmək istədik və DRY prinsipi burada bizə müdaxilə etdi. Tərtibatçılar təkrarlamanın qarşısını almaq üçün qonşu məclislərin siniflərini təkrar istifadə etmək istədilər və nəticədə domenlər yenidən bir-biri ilə əlaqə yaratmağa başladı. Nəticələri təhlil etdik və qərara gəldik ki, bəlkə də problem mənbə kodu anbar cihazının ərazisindədir. Bütün mənbə kodları olan böyük bir depomuz var idi. Bütün layihə üçün həlli yerli maşın üzərində qurmaq çox çətin idi. Buna görə də, layihənin hissələri üçün ayrıca kiçik həllər yaradıldı və heç kim onlara ümumi və ya domen yığıncağı əlavə etməyi və onlardan təkrar istifadə etməyi qadağan etmədi. Bizə bunu etməyə imkan verməyən yeganə vasitə baxış kodu idi. Amma bəzən o da qarışırdı.
Sonra ayrı-ayrı depoları olan bir modelə keçməyə başladıq. Biznes məntiqi xidmətdən xidmətə keçməyi dayandırdı, domenlər həqiqətən müstəqil oldu. Məhdud kontekstlər daha açıq şəkildə dəstəklənir. İnfrastruktur kitabxanalarından necə təkrar istifadə edirik? Onları ayrıca bir depoya ayırdıq, sonra onları Artifactory-də yerləşdirdiyimiz Nuget paketlərinə qoyduq. Hər hansı bir dəyişikliklə, montaj və nəşr avtomatik olaraq baş verir.

Xidmətlərimiz xarici infrastruktur paketləri ilə eyni şəkildə daxili infrastruktur paketlərinə istinad etməyə başladı. Biz Nuget-dən xarici kitabxanaları yükləyirik. Bu paketləri yerləşdirdiyimiz Artifactory ilə işləmək üçün iki paket menecerindən istifadə etdik. Kiçik depolarda biz də Nuget-dən istifadə etdik. Çoxsaylı xidmətləri olan depolarda modullar arasında daha çox versiya uyğunluğu təmin edən Paketdən istifadə etdik.

Beləliklə, mənbə kodu üzərində işləyərək, arxitekturanı bir az dəyişdirərək və depoları ayıraraq, xidmətlərimizi daha müstəqil edirik.
İnfrastruktur məsələləri
Mikroservislərə keçidin mənfi tərəflərinin əksəriyyəti infrastrukturla bağlıdır. Sizə avtomatlaşdırılmış yerləşdirmə, infrastrukturu idarə etmək üçün yeni kitabxanalara ehtiyacınız olacaq.
Mühitlərdə əl ilə quraşdırma
Əvvəlcə həlli mühitlərə əl ilə quraşdırdıq. Bu prosesi avtomatlaşdırmaq üçün biz CI/CD boru xətti yaratdıq. Davamlı çatdırılma prosesini seçdik, çünki davamlı yerləşdirmə biznes prosesləri baxımından bizim üçün hələ də qəbuledilməzdir. Buna görə istismara göndərmə bir düymə ilə, sınaq üçün isə avtomatik olaraq həyata keçirilir.

Mənbə saxlama üçün Atlassian, Bitbucket və tikinti üçün Bamboo istifadə edirik. Biz Cake-də qurma skriptləri yazmağı sevirik, çünki o, eyni C#-dır. Hazır paketlər Artifactory-ə gəlir və Ansible avtomatik olaraq test serverlərinə daxil olur, bundan sonra onlar dərhal sınaqdan keçirilə bilər.

Ayrı-ayrı giriş
Bir vaxtlar monolitin ideyalarından biri müştərək ağac kəsilməsini təmin etmək idi. Biz həmçinin disklərdə olan fərdi qeydlərlə nə edəcəyimizi anlamalı olduq. Qeydlər mətn fayllarına yazılır. Standart ELK yığınından istifadə etmək qərarına gəldik. Biz birbaşa provayderlər vasitəsilə ELK-a yazmadıq, lakin qərara gəldik ki, mətn qeydlərini yekunlaşdıraq və onlara iz identifikatorunu identifikator kimi yazaq və bu qeydləri təhlil etmək üçün xidmət adını əlavə edək.

Filebeat ilə qeydlərimizi aşağıdakılardan toplaya bilirik serverlər, sonra onları çevirin, UI-də sorğular yaratmaq üçün Kibana-dan istifadə edin və zəngin xidmətlər arasında necə yönləndirildiyini görün. İzləmə ID-ləri bunun üçün çox faydalıdır.
Müvafiq xidmətlərin sınaqdan keçirilməsi və sazlanması
Əvvəlcə biz inkişaf etdirdiyimiz xidmətləri necə sazlaya biləcəyimizi tam başa düşmədik. Monolitlə hər şey sadə idi, biz onu yerli maşında işlədirdik. Əvvəlcə mikroservislərlə eyni şeyi etməyə çalışdılar, lakin bəzən bir mikroservisi tam işə salmaq üçün bir neçə digərini işə salmaq lazımdır və bu, əlverişsizdir. Yalnız yerli maşında sazlamaq istədiyimiz xidmət və ya xidmətləri tərk etdikdə modelə keçmək lazım olduğunu başa düşdük. Qalan xidmətlər prod ilə konfiqurasiyaya uyğun gələn serverlərdən istifadə olunur. Sazlamadan sonra, sınaq zamanı hər bir tapşırıq üçün test serverinə yalnız dəyişdirilmiş xidmətlər verilir. Beləliklə, məhlul gələcəkdə satışa çıxarılacağı formada sınaqdan keçirilir.
Xidmətlərin yalnız istehsal versiyalarının quraşdırıldığı serverlər var. Bu serverlər insidentlər, yerləşdirmədən əvvəl çatdırılma yoxlamaları və daxili təlimlər üçün lazımdır.
Məşhur Specflow kitabxanasından istifadə edərək avtomatlaşdırılmış sınaq prosesi əlavə etdik. Testlər Ansible-dan yerləşdirilən kimi NUnit tərəfindən avtomatik olaraq həyata keçirilir. Tapşırığın əhatə dairəsi tam avtomatikdirsə, əllə sınaqdan keçirməyə ehtiyac yoxdur. Baxmayaraq ki, bəzən əlavə əl testi hələ də tələb olunur. Müəyyən bir problem üçün hansı testlərin aparılacağını müəyyən etmək üçün Jira-da etiketlərdən istifadə edirik.
Bundan əlavə, yük testinə ehtiyac artdı, əvvəllər yalnız nadir hallarda həyata keçirilirdi. Testləri yerinə yetirmək üçün JMeter-dən, onları saxlamaq üçün InfluxDB-dən və prosesi qurmaq üçün Grafana-dan istifadə edirik.
Nəyə nail olduq?
Birincisi, biz “buraxılış” anlayışından xilas olduq. İki aylıq dəhşətli buraxılışlar, bu nəhəng istehsal mühitində yerləşdirildikdə, bir müddət iş proseslərini pozaraq yox oldu. İndi biz orta hesabla hər 1,5 gündən bir xidmətləri qruplaşdıraraq yerləşdiririk, çünki onlar təsdiq edildikdən sonra işə düşür.
Sistemimizdə ölümcül qəzalar yoxdur. Əgər səhvi olan bir mikroservisi buraxsaq, onunla əlaqəli funksionallıq pozulacaq və bütün digər funksionallıq təsirlənməyəcək. Bu, istifadəçi təcrübəsini xeyli yaxşılaşdırır.
Yerləşdirmə sxeminə nəzarət edə bilərik. Lazım gələrsə, xidmət qruplarını həllin qalan hissəsindən ayrıca ayıra bilərsiniz.
Bundan əlavə, böyük bir təkmilləşdirmə növbəsi ilə problemi əhəmiyyətli dərəcədə azaltdıq. Bəzi xidmətlərlə müstəqil işləyən ayrıca məhsul qruplarımız var. Scrum prosesinin lazımlı olduğu yer budur. Müəyyən bir komandanın ona tapşırıqlar verən ayrıca məhsul sahibi ola bilər.
Xülasə
- Mikroservislər mürəkkəb sistemləri parçalamaq üçün yaxşı uyğun gəlir. Bu prosesdə sistemimizdə nə olduğunu, məhdud kontekstlərin nə olduğunu, onların sərhədlərinin harada olduğunu anlamağa başlayırıq. Bu, modullara təkmilləşdirmələri düzgün paylamağa və kodun qarışmasının qarşısını almağa imkan verir.
- Mikroservislər təşkilati faydalar təmin edir. Onlara çox vaxt yalnız memarlıq deyilir, lakin hər hansı bir memarlıq özlüyündə deyil, biznes ehtiyaclarını həll etmək üçün lazımdır. Buna görə də, Scrum-un hazırda çox populyar olduğunu nəzərə alsaq, mikroservislərin kiçik komandalarda problemlərin həlli üçün yaxşı uyğunlaşdığını söyləyə bilərik.
- Ayrılma təkrarlanan bir prosesdir. Tətbiqi qəbul edib onu sadəcə mikroservislərə bölmək olmaz. Nəticədə məhsulun işlək olması ehtimalı azdır. Mikroservisləri vurğulayarkən, mövcud mirasın yenidən yazılması, yəni onu bizim bəyəndiyimiz və funksionallıq və sürət baxımından biznesin ehtiyaclarına daha yaxşı cavab verən koda çevirmək faydalıdır.
Kiçik xəbərdarlıq: Mikroservislərə köçürmə xərcləri olduqca əhəmiyyətlidir. İnfrastruktur problemini həll etmək çox vaxt apardı. Buna görə də, xüsusi miqyas tələb etməyən kiçik bir tətbiqiniz varsa, komandanızın diqqəti və vaxtı üçün mübarizə aparan çoxlu sayda müştərilər yoxdursa, bəlkə də mikroservislər bu gün sizə lazım olan şey deyil. Olduqca bahadır. Prosesi mikroservislərlə başlasanız, əvvəlcə xərclər eyni layihənin monolitin inkişafı ilə başlamasından daha çox olacaq.
PS Daha emosional hekayə (və sanki şəxsən sizə) - müəllif .
Hesabatın tam versiyasını təqdim edirik.
Mənbə: www.habr.com
