RBKmoney Pembayaran di bawah tenda - layanan Microsoft, protokol dan konfigurasi platform

Hai Habr! RBKmoney kembali menghubungi dan melanjutkan serangkaian artikel tentang cara menulis pemrosesan pembayaran do-it-yourself.



Saya ingin segera terjun ke detail deskripsi penerapan proses bisnis pembayaran sebagai mesin negara, menunjukkan contoh mesin seperti itu dengan serangkaian acara, fitur implementasi ... Tetapi sepertinya Anda tidak dapat melakukannya tanpa beberapa artikel ulasan lagi. Area subjek ternyata terlalu besar. Posting ini akan mengungkapkan nuansa kerja dan interaksi antara layanan microser platform kami, interaksi dengan sistem eksternal dan bagaimana kami mengelola konfigurasi bisnis.


Layanan makro


Sistem kami terdiri dari banyak layanan mikro, yang, mengimplementasikan masing-masing bagian akhir dari logika bisnis, berinteraksi satu sama lain dan bersama-sama membentuk layanan makro. Sebenarnya, layanan makro yang digunakan di pusat data, yang terhubung ke bank dan sistem pembayaran lainnya, adalah proses pembayaran kami.


Templat microservice


Kami menggunakan pendekatan terpadu untuk pengembangan layanan Microsoft apa pun dalam bahasa apa pun yang ditulis. Setiap microservice adalah wadah Docker yang berisi:


  • aplikasi itu sendiri yang mengimplementasikan logika bisnis yang ditulis dalam bahasa Erlang atau Jawa;
  • RPClib - perpustakaan yang mengimplementasikan komunikasi antara layanan microser;
    • kami menggunakan Apache Thrift, keunggulan utamanya adalah pustaka server-klien yang siap pakai dan kemampuan untuk secara ketat menentukan deskripsi semua metode publik yang diberikan oleh setiap layanan mikro;
    • fitur kedua dari perpustakaan adalah implementasi Google Dapper kami , yang memungkinkan kami untuk dengan cepat melacak permintaan dengan pencarian sederhana di Elasticsearch. Layanan microser pertama yang menerima permintaan dari sistem eksternal menghasilkan trace_id unik, yang disimpan oleh setiap rantai permintaan berikutnya. Selain itu, kami membuat dan menyimpan parent_id dan span_id , yang memungkinkan Anda untuk membangun pohon permintaan, memantau secara visual seluruh rantai layanan-layanan microser yang terlibat dalam pemrosesan permintaan;
    • fitur ketiga - kami secara aktif menggunakan transfer pada tingkat transportasi dari berbagai informasi tentang konteks permintaan. Misalnya, tenggat waktu (perkiraan waktu permintaan yang ditetapkan pada klien), atau atas nama siapa kami melakukan panggilan ke suatu metode;
  • Templat Konsul adalah agen penemuan layanan yang mengelola informasi tentang lokasi, ketersediaan, dan status layanan mikro. Layanan Microsoft menemukan satu sama lain dengan nama DNS, zona TTL adalah nol, layanan yang telah meninggal atau belum lulus pemeriksaan kesehatan berhenti menyelesaikan dan dengan demikian menerima lalu lintas;
  • log yang ditulis oleh aplikasi dalam format yang dapat dimengerti oleh Elasticsearch ke file container lokal dan filebeat , yang berjalan pada mesin host relatif terhadap container, mengambil log ini dan mengirimkannya ke cluster Elasticsearch;
    • karena kami menerapkan platform sesuai dengan model Pengadaan Acara, rantai log yang dihasilkan juga digunakan untuk visualisasi dalam berbagai dasbor Grafana, yang memungkinkan kami mengurangi waktu untuk mengimplementasikan metrik yang berbeda (kami juga menggunakan metrik terpisah).


Ketika mengembangkan layanan microser, kami menggunakan batasan yang telah kami ciptakan secara khusus, yang dirancang untuk memecahkan masalah ketersediaan tinggi platform dan toleransi kesalahannya:


  • batas memori ketat untuk setiap wadah, ketika Anda melampaui batas - OOM, sebagian besar layanan microsecer hidup dalam 256-512M. Ini membuatnya lebih terfragmentasi dalam implementasi logika bisnis, melindungi terhadap penyimpangan terhadap monolit, mengurangi biaya titik kegagalan, memberikan keuntungan tambahan kemampuan untuk bekerja pada perangkat keras yang murah (platform digunakan dan berjalan pada server prosesor tunggal yang murah);
  • sesedikit mungkin layanan microsoft stateful dan implementasi stateless sebanyak mungkin. Ini memungkinkan kami untuk memecahkan masalah toleransi kesalahan, kecepatan pemulihan dan, secara umum, meminimalkan tempat dengan perilaku yang berpotensi tidak dapat dipahami. Ini menjadi sangat penting dengan peningkatan umur sistem ketika warisan besar terakumulasi;
  • biarkan crash dan "itu pasti akan merusak" pendekatan. Kami tahu bahwa setiap bagian dari sistem kami pasti akan gagal, jadi kami mendesainnya sehingga ini tidak mempengaruhi kebenaran umum dari informasi yang terakumulasi dalam platform. Membantu meminimalkan jumlah status tidak terdefinisi dalam sistem.

Tentunya tidak asing lagi bagi banyak pihak yang berintegrasi dengan pihak ketiga, situasi. Kami mengharapkan tanggapan dari pihak ketiga terhadap permintaan untuk menghapus uang sesuai dengan protokol, dan jawaban yang sama sekali berbeda datang, tidak dijelaskan dalam spesifikasi apa pun, yang tidak diketahui bagaimana menafsirkannya.


Dalam situasi ini, kami membunuh mesin negara yang melayani pembayaran ini, tindakan apa pun dari luar akan menerima kesalahan 500. Dan di dalam kami mengetahui keadaan pembayaran saat ini, membawa keadaan mesin sesuai dengan kenyataan dan menghidupkan kembali mesin negara.


Pengembangan yang Berorientasi pada Protokol



Pada saat penulisan, 636 cek berbeda telah didaftarkan dalam Penemuan Layanan kami untuk layanan yang memastikan berfungsinya platform. Bahkan dengan mempertimbangkan bahwa beberapa pemeriksaan sedang dilakukan pada satu layanan, dan juga bahwa sebagian besar layanan tanpa kewarganegaraan bekerja dalam setidaknya tiga kali lipat, Anda masih bisa mendapatkan lima puluh aplikasi yang harus dapat terhubung entah bagaimana satu sama lain dan tidak gagal di neraka RPC.


Situasinya diperumit oleh fakta bahwa kami memiliki tiga bahasa pengembangan pada stack - Erlang, Java, JS, dan mereka semua harus dapat berkomunikasi secara transparan satu sama lain.


Tugas pertama yang perlu dipecahkan adalah merancang arsitektur yang benar untuk bertukar data antara layanan microser. Sebagai dasar, kami mengambil Apache Thrift. Semua microservices bertukar binari trift, kami menggunakan HTTP sebagai transportasi.


Kami menempatkan spesifikasi fonta dalam bentuk repositori terpisah di github kami, sehingga mereka tersedia untuk setiap pengembang yang memiliki akses ke sana. Awalnya, mereka menggunakan satu repositori umum untuk semua protokol, tetapi seiring waktu mereka sampai pada kesimpulan bahwa ini adalah kerja paralel - sambungan yang tidak nyaman pada protokol yang berubah menjadi sakit kepala yang konstan. Tim yang berbeda dan bahkan pengembang yang berbeda dipaksa untuk menyetujui nama variabel, upaya untuk memecah menjadi namespace juga tidak membantu.


Secara umum, kita dapat mengatakan bahwa kita memiliki pengembangan berbasis protokol. Sebelum memulai implementasi apa pun, kami mengembangkan protokol layanan-mikro di masa depan dalam bentuk spesifikasi lift, melewati 7 lingkaran peninjauan, menarik pelanggan-pelanggan masa depan dari layanan-mikro ini, dan mendapatkan kesempatan untuk secara bersamaan mulai mengembangkan beberapa layanan-mikro secara paralel, karena kami tahu semua metode di masa depan dan kami sudah dapat menulis penangan mereka, opsional menggunakan moki.


Langkah terpisah dalam proses pengembangan protokol adalah tinjauan keamanan, di mana orang-orang melihat dari sudut pandang pentester mereka pada nuansa spesifikasi yang dikembangkan.


Kami juga menganggap perlu untuk menyoroti peran terpisah dari pemilik protokol dalam tim. Tugasnya sulit, seseorang harus mengingat secara spesifik semua layanan mikro, tetapi terbayar dalam urutan besar dan adanya satu titik eskalasi.


Tanpa persetujuan final dari permintaan penarikan oleh karyawan ini, protokol tidak dapat digabung menjadi cabang utama. Ada fungsi yang sangat nyaman di github untuk ini - pemilik kode , kami menggunakannya dengan senang hati.


Jadi, kami memecahkan masalah komunikasi antara layanan microser, kemungkinan masalah kesalahpahaman seperti apa layanan microser muncul di platform, dan mengapa itu diperlukan. Serangkaian protokol ini mungkin satu-satunya bagian dari platform di mana kami tanpa syarat memilih kualitas daripada biaya dan kecepatan pengembangan, karena implementasi satu layanan-mikro dapat ditulis ulang secara relatif tanpa rasa sakit, dan protokol di mana beberapa lusin sudah mahal dan menyakitkan.


Sepanjang jalan, pencatatan yang akurat membantu dalam memecahkan masalah dokumentasi. Nama metode dan parameter yang dipilih secara wajar, beberapa komentar, dan spesifikasi yang didokumentasikan sendiri menghemat banyak waktu!


Sebagai contoh, ini adalah bagaimana spesifikasi metode salah satu dari layanan microser kami terlihat, memungkinkan Anda untuk mendapatkan daftar peristiwa yang terjadi di platform:


 /**    */ typedef i64 EventID /* Event sink service definitions */ service EventSink { /** *       ,   *    ,  ,  `range`.  *      `0`  `range.limit` . * *   `range.after`    ,   * ,        , *   `EventNotFound`. */ Events GetEvents (1: EventRange range) throws (1: EventNotFound ex1, 2: base.InvalidRequest ex2) /** *         *  . */ base.EventID GetLastEventID () throws (1: NoLastEvent ex1) } /* Events */ typedef list<Event> Events /** * ,    -,  . */ struct Event { /** *  . *    ,     *      (total order). */ 1: required base.EventID id /** *   . */ 2: required base.Timestamp created_at /** *  -,  . */ 3: required EventSource source /** *  ,    ( ) *   -,  . */ 4: required EventPayload payload /** *      . *    . */ 5: optional base.SequenceID sequence } // Exceptions exception EventNotFound {} exception NoLastEvent {} /** * ,       -   */ exception InvalidRequest { /**          */ 1: required list<string> errors } 

Klien konsol hemat


Terkadang kita dihadapkan dengan tugas memanggil metode-metode tertentu dari layanan-mikro yang diperlukan secara langsung, misalnya, dengan tangan kita dari terminal. Ini bisa berguna untuk debugging, memperoleh kumpulan data mentah, atau ketika tugas sangat jarang sehingga pengembangan antarmuka pengguna yang terpisah tidak praktis.


Oleh karena itu, kami mengembangkan alat untuk diri kami sendiri yang menggabungkan fungsi curl , tetapi memungkinkan Anda untuk membuat permintaan trift dalam bentuk struktur JSON. Kami memanggilnya sesuai - woorl . Utilitas bersifat universal, cukup untuk mentransfer lokasi sembarang spesifikasi lift dengan menggunakan parameter baris perintah, ia akan melakukan sisanya sendiri. Utilitas yang sangat nyaman, Anda dapat memulai pembayaran langsung dari terminal, misalnya.


Ini adalah bagaimana daya tarik terlihat langsung ke microservice platform, yang bertanggung jawab untuk mengelola aplikasi (misalnya, untuk membuat toko). Saya meminta data pada akun pengujian saya:



Mengamati pembaca mungkin memperhatikan satu fitur di tangkapan layar. Kami juga tidak suka itu. Hal ini diperlukan untuk mempercepat otorisasi panggilan trift antara layanan microser, perlu untuk merekatkan TLS dengan cara yang baik. Tetapi sementara sumber daya, seperti biasa, tidak cukup. Kami membatasi diri pada selungkup total perimeter tempat pemrosesan layanan microser.


Protokol untuk berkomunikasi dengan sistem eksternal


Untuk mempublikasikan spesifikasi angkat luar dan memaksa pedagang kami untuk berkomunikasi menggunakan protokol biner, kami menganggapnya terlalu kejam bagi mereka. Itu perlu untuk memilih protokol yang dapat dibaca manusia yang akan memungkinkan kita untuk berintegrasi dengan kami, men-debug dan dapat dengan mudah mendokumentasikan. Kami memilih standar Open API, juga dikenal sebagai Swagger .


Kembali ke masalah dokumentasi protokol, Swagger memungkinkan Anda untuk dengan cepat dan murah menyelesaikan masalah ini. Jaringan ini memiliki banyak implementasi dari desain yang indah dari spesifikasi Swagger dalam bentuk dokumentasi pengembang. Kami melihat semua yang dapat kami temukan dan akhirnya memilih ReDoc , perpustakaan JS yang menerima swagger.json sebagai input, dan menghasilkan dokumentasi tiga kolom seperti itu pada output: https://developer.rbk.money/api/ .


Pendekatan untuk pengembangan kedua protokol, penghematan internal dan kesombongan eksternal, benar-benar identik untuk kita. Ini menambah waktu untuk pengembangan, tetapi terbayar dalam jangka panjang.


Kami juga perlu menyelesaikan masalah penting lainnya - kami tidak hanya menerima permintaan untuk menghapus uang, tetapi juga mengirimkannya lebih lanjut - ke bank dan sistem pembayaran.


Memaksa mereka untuk menerapkan lift kami akan menjadi tugas yang bahkan lebih tidak praktis daripada mengirimkannya ke API publik.


Oleh karena itu, kami membuat dan menerapkan konsep adapter protokol. Ini hanyalah layanan microser lain yang mengimplementasikan spesifikasi pengangkatan internal kami di satu sisi, yang sama untuk seluruh platform, dan yang kedua adalah protokol eksternal khusus untuk bank atau PS tertentu.


Masalah yang muncul saat menulis adaptor seperti itu ketika Anda harus berinteraksi dengan pihak ketiga adalah topik yang kaya akan berbagai cerita. Dalam praktik kami, kami telah bertemu hal-hal yang berbeda, jawaban dari formulir: "Anda, tentu saja, dapat menerapkan fungsi ini seperti yang dijelaskan dalam protokol yang kami berikan kepada Anda, tetapi saya tidak memberikan jaminan apa pun. Inilah pasien kami yang akan semua jawaban ini, dan Anda meminta konfirmasi kepadanya. " Juga, situasi seperti itu tidak jarang: "ini adalah nama pengguna dan kata sandi dari server kami, pergi ke sana dan konfigurasikan semuanya sendiri."


Saya merasa sangat menarik ketika kami terintegrasi dengan mitra pembayaran, yang, pada gilirannya, sebelumnya terintegrasi dengan platform kami dan berhasil melakukan pembayaran melalui kami (ini sering terjadi, spesifik bisnis dari industri pembayaran). Menanggapi permintaan kami untuk lingkungan pengujian, mitra menjawab bahwa ia tidak memiliki lingkungan pengujian seperti itu, tetapi ia bisa mendapatkan lalu lintas untuk integrasi dengan RBC, yaitu, dengan platform kami, di mana kami dapat terlibat. Begitulah kita, melalui pasangan, terintegrasi dengan diri kita sendiri sekali.


Dengan demikian, kami cukup memecahkan masalah penerapan koneksi paralel massal dari berbagai sistem pembayaran dan pihak ketiga lainnya. Dalam sebagian besar kasus, Anda tidak perlu menyentuh kode platform untuk ini, cukup tulis adapter dan tambahkan lebih banyak instrumen pembayaran ke enum.


Akibatnya, kami mendapat skema kerja seperti itu - kami melihat di luar layanan mikro RBKmoney API (kami menyebutnya API Umum, atau capi *, Anda melihatnya di konsul di atas), yang memvalidasi input data sesuai dengan spesifikasi Swagger publik, mengesahkan klien, menyiarkan metode ini untuk panggilan angkat internal kami dan mengirimkan permintaan ke rantai ke layanan microser berikutnya. Selain itu, layanan ini menerapkan persyaratan platform lain, spesifikasi teknis yang dirumuskan sebagai: "sistem harus selalu memiliki kesempatan untuk mendapatkan kucing."


Ketika kita perlu melakukan panggilan ke beberapa sistem eksternal, microservices internal menarik metode lift adaptor protokol yang sesuai, mereka menerjemahkannya ke dalam bahasa bank atau sistem pembayaran tertentu dan mengirimkannya keluar.


Protokol Kesulitan Kompatibilitas Mundur


Platform ini terus berkembang, fungsi baru ditambahkan, yang lama diubah. Dalam keadaan seperti itu, Anda harus berinvestasi dalam mendukung kompatibilitas ke belakang atau terus-menerus memperbarui layanan microsoft yang tergantung. Dan jika situasi ketika bidang yang diperlukan berubah menjadi opsional sederhana, Anda tidak dapat melakukan apa pun, maka dalam kasus sebaliknya Anda harus menghabiskan sumber daya tambahan.


Dengan seperangkat protokol internal, segalanya menjadi lebih mudah. Industri pembayaran jarang berubah sehingga beberapa metode interaksi baru yang fundamental muncul. Ambil, misalnya, tugas umum bagi kami - menghubungkan penyedia baru dengan instrumen pembayaran baru. Misalnya, pemrosesan dompet lokal, yang memungkinkan Anda memproses pembayaran di Kazakhstan di tenge. Ini adalah dompet baru untuk platform kami, tetapi pada prinsipnya dompet tidak berbeda dari dompet Qiwi yang sama - dompet ini selalu memiliki beberapa pengidentifikasi unik dan metode yang memungkinkan Anda untuk mendebet / membatalkan debit dari itu.


Dengan demikian, spesifikasi lift kami untuk semua penyedia dompet terlihat seperti ini:


 typedef string DigitalWalletID struct DigitalWallet { 1: required DigitalWalletProvider provider 2: required DigitalWalletID id } enum DigitalWalletProvider { qiwi rbkmoney } 

dan menambahkan cara pembayaran baru dalam bentuk dompet baru hanya melengkapi enum:


 enum DigitalWalletProvider { qiwi rbkmoney newwallet } 

Sekarang tinggal menabrak semua layanan microser menggunakan spesifikasi ini, menyinkronkan dengan wizard repositori dengan spesifikasi dan meluncurkannya melalui CI / CD.


Protokol eksternal lebih rumit. Setiap pembaruan spesifikasi Swagger, terutama tanpa kompatibilitas ke belakang, hampir tidak mungkin untuk diterapkan dalam jangka waktu yang wajar - tidak mungkin bahwa mitra kami akan menjaga sumber daya pengembang gratis khusus untuk memperbarui platform kami.


Dan kadang-kadang ini tidak mungkin, kami kadang-kadang menghadapi situasi seperti: "programmer menulis kepada kami dan pergi, mengambil kode sumber dengannya, bagaimana kami bekerja, kami tidak tahu, ini bekerja dan tidak menyentuhnya."


Oleh karena itu, kami berinvestasi dalam mendukung kompatibilitas ke belakang pada protokol eksternal. Dalam arsitektur kami, ini sedikit lebih mudah - karena kami menggunakan adapter protokol terpisah untuk setiap versi tertentu dari Common API, kami hanya membiarkan layanan microsoft lama berfungsi, hanya mengubah bagian yang terlihat seperti trift di dalam platform jika perlu. Jadi microservices capi-v1 , capi-v2 , capi-v3 dan seterusnya muncul dan tetap bersama kita selamanya.


Apa yang akan terjadi ketika capi-v33 kami mungkin harus mencabut beberapa versi lama, mungkin.


Pada titik ini, saya biasanya mulai memahami dengan sangat baik perusahaan seperti Microsoft dan semua kesulitan mereka dalam mendukung kompatibilitas mundur solusi yang telah bekerja selama beberapa dekade.


Sesuaikan sistem


Dan, mengakhiri topik, kami akan memberi tahu Anda bagaimana kami mengelola pengaturan platform khusus bisnis.


Hanya melakukan pembayaran tidak semudah kelihatannya. Untuk setiap pembayaran, pelanggan bisnis ingin melampirkan sejumlah besar kondisi - mulai dari komisi hingga, pada prinsipnya, kemungkinan implementasi yang sukses tergantung pada waktu hari. Kami menetapkan tugas untuk mendigitalkan seluruh rangkaian kondisi yang dapat ditemukan oleh pelanggan bisnis sekarang dan di masa depan dan menerapkan set ini untuk setiap pembayaran yang baru diluncurkan.


Sebagai hasilnya, kami memutuskan untuk mengembangkan DSL kami sendiri, di mana kami mengacaukan alat untuk manajemen yang nyaman yang memungkinkan kami untuk menggambarkan model bisnis dengan cara yang benar: pilihan adapter protokol, deskripsi rencana posting, yang menurutnya uang akan tersebar ke dalam akun dalam sistem, menetapkan batas, komisi, kategori dan hal-hal lain khusus untuk sistem pembayaran.


Misalnya, ketika kami ingin mengambil komisi 1% untuk memperoleh kartu maestro dan MS dan menyebarkannya di akun di dalam sistem, kami mengonfigurasi domain seperti ini:


 { "cash_flow": { "decisions": [ { "if_": { "any_of": [ { "condition": { "payment_tool": { "bank_card": { "definition": { "payment_system_is": "maestro" } } } } }, { "condition": { "payment_tool": { "bank_card": { "definition": { "payment_system_is": "mastercard" } } } } } ] }, "then_": { "value": [ { "source": { "system": "settlement" }, "destination": { "provider": "settlement" }, "volume": { "share": { "parts": { "p": 1, "q": 100 }, "of": "operation_amount" } }, "details": "1% processing fee" } ] } } ] } } 

, , . , JSON. , , , . , , . , CVS/SVN-.


" ". , , , 1%, , , . , , . , .


cvs-like , . , — stateless, , . . .


- . , , . , , .


. , 10 , , .


, , , -, woorl-. - JSON- . - JS, , UX:



, , , .


, , .


, , SaltStack.


, !

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


All Articles