Rekomendasi QLDB driver Amazon - Database Buku Besar Amazon Quantum (AmazonQLDB)

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Rekomendasi QLDB driver Amazon

penting

Pemberitahuan akhir dukungan: Pelanggan yang ada akan dapat menggunakan Amazon QLDB hingga akhir dukungan pada 07/31/2025. Untuk detail selengkapnya, lihat Memigrasi QLDB Buku Besar Amazon ke Amazon Aurora Postgre. SQL

Bagian ini menjelaskan praktik terbaik untuk mengonfigurasi dan menggunakan QLDB driver Amazon untuk bahasa apa pun yang didukung. Contoh kode yang diberikan khusus untuk Java.

Rekomendasi ini berlaku untuk sebagian besar kasus penggunaan umum, tetapi satu ukuran tidak cocok untuk semua. Gunakan rekomendasi berikut sesuai keinginan Anda untuk aplikasi Anda.

Mengkonfigurasi objek QldbDriver

QldbDriverObjek mengelola koneksi ke buku besar Anda dengan mempertahankan kumpulan sesi yang digunakan kembali di seluruh transaksi. Sesi mewakili koneksi tunggal ke buku besar. QLDBmendukung satu transaksi yang aktif berjalan per sesi.

penting

Untuk versi driver yang lebih lama, fungsionalitas penyatuan sesi masih ada di PooledQldbDriver objek, bukan. QldbDriver Jika Anda menggunakan salah satu versi berikut, ganti penyebutan apa pun QldbDriver dengan PooledQldbDriver untuk sisa topik ini.

Driver Versi
Java 1.1.0atau sebelumnya
.NET 0.1.0-beta
Node.js 1.0.0-rc.1atau sebelumnya
Python 2.0.2atau sebelumnya

PooledQldbDriverObjek tidak digunakan lagi di versi driver terbaru. Kami menyarankan Anda meningkatkan ke versi terbaru dan mengonversi instance apa pun dari PooledQldbDriver keQldbDriver.

Konfigurasikan QldbDriver sebagai objek global

Untuk mengoptimalkan penggunaan driver dan sesi, pastikan bahwa hanya satu instance global driver yang ada di instance aplikasi Anda. Misalnya di Java, Anda dapat menggunakan kerangka kerja injeksi ketergantungan seperti Spring, Google Guice, atau Dagger. Contoh kode berikut menunjukkan cara mengkonfigurasi QldbDriver sebagai singleton.

@Singleton public QldbDriver qldbDriver (AWSCredentialsProvider credentialsProvider, @Named(LEDGER_NAME_CONFIG_PARAM) String ledgerName) { QldbSessionClientBuilder builder = QldbSessionClient.builder(); if (null != credentialsProvider) { builder.credentialsProvider(credentialsProvider); } return QldbDriver.builder() .ledger(ledgerName) .transactionRetryPolicy(RetryPolicy .builder() .maxRetries(3) .build()) .sessionClientBuilder(builder) .build(); }

Konfigurasikan upaya coba lagi

Pengemudi secara otomatis mencoba ulang transaksi ketika pengecualian sementara umum (seperti SocketTimeoutException atau) terjadi. NoHttpResponseException Untuk mengatur jumlah maksimum percobaan ulang, Anda dapat menggunakan maxRetries parameter objek transactionRetryPolicy konfigurasi saat membuat instance dari. QldbDriver (Untuk versi driver yang lebih lama seperti yang tercantum di bagian sebelumnya, gunakan retryLimit parameterPooledQldbDriver.)

Nilai default maxRetries adalah 4.

Kesalahan sisi klien seperti tidak InvalidParameterException dapat dicoba lagi. Ketika terjadi, transaksi dibatalkan, sesi dikembalikan ke kolam, dan pengecualian dilemparkan ke klien pengemudi.

Konfigurasikan jumlah maksimum sesi dan transaksi bersamaan

Jumlah maksimum sesi buku besar yang digunakan oleh instance QldbDriver untuk menjalankan transaksi ditentukan oleh maxConcurrentTransactions parameternya. (Untuk versi driver yang lebih lama seperti yang tercantum di bagian sebelumnya, ini ditentukan oleh poolLimit parameterPooledQldbDriver.)

Batas ini harus lebih besar dari nol dan kurang dari atau sama dengan jumlah maksimum HTTP koneksi terbuka yang diizinkan oleh klien sesi, sebagaimana didefinisikan oleh spesifik AWS SDK. Misalnya di Java, jumlah maksimum koneksi diatur dalam ClientConfigurationobjek.

Nilai default maxConcurrentTransactions adalah pengaturan koneksi maksimum Anda AWS SDK.

Saat Anda mengonfigurasi QldbDriver dalam aplikasi Anda, ambil pertimbangan penskalaan berikut:

  • Pool Anda harus selalu memiliki setidaknya sesi sebanyak jumlah transaksi yang berjalan secara bersamaan yang Anda rencanakan untuk dimiliki.

  • Dalam model multi-utas di mana utas supervisor mendelegasikan ke utas pekerja, pengemudi harus memiliki setidaknya sesi sebanyak jumlah utas pekerja. Jika tidak, pada beban puncak, utas akan mengantri untuk sesi yang tersedia.

  • Batas layanan sesi aktif bersamaan per buku besar didefinisikan dalam. Kuota dan batasan di Amazon QLDB Pastikan Anda tidak mengonfigurasi lebih dari batas sesi bersamaan ini untuk digunakan untuk satu buku besar di semua klien.

Mencoba lagi pengecualian

Saat mencoba kembali pengecualian yang terjadi diQLDB, pertimbangkan rekomendasi berikut.

Mencoba lagi OccConflictException

Optimistic concurrency control (OCC) pengecualian konflik terjadi ketika data yang diakses transaksi telah berubah sejak awal transaksi. QLDBmelempar pengecualian ini saat mencoba melakukan transaksi. Pengemudi mencoba ulang transaksi hingga sebanyak yang maxRetries dikonfigurasi.

Untuk informasi selengkapnya tentang OCC dan praktik terbaik untuk menggunakan indeks untuk membatasi OCC konflik, lihatModel QLDB konkurensi Amazon.

Mencoba lagi pengecualian lain di luar QldbDriver

Untuk mencoba kembali transaksi di luar driver ketika pengecualian khusus, yang ditentukan aplikasi dilemparkan selama runtime, Anda harus membungkus transaksi. Misalnya di Java, kode berikut menunjukkan cara menggunakan pustaka Resslience4J untuk mencoba kembali transaksi di. QLDB

private final RetryConfig retryConfig = RetryConfig.custom() .maxAttempts(MAX_RETRIES) .intervalFunction(IntervalFunction.ofExponentialRandomBackoff()) // Retry this exception .retryExceptions(InvalidSessionException.class, MyRetryableException.class) // But fail for any other type of exception extended from RuntimeException .ignoreExceptions(RuntimeException.class) .build(); // Method callable by a client public void myTransactionWithRetries(Params params) { Retry retry = Retry.of("registerDriver", retryConfig); Function<Params, Void> transactionFunction = Retry.decorateFunction( retry, parameters -> transactionNoReturn(params)); transactionFunction.apply(params); } private Void transactionNoReturn(Params params) { try (driver.execute(txn -> { // Transaction code }); } return null; }
catatan

Mencoba kembali transaksi di luar QLDB pengemudi memiliki efek pengganda. Misalnya, jika QldbDriver dikonfigurasi untuk mencoba lagi tiga kali, dan logika coba ulang kustom juga mencoba ulang tiga kali, transaksi yang sama dapat dicoba ulang hingga sembilan kali.

Membuat transaksi idempoten

Sebagai praktik terbaik, buat transaksi tulis Anda idempoten untuk menghindari efek samping yang tidak terduga dalam kasus percobaan ulang. Transaksi adalah idempoten jika dapat berjalan beberapa kali dan menghasilkan hasil yang identik setiap kali.

Untuk mempelajari selengkapnya, lihat Model QLDB konkurensi Amazon.

Mengoptimalkan performa

Untuk mengoptimalkan kinerja saat Anda menjalankan transaksi menggunakan driver, ambil pertimbangan berikut:

  • executeOperasi selalu membuat minimal tiga SendCommand API panggilan keQLDB, termasuk perintah berikut:

    1. StartTransaction

    2. ExecuteStatement

      Perintah ini dipanggil untuk setiap pernyataan PartiQL yang Anda jalankan di blok. execute

    3. CommitTransaction

    Pertimbangkan jumlah total API panggilan yang dilakukan saat Anda menghitung beban kerja keseluruhan aplikasi Anda.

  • Secara umum, kami merekomendasikan memulai dengan penulis single-threaded dan mengoptimalkan transaksi dengan mengelompokkan beberapa pernyataan dalam satu transaksi. Maksimalkan kuota pada ukuran transaksi, ukuran dokumen, dan jumlah dokumen per transaksi, sebagaimana didefinisikan dalamKuota dan batasan di Amazon QLDB.

  • Jika batching tidak cukup untuk beban transaksi besar, Anda dapat mencoba multi-threading dengan menambahkan penulis tambahan. Namun, Anda harus mempertimbangkan dengan cermat persyaratan aplikasi Anda untuk pengurutan dokumen dan transaksi serta kompleksitas tambahan yang ditimbulkannya.

Menjalankan beberapa pernyataan per transaksi

Seperti yang dijelaskan di bagian sebelumnya, Anda dapat menjalankan beberapa pernyataan per transaksi untuk mengoptimalkan kinerja aplikasi Anda. Dalam contoh kode berikut, Anda menanyakan tabel dan kemudian memperbarui dokumen dalam tabel tersebut dalam transaksi. Anda melakukan ini dengan meneruskan ekspresi lambda ke execute operasi.

Java
// This code snippet is intentionally trivial. In reality you wouldn't do this because you'd // set your UPDATE to filter on vin and insured, and check if you updated something or not. public static boolean InsureCar(QldbDriver qldbDriver, final String vin) { final IonSystem ionSystem = IonSystemBuilder.standard().build(); final IonString ionVin = ionSystem.newString(vin); return qldbDriver.execute(txn -> { Result result = txn.execute( "SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE", ionVin); if (!result.isEmpty()) { txn.execute("UPDATE Vehicles SET insured = TRUE WHERE vin = ?", ionVin); return true; } return false; }); }
.NET
// This code snippet is intentionally trivial. In reality you wouldn't do this because you'd // set your UPDATE to filter on vin and insured, and check if you updated something or not. public static async Task<bool> InsureVehicle(IAsyncQldbDriver driver, string vin) { ValueFactory valueFactory = new ValueFactory(); IIonValue ionVin = valueFactory.NewString(vin); return await driver.Execute(async txn => { // Check if the vehicle is insured. Amazon.QLDB.Driver.IAsyncResult result = await txn.Execute( "SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE", ionVin); if (await result.CountAsync() > 0) { // If the vehicle is not insured, insure it. await txn.Execute( "UPDATE Vehicles SET insured = TRUE WHERE vin = ?", ionVin); return true; } return false; }); }
Go
// This code snippet is intentionally trivial. In reality you wouldn't do this because you'd // set your UPDATE to filter on vin and insured, and check if you updated something or not. func InsureCar(driver *qldbdriver.QLDBDriver, vin string) (bool, error) { insured, err := driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { result, err := txn.Execute( "SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE", vin) if err != nil { return false, err } hasNext := result.Next(txn) if !hasNext && result.Err() != nil { return false, result.Err() } if hasNext { _, err = txn.Execute( "UPDATE Vehicles SET insured = TRUE WHERE vin = ?", vin) if err != nil { return false, err } return true, nil } return false, nil }) if err != nil { panic(err) } return insured.(bool), err }
Node.js
// This code snippet is intentionally trivial. In reality you wouldn't do this because you'd // set your UPDATE to filter on vin and insured, and check if you updated something or not. async function insureCar(driver: QldbDriver, vin: string): Promise<boolean> { return await driver.executeLambda(async (txn: TransactionExecutor) => { const results: dom.Value[] = (await txn.execute( "SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE", vin)).getResultList(); if (results.length > 0) { await txn.execute( "UPDATE Vehicles SET insured = TRUE WHERE vin = ?", vin); return true; } return false; }); };
Python
# This code snippet is intentionally trivial. In reality you wouldn't do this because you'd # set your UPDATE to filter on vin and insured, and check if you updated something or not. def do_insure_car(transaction_executor, vin): cursor = transaction_executor.execute_statement( "SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE", vin) first_record = next(cursor, None) if first_record: transaction_executor.execute_statement( "UPDATE Vehicles SET insured = TRUE WHERE vin = ?", vin) return True else: return False def insure_car(qldb_driver, vin_to_insure): return qldb_driver.execute_lambda( lambda executor: do_insure_car(executor, vin_to_insure))

executeOperasi pengemudi secara implisit memulai sesi dan transaksi dalam sesi itu. Setiap pernyataan yang Anda jalankan dalam ekspresi lambda dibungkus dalam transaksi. Setelah semua pernyataan berjalan, pengemudi melakukan transaksi secara otomatis. Jika ada pernyataan yang gagal setelah batas coba ulang otomatis habis, transaksi dibatalkan.

Menyebarkan pengecualian dalam transaksi

Saat menjalankan beberapa pernyataan per transaksi, kami umumnya tidak menyarankan Anda menangkap dan menelan pengecualian dalam transaksi.

Misalnya di Java, program berikut menangkap setiap contohRuntimeException, mencatat kesalahan, dan melanjutkan. Contoh kode ini dianggap praktik buruk karena transaksi berhasil bahkan ketika UPDATE pernyataan gagal. Jadi, klien mungkin berasumsi bahwa pembaruan berhasil padahal tidak.

Awas

Jangan gunakan contoh kode ini. Ini disediakan untuk menunjukkan contoh anti-pola yang dianggap praktik buruk.

// DO NOT USE this code example because it is considered bad practice public static void main(final String... args) { ConnectToLedger.getDriver().execute(txn -> { final Result selectTableResult = txn.execute("SELECT * FROM Vehicle WHERE VIN ='123456789'"); // Catching an error inside the transaction is an anti-pattern because the operation might // not succeed. // In this example, the transaction succeeds even when the update statement fails. // So, the client might assume that the update succeeded when it didn't. try { processResults(selectTableResult); String model = // some code that extracts the model final Result updateResult = txn.execute("UPDATE Vehicle SET model = ? WHERE VIN = '123456789'", Constants.MAPPER.writeValueAsIonValue(model)); } catch (RuntimeException e) { log.error("Exception when updating the Vehicle table {}", e.getMessage()); } }); log.info("Vehicle table updated successfully."); }

Sebarkan (gelembung) pengecualian sebagai gantinya. Jika ada bagian dari transaksi yang gagal, biarkan execute operasi membatalkan transaksi sehingga klien dapat menangani pengecualian yang sesuai.