Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Dalam artikel ini, saya akan bercakap tentang cara projek yang saya sedang usahakan berubah daripada monolit besar kepada satu set perkhidmatan mikro.

Projek ini memulakan sejarahnya agak lama dahulu, pada awal tahun 2000. Versi pertama ditulis dalam Visual Basic 6. Dari masa ke masa, ia menjadi jelas bahawa pembangunan dalam bahasa ini sukar untuk disokong pada masa hadapan, kerana IDE dan bahasa itu sendiri kurang berkembang. Pada penghujung tahun 2000-an, ia telah memutuskan untuk beralih kepada C# yang lebih menjanjikan. Versi baharu ditulis selari dengan semakan yang lama, secara beransur-ansur semakin banyak kod ditulis dalam .NET. Backend dalam C# pada mulanya tertumpu pada seni bina perkhidmatan, tetapi semasa pembangunan, perpustakaan biasa dengan logik digunakan, dan perkhidmatan dilancarkan dalam satu proses. Hasilnya ialah aplikasi yang kami panggil "monolit perkhidmatan."

Salah satu daripada beberapa kelebihan gabungan ini ialah keupayaan perkhidmatan untuk memanggil satu sama lain melalui API luaran. Terdapat prasyarat yang jelas untuk peralihan kepada perkhidmatan yang lebih betul, dan pada masa hadapan, seni bina perkhidmatan mikro.

Kami memulakan kerja kami pada penguraian sekitar tahun 2015. Kami masih belum mencapai keadaan yang ideal - masih terdapat bahagian projek besar yang hampir tidak boleh dipanggil monolit, tetapi mereka juga tidak kelihatan seperti perkhidmatan mikro. Namun begitu, kemajuan adalah ketara.
Saya akan bercakap mengenainya dalam artikel.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Π‘ΠΎΠ΄Π΅Ρ€ΠΆΠ°Π½ΠΈΠ΅

Seni bina dan masalah penyelesaian sedia ada


Pada mulanya, seni bina kelihatan seperti ini: UI adalah aplikasi berasingan, bahagian monolitik ditulis dalam Visual Basic 6, aplikasi .NET ialah satu set perkhidmatan berkaitan yang bekerja dengan pangkalan data yang agak besar.

Kelemahan penyelesaian sebelumnya

Satu titik kegagalan
Kami mempunyai satu titik kegagalan: aplikasi .NET berjalan dalam satu proses. Jika mana-mana modul gagal, keseluruhan aplikasi gagal dan terpaksa dimulakan semula. Memandangkan kami mengautomasikan sejumlah besar proses untuk pengguna yang berbeza, disebabkan kegagalan dalam salah satu daripadanya, semua orang tidak dapat berfungsi untuk beberapa lama. Dan sekiranya berlaku ralat perisian, sandaran pun tidak membantu.

Barisan penambahbaikan
Kelemahan ini agak berorganisasi. Aplikasi kami mempunyai ramai pelanggan, dan mereka semua mahu memperbaikinya secepat mungkin. Sebelum ini, adalah mustahil untuk melakukan ini secara selari, dan semua pelanggan berdiri dalam barisan. Proses ini negatif untuk perniagaan kerana mereka perlu membuktikan bahawa tugas mereka adalah berharga. Dan pasukan pembangunan menghabiskan masa mengatur baris gilir ini. Ini mengambil banyak masa dan usaha, dan produk akhirnya tidak boleh berubah secepat yang mereka mahukan.

Penggunaan sumber yang tidak optimum
Apabila mengehos perkhidmatan dalam satu proses, kami sentiasa menyalin konfigurasi sepenuhnya dari pelayan ke pelayan. Kami mahu meletakkan perkhidmatan yang paling banyak dimuatkan secara berasingan supaya tidak membazir sumber dan mendapatkan kawalan yang lebih fleksibel ke atas skim penggunaan kami.

Sukar untuk melaksanakan teknologi moden
Masalah yang biasa kepada semua pemaju: terdapat keinginan untuk memperkenalkan teknologi moden ke dalam projek, tetapi tidak ada peluang. Dengan penyelesaian monolitik yang besar, sebarang kemas kini perpustakaan semasa, apatah lagi peralihan kepada yang baharu, bertukar menjadi tugas yang agak tidak remeh. Ia mengambil masa yang lama untuk membuktikan kepada ketua pasukan bahawa ini akan membawa lebih banyak bonus daripada saraf yang sia-sia.

Kesukaran mengeluarkan perubahan
Ini adalah masalah paling serius - kami mengeluarkan keluaran setiap dua bulan.
Setiap keluaran bertukar menjadi bencana sebenar untuk bank, walaupun ujian dan usaha pemaju. Perniagaan memahami bahawa pada awal minggu beberapa fungsinya tidak akan berfungsi. Dan pemaju memahami bahawa seminggu insiden serius menanti mereka.
Setiap orang mempunyai keinginan untuk mengubah keadaan.

Jangkaan daripada perkhidmatan mikro


Isu komponen apabila siap. Penghantaran komponen apabila siap dengan mengurai penyelesaian dan mengasingkan proses yang berbeza.

Pasukan produk kecil. Ini penting kerana pasukan besar yang bekerja pada monolit lama sukar diurus. Pasukan sedemikian terpaksa bekerja mengikut proses yang ketat, tetapi mereka mahukan lebih kreativiti dan kebebasan. Hanya pasukan kecil yang mampu membelinya.

Pengasingan perkhidmatan dalam proses berasingan. Sebaik-baiknya, saya ingin mengasingkannya dalam bekas, tetapi sebilangan besar perkhidmatan yang ditulis dalam Rangka Kerja .NET hanya dijalankan pada Windows. Perkhidmatan berdasarkan Teras .NET kini muncul, tetapi terdapat beberapa daripada mereka lagi.

Fleksibiliti penggunaan. Kami ingin menggabungkan perkhidmatan mengikut cara yang kami perlukan, dan bukan cara kod memaksanya.

Penggunaan teknologi baharu. Ini menarik kepada mana-mana pengaturcara.

Masalah peralihan


Sudah tentu, jika mudah untuk memecahkan monolit kepada perkhidmatan mikro, tidak perlu membincangkannya di persidangan dan menulis artikel. Terdapat banyak perangkap dalam proses ini; saya akan menerangkan yang utama yang menghalang kami.

Masalah pertama tipikal untuk kebanyakan monolit: koheren logik perniagaan. Apabila kita menulis monolit, kita mahu menggunakan semula kelas kita supaya tidak menulis kod yang tidak diperlukan. Dan apabila beralih ke perkhidmatan mikro, ini menjadi masalah: semua kod digandingkan agak rapat, dan sukar untuk memisahkan perkhidmatan.

Pada masa permulaan kerja, repositori mempunyai lebih daripada 500 projek dan lebih daripada 700 ribu baris kod. Ini adalah keputusan yang agak besar dan masalah kedua. Tidak mungkin untuk mengambilnya dan membahagikannya kepada perkhidmatan mikro.

Masalah ketiga - kekurangan infrastruktur yang diperlukan. Malah, kami menyalin kod sumber secara manual ke pelayan.

Bagaimana untuk beralih dari monolit kepada perkhidmatan mikro


Peruntukan Perkhidmatan Mikro

Pertama, kami segera menentukan sendiri bahawa pengasingan perkhidmatan mikro adalah proses berulang. Kami sentiasa dikehendaki untuk membangunkan masalah perniagaan secara selari. Bagaimana kami akan melaksanakan ini secara teknikal sudah menjadi masalah kami. Oleh itu, kami bersedia untuk proses berulang. Ia tidak akan berfungsi dengan cara lain jika anda mempunyai aplikasi yang besar dan pada mulanya ia tidak bersedia untuk ditulis semula.

Apakah kaedah yang kami gunakan untuk mengasingkan perkhidmatan mikro?

Cara pertama β€” memindahkan modul sedia ada sebagai perkhidmatan. Dalam hal ini, kami bernasib baik: sudah ada perkhidmatan berdaftar yang berfungsi menggunakan protokol WCF. Mereka dipisahkan kepada perhimpunan yang berasingan. Kami mengalihkannya secara berasingan, menambahkan pelancar kecil pada setiap binaan. Ia ditulis menggunakan perpustakaan Topshelf yang indah, yang membolehkan anda menjalankan aplikasi sebagai perkhidmatan dan sebagai konsol. Ini mudah untuk nyahpepijat kerana tiada projek tambahan diperlukan dalam penyelesaian.

Perkhidmatan disambungkan mengikut logik perniagaan, kerana ia menggunakan perhimpunan biasa dan berfungsi dengan pangkalan data biasa. Mereka hampir tidak boleh dipanggil perkhidmatan mikro dalam bentuk tulennya. Walau bagaimanapun, kami boleh menyediakan perkhidmatan ini secara berasingan, dalam proses yang berbeza. Ini sahaja memungkinkan untuk mengurangkan pengaruh mereka antara satu sama lain, mengurangkan masalah dengan pembangunan selari dan satu titik kegagalan.

Perhimpunan dengan hos hanyalah satu baris kod dalam kelas Program. Kami menyembunyikan kerja dengan Topshelf dalam kelas tambahan.

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

       }
    }
}

Cara kedua untuk memperuntukkan perkhidmatan mikro ialah: mencipta mereka untuk menyelesaikan masalah baru. Jika pada masa yang sama monolit tidak berkembang, ini sudah sangat baik, yang bermaksud kita bergerak ke arah yang betul. Untuk menyelesaikan masalah baharu, kami cuba mencipta perkhidmatan berasingan. Sekiranya terdapat peluang sedemikian, maka kami mencipta lebih banyak perkhidmatan "kanonikal" yang mengurus sepenuhnya model data mereka sendiri, pangkalan data yang berasingan.

Kami, seperti kebanyakan orang, bermula dengan perkhidmatan pengesahan dan kebenaran. Mereka sesuai untuk ini. Mereka bebas, sebagai peraturan, mereka mempunyai model data yang berasingan. Mereka sendiri tidak berinteraksi dengan monolit, hanya ia beralih kepada mereka untuk menyelesaikan beberapa masalah. Menggunakan perkhidmatan ini, anda boleh memulakan peralihan kepada seni bina baharu, nyahpepijat infrastruktur padanya, mencuba beberapa pendekatan yang berkaitan dengan perpustakaan rangkaian, dsb. Kami tidak mempunyai sebarang pasukan dalam organisasi kami yang tidak dapat membuat perkhidmatan pengesahan.

Cara ketiga untuk memperuntukkan perkhidmatan mikroYang kami gunakan adalah khusus untuk kami. Ini ialah penyingkiran logik perniagaan daripada lapisan UI. Aplikasi UI utama kami ialah desktop; ia, seperti bahagian belakang, ditulis dalam C#. Pembangun secara berkala membuat kesilapan dan memindahkan bahagian logik ke UI yang sepatutnya wujud di bahagian belakang dan digunakan semula.

Jika anda melihat contoh sebenar daripada kod bahagian UI, anda boleh melihat bahawa kebanyakan penyelesaian ini mengandungi logik perniagaan sebenar yang berguna dalam proses lain, bukan hanya untuk membina borang UI.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Logik UI sebenar hanya terdapat dalam beberapa baris terakhir. Kami memindahkannya ke pelayan supaya ia boleh digunakan semula, dengan itu mengurangkan UI dan mencapai seni bina yang betul.

Cara keempat dan paling penting untuk mengasingkan perkhidmatan mikro, yang memungkinkan untuk mengurangkan monolit, ialah penyingkiran perkhidmatan sedia ada dengan pemprosesan. Apabila kami mengeluarkan modul sedia ada seperti sedia ada, hasilnya tidak selalu sesuai dengan keinginan pembangun, dan proses perniagaan mungkin telah ketinggalan zaman sejak fungsi itu dicipta. Dengan pemfaktoran semula, kami boleh menyokong proses perniagaan baharu kerana keperluan perniagaan sentiasa berubah. Kami boleh menambah baik kod sumber, mengalih keluar kecacatan yang diketahui dan mencipta model data yang lebih baik. Terdapat banyak faedah yang diperolehi.

Mengasingkan perkhidmatan daripada pemprosesan adalah berkait rapat dengan konsep konteks terikat. Ini adalah konsep daripada Reka Bentuk Dipacu Domain. Ia bermaksud bahagian model domain di mana semua istilah bahasa tunggal ditakrifkan secara unik. Mari kita lihat konteks insurans dan bil sebagai contoh. Kami mempunyai aplikasi monolitik, dan kami perlu bekerja dengan akaun dalam insurans. Kami mengharapkan pembangun mencari kelas Akaun sedia ada dalam perhimpunan lain, merujuknya daripada kelas Insurans dan kami akan mempunyai kod kerja. Prinsip DRY akan dihormati, tugas akan dilakukan dengan lebih cepat dengan menggunakan kod sedia ada.

Akibatnya, ternyata bahawa konteks akaun dan insurans adalah berkaitan. Apabila keperluan baharu muncul, gandingan ini akan mengganggu pembangunan, meningkatkan kerumitan logik perniagaan yang sudah kompleks. Untuk menyelesaikan masalah ini, anda perlu mencari sempadan antara konteks dalam kod dan mengalih keluar pelanggarannya. Sebagai contoh, dalam konteks insurans, ada kemungkinan bahawa nombor akaun Bank Pusat 20 digit dan tarikh akaun dibuka adalah mencukupi.

Untuk memisahkan konteks bersempadan ini antara satu sama lain dan memulakan proses mengasingkan perkhidmatan mikro daripada penyelesaian monolitik, kami menggunakan pendekatan seperti mencipta API luaran dalam aplikasi. Jika kami tahu bahawa sesetengah modul harus menjadi perkhidmatan mikro, entah bagaimana diubah suai dalam proses, maka kami segera membuat panggilan ke logik yang dimiliki oleh konteks terhad lain melalui panggilan luaran. Contohnya, melalui REST atau WCF.

Kami dengan tegas memutuskan bahawa kami tidak akan mengelakkan kod yang memerlukan transaksi yang diedarkan. Dalam kes kami, ternyata agak mudah untuk mengikuti peraturan ini. Kami belum lagi menghadapi situasi di mana transaksi pengedaran yang ketat sangat diperlukan - konsistensi akhir antara modul adalah cukup memadai.

Mari lihat contoh khusus. Kami mempunyai konsep orkestra - saluran paip yang memproses entiti "aplikasi". Dia mencipta pelanggan, akaun dan kad bank secara bergilir-gilir. Jika pelanggan dan akaun berjaya dibuat, tetapi penciptaan kad gagal, aplikasi tidak beralih ke status "berjaya" dan kekal dalam status "kad tidak dibuat". Pada masa hadapan, aktiviti latar belakang akan mengambilnya dan menyelesaikannya. Sistem ini telah berada dalam keadaan tidak konsisten untuk beberapa waktu, tetapi kami secara amnya berpuas hati dengan perkara ini.

Jika situasi timbul apabila perlu untuk menyimpan sebahagian daripada data secara konsisten, kemungkinan besar kami akan pergi untuk penyatuan perkhidmatan untuk memprosesnya dalam satu proses.

Mari lihat contoh memperuntukkan perkhidmatan mikro. Bagaimanakah anda boleh membawanya ke pengeluaran dengan agak selamat? Dalam contoh ini, kami mempunyai bahagian sistem yang berasingan - modul perkhidmatan gaji, salah satu bahagian kod yang kami ingin buat perkhidmatan mikro.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Pertama sekali, kami mencipta perkhidmatan mikro dengan menulis semula kod. Kami sedang menambah baik beberapa aspek yang kami tidak berpuas hati. Kami melaksanakan keperluan perniagaan baharu daripada pelanggan. Kami menambah Gateway API pada sambungan antara UI dan bahagian belakang, yang akan menyediakan pemajuan panggilan.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Seterusnya, kami melepaskan konfigurasi ini ke dalam operasi, tetapi dalam keadaan perintis. Kebanyakan pengguna kami masih bekerja dengan proses perniagaan lama. Untuk pengguna baharu, kami sedang membangunkan versi baharu aplikasi monolitik yang tidak lagi mengandungi proses ini. Pada asasnya, kami mempunyai gabungan monolit dan perkhidmatan mikro yang berfungsi sebagai juruterbang.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Dengan juruterbang yang berjaya, kami memahami bahawa konfigurasi baharu sememangnya boleh dilaksanakan, kami boleh mengalih keluar monolit lama daripada persamaan dan meninggalkan konfigurasi baharu menggantikan penyelesaian lama.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Secara keseluruhan, kami menggunakan hampir semua kaedah sedia ada untuk memisahkan kod sumber monolit. Kesemuanya membolehkan kami mengurangkan saiz bahagian aplikasi dan menterjemahkannya ke perpustakaan baharu, menjadikan kod sumber yang lebih baik.

Bekerja dengan pangkalan data


Pangkalan data boleh dibahagikan lebih teruk daripada kod sumber, kerana ia mengandungi bukan sahaja skema semasa, tetapi juga data sejarah terkumpul.

Pangkalan data kami, seperti kebanyakan yang lain, mempunyai satu lagi kelemahan penting - saiznya yang besar. Pangkalan data ini telah direka bentuk mengikut logik perniagaan yang rumit bagi monolit, dan hubungan terkumpul antara jadual pelbagai konteks sempadan.

Dalam kes kami, untuk mengatasi semua masalah (pangkalan data yang besar, banyak sambungan, kadangkala sempadan yang tidak jelas antara jadual), masalah timbul yang berlaku dalam banyak projek besar: penggunaan templat pangkalan data yang dikongsi. Data diambil dari jadual melalui paparan, melalui replikasi, dan dihantar ke sistem lain di mana replikasi ini diperlukan. Akibatnya, kami tidak dapat mengalihkan jadual ke dalam skema yang berasingan kerana ia digunakan secara aktif.

Pembahagian yang sama ke dalam konteks terhad dalam kod membantu kami dalam pemisahan. Ia biasanya memberi kita idea yang cukup bagus tentang cara kita memecahkan data pada peringkat pangkalan data. Kami memahami jadual mana yang tergolong dalam satu konteks bersempadan dan yang mana satu lagi.

Kami menggunakan dua kaedah global pembahagian pangkalan data: pembahagian jadual sedia ada dan pembahagian dengan pemprosesan.

Memisahkan jadual sedia ada ialah kaedah yang baik untuk digunakan jika struktur data adalah baik, memenuhi keperluan perniagaan dan semua orang berpuas hati dengannya. Dalam kes ini, kita boleh memisahkan jadual sedia ada ke dalam skema yang berasingan.

Jabatan dengan pemprosesan diperlukan apabila model perniagaan telah banyak berubah, dan jadual tidak lagi memuaskan hati kami sama sekali.

Membahagikan jadual sedia ada. Kita perlu tentukan apa yang akan kita pisahkan. Tanpa pengetahuan ini, tiada apa yang akan berfungsi, dan di sini pemisahan konteks terikat dalam kod akan membantu kami. Sebagai peraturan, jika anda boleh memahami sempadan konteks dalam kod sumber, menjadi jelas jadual mana yang harus dimasukkan dalam senarai untuk jabatan itu.

Bayangkan kita mempunyai penyelesaian di mana dua modul monolit berinteraksi dengan satu pangkalan data. Kita perlu memastikan bahawa hanya satu modul berinteraksi dengan bahagian jadual yang dipisahkan, dan satu lagi mula berinteraksi dengannya melalui API. Sebagai permulaan, cukuplah hanya rakaman dijalankan melalui API. Ini adalah syarat yang perlu untuk kita bercakap tentang kebebasan perkhidmatan mikro. Sambungan membaca boleh kekal selagi tiada masalah besar.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Langkah seterusnya ialah kita boleh memisahkan bahagian kod yang berfungsi dengan jadual yang dipisahkan, dengan atau tanpa pemprosesan, ke dalam perkhidmatan mikro yang berasingan dan menjalankannya dalam proses berasingan, sebuah bekas. Ini akan menjadi perkhidmatan berasingan dengan sambungan ke pangkalan data monolit dan jadual yang tidak berkaitan secara langsung dengannya. Monolit masih berinteraksi untuk membaca dengan bahagian yang boleh ditanggalkan.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Kemudian kami akan mengalih keluar sambungan ini, iaitu membaca data daripada aplikasi monolitik daripada jadual yang dipisahkan juga akan dipindahkan ke API.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Seterusnya, kami akan memilih daripada pangkalan data umum jadual yang hanya berfungsi dengan perkhidmatan mikro baharu. Kita boleh mengalihkan jadual ke skema yang berasingan atau bahkan ke pangkalan data fizikal yang berasingan. Masih terdapat sambungan bacaan antara perkhidmatan mikro dan pangkalan data monolit, tetapi tiada apa yang perlu dibimbangkan, dalam konfigurasi ini ia boleh hidup untuk masa yang agak lama.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Langkah terakhir ialah mengalih keluar sepenuhnya semua sambungan. Dalam kes ini, kami mungkin perlu memindahkan data daripada pangkalan data utama. Kadangkala kami ingin menggunakan semula beberapa data atau direktori yang direplikasi daripada sistem luaran dalam beberapa pangkalan data. Ini berlaku kepada kita secara berkala.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Jabatan pemprosesan. Kaedah ini sangat serupa dengan yang pertama, hanya dalam urutan terbalik. Kami segera memperuntukkan pangkalan data baharu dan perkhidmatan mikro baharu yang berinteraksi dengan monolit melalui API. Tetapi pada masa yang sama, masih terdapat satu set jadual pangkalan data yang ingin kami padamkan pada masa hadapan. Kami tidak lagi memerlukannya; kami menggantikannya dalam model baharu.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Untuk skim ini berfungsi, kami mungkin memerlukan tempoh peralihan.

Kemudian terdapat dua pendekatan yang mungkin.

Pertama: kami menduplikasi semua data dalam pangkalan data baharu dan lama. Dalam kes ini, kami mempunyai lebihan data dan masalah penyegerakan mungkin timbul. Tetapi kita boleh mengambil dua pelanggan yang berbeza. Satu akan berfungsi dengan versi baharu, satu lagi dengan versi lama.

Kedua: kami membahagikan data mengikut beberapa kriteria perniagaan. Sebagai contoh, kami mempunyai 5 produk dalam sistem yang disimpan dalam pangkalan data lama. Kami meletakkan yang keenam dalam tugas perniagaan baharu dalam pangkalan data baharu. Tetapi kami memerlukan Gateway API yang akan menyegerakkan data ini dan menunjukkan kepada pelanggan dari mana dan apa yang hendak diperolehi.

Kedua-dua pendekatan berfungsi, pilih bergantung pada keadaan.

Selepas kami yakin semuanya berfungsi, bahagian monolit yang berfungsi dengan struktur pangkalan data lama boleh dilumpuhkan.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Langkah terakhir ialah mengalih keluar struktur data lama.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Untuk meringkaskan, kita boleh mengatakan bahawa kita mempunyai masalah dengan pangkalan data: sukar untuk bekerja dengannya berbanding dengan kod sumber, lebih sukar untuk dikongsi, tetapi ia boleh dan harus dilakukan. Kami telah menemui beberapa cara yang membolehkan kami melakukan ini dengan agak selamat, tetapi masih lebih mudah untuk membuat kesilapan dengan data berbanding dengan kod sumber.

Bekerja dengan kod sumber


Inilah rupa rajah kod sumber apabila kami mula menganalisis projek monolitik.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Ia boleh dibahagikan secara kasar kepada tiga lapisan. Ini adalah lapisan modul yang dilancarkan, pemalam, perkhidmatan dan aktiviti individu. Sebenarnya, ini adalah titik masuk dalam penyelesaian monolitik. Kesemuanya dimeterai rapat dengan lapisan Biasa. Ia mempunyai logik perniagaan yang dikongsi oleh perkhidmatan dan banyak sambungan. Setiap perkhidmatan dan pemalam menggunakan sehingga 10 atau lebih pemasangan biasa, bergantung pada saiz dan hati nurani pembangun.

Kami bertuah kerana mempunyai perpustakaan infrastruktur yang boleh digunakan secara berasingan.

Kadangkala situasi timbul apabila beberapa objek biasa sebenarnya bukan milik lapisan ini, tetapi adalah perpustakaan infrastruktur. Ini telah diselesaikan dengan menamakan semula.

Kebimbangan terbesar adalah konteks terhad. Kebetulan 3-4 konteks dicampur dalam satu perhimpunan Biasa dan digunakan antara satu sama lain dalam fungsi perniagaan yang sama. Adalah perlu untuk memahami di mana ini boleh dibahagikan dan di sepanjang sempadan apa, dan apa yang perlu dilakukan seterusnya dengan memetakan bahagian ini ke dalam himpunan kod sumber.

Kami telah merumuskan beberapa peraturan untuk proses pemisahan kod.

Yang pertama: Kami tidak lagi mahu berkongsi logik perniagaan antara perkhidmatan, aktiviti dan pemalam. Kami mahu menjadikan logik perniagaan bebas dalam perkhidmatan mikro. Microservices, sebaliknya, dianggap sebagai perkhidmatan yang wujud sepenuhnya secara bebas. Saya percaya bahawa pendekatan ini agak membazir, dan sukar untuk dicapai, kerana, sebagai contoh, perkhidmatan dalam C# akan dalam apa jua keadaan disambungkan oleh perpustakaan standard. Sistem kami ditulis dalam C#; kami belum lagi menggunakan teknologi lain. Oleh itu, kami memutuskan bahawa kami mampu menggunakan perhimpunan teknikal biasa. Perkara utama ialah mereka tidak mengandungi sebarang serpihan logik perniagaan. Jika anda mempunyai pembungkus kemudahan atas ORM yang anda gunakan, maka menyalinnya dari perkhidmatan ke perkhidmatan adalah sangat mahal.

Pasukan kami adalah peminat reka bentuk dipacu domain, jadi seni bina bawang sangat sesuai untuk kami. Asas perkhidmatan kami bukanlah lapisan akses data, tetapi himpunan dengan logik domain, yang mengandungi hanya logik perniagaan dan tidak mempunyai kaitan dengan infrastruktur. Pada masa yang sama, kami boleh mengubah suai pemasangan domain secara bebas untuk menyelesaikan masalah yang berkaitan dengan rangka kerja.

Pada peringkat ini kami menghadapi masalah serius pertama kami. Perkhidmatan ini perlu merujuk kepada satu himpunan domain, kami mahu menjadikan logik itu bebas, dan prinsip DRY sangat menghalang kami di sini. Pembangun mahu menggunakan semula kelas daripada perhimpunan bersebelahan untuk mengelakkan pertindihan, dan akibatnya, domain mula dipautkan bersama sekali lagi. Kami menganalisis keputusan dan memutuskan bahawa mungkin masalahnya juga terletak pada kawasan peranti penyimpanan kod sumber. Kami mempunyai repositori besar yang mengandungi semua kod sumber. Penyelesaian untuk keseluruhan projek adalah sangat sukar untuk dipasang pada mesin tempatan. Oleh itu, penyelesaian kecil yang berasingan telah dicipta untuk bahagian projek, dan tiada siapa yang melarang menambah beberapa himpunan biasa atau domain kepada mereka dan menggunakannya semula. Satu-satunya alat yang tidak membenarkan kami melakukan ini ialah semakan kod. Tetapi kadang-kadang ia juga gagal.

Kemudian kami mula beralih ke model dengan repositori berasingan. Logik perniagaan tidak lagi mengalir dari perkhidmatan ke perkhidmatan, domain benar-benar menjadi bebas. Konteks terikat disokong dengan lebih jelas. Bagaimanakah kita menggunakan semula perpustakaan infrastruktur? Kami memisahkannya ke dalam repositori yang berasingan, kemudian memasukkannya ke dalam pakej Nuget, yang kami masukkan ke dalam Artifactory. Dengan sebarang perubahan, pemasangan dan penerbitan berlaku secara automatik.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Perkhidmatan kami mula merujuk pakej infrastruktur dalaman dengan cara yang sama seperti pakej luaran. Kami memuat turun perpustakaan luaran daripada Nuget. Untuk bekerja dengan Artifactory, tempat kami meletakkan pakej ini, kami menggunakan dua pengurus pakej. Dalam repositori kecil kami juga menggunakan Nuget. Dalam repositori dengan pelbagai perkhidmatan, kami menggunakan Paket, yang menyediakan lebih banyak versi konsistensi antara modul.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Oleh itu, dengan mengusahakan kod sumber, mengubah sedikit seni bina dan mengasingkan repositori, kami menjadikan perkhidmatan kami lebih bebas.

Masalah infrastruktur


Kebanyakan kelemahan untuk beralih ke perkhidmatan mikro adalah berkaitan dengan infrastruktur. Anda memerlukan penggunaan automatik, anda memerlukan perpustakaan baharu untuk menjalankan infrastruktur.

Pemasangan manual dalam persekitaran

Pada mulanya, kami memasang penyelesaian untuk persekitaran secara manual. Untuk mengautomasikan proses ini, kami mencipta saluran paip CI/CD. Kami memilih proses penghantaran berterusan kerana penggunaan berterusan belum lagi boleh diterima untuk kami dari sudut pandangan proses perniagaan. Oleh itu, penghantaran untuk operasi dijalankan menggunakan butang, dan untuk ujian - secara automatik.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Kami menggunakan Atlassian, Bitbucket untuk penyimpanan kod sumber dan Bamboo untuk membina. Kami suka menulis skrip bina dalam Cake kerana ia sama dengan C#. Pakej siap sedia datang ke Artifactory, dan Ansible secara automatik sampai ke pelayan ujian, selepas itu ia boleh diuji serta-merta.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Pembalakan berasingan


Pada satu masa, salah satu idea monolit adalah untuk menyediakan pembalakan bersama. Kami juga perlu memahami perkara yang perlu dilakukan dengan log individu yang ada pada cakera. Log kami ditulis pada fail teks. Kami memutuskan untuk menggunakan tindanan ELK standard. Kami tidak menulis kepada ELK secara langsung melalui pembekal, tetapi memutuskan bahawa kami akan memuktamadkan log teks dan menulis ID surih di dalamnya sebagai pengecam, menambah nama perkhidmatan, supaya log ini boleh dihuraikan kemudian.

Peralihan daripada monolit kepada perkhidmatan mikro: sejarah dan amalan

Menggunakan Filebeat, kami mendapat peluang untuk mengumpul log kami daripada pelayan, kemudian mengubahnya, menggunakan Kibana untuk membina pertanyaan dalam UI dan melihat bagaimana panggilan itu berlaku antara perkhidmatan. Trace ID banyak membantu dalam hal ini.

Menguji dan menyahpepijat perkhidmatan berkaitan


Pada mulanya, kami tidak memahami sepenuhnya cara untuk menyahpepijat perkhidmatan yang sedang dibangunkan. Segala-galanya mudah dengan monolit; kami menjalankannya pada mesin tempatan. Pada mulanya mereka cuba melakukan perkara yang sama dengan perkhidmatan mikro, tetapi kadangkala untuk melancarkan sepenuhnya satu perkhidmatan mikro anda perlu melancarkan beberapa perkhidmatan lain, dan ini menyusahkan. Kami menyedari bahawa kami perlu beralih kepada model yang kami tinggalkan pada mesin tempatan hanya perkhidmatan atau perkhidmatan yang ingin kami nyahpepijat. Perkhidmatan selebihnya digunakan daripada pelayan yang sepadan dengan konfigurasi dengan prod. Selepas penyahpepijatan, semasa ujian, untuk setiap tugas, hanya perkhidmatan yang diubah dikeluarkan kepada pelayan ujian. Oleh itu, penyelesaian itu diuji dalam bentuk di mana ia akan muncul dalam pengeluaran pada masa hadapan.

Terdapat pelayan yang hanya menjalankan versi pengeluaran perkhidmatan. Pelayan ini diperlukan sekiranya berlaku insiden, untuk menyemak penghantaran sebelum penggunaan dan untuk latihan dalaman.

Kami telah menambah proses ujian automatik menggunakan perpustakaan Specflow yang popular. Ujian dijalankan secara automatik menggunakan NUnit sejurus selepas penggunaan daripada Ansible. Jika liputan tugas adalah automatik sepenuhnya, maka tidak ada keperluan untuk ujian manual. Walaupun kadangkala ujian manual tambahan masih diperlukan. Kami menggunakan teg dalam Jira untuk menentukan ujian yang hendak dijalankan untuk isu tertentu.

Di samping itu, keperluan untuk ujian beban telah meningkat; sebelum ini ia dijalankan hanya dalam kes yang jarang berlaku. Kami menggunakan JMeter untuk menjalankan ujian, InfluxDB untuk menyimpannya dan Grafana untuk membina graf proses.

Apa yang telah kita capai?


Pertama, kami telah menyingkirkan konsep "pelepasan". Sudah tiada lagi keluaran dahsyat selama dua bulan apabila raksasa ini digunakan dalam persekitaran pengeluaran, yang mengganggu proses perniagaan buat sementara waktu. Kini kami menggunakan perkhidmatan secara purata setiap 1,5 hari, mengumpulkannya kerana perkhidmatan tersebut mula beroperasi selepas diluluskan.

Tiada kegagalan maut dalam sistem kami. Jika kami mengeluarkan perkhidmatan mikro dengan pepijat, maka fungsi yang dikaitkan dengannya akan rosak dan semua fungsi lain tidak akan terjejas. Ini sangat meningkatkan pengalaman pengguna.

Kita boleh mengawal corak penggunaan. Anda boleh memilih kumpulan perkhidmatan secara berasingan daripada penyelesaian yang lain, jika perlu.

Di samping itu, kami telah mengurangkan masalah dengan ketara dengan barisan penambahbaikan yang besar. Kami kini mempunyai pasukan produk berasingan yang bekerja dengan beberapa perkhidmatan secara bebas. Proses Scrum sudah sesuai di sini. Pasukan tertentu mungkin mempunyai Pemilik Produk berasingan yang memberikan tugas kepadanya.

Ringkasan

  • Perkhidmatan mikro sangat sesuai untuk mengurai sistem yang kompleks. Dalam proses itu, kami mula memahami apa yang ada dalam sistem kami, konteks terhad yang ada, di mana sempadannya terletak. Ini membolehkan anda mengedarkan penambahbaikan dengan betul antara modul dan mengelakkan kekeliruan kod.
  • Perkhidmatan mikro menyediakan faedah organisasi. Mereka sering bercakap hanya sebagai seni bina, tetapi apa-apa seni bina diperlukan untuk menyelesaikan keperluan perniagaan, dan bukan sendiri. Oleh itu, kita boleh mengatakan bahawa perkhidmatan mikro sangat sesuai untuk menyelesaikan masalah dalam pasukan kecil, memandangkan Scrum sangat popular sekarang.
  • Pemisahan adalah proses berulang. Anda tidak boleh mengambil aplikasi dan hanya membahagikannya kepada perkhidmatan mikro. Produk yang dihasilkan tidak mungkin berfungsi. Apabila mendedikasikan perkhidmatan mikro, adalah berfaedah untuk menulis semula warisan sedia ada, iaitu mengubahnya menjadi kod yang kita suka dan lebih memenuhi keperluan perniagaan dari segi fungsi dan kelajuan.

    Kaveat kecil: Kos untuk berpindah ke perkhidmatan mikro agak besar. Ia mengambil masa yang lama untuk menyelesaikan masalah infrastruktur sahaja. Jadi, jika anda mempunyai aplikasi kecil yang tidak memerlukan penskalaan khusus, melainkan anda mempunyai sejumlah besar pelanggan yang bersaing untuk perhatian dan masa pasukan anda, maka perkhidmatan mikro mungkin bukan yang anda perlukan hari ini. Ia agak mahal. Jika anda memulakan proses dengan perkhidmatan mikro, maka kos pada mulanya akan lebih tinggi daripada jika anda memulakan projek yang sama dengan pembangunan monolit.

    PS Kisah yang lebih emosional (dan seolah-olah untuk anda secara peribadi) - menurut pautan.
    Berikut ialah versi penuh laporan.

Sumber: www.habr.com

Tambah komen