

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

# Penguncian terdistribusi dengan DynamoDB Lock Client
<a name="BestPractices_DistributedLocking"></a>

Untuk aplikasi yang memerlukan semantik lock-acquire-release tradisional, DynamoDB Lock Client adalah pustaka sumber terbuka yang mengimplementasikan penguncian terdistribusi menggunakan tabel DynamoDB sebagai toko kunci. Pendekatan ini berguna ketika Anda perlu mengoordinasikan akses ke sumber daya eksternal (seperti objek S3 atau konfigurasi bersama) di beberapa instance aplikasi.

Klien kunci tersedia sebagai [pustaka Java](https://github.com/awslabs/amazon-dynamodb-lock-client) open-source.

## Cara kerjanya
<a name="BestPractices_DistributedLocking_HowItWorks"></a>

Klien kunci menggunakan tabel DynamoDB khusus untuk melacak kunci. Setiap kunci direpresentasikan sebagai item dengan atribut kunci berikut:
+ Kunci partisi yang mengidentifikasi sumber daya yang dikunci.
+ Durasi sewa yang menentukan berapa lama kunci valid. Jika pemegang kunci mogok atau menjadi tidak responsif, kunci secara otomatis kedaluwarsa setelah durasi sewa.
+ Detak jantung yang dikirim pemegang kunci secara berkala untuk memperpanjang sewa. Ini mencegah kunci kedaluwarsa saat dudukan masih aktif diproses.

Klien kunci menggunakan penulisan bersyarat untuk memastikan bahwa hanya satu proses yang dapat memperoleh kunci pada satu waktu. Jika kunci sudah ditahan, penelepon dapat memilih untuk menunggu dan mencoba lagi atau gagal segera.

## Kapan harus menggunakan klien kunci
<a name="BestPractices_DistributedLocking_WhenToUse"></a>

Klien kunci sangat cocok ketika:
+ Anda perlu mengoordinasikan akses ke sumber daya bersama di beberapa instance aplikasi atau layanan mikro.
+ Bagian kritis berjalan lama (detik hingga menit) dan mencoba kembali seluruh operasi pada konflik akan mahal.
+ Anda memerlukan kedaluwarsa kunci otomatis untuk menangani kegagalan proses dengan anggun.

Contoh umum termasuk mengatur alur kerja terdistribusi, mengoordinasikan pekerjaan cron di beberapa instance, dan mengelola akses ke sumber daya eksternal bersama.

## Pengorbanan
<a name="BestPractices_DistributedLocking_Tradeoffs"></a>

**Infrastruktur tambahan**  
Membutuhkan tabel DynamoDB khusus untuk manajemen kunci, dengan kapasitas baca dan tulis tambahan untuk operasi kunci dan detak jantung.

**Ketergantungan jam**  
Kedaluwarsa kunci bergantung pada stempel waktu. Kemiringan jam yang signifikan antara klien dapat menyebabkan perilaku yang tidak terduga, terutama untuk jangka waktu sewa yang pendek.

**Risiko kebuntuan**  
Jika aplikasi Anda memperoleh kunci pada beberapa sumber daya, Anda harus mendapatkannya dalam urutan yang konsisten untuk menghindari kebuntuan. Durasi sewa menyediakan jaring pengaman dengan secara otomatis melepaskan kunci dari pemegang yang tidak responsif.

## Implementasi
<a name="BestPractices_DistributedLocking_Implementation"></a>

Contoh berikut menunjukkan cara menggunakan DynamoDB Lock Client untuk memperoleh dan melepaskan kunci:

```
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;

final DynamoDbClient dynamoDB = DynamoDbClient.builder()
    .region(Region.US_WEST_2)
    .build();

final AmazonDynamoDBLockClient lockClient = new AmazonDynamoDBLockClient(
    AmazonDynamoDBLockClientOptions.builder(dynamoDB, "Locks")
        .withTimeUnit(TimeUnit.SECONDS)
        .withLeaseDuration(10L)
        .withHeartbeatPeriod(3L)
        .withCreateHeartbeatBackgroundThread(true)
        .build());

// Try to acquire a lock on a resource
final Optional<LockItem> lock =
    lockClient.tryAcquireLock(AcquireLockOptions.builder("my-shared-resource").build());

if (lock.isPresent()) {
    try {
        // Perform operations that require exclusive access
        processSharedResource();
    } finally {
        // Always release the lock when done
        lockClient.releaseLock(lock.get());
    }
} else {
    System.out.println("Failed to acquire lock.");
}

lockClient.close();
```

**penting**  
Selalu lepaskan kunci di `finally` blok untuk memastikan kunci dilepaskan bahkan jika logika pemrosesan Anda melempar pengecualian. Kunci yang belum dirilis memblokir proses lain sampai masa sewa berakhir.

Anda juga dapat menerapkan mekanisme penguncian sederhana tanpa pustaka klien kunci dengan menggunakan penulisan bersyarat secara langsung. Contoh berikut menggunakan `UpdateItem` dengan ekspresi kondisi untuk memperoleh kunci, dan `DeleteItem` untuk melepaskannya:

```
from datetime import datetime, timedelta
from boto3.dynamodb.conditions import Attr

def acquire_lock(table, resource_name, owner_id, ttl_seconds):
    """Attempt to acquire a lock. Returns True if successful."""
    expiry = (datetime.now() + timedelta(seconds=ttl_seconds)).isoformat()
    now = datetime.now().isoformat()
    try:
        table.update_item(
            Key={'LockID': resource_name},
            UpdateExpression='SET #owner = :owner, #expiry = :expiry',
            ConditionExpression=Attr('LockID').not_exists() | Attr('ExpiresAt').lt(now),
            ExpressionAttributeNames={'#owner': 'OwnerID', '#expiry': 'ExpiresAt'},
            ExpressionAttributeValues={':owner': owner_id, ':expiry': expiry}
        )
        return True
    except table.meta.client.exceptions.ConditionalCheckFailedException:
        return False

def release_lock(table, resource_name, owner_id):
    """Release a lock. Only succeeds if the caller is the lock owner."""
    try:
        table.delete_item(
            Key={'LockID': resource_name},
            ConditionExpression=Attr('OwnerID').eq(owner_id)
        )
        return True
    except table.meta.client.exceptions.ConditionalCheckFailedException:
        return False
```

Pendekatan ini menggunakan ekspresi kondisi untuk memastikan bahwa kunci hanya dapat diperoleh jika tidak ada atau telah kedaluwarsa, dan hanya dapat dilepaskan oleh proses yang memperolehnya. Pertimbangkan untuk mengaktifkan [Time to Live (TTL)](TTL.md) di meja kunci untuk secara otomatis membersihkan item kunci yang kedaluwarsa.