Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Penemuan klien cluster dan backoff eksponensial (Valkey dan Redis OSS)
Saat menghubungkan ke cluster ElastiCache Valkey atau Redis OSS dalam mode cluster diaktifkan, pustaka klien yang sesuai harus sadar cluster. Klien harus mendapatkan peta slot hash ke simpul yang sesuai di klaster untuk mengirim permintaan ke simpul yang tepat dan menghindari overhead performa penanganan pengalihan klaster. Akibatnya, klien harus menemukan daftar lengkap slot dan simpul yang dipetakan dalam dua situasi berbeda:
Klien diinisialisasi dan harus mengisi konfigurasi slot awal
Pengalihan MOVED diterima dari server, seperti dalam situasi failover ketika semua slot yang dilayani oleh simpul primer sebelumnya diambil alih oleh replika, atau melakukan resharding ketika slot dipindahkan dari simpul primer sumber ke simpul primer target
Penemuan klien biasanya dilakukan dengan mengeluarkan perintah CLUSTER SLOTS atau CLUSTER NODES ke server Valkey atau Redis OSS. Kami merekomendasikan metode CLUSTER SLOTS karena mengembalikan set rentang slot dan node primer dan replika terkait kembali ke klien. Metode ini tidak memerlukan parsing tambahan dari klien dan lebih efisien.
Tergantung pada topologi cluster, ukuran respons untuk perintah CLUSTER SLOTS dapat bervariasi berdasarkan ukuran cluster. Klaster yang lebih besar dengan lebih banyak simpul menghasilkan respons yang lebih besar. Oleh karena itu, penting untuk memastikan bahwa jumlah klien yang melakukan penemuan topologi klaster tidak bertambah tanpa batas. Misalnya, ketika aplikasi klien diaktifkan atau kehilangan koneksi dari server dan harus melakukan penemuan klaster, satu kesalahan umumnya adalah bahwa aplikasi klien memicu beberapa permintaan koneksi ulang dan penemuan tanpa menambahkan backoff eksponensial saat mencoba lagi. Ini dapat membuat server Valkey atau Redis OSS tidak responsif untuk jangka waktu yang lama, dengan pemanfaatan CPU 100%. Pemadaman diperpanjang jika setiap perintah CLUSTER SLOTS harus memproses sejumlah besar node di bus cluster. Kami telah mengamati beberapa pemadaman klien sebelumnya karena perilaku ini di sejumlah bahasa yang berbeda termasuk Python (redis-py-cluster) dan Java (Lettuce dan Redisson).
Dalam cache nirserver, banyak masalah secara otomatis dikurangi karena topologi klaster yang dinyatakan bersifat statis dan terdiri dari dua entri: titik akhir tulis dan titik akhir baca. Penemuan klaster juga secara otomatis tersebar di beberapa simpul saat menggunakan titik akhir cache. Namun, rekomendasi berikut masih berguna.
Untuk mengurangi dampak yang disebabkan oleh masuknya permintaan koneksi dan penemuan secara tiba-tiba, kami merekomendasikan hal berikut:
Menerapkan pool koneksi klien dengan ukuran terbatas untuk membatasi jumlah koneksi masuk konkuren dari aplikasi klien.
Ketika klien terputus dari server karena waktu habis, coba lagi dengan backoff eksponensial dengan jitter. Hal ini membantu menghindari banyak klien membebani server pada waktu yang sama.
Gunakan panduan dalam Menemukan titik akhir koneksi di ElastiCache guna menemukan titik akhir klaster untuk melakukan penemuan klaster. Dengan begitu, Anda menyebarkan beban penemuan ke semua simpul di klaster (hingga 90), bukan memanfaatkan hanya beberapa simpul seed hardcode di klaster.
Berikut ini adalah beberapa contoh kode untuk logika percobaan ulang backoff eksponensial di redis-py, PHPRedis, dan Lettuce.
Contoh logika backoff 1: redis-py
redis-py memiliki mekanisme coba ulang bawaan yang mendukung backoff eksponensial dengan jitter. Jika tidak ada retry parameter yang disediakan, redis-py default dengan 3 percobaan ulang. ExponentialWithJitterBackoff Anda dapat menyesuaikan perilaku coba lagi melalui retry_on_error argumen retry dan saat membuat klien Redis
from redis.backoff import ExponentialBackoff from redis.retry import Retry from redis.client import Redis from redis.exceptions import ConnectionError, TimeoutError, BusyLoadingError # Run 3 retries with exponential backoff strategy retry = Retry(ExponentialBackoff(), 3) # Redis client with retries client = Redis( host="clustercfg.my-cluster.us-east-1.cache.amazonaws.com", port=6379, retry=retry, retry_on_error=[BusyLoadingError, ConnectionError, TimeoutError], ssl=True )
Untuk informasi selengkapnya tentang opsi konfigurasi coba lagi, lihat Coba Lagi Pembantu di dokumentasi redis-py
Contoh logika backoff 2: PHPRedis
PHPRedis memiliki mekanisme percobaan ulang bawaan yang mencoba ulang (tidak dapat dikonfigurasi) maksimal sebanyak 10 kali. Ada penundaan yang dapat dikonfigurasi di antara percobaan (dengan jitter dari percobaan ulang kedua dan seterusnya). Untuk informasi selengkapnya, lihat kode sampel
$timeout = 0.1; // 100 millisecond connection timeout $retry_interval = 100; // 100 millisecond retry interval $client = new Redis(); if($client->pconnect($HOST, $PORT, $timeout, NULL, $retry_interval) != TRUE) { return; // ERROR: connection failed } $client->set($key, $value);
Contoh logika backoff 3: Lettuce
Lettuce memiliki mekanisme percobaan ulang bawaan berdasarkan strategi backoff eksponensial yang dijelaskan dalam postingan Backoff Eksponensial dan Jitter
public static void main(String[] args) { ClientResources resources = null; RedisClient client = null; try { resources = DefaultClientResources.builder() .reconnectDelay(Delay.fullJitter( Duration.ofMillis(100), // minimum 100 millisecond delay Duration.ofSeconds(5), // maximum 5 second delay 100, TimeUnit.MILLISECONDS) // 100 millisecond base ).build(); client = RedisClient.create(resources, RedisURI.create(HOST, PORT)); client.setOptions(ClientOptions.builder() .socketOptions(SocketOptions.builder().connectTimeout(Duration.ofMillis(100)).build()) // 100 millisecond connection timeout .timeoutOptions(TimeoutOptions.builder().fixedTimeout(Duration.ofSeconds(5)).build()) // 5 second command timeout .build()); // use the connection pool from above example } finally { if (connection != null) { connection.close(); } if (client != null){ client.shutdown(); } if (resources != null){ resources.shutdown(); } } }