CodeGym /Java Course /All lectures for ID purposes /Cara mengimplementasikan ACID dalam aplikasi: praktek

Cara mengimplementasikan ACID dalam aplikasi: praktek

All lectures for ID purposes
Level 1 , Pelajaran 889
Tersedia

8.1 ID Transaksi

Itu ditetapkan sebagai XID atau TxID (jika ada perbedaan, beri tahu saya). Stempel waktu dapat digunakan sebagai TxID, yang dapat digunakan jika kita ingin mengembalikan semua tindakan ke beberapa titik waktu. Masalah bisa muncul jika stempel waktu tidak cukup terperinci - maka transaksi bisa mendapatkan ID yang sama.

Oleh karena itu, opsi yang paling andal adalah membuat ID prod UUID yang unik. Dalam Python ini sangat mudah:

>>> import uuid 
>>> str(uuid.uuid4()) 
'f50ec0b7-f960-400d-91f0-c42a6d44e3d0' 
>>> str(uuid.uuid4()) 
'd15bed89-c0a5-4a72-98d9-5507ea7bc0ba' 

Ada juga opsi untuk hash satu set data yang menentukan transaksi dan menggunakan hash ini sebagai TxID.

8.2 Coba lagi

Jika kita mengetahui bahwa fungsi atau program tertentu bersifat idempoten, maka ini berarti kita dapat dan harus mencoba mengulangi pemanggilannya jika terjadi kesalahan. Dan kita hanya harus bersiap untuk fakta bahwa beberapa operasi akan memberikan kesalahan - mengingat aplikasi modern didistribusikan melalui jaringan dan perangkat keras, kesalahan harus dianggap bukan sebagai pengecualian, tetapi sebagai norma. Kesalahan dapat terjadi karena server crash, kesalahan jaringan, kemacetan aplikasi jarak jauh. Bagaimana seharusnya perilaku aplikasi kita? Benar, coba ulangi operasinya.

Karena satu bagian kode dapat mengatakan lebih dari satu halaman penuh kata, mari kita gunakan satu contoh untuk memahami bagaimana mekanisme percobaan ulang yang naif seharusnya bekerja. Saya akan mendemonstrasikan ini menggunakan perpustakaan Tenacity (ini dirancang dengan sangat baik bahkan jika Anda tidak berencana untuk menggunakannya, contohnya akan menunjukkan kepada Anda bagaimana Anda dapat merancang mekanisme perulangan):

import logging
import random
import sys
from tenacity import retry, stop_after_attempt, stop_after_delay, wait_exponential, retry_if_exception_type, before_log

logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logger = logging.getLogger(__name__)

@retry(
	stop=(stop_after_delay(10) | stop_after_attempt(5)),
	wait=wait_exponential(multiplier=1, min=4, max=10),
	retry=retry_if_exception_type(IOError),
	before=before_log(logger, logging.DEBUG)
)
def do_something_unreliable():
	if random.randint(0, 10) > 1:
    	raise IOError("Broken sauce, everything is hosed!!!111one")
	else:
    	return "Awesome sauce!"

print(do_something_unreliable.retry.statistics)

> Untuk berjaga-jaga, saya akan mengatakan: \@retry(...) adalah sintaks Python khusus yang disebut "dekorator". Itu hanya fungsi coba lagi(...) yang membungkus fungsi lain dan melakukan sesuatu sebelum atau sesudah dieksekusi.

Seperti yang dapat kita lihat, percobaan ulang dapat dirancang secara kreatif:

  • Anda dapat membatasi upaya berdasarkan waktu (10 detik) atau jumlah upaya (5).
  • Bisa eksponensial (yaitu, 2 ** beberapa angka yang meningkat n ). atau entah bagaimana (misalnya, diperbaiki) untuk menambah waktu antara upaya terpisah. Varian eksponensial disebut "keruntuhan kemacetan".
  • Anda dapat mencoba lagi hanya untuk jenis kesalahan tertentu (IOError).
  • Percobaan ulang dapat didahului atau diselesaikan oleh beberapa entri khusus di log.

Sekarang kita telah menyelesaikan kursus petarung muda dan mengetahui blok bangunan dasar yang kita perlukan untuk bekerja dengan transaksi di sisi aplikasi, mari berkenalan dengan dua metode yang memungkinkan kita mengimplementasikan transaksi dalam sistem terdistribusi.

8.3 Alat canggih untuk pecinta transaksi

Saya hanya akan memberikan definisi yang cukup umum, karena topik ini layak untuk artikel besar yang terpisah.

Komit dua fase (2pc) . 2pc memiliki dua fase: fase persiapan dan fase komit. Selama fase persiapan, semua layanan mikro akan diminta untuk mempersiapkan beberapa perubahan data yang dapat dilakukan secara atomik. Setelah semuanya siap, fase komit akan membuat perubahan yang sebenarnya. Untuk mengoordinasikan proses, diperlukan koordinator global, yang mengunci objek yang diperlukan - yaitu, mereka menjadi tidak dapat diakses untuk perubahan sampai koordinator membuka kuncinya. Jika layanan mikro tertentu tidak siap untuk perubahan (misalnya, tidak merespons), koordinator akan membatalkan transaksi dan memulai proses rollback.

Mengapa protokol ini bagus? Ini memberikan atomisitas. Selain itu, ini menjamin isolasi saat menulis dan membaca. Ini berarti bahwa perubahan pada satu transaksi tidak dapat dilihat oleh orang lain sampai koordinator melakukan perubahan tersebut. Tetapi properti ini juga memiliki kerugian: karena protokol ini sinkron (memblokir), ini memperlambat sistem (meskipun panggilan RPC itu sendiri cukup lambat). Dan lagi, ada bahaya saling blokir.

Saga . Dalam pola ini, transaksi terdistribusi dijalankan oleh transaksi lokal asinkron di semua layanan mikro terkait. Layanan mikro berkomunikasi satu sama lain melalui bus acara. Jika ada layanan mikro yang gagal menyelesaikan transaksi lokalnya, layanan mikro lainnya akan melakukan transaksi kompensasi untuk mengembalikan perubahan.

Keunggulan Saga adalah tidak ada objek yang diblokir. Tapi tentu saja ada kerugiannya.

Saga sulit untuk di-debug, terutama jika ada banyak layanan mikro yang terlibat. Kerugian lain dari pola Saga adalah kurangnya isolasi baca. Artinya, jika properti yang ditunjukkan dalam ACID penting bagi kami, maka Saga sangat tidak cocok untuk kami.

Apa yang kita lihat dari uraian kedua teknik ini? Fakta bahwa dalam sistem terdistribusi, tanggung jawab untuk atomisitas dan isolasi terletak pada aplikasinya. Hal yang sama terjadi saat menggunakan database yang tidak memberikan jaminan ACID. Artinya, hal-hal seperti resolusi konflik, rollback, komit, dan membebaskan ruang berada di pundak pengembang.

8.4 Bagaimana saya tahu kapan saya memerlukan jaminan ASAM?

Ketika ada kemungkinan besar bahwa kumpulan pengguna atau proses tertentu akan secara bersamaan bekerja pada data yang sama .

Maaf atas banalitasnya, tetapi contoh tipikal adalah transaksi keuangan.

Ketika urutan transaksi dieksekusi penting.

Bayangkan perusahaan Anda akan beralih dari messenger FunnyYellowChat ke messenger FunnyRedChat, karena FunnyRedChat memungkinkan Anda mengirim gif, tetapi FunnyYellowChat tidak bisa. Tetapi Anda tidak hanya mengubah kurir - Anda memindahkan korespondensi perusahaan Anda dari satu kurir ke yang lain. Anda melakukan ini karena pemrogram Anda terlalu malas untuk mendokumentasikan program dan proses di suatu tempat secara terpusat, dan sebaliknya mereka menerbitkan semuanya di saluran berbeda di messenger. Ya, dan penjual Anda menerbitkan detail negosiasi dan perjanjian di tempat yang sama. Singkatnya, seluruh hidup perusahaan Anda ada di sana, dan karena tidak ada yang punya waktu untuk mentransfer semuanya ke layanan untuk dokumentasi, dan pencarian pengirim pesan instan berfungsi dengan baik, Anda memutuskan alih-alih membersihkan puing-puing, cukup menyalin semua pesan ke lokasi baru. Urutan pesan itu penting

Ngomong-ngomong, untuk korespondensi di messenger, urutan umumnya penting, tetapi ketika dua orang menulis sesuatu di obrolan yang sama pada saat yang sama, maka secara umum tidak begitu penting pesan siapa yang akan muncul lebih dulu. Jadi, untuk skenario khusus ini, ACID tidak diperlukan.

Contoh lain yang mungkin adalah bioinformatika. Saya tidak mengerti sama sekali, tetapi saya berasumsi bahwa keteraturan itu penting saat menguraikan genom manusia. Namun, saya mendengar bahwa ahli bioinformatika umumnya menggunakan beberapa alat mereka untuk semuanya - mungkin mereka memiliki database sendiri.

Saat Anda tidak dapat memberikan pengguna atau memproses data basi.

Dan lagi - transaksi keuangan. Sejujurnya, saya tidak bisa memikirkan contoh lain.

Ketika transaksi yang tertunda dikaitkan dengan biaya yang signifikan. Bayangkan masalah yang dapat timbul ketika seorang dokter dan perawat memperbarui catatan pasien dan menghapus perubahan satu sama lain pada saat yang sama, karena database tidak dapat mengisolasi transaksi. Sistem perawatan kesehatan adalah bidang lain, selain keuangan, di mana jaminan ASAM cenderung kritis.

8.5 Kapan saya tidak membutuhkan ACID?

Saat pengguna hanya memperbarui beberapa data pribadi mereka.

Misalnya, pengguna meninggalkan komentar atau catatan tempel di halaman web. Atau edit data pribadi di akun pribadi dengan penyedia layanan apa pun.

Ketika pengguna tidak memperbarui data sama sekali, tetapi hanya melengkapi dengan yang baru (tambahkan).

Misalnya, aplikasi yang sedang berjalan yang menyimpan data saat Anda berlari: seberapa banyak Anda berlari, untuk jam berapa, rute, dll. Setiap proses baru adalah data baru, dan yang lama tidak diedit sama sekali. Mungkin, berdasarkan data, Anda mendapatkan analitik - dan hanya database NoSQL yang bagus untuk skenario ini.

Ketika logika bisnis tidak menentukan kebutuhan akan urutan tertentu di mana transaksi dilakukan.

Mungkin bagi seorang blogger Youtube yang mengumpulkan donasi untuk produksi materi baru selama siaran langsung berikutnya, tidak begitu penting siapa, kapan dan dalam urutan apa, memberinya uang.

Ketika pengguna akan tetap berada di halaman web atau jendela aplikasi yang sama selama beberapa detik atau bahkan menit, dan oleh karena itu mereka entah bagaimana akan melihat data basi.

Secara teoritis, ini adalah media berita online, atau Youtube yang sama. Atau "Habr". Jika tidak masalah bagi Anda bahwa transaksi yang belum selesai dapat disimpan sementara di sistem, Anda dapat mengabaikannya tanpa kerusakan apa pun.

Jika Anda menggabungkan data dari banyak sumber, dan data yang diperbarui dengan frekuensi tinggi - misalnya, data hunian tempat parkir di kota yang berubah setidaknya setiap 5 menit, maka secara teori tidak akan menjadi masalah besar. untuk Anda jika suatu saat transaksi untuk salah satu tempat parkir tidak berhasil. Meskipun, tentu saja, itu tergantung pada apa yang ingin Anda lakukan dengan data ini.

Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION