Penemuan klien cluster dan backoff eksponensial (Valkey dan Redis) OSS - Amazon ElastiCache

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 OSS cluster ElastiCache Valkey atau Redis 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

  • MOVEDPengalihan diterima dari server, seperti dalam situasi failover ketika semua slot yang dilayani oleh node primer sebelumnya diambil alih oleh replika, atau re-sharding ketika slot dipindahkan dari sumber primer ke node primer target

Penemuan klien biasanya dilakukan dengan mengeluarkan CLUSTER NODE perintah CLUSTER SLOT atau ke server Valkey atau OSS Redis. Kami merekomendasikan CLUSTER SLOT metode ini 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.

Bergantung pada topologi cluster, ukuran respons untuk CLUSTER SLOT perintah 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 OSS server Valkey atau Redis tidak responsif untuk jangka waktu yang lama, dengan CPU pemanfaatan 100%. Pemadaman diperpanjang jika setiap CLUSTER SLOT perintah harus memproses sejumlah besar node di bus cluster. Kami telah mengamati beberapa pemadaman klien di masa lalu 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,, dan Lettuce. PHPRedis

Contoh logika backoff 1: redis-py

redis-py memiliki mekanisme percobaan ulang bawaan yang mencoba ulang satu kali segera setelah kegagalan. Mekanisme ini dapat diaktifkan melalui retry_on_timeout argumen yang diberikan saat membuat OSS objek Redis. Di sini kita mendemonstrasikan mekanisme percobaan ulang kustom dengan backoff eksponensial dan jitter. Kami telah mengirimkan permintaan tarik untuk mengimplementasikan backoff eksponensial secara native di redis-py (#1494). Di masa depan, hal tersebut mungkin tidak perlu diimplementasikan secara manual.

def run_with_backoff(function, retries=5): base_backoff = 0.1 # base 100ms backoff max_backoff = 10 # sleep for maximum 10 seconds tries = 0 while True: try: return function() except (ConnectionError, TimeoutError): if tries >= retries: raise backoff = min(max_backoff, base_backoff * (pow(2, tries) + random.random())) print(f"sleeping for {backoff:.2f}s") sleep(backoff) tries += 1

Anda kemudian dapat menggunakan kode berikut untuk menetapkan nilai:

client = redis.Redis(connection_pool=redis.BlockingConnectionPool(host=HOST, max_connections=10)) res = run_with_backoff(lambda: client.set("key", "value")) print(res)

Bergantung pada beban kerja Anda, Anda sebaiknya mengubah nilai backoff dasar dari 1 detik menjadi puluhan atau ratusan milidetik untuk beban kerja yang sensitif terhadap latensi.

Contoh logika backoff 2: PHPRedis

PHPRedismemiliki mekanisme coba ulang bawaan yang mencoba ulang maksimum (tidak dapat dikonfigurasi) 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 berikut. Kami telah mengirimkan permintaan tarik untuk menerapkan backoff eksponensial secara native di PHPredis(#1986) yang telah digabungkan dan didokumentasikan. Bagi mereka yang berada di rilis terbaruPHPRedis, tidak perlu mengimplementasikan secara manual tetapi kami telah menyertakan referensi di sini untuk mereka yang ada di versi sebelumnya. Untuk saat ini, berikut ini adalah contoh kode yang mengonfigurasi penundaan mekanisme percobaan ulang:

$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. Berikut ini adalah kutipan kode yang menunjukkan pendekatan jitter penuh:

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(); } } }