
Artikel
tidak akan berbicara tentang karyawan yang tidak bertanggung jawab, seperti yang mungkin disarankan dari judul artikel. Kami akan membahas satu bahaya teknis nyata yang mungkin menanti Anda jika Anda membuat sistem terdistribusi.
Dalam satu sistem Enterprise, ada komponen. Komponen ini mengumpulkan data dari pengguna tentang produk tertentu dan mencatatnya di bank data. Dan itu terdiri dari tiga bagian standar: antarmuka pengguna, logika bisnis di server, dan tabel di bank data.
Komponen bekerja dengan baik, dan selama beberapa tahun tidak ada yang menyentuh kodenya.
Tetapi sekali, tanpa alasan, hal-hal aneh mulai terjadi pada komponen.
Saat bekerja dengan beberapa pengguna, komponen di tengah sesi tiba-tiba mulai melempar kesalahan. Itu jarang terjadi, tetapi seperti biasa, pada saat yang paling tidak tepat. Dan apa yang paling tidak bisa dipahami, kesalahan pertama muncul dalam versi stabil dari sistem dalam produksi. Dalam versi yang selama beberapa bulan tidak ada komponen yang berubah sama sekali.
Kami mulai menganalisis situasi dan memeriksa komponen di bawah beban berat. Ini bekerja dengan baik. Tes integrasi berulang cukup luas. Dalam tes integrasi, komponen kami berfungsi dengan baik.
Singkatnya, kesalahannya tidak jelas kapan dan tidak jelas di mana.
Mereka mulai menggali lebih dalam. Analisis terperinci dan perbandingan file log menunjukkan bahwa penyebab pesan kesalahan yang ditampilkan kepada pengguna adalah kendala pelanggaran pada kunci utama dalam tabel yang telah disebutkan dalam database.
Komponen menulis data ke tabel menggunakan Hibernate, dan kadang-kadang Hibernate, ketika mencoba menulis baris berikutnya, melaporkan pelanggaran kendala.
Saya tidak akan membuat pembaca bosan dengan detail teknis lebih lanjut dan segera memberi tahu Anda tentang esensi kesalahan. Ternyata tidak hanya komponen kita menulis ke tabel di atas, tetapi kadang-kadang (sangat jarang) beberapa komponen lain. Dan dia melakukannya dengan sangat sederhana, dengan pernyataan SQL INSERT sederhana. Hibernate berfungsi secara default saat menulis sebagai berikut. Untuk mengoptimalkan proses penulisan, ia meminta indeks kunci utama berikutnya satu kali dalam indeks, dan kemudian menulis beberapa kali hanya meningkatkan nilai kunci (10 kali secara default). Dan jika itu terjadi bahwa setelah permintaan, komponen kedua macet dalam proses dan menulis data ke tabel menggunakan nilai kunci utama berikut, maka upaya berikutnya untuk menulis dari Hibernate menyebabkan pelanggaran kendala.
Jika Anda tertarik pada detail teknis, lihat di bawah ini.
Rincian teknis.
Kode kelas dimulai seperti ini:
@Entity @Table(name="PRODUCT_XXX") public class ProductXXX { @Id @Basic(optional=false) @Column( name="PROD_ID", columnDefinition="integer not null", insertable=true, updatable=false) @SequenceGenerator( name="GEN_PROD_ID", sequenceName="SEQ_PROD_ID", allocationSize=10) @GeneratedValue( strategy=GenerationType.SEQUENCE, generator="GEN_PROD_ID") private long prodId;
Satu diskusi tentang masalah serupa di Stackoverflow:
https://stackoverflow.com/questions/12745751/hibernate-afterencegenerator-and-allocationsize Dan kebetulan bahwa selama berbulan-bulan setelah mengubah komponen kedua dan mengimplementasikan entri dalam tabel di dalamnya, proses penulisan komponen pertama dan kedua tidak pernah tumpang tindih dalam waktu. Dan mereka mulai berpotongan ketika, di salah satu unit menggunakan sistem, jadwal kerja sedikit berubah.
Nah, tes integrasi berjalan dengan lancar, karena interval waktu untuk menguji kedua komponen di dalam tes integrasi juga tidak bersinggungan.
Di satu sisi, kita dapat mengatakan bahwa tidak ada yang benar-benar disalahkan atas kesalahan tersebut.
Atau tidak?
Pengamatan dan Pikiran
Setelah menemukan penyebab sebenarnya dari kesalahan, itu diperbaiki.
Tetapi tidak dengan akhir yang bahagia ini, saya ingin mengakhiri artikel ini, tetapi merenungkan kesalahan ini sebagai perwakilan dari kategori besar kesalahan yang telah mendapatkan popularitas setelah transisi dari sistem monolitik ke sistem terdistribusi.
Dari sudut pandang masing-masing komponen atau layanan dalam sistem Enterprise yang dijelaskan, semuanya dilakukan semuanya tampak benar. Semua komponen, atau layanan, memiliki siklus hidup mandiri. Dan ketika perlu muncul untuk menulis ke tabel di komponen kedua, karena tidak pentingnya operasi, keputusan pragmatis dibuat untuk mengimplementasikan ini secara langsung dalam komponen ini dengan cara paling sederhana, dan tidak menyentuh komponen pertama yang berfungsi stabil.
Tetapi sayangnya, apa yang terjadi sering dalam sistem terdistribusi (dan relatif lebih jarang dalam sistem monolitik) terjadi: tanggung jawab untuk melakukan operasi pada objek tertentu
tersebar di antara subsistem. Tentunya, jika kedua operasi penulisan diimplementasikan dalam microservice yang sama, satu teknologi akan dipilih untuk implementasinya. Dan kemudian kesalahan yang dijelaskan tidak akan terjadi.
Sistem terdistribusi, terutama konsep layanan mikro, telah secara efektif membantu memecahkan sejumlah masalah yang melekat dalam sistem monolitik. Namun, secara paradoksal, pemisahan tanggung jawab untuk layanan individual memprovokasi efek sebaliknya. Komponen sekarang "hidup" semandiri mungkin. Dan mau tidak mau ada godaan, membuat perubahan besar pada satu komponen, untuk "sekrup di sini" sedikit fungsionalitas yang akan lebih baik diimplementasikan dalam komponen lain. Ini dengan cepat mencapai efek akhir, mengurangi volume persetujuan dan pengujian. Jadi, dari perubahan ke perubahan, komponen ditumbuhi dengan fitur yang tidak biasa bagi mereka, algoritma dan fungsi internal yang sama digandakan, multivarian pemecahan masalah (dan kadang-kadang non-determinisme mereka) muncul. Dengan kata lain, sistem terdistribusi menurun seiring waktu, tetapi berbeda dari yang monolitik.
Tanggung jawab βmengolesiβ komponen dalam sistem besar yang terdiri dari banyak layanan adalah salah satu masalah khas dan menyakitkan sistem terdistribusi modern. Situasi ini semakin rumit dan membingungkan oleh subsistem optimisasi bersama seperti caching, prediksi operasi berikut (prediksi), serta orkestrasi layanan, dll.
Memusatkan akses ke database, setidaknya di tingkat perpustakaan tunggal, persyaratannya cukup jelas. Namun, banyak sistem terdistribusi modern secara historis tumbuh di sekitar basis data dan menggunakan data yang disimpan di dalamnya secara langsung (melalui SQL) daripada melalui layanan akses.
"Membantu" penyebaran tanggung jawab dan kerangka kerja ORM dan perpustakaan seperti Hibernate. Menggunakan mereka, banyak pengembang layanan akses database tanpa disadari ingin memberikan objek setinggi mungkin sebagai hasil dari permintaan. Contoh khas adalah permintaan data pengguna untuk menampilkannya dalam sambutan atau di bidang dengan hasil otentikasi. Alih-alih mengembalikan nama pengguna dalam bentuk tiga variabel teks (first_name, mid_name, last_name), permintaan seperti itu sering mengembalikan objek pengguna lengkap dengan puluhan atribut dan objek yang terhubung, seperti daftar peran pengguna yang diminta. Ini, pada gilirannya, memperumit logika pemrosesan hasil permintaan, menghasilkan dependensi yang tidak perlu dari pawang pada jenis objek yang dikembalikan dan ... - menimbulkan noda tanggung jawab karena kemungkinan menerapkan logika yang terkait dengan objek dari luar yang bertanggung jawab atas objek layanan ini.
Apa yang harus dilakukan (Rekomendasi)
Sayangnya, pengolesan tanggung jawab dalam kasus-kasus tertentu terkadang dipaksakan, dan kadang-kadang bahkan tidak dapat dihindari dan dibenarkan.
Namun demikian, jika memungkinkan, Anda harus mencoba mematuhi prinsip distribusi tanggung jawab antara komponen-komponen tersebut. Satu komponen adalah satu tanggung jawab.
Nah, jika tidak mungkin untuk memusatkan operasi pada objek tertentu secara ketat dalam satu sistem, noda tersebut harus sangat hati-hati dicatat dalam dokumentasi seluruh sistem ("super-komponen") sebagai ketergantungan spesifik dari komponen pada elemen data, pada objek domain, atau pada satu sama lain.
Akan menarik untuk mengetahui pendapat Anda tentang masalah ini serta kasus-kasus dari praktik yang mengkonfirmasi atau menyangkal tesis artikel ini.
Terima kasih telah membaca artikel sampai akhir.
Ilustrasi "Multimedia Mikher" oleh penulis artikel.