Go to Go! Bagaimana tim PHP mengambil untuk menulis layanan microser

Halo semuanya! Nama saya Alexey Skorobogaty, saya seorang arsitek sistem di Lamoda. Pada bulan Februari 2019, saya berbicara di Go Meetup ketika masih dalam posisi memimpin tim di tim Inti. Hari ini saya ingin menyajikan transkrip laporan saya, yang juga bisa Anda lihat.


Tim kami disebut Core karena suatu alasan: area tanggung jawab mencakup segala sesuatu yang terkait dengan pesanan dalam platform e-commerce. Tim ini dibentuk dari pengembang dan spesialis PHP dalam pemrosesan pesanan kami, yang pada saat itu merupakan satu monolit. Kami terlibat dan terus berurusan dengan dekomposisi menjadi layanan microser.


gambar


Pesanan dalam sistem kami terdiri dari komponen terkait: ada unit pengiriman dan keranjang, unit diskon dan pembayaran, dan pada akhirnya ada tombol yang mengirimkan pesanan yang akan dikumpulkan di gudang. Pada saat inilah pekerjaan sistem pemrosesan pesanan dimulai, di mana semua data pesanan akan divalidasi dan informasi dikumpulkan.


gambar


Di dalam semua ini adalah logika multikriteria yang kompleks. Blok saling berinteraksi dan saling memengaruhi. Perubahan terus menerus dan konstan dari bisnis menambah kompleksitas kriteria. Selain itu, kami memiliki platform berbeda di mana pelanggan dapat membuat pesanan: situs web, aplikasi, pusat panggilan, platform B2B. Serta kriteria SLA / MTTI / MTTR yang ketat (metrik registrasi dan resolusi insiden). Semua ini membutuhkan fleksibilitas dan stabilitas tinggi dari layanan.


Warisan arsitektur


Seperti yang sudah saya katakan, pada saat pembentukan tim kami, sistem pemrosesan pesanan adalah monolit - hampir 100 ribu baris kode yang secara langsung menggambarkan logika bisnis. Bagian utama ditulis pada tahun 2011 menggunakan arsitektur MVC multi-layer klasik. Itu didasarkan pada PHP (kerangka kerja ZF1), yang secara bertahap ditumbuhi adapter dan komponen symfony untuk berinteraksi dengan berbagai layanan. Selama keberadaannya, sistem memiliki lebih dari 50 kontributor, dan meskipun kami berhasil mempertahankan gaya penulisan kode yang terpadu, ini juga memberlakukan batasannya. Selain itu, sejumlah besar konteks campuran muncul - karena berbagai alasan, beberapa mekanisme diterapkan dalam sistem yang tidak secara langsung terkait dengan pemrosesan pesanan. Semua ini mengarah pada fakta bahwa saat ini kami memiliki database MySQL yang lebih besar dari 1 terabyte.


Secara skematis, arsitektur awal dapat direpresentasikan sebagai berikut:


gambar


Urutan, tentu saja, ada di masing-masing lapisan - tetapi selain urutan, ada konteks lain. Kami mulai dengan mendefinisikan konteks pesanan yang terbatas dan menyebutnya Pesanan Pelanggan, karena selain pesanan itu sendiri, ada beberapa blok yang saya sebutkan di awal: pengiriman, pembayaran, dll. Di dalam monolith, semua ini sulit untuk dikelola: perubahan apa pun menyebabkan peningkatan dependensi, kode dikirim ke prod untuk waktu yang sangat lama, dan probabilitas kesalahan dan kegagalan sistem meningkat sepanjang waktu. Tetapi kita berbicara tentang membuat pesanan, metrik utama dari toko online - jika pesanan tidak dibuat, maka sisanya tidak begitu penting. Kegagalan sistem menyebabkan penurunan penjualan.


Oleh karena itu, kami memutuskan untuk mentransfer konteks Pesanan Pelanggan dari sistem Pemrosesan Pesanan ke layanan microser terpisah, yang disebut Manajemen Pesanan.


gambar


Persyaratan dan Alat


Setelah menentukan konteks yang kami putuskan untuk dihapus dari monolith sejak awal, kami membentuk persyaratan untuk layanan kami di masa depan:


  • Performa
  • Konsistensi data
  • Keberlanjutan
  • Prediktabilitas
  • Transparansi
  • Peningkatan perubahan

Kami ingin agar kode sejelas dan semudah mungkin diedit, sehingga generasi pengembang selanjutnya dapat dengan cepat membuat perubahan yang diperlukan untuk bisnis.


Akibatnya, kami sampai pada struktur tertentu yang kami gunakan di semua layanan microser baru:


Konteks Terbatas . Setiap layanan mikro baru, dimulai dengan Manajemen Pesanan, kami buat berdasarkan persyaratan bisnis. Harus ada penjelasan spesifik tentang bagian mana dari sistem dan mengapa diperlukan untuk menempatkannya dalam layanan mikro yang terpisah.


Infrastruktur dan alat yang ada. Kami bukan tim pertama di Lamoda yang mulai menerapkan Go, sebelum kami ada pelopor - tim Go sendiri, yang menyiapkan infrastruktur dan alat:


  1. Gogi (kesombongan) adalah generator spesifikasi kesombongan.
  2. Gonkey (pengujian) - untuk tes fungsional.
  3. Kami menggunakan Json-rpc dan menghasilkan pengikatan klien / server dengan kesombongan. Kami juga menyebarkan semua ini ke Kubernetes, mengumpulkan metrik di Prometheus, menggunakan ELK / Jaeger untuk melacak - semua ini termasuk dalam bundel yang dibuat Gogi untuk setiap layanan-mikro baru dengan spesifikasi.

Ini adalah apa yang tampak seperti layanan microser Manajemen Pesanan baru kami:


gambar


Pada input, kami memiliki data, kami mengumpulkannya, memvalidasinya, berinteraksi dengan layanan pihak ketiga, membuat keputusan dan mentransfer hasilnya lebih jauh ke Pemrosesan Pesanan - monolit yang sama yang besar, tidak stabil, dan membutuhkan sumber daya. Ini juga perlu dipertimbangkan saat membangun layanan mikro.


Pergeseran paradigma


Memilih Go, kami segera mendapatkan beberapa keuntungan:


  • Pengetikan kuat statis segera memotong sejumlah bug yang mungkin terjadi.
  • Model konkurensi cocok dengan tugas kita dengan baik, karena kita perlu berjalan-jalan dan secara bersamaan melakukan polling beberapa layanan.
  • Komposisi dan antarmuka juga membantu kami dalam pengujian.
  • "Kesederhanaan" studi - di sinilah tidak hanya nilai tambah yang ditemukan, tetapi juga masalah.

Bahasa Go membatasi imajinasi pengembang. Ini menjadi batu sandungan bagi tim kami, yang terbiasa dengan PHP ketika kami beralih ke pengembangan di Go. Kita dihadapkan dengan perubahan paradigma nyata. Kami harus melalui beberapa tahap dan memahami beberapa hal:


  1. Go sulit membangun abstraksi.
  2. Go dapat dikatakan berbasis objek, tetapi bukan bahasa yang berorientasi objek, karena tidak ada pewarisan langsung dan beberapa hal lainnya.
  3. Go membantu menulis secara eksplisit, daripada menyembunyikan objek di balik abstraksi.
  4. Go memiliki pipelining. Ini menginspirasi kami untuk membangun rantai pengolah data.

Sebagai hasilnya, kami memahami bahwa Go adalah bahasa pemrograman prosedural.
gambar


Data dulu


Saya sedang memikirkan bagaimana memvisualisasikan masalah yang kami hadapi dan menemukan gambar ini:


gambar


Ini adalah pandangan "berorientasi objek" tentang dunia di mana kita membangun abstraksi dan menutup objek di belakangnya. Misalnya, di sini bukan hanya sebuah pintu, tetapi Penginisialisasi Sesi Dalam Ruangan. Bukan murid, tetapi Interface Monitor Pengunjung - dan sebagainya.


Kami meninggalkan pendekatan ini, dan menempatkan entitas di tempat pertama, tanpa menjadi dikaburkan oleh abstraksi.


Dengan alasan seperti ini, kami menempatkan data di tempat pertama, dan mendapatkan Pipelining seperti itu di layanan:


gambar


Awalnya, kami mendefinisikan model data yang memasuki pipa penangan. Data bisa berubah, dan perubahan dapat terjadi baik secara berurutan maupun konkurensi. Dengan ini, kami menang dalam kecepatan.


Kembali ke masa depan


Tiba-tiba, mengembangkan layanan microser, kami sampai pada model pemrograman tahun 70-an. Setelah 70-an, monolit perusahaan besar muncul, di mana pemrograman berorientasi objek muncul, dan pemrograman fungsional - abstraksi besar yang memungkinkan untuk menyimpan kode di monolit ini. Dalam layanan mikro, kami tidak membutuhkan semua ini, dan kami dapat menggunakan model CSP yang sangat baik ( mengkomunikasikan proses berurutan ), gagasan yang diajukan pada tahun 70-an oleh Charles Choir.


Kami juga menggunakan Sequence / Selection / Interation - sebuah paradigma pemrograman struktural yang dengannya semua kode program dapat terdiri dari struktur kontrol yang sesuai.


Nah, pemrograman prosedural, yang merupakan arus utama di tahun 70-an :)


Struktur proyek


gambar


Seperti yang saya katakan, pertama-tama kita menempatkan data. Selain itu, kami mengganti pembangunan proyek "dari infrastruktur" dengan yang berorientasi bisnis. Sehingga pengembang, memasukkan kode proyek, segera melihat apa yang dilakukan layanan - ini adalah transparansi yang telah kami identifikasi sebagai salah satu persyaratan dasar untuk struktur layanan microser kami.


Hasilnya, kami memiliki arsitektur datar: lapisan API kecil plus model data. Dan semua logika (yang dibatasi dalam konteks kita oleh persyaratan bisnis dari layanan mikro) disimpan dalam prosesor (penangan).


Kami berusaha untuk tidak membuat layanan microser terpisah baru tanpa permintaan yang jelas dari bisnis - ini adalah bagaimana kami mengontrol rincian seluruh sistem. Jika ada logika yang terkait erat dengan layanan Microsoft yang ada, tetapi pada dasarnya merujuk pada konteks yang berbeda, kami pertama-tama menyimpulkannya dalam layanan yang disebut. Dan hanya ketika kebutuhan bisnis yang konstan muncul, kami membawanya ke microservice terpisah, yang kemudian kami beralih menggunakan panggilan rpc.


Untuk mengontrol granularitas dan untuk tidak menghasilkan layanan microser tanpa berpikir, kami menyimpulkan logika yang tidak terkait langsung dengan konteks ini, tetapi terkait erat dengan layanan mikro ini, di lapisan layanan. Dan kemudian, jika ada kebutuhan bisnis, kami membawanya ke microservice terpisah - dan kemudian kami menggunakannya dengan panggilan rpc untuk mengaksesnya.


gambar


Dengan demikian, untuk API internal dalam prosesor layanan, interaksi tidak berubah dengan cara apa pun.


Keberlanjutan


Kami memutuskan untuk tidak mengambil perpustakaan pihak ketiga terlebih dahulu, karena data yang kami kerjakan cukup sensitif. Jadi kami bersepeda sedikit :) Sebagai contoh, kami sendiri menerapkan beberapa mekanisme klasik - untuk Idempotensi, pekerja Antrian, Toleransi Kesalahan, Kompensasi transaksi. Langkah selanjutnya adalah mencoba menggunakannya kembali. Bungkus di perpustakaan, mungkin kontainer mobil samping di Kubernetes Pods. Tapi sekarang kita bisa menerapkan pola-pola ini.


Kami menerapkan dalam sistem kami pola yang disebut degradasi anggun: layanan harus terus bekerja, terlepas dari panggilan eksternal di mana kami mengumpulkan informasi. Pada contoh membuat pesanan: jika permintaan masuk ke layanan, kami akan membuat pesanan dalam hal apa pun. Sekalipun layanan tetangga jatuh, yang bertanggung jawab atas sebagian informasi yang harus kami agregat atau validasikan. Selain itu - kami tidak akan kehilangan pesanan, bahkan jika kami tidak bisa dalam penolakan jangka pendek pemrosesan pesanan, di mana kami harus mentransfer. Ini juga salah satu kriteria yang dengannya kami memutuskan apakah akan menempatkan logika dalam layanan terpisah. Jika suatu layanan tidak dapat memberikan kerjanya ketika layanan berikut tidak tersedia di jaringan, maka Anda harus mendesain ulang atau berpikir apakah harus dikeluarkan dari monolith sama sekali.


Go to Go!


Ketika Anda datang untuk menulis microservices produk yang berorientasi bisnis dari arsitektur berorientasi layanan klasik, khususnya PHP, Anda menjumpai perubahan paradigma. Dan itu harus dilewati, kalau tidak Anda bisa menginjak menyapu tanpa henti. Struktur proyek yang berorientasi bisnis memungkinkan kita untuk tidak menyulitkan kode sekali lagi dan mengontrol rincian layanan.


Salah satu tugas utama kami adalah meningkatkan stabilitas layanan. Tentu saja, Go tidak memberikan peningkatan stabilitas di luar kotak. Tetapi, menurut pendapat saya, dalam ekosistem Go, ternyata lebih mudah untuk membuat semua perangkat Keandalan yang diperlukan, bahkan dengan tangan Anda sendiri, tanpa menggunakan perpustakaan pihak ketiga.


Tugas penting lainnya adalah meningkatkan fleksibilitas sistem. Dan di sini saya dapat mengatakan bahwa laju pengenalan perubahan yang dibutuhkan oleh bisnis telah tumbuh secara signifikan. Berkat arsitektur microservices baru, pengembang dibiarkan sendiri dengan fitur bisnis, ia tidak perlu memikirkan membangun klien, mengirim pemantauan, mengirim pelacakan, dan mengatur logging. Kami meninggalkan bagi pengembang persis lapisan penulisan logika bisnis, memungkinkannya untuk tidak memikirkan seluruh bundel infrastruktur.


Apakah kita akan sepenuhnya menulis ulang semuanya di Go dan mengabaikan PHP?


Tidak, karena kita menjauh dari kebutuhan bisnis, dan ada beberapa konteks di mana PHP sangat cocok - itu tidak membutuhkan kecepatan dan seluruh toolkit Go-go. Semua otomatisasi operasi untuk pengiriman pesanan dan manajemen studio foto dilakukan dalam PHP. Tapi, misalnya, dalam platform e-commerce di sisi pelanggan, kami hampir menulis ulang semua yang ada di Go, karena itu dibenarkan.

Source: https://habr.com/ru/post/id478740/


All Articles