Implementasi OpenStack LBaaS UI



Ketika saya mengimplementasikan antarmuka pengguna penyeimbang beban untuk cloud pribadi virtual, saya harus menghadapi kesulitan yang signifikan. Hal ini membuat saya merenungkan peran frontend, yang ingin saya bagikan terlebih dahulu. Dan kemudian membenarkan pikiran mereka, menggunakan contoh tugas tertentu.

Solusi untuk masalah itu ternyata, menurut saya, cukup kreatif, dan saya harus mencarinya dalam kerangka kerja yang sangat terbatas, jadi saya pikir itu bisa menarik.

Peran frontend


Saya harus segera mengatakan bahwa saya tidak berpura-pura kebenaran dan mengangkat masalah kontroversial. Saya agak tertekan oleh ironi front-end dan web khususnya, sebagai sesuatu yang tidak signifikan. Dan bahkan lebih menyedihkan bahwa kadang-kadang ini terjadi secara wajar. Sekarang mode sudah tertidur, tetapi ada saat ketika semua orang berlarian dengan kerangka kerja, paradigma dan entitas lainnya, mereka dengan keras mengatakan bahwa semua ini sangat penting dan sangat diperlukan, dan sebagai imbalannya mereka menerima ironi bahwa front-end berurusan dengan output dari bentuk dan memproses klik pada tombol, yang dapat dilakukan "di lutut".

Sekarang, tampaknya, semuanya telah lebih atau kurang kembali normal. Tidak ada yang benar-benar ingin berbicara tentang setiap rilis kecil dari kerangka kerja berikutnya. Hanya sedikit orang yang mencari alat atau pendekatan yang sempurna, karena meningkatnya kesadaran akan utilitas mereka. Tetapi bahkan ini, misalnya, tidak mengganggu kritik yang hampir tidak dapat dibenarkan terhadap Elektron dan aplikasi di dalamnya. Saya pikir ini karena kurangnya pemahaman tentang tugas yang diselesaikan oleh front-end.

Frontend bukan hanya sarana menampilkan informasi yang disediakan oleh backend, dan bukan hanya sarana untuk memproses tindakan pengguna. Frontend adalah sesuatu yang lebih, sesuatu yang abstrak, dan jika Anda memberikan definisi yang sederhana dan jelas, maka maknanya pasti akan hilang.

Frontend ada dalam beberapa "kerangka". Misalnya, dalam istilah teknis, itu adalah antara API yang disediakan oleh backend dan API yang disediakan oleh fasilitas I / O. Dalam hal tugas, itu adalah antara tugas-tugas antarmuka pengguna yang memecahkan UX dan tugas-tugas yang memecahkan backend. Dengan demikian, spesialisasi frontend agak sempit diperoleh, spesialisasi lapisan. Ini tidak berarti bahwa penyedia front-end tidak dapat memberikan pengaruh pada area di luar spesialisasi mereka, tetapi pada saat pengaruh ini tidak mungkin, tugas front-end yang sebenarnya muncul.

Masalah ini dapat diekspresikan melalui kontradiksi. Antarmuka pengguna tidak diperlukan untuk menyesuaikan dengan model data dan perilaku backend. Model perilaku dan data backend tidak diperlukan untuk memenuhi tugas-tugas antarmuka pengguna. Dan kemudian tugas dari front-end adalah untuk menghilangkan kontradiksi ini. Semakin besar perbedaan antara tugas-tugas backend dan antarmuka pengguna, semakin penting peran frontend. Dan untuk memperjelas apa yang saya bicarakan, saya akan memberikan contoh di mana perbedaan ini, untuk beberapa alasan, ternyata signifikan.

Pernyataan masalah


OpenStack LBaaS, menurut pendapat saya, adalah perangkat keras-lunak dari alat yang diperlukan untuk menyeimbangkan beban antar server. Penting bagi saya bahwa implementasinya tergantung pada faktor-faktor objektif, pada tampilan fisik. Karena itu, ada beberapa kekhasan dalam API dan cara berinteraksi dengan API ini.

Saat mengembangkan antarmuka pengguna, minat utama bukanlah fitur teknis backend, tetapi kemampuan dasarnya. Antarmuka dibuat untuk pengguna, dan pengguna membutuhkan antarmuka untuk mengelola parameter penyeimbang, dan pengguna tidak perlu masuk ke fitur internal implementasi backend.

Backend sebagian besar dikembangkan oleh masyarakat, dan dimungkinkan untuk mempengaruhi perkembangannya dalam jumlah yang sangat terbatas. Salah satu fitur utama bagi saya adalah bahwa pengembang backend siap untuk mengorbankan kenyamanan dan kesederhanaan kontrol demi kinerja, dan ini benar-benar dibenarkan, karena ini adalah masalah menyeimbangkan beban.

Ada satu hal lagi yang halus, dan saya ingin segera menguraikannya, memperingatkan beberapa pertanyaan. Jelas bahwa pada OpenStack dan API mereka lampu tidak menyatu. Anda selalu dapat mengembangkan set alat Anda sendiri atau "lapisan" yang akan bekerja dengan OpenStack API, menghasilkan API sendiri yang nyaman untuk tugas-tugas pengguna. Satu-satunya pertanyaan adalah kemanfaatan. Jika alat yang tersedia awalnya memungkinkan Anda untuk mengimplementasikan antarmuka pengguna seperti yang dimaksudkan, apakah masuk akal untuk menghasilkan entitas?

Jawaban untuk pertanyaan ini beragam dan untuk bisnis akan bergantung pada pengembang, pekerjaan mereka, kompetensi mereka, pertanyaan tentang tanggung jawab, dukungan dan sebagainya. Dalam kasus kami, itu paling bijaksana untuk menyelesaikan beberapa tugas di front-end.

Fitur dari OpenStack LBaaS


Saya hanya ingin mengidentifikasi fitur-fitur yang memiliki pengaruh kuat di frontend. Pertanyaan mengapa fitur ini muncul atau apa yang mereka andalkan sudah berada di luar cakupan artikel ini.

Saya bekerja dengan dokumentasi yang sudah jadi dan harus menerima fitur-fiturnya. Mereka yang tertarik dengan apa OpenStack Octavia dari dalam dapat berkenalan dengan dokumentasi resmi . Octavia adalah nama seperangkat alat yang dirancang untuk menyeimbangkan beban di ekosistem OpenStack.

Fitur pertama yang saya temui selama pengembangan adalah sejumlah besar model dan hubungan yang diperlukan untuk menampilkan keadaan penyeimbang. Octavia API menggambarkan 12 model, tetapi hanya 7 yang diperlukan untuk sisi klien. Model-model ini memiliki koneksi, sering didenormalisasi, gambar di bawah ini menunjukkan perkiraan diagram:



"Seven" tidak terdengar sangat mengesankan, tetapi pada kenyataannya, untuk memastikan pengoperasian penuh antarmuka, pada saat menulis teks ini, saya harus menggunakan 16 model data dan sekitar 30 hubungan di antara mereka. Karena Octavia hanya penyeimbang, ia membutuhkan modul OpenStack lainnya untuk berfungsi. Dan semua ini diperlukan hanya untuk dua halaman di antarmuka pengguna.

Fitur kedua dan ketiga adalah Octavia asinkron dan transaksional. Model data memiliki bidang status yang mencerminkan keadaan operasi yang dilakukan pada objek.
StatusDeskripsi
AKTIFObjek dalam kondisi baik
DIHAPUSObjek dihapus
KesalahanObyek rusak
PENDING_CREATEObyek dalam pembuatan
PENDING_UPDATEObyek dalam proses memperbarui
PENDING_DELETEObyek dalam proses penghapusan
Operasi membaca objek terjadi secara serempak dan tidak memiliki batasan. Tetapi membuat, memperbarui, dan menghapus operasi dapat membutuhkan waktu yang tidak terbatas. Hal ini disebabkan oleh fakta bahwa model data memiliki, secara umum, makna fisik.

Setelah mengirim permintaan untuk pembuatan, kita dapat mengetahui bahwa catatan telah muncul, kita dapat membacanya, tetapi sampai operasi pembuatan selesai, kita tidak dapat melakukan operasi lain pada catatan ini. Upaya semacam itu akan menghasilkan kesalahan. Operasi mengubah objek hanya dapat dimulai ketika objek dalam status ACTIVE , Anda dapat mengirim objek untuk dihapus dalam status ACTIVE dan ERROR .

Status ini dapat datang melalui WebSockets, yang sangat memudahkan pemrosesan mereka, tetapi transaksi adalah masalah yang jauh lebih besar. Saat melakukan perubahan pada objek apa pun, semua model terkait juga akan berpartisipasi dalam transaksi. Misalnya, ketika membuat perubahan pada Anggota , Pool , Listener, dan Loadbalancer terkait akan diblokir. Ini seperti apa dalam hal peristiwa yang diterima di soket web:

  • empat peristiwa pertama adalah transfer objek ke status PENDING_UPDATE : bidang target berisi nama model objek yang berpartisipasi dalam transaksi;
  • acara kelima hanyalah duplikat (saya tidak tahu terhubung dengan apa);
  • empat yang terakhir adalah kembali ke status AKTIF . Dalam hal ini, ini adalah operasi perubahan berat badan, dan itu membutuhkan waktu kurang dari satu detik, tetapi kadang-kadang membutuhkan lebih banyak waktu.

Anda juga dapat melihat di tangkapan layar bahwa urutan acara tidak harus ketat. Dengan demikian, ternyata bahwa untuk memulai operasi apa pun, perlu untuk mengetahui tidak hanya status objek itu sendiri, tetapi juga status semua dependensi yang juga akan berpartisipasi dalam transaksi.

Fitur Antarmuka Pengguna


Sekarang bayangkan diri Anda di tempat pengguna yang perlu tahu di suatu tempat bahwa untuk menyeimbangkan antara dua server:

  1. Penting untuk membuat pendengar di mana algoritma penyeimbang akan ditentukan.
  2. Buat kolam.
  3. Tetapkan kelompok untuk pendengar.
  4. Tambahkan tautan ke port seimbang ke pool.

Setiap kali perlu menunggu penyelesaian operasi, yang tergantung pada semua objek yang dibuat sebelumnya.

Seperti yang ditunjukkan oleh studi internal, dalam pandangan pengguna biasa, hanya ada perkiraan perkiraan bahwa penyeimbang harus memiliki titik masuk, harus ada titik keluar dan parameter penyeimbangan yang harus dilakukan: algoritma, berat dan lain-lain. Pengguna tidak harus tahu apa itu OpenStack.

Saya tidak tahu betapa rumitnya antarmuka untuk persepsi, di mana pengguna sendiri harus mengikuti semua fitur teknis backend yang dijelaskan di atas. Untuk konsol, ini mungkin diizinkan, karena penggunaannya menyiratkan tingkat tinggi perendaman dalam teknologi, tetapi untuk web antarmuka seperti itu mengerikan.

Di web, pengguna berharap untuk mengisi satu formulir yang jelas dan logis, tekan satu tombol, tunggu dan semuanya akan berfungsi. Mungkin ini bisa diperdebatkan, tetapi saya mengusulkan untuk berkonsentrasi pada fitur-fitur yang mempengaruhi implementasi frontend.

Antarmuka dirancang sedemikian rupa sehingga melibatkan penggunaan operasi kaskade: satu tindakan dalam antarmuka dapat melibatkan beberapa operasi. Antarmuka tidak menyiratkan bahwa pengguna dapat melakukan tindakan yang saat ini tidak mungkin, tetapi antarmuka mengasumsikan bahwa pengguna harus memahami mengapa demikian. Antarmuka adalah satu kesatuan tunggal, dan oleh karena itu, elemen individualnya dapat menggunakan informasi dari berbagai entitas dependen, termasuk meta-informasi.



Jika kita mempertimbangkan bahwa ada beberapa fitur antarmuka yang tidak unik untuk penyeimbang, seperti sakelar, akordeon, tab, menu konteks, dan menganggap bahwa prinsip pengoperasian mereka jelas pada awalnya, maka saya pikir untuk pengguna yang tahu apa penyeimbangan beban, bukan akan sangat sulit untuk membaca sebagian besar antarmuka di atas dan membuat asumsi tentang cara mengelolanya. Tetapi untuk menyoroti bagian antarmuka mana yang tersembunyi di balik model penyeimbang, pendengar, kelompok, anggota, dan entitas lainnya bukan lagi tugas yang paling jelas.

Menyelesaikan Kontradiksi


Saya harap saya dapat menunjukkan bahwa fitur-fitur backend tidak cocok dengan antarmuka dengan baik, dan bahwa fitur-fitur ini tidak selalu dapat dihilangkan oleh backend. Bersamaan dengan ini, fitur antarmuka tidak pas di backend, dan juga tidak selalu dapat dihilangkan tanpa menyulitkan antarmuka. Masing-masing bidang ini memecahkan masalahnya sendiri. Tanggung jawab front-end adalah untuk menyelesaikan masalah untuk memastikan tingkat interaksi yang diperlukan antara antarmuka dan back-end.

Dalam latihan saya, saya segera bergegas ke kolam dengan kepala saya, tidak memperhatikan, atau bahkan tidak mencoba untuk mencari tahu fitur-fitur yang lebih tinggi, tetapi saya beruntung atau pengalaman membantu (dan vektor yang benar dipilih). Saya berulang kali memperhatikan sendiri bahwa ketika menggunakan API atau pustaka pihak ketiga, sangat berguna untuk membiasakan diri Anda dengan dokumentasi terlebih dahulu: semakin detail, semakin baik. Dokumentasi sering mirip satu sama lain, orang masih mengandalkan pengalaman orang lain, tetapi ada deskripsi fitur dari masing-masing sistem individu, dan terkandung dalam detailnya.

Jika saya awalnya menghabiskan beberapa jam ekstra mempelajari dokumentasi, daripada menarik informasi yang diperlukan dengan kata kunci, saya akan memikirkan masalah yang harus dihadapi, dan pengetahuan ini dapat berdampak pada arsitektur proyek dari tahap awal. Kembali untuk menghilangkan kesalahan yang dilakukan di awal sangat melemahkan semangat. Dan tanpa konteks penuh, terkadang Anda harus kembali beberapa kali.

Sebagai pilihan, Anda dapat menekuk baris Anda, secara bertahap menghasilkan lebih banyak dan lebih banyak kode "dengan gigitan", tetapi semakin banyak tumpukan kode ini, semakin banyak yang akan disapu pada akhirnya. Ketika mendesain arsitektur, tentu saja, seseorang tidak boleh menyelam terlalu dalam, memperhitungkan semua opsi yang mungkin dan tidak mungkin, menghabiskan banyak waktu untuk itu, penting untuk mencari keseimbangan. Tetapi perkenalan yang kurang lebih terperinci dengan dokumentasi sering terbukti menjadi investasi yang sangat bermanfaat dan tidak terlalu banyak waktu.

Namun demikian, sejak awal, setelah melihat sejumlah besar model yang terlibat, saya menyadari bahwa akan perlu untuk membangun pemetaan kondisi backend ke klien dengan semua koneksi terpelihara. Setelah saya berhasil menampilkan semua informasi yang diperlukan pada klien, dengan semua koneksi dan sebagainya, perlu untuk mengatur antrian tugas.

Data diperbarui secara tidak sinkron, ketersediaan operasi ditentukan oleh berbagai kondisi, dan ketika operasi cascading diperlukan, tidak ada antrian yang dapat ditiadakan dalam kondisi seperti itu. Singkatnya, ini adalah seluruh arsitektur solusi saya: penyimpanan dengan refleksi dari keadaan backend dan antrian tugas.

Arsitektur Solusi


Karena jumlah model dan hubungan yang tidak terbatas, saya menempatkan skalabilitas ke dalam struktur repositori dengan melakukan ini menggunakan pabrik yang mengembalikan deskripsi deklaratif dari koleksi repositori. Koleksinya memiliki layanan, kelas model sederhana dengan CRUD. Dimungkinkan untuk membuat deskripsi tautan dalam model, seperti yang dilakukan, misalnya, dalam RoR atau dalam Backbone lama yang baik, tetapi ini membutuhkan sejumlah besar kode untuk diubah. Oleh karena itu, deskripsi relasi terletak di sebelah kelas model:



Secara total, saya mendapat 2 jenis koneksi: satu ke satu, satu ke banyak. Umpan balik juga dapat diuraikan. Selain tipe, kumpulan dependensi ditunjukkan, bidang tempat dependensi yang ditemukan dilampirkan dan bidang dari mana ID objek dependen dibaca (dalam kasus komunikasi satu-ke-banyak, daftar ID dibaca). Jika kondisi suatu objek untuk komunikasi lebih rumit daripada tautan sederhana ke objek, maka di pabrik seseorang dapat menggambarkan fungsi pengujian dua objek, yang hasilnya akan menentukan keberadaan koneksi. Semuanya terlihat sedikit "sepeda", tetapi bekerja tanpa ketergantungan yang tidak perlu dan persis seperti seharusnya.

Repositori memiliki modul untuk menunggu untuk menambah dan menghapus sumber daya, pada dasarnya ia sedang memproses peristiwa satu kali dengan pemeriksaan bersyarat dan dengan antarmuka promis. Saat berlangganan, jenis acara (tambah, hapus), fungsi tes, dan pawang dilewatkan. Ketika peristiwa tertentu terjadi dan dengan hasil tes positif, pawang dieksekusi, setelah itu pelacakan berhenti. Suatu peristiwa dapat terjadi ketika berlangganan secara sinkron.

Penggunaan pola semacam itu memungkinkan untuk secara otomatis membubuhkan hubungan kompleks yang sewenang-wenang antara model, dan melakukannya di satu tempat. Tempat ini saya sebut pelacak. Saat menambahkan objek ke repositori, ia mulai melacak hubungannya. Modul menunggu memungkinkan Anda untuk merespons acara dan memeriksa koneksi antara objek yang dipantau dan objek di penyimpanan. Jika objek sudah ada di repositori, maka modul tunggu segera memanggil pawang.

Perangkat penyimpanan semacam itu memungkinkan Anda untuk menggambarkan sejumlah koleksi dan hubungan di antara mereka. Saat menambahkan dan menghapus objek, toko secara otomatis menempatkan atau me-reset properti dengan konten objek dependen. Keuntungan dari pendekatan ini adalah bahwa semua hubungan dijelaskan secara eksplisit, dan mereka dimonitor dan diperbarui oleh satu sistem; kontra - dalam kompleksitas implementasi dan debugging.

Secara umum, repositori semacam itu cukup sepele dan saya melakukannya sendiri, karena akan jauh lebih sulit untuk mengintegrasikan solusi yang sudah jadi ke dalam basis kode yang ada, tetapi akan lebih sulit untuk melampirkan antrian tugas ke solusi yang sudah jadi.

Semua tugas, seperti koleksi, memiliki deskripsi deklaratif dan dibuat oleh pabrik. Tugas dapat memiliki dalam deskripsi kondisi untuk memulai dan daftar tugas yang perlu ditambahkan ke antrian setelah yang saat ini selesai.


Contoh di atas menjelaskan tugas membuat kumpulan. Dalam dependensi, penyeimbang dan pendengar ditunjukkan, secara default, pemeriksaan dilakukan untuk status AKTIF . Objek penyeimbang diblokir, karena tugas pemrosesan dalam antrian dapat terjadi secara serempak, memblokir menghindari konflik pada saat permintaan eksekusi dikirim, tetapi statusnya belum berubah, tetapi diasumsikan bahwa itu akan berubah. Alih-alih ORANGTUA , jika kumpulan dibuat sebagai hasil dari kaskade tugas, ID akan diganti secara otomatis.

Setelah membuat kumpulan, tugas akan ditambahkan ke antrian untuk membuat monitor ketersediaan dan membuat semua anggota kumpulan ini. Outputnya adalah struktur yang dapat sepenuhnya dikonversi ke JSON. Ini dilakukan untuk dapat mengembalikan antrian jika terjadi kegagalan.

Antrian, berdasarkan pada deskripsi tugas, secara independen memonitor semua perubahan dalam repositori dan memeriksa kondisi yang harus dipenuhi untuk menjalankan tugas. Seperti yang sudah saya katakan, status datang melalui soket web, dan sangat mudah untuk menghasilkan acara yang diperlukan untuk antrian, tetapi jika perlu tidak akan ada masalah untuk melampirkan mekanisme pembaruan data pengatur waktu (ini awalnya diletakkan dalam arsitektur, karena soket web dibuat karena berbagai alasan mungkin tidak bekerja dengan sangat stabil). Setelah tugas selesai, antrian secara otomatis menginformasikan repositori tentang perlunya memperbarui tautan dalam objek yang ditentukan.

Kesimpulan


Kebutuhan akan skalabilitas telah mengarah pada pendekatan deklaratif. Kebutuhan untuk menampilkan model dan hubungan di antara mereka telah menyebabkan repositori tunggal. Kebutuhan untuk memproses objek dependen telah menyebabkan antrian.

Menggabungkan kebutuhan ini mungkin bukan tugas yang paling mudah dalam hal implementasi (tetapi ini adalah masalah yang terpisah). Tetapi dalam hal arsitektur, solusinya sangat sederhana dan memungkinkan Anda untuk menghilangkan semua kontradiksi antara tugas-tugas backend dan antarmuka pengguna, untuk membangun interaksi mereka dan meletakkan dasar untuk fitur-fitur lain yang mungkin dari salah satu pihak.

Dari sisi panel kontrol Selectel , proses penyeimbangan sederhana dan mudah, yang memungkinkan pelanggan layanan untuk tidak menghabiskan sumber daya pada implementasi independen penyeimbang, sambil mempertahankan kemampuan untuk mengontrol lalu lintas secara fleksibel.

Coba penyeimbang kami dalam tindakan sekarang dan tulis ulasan Anda di komentar.

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


All Articles