Konfigurasi klien Lettuce - Amazon ElastiCache (Redis) OSS

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

Konfigurasi klien Lettuce

Bagian ini menjelaskan opsi konfigurasi Java dan Lettuce yang direkomendasikan, dan bagaimana penerapannya pada ElastiCache cluster.

Rekomendasi di bagian ini diuji dengan Lettuce versi 6.2.2.

TTL cache DNS Java

Mesin virtual Java (JVM) menyimpan cache pencarian nama DNS. Ketika JVM menyelesaikan nama host ke alamat IP, itu menyimpan alamat IP untuk jangka waktu tertentu, yang dikenal sebagai (TTL). time-to-live

Pilihan nilai TTL merupakan kompromi antara latensi dan responsivitas terhadap perubahan. Dengan TTL yang lebih pendek, peresolusi DNS menemukan pembaruan dalam DNS klaster dengan lebih cepat. Hal ini dapat membuat aplikasi Anda lebih cepat dalam merespons penggantian atau alur kerja lain yang dialami klaster Anda. Namun, jika TTL terlalu rendah, hal ini meningkatkan volume kueri, yang dapat meningkatkan latensi aplikasi Anda. Meskipun tidak ada nilai TTL yang benar, sebaiknya pertimbangkan lama waktu yang sesuai bagi Anda untuk menunggu perubahan berlaku saat menetapkan nilai TTL Anda.

Karena ElastiCache node menggunakan entri nama DNS yang mungkin berubah, kami sarankan Anda mengonfigurasi JVM Anda dengan TTL rendah 5 hingga 10 detik. Hal ini dapat memastikan bahwa ketika alamat IP simpul berubah, aplikasi Anda dapat menerima dan menggunakan alamat IP baru sumber daya dengan mengueri ulang DNS.

Pada beberapa konfigurasi Java, TTL default JVM diatur untuk tidak pernah menyegarkan entri DNS hingga JVM dimulai ulang.

Untuk detail tentang cara mengatur TTL JVM Anda, lihat How to set the JVM TTL.

Versi Lettuce

Sebaiknya gunakan Lettuce versi 6.2.2 atau versi yang lebih baru.

Titik akhir

Saat Anda menggunakan klaster dengan mode klaster diaktifkan, atur redisUri ke titik akhir konfigurasi klaster. Pencarian DNS untuk URI ini menampilkan daftar semua simpul yang tersedia di klaster, dan diresolusi secara acak ke salah satu simpul selama inisialisasi klaster. Untuk detail selengkapnya tentang cara kerja penyegaran topologi, lihat dynamicRefreshResourcesnanti dalam topik ini.

SocketOption

Aktifkan KeepAlive. Mengaktifkan opsi ini akan mengurangi kebutuhan untuk menangani koneksi yang gagal selama runtime perintah.

Pastikan Anda menetapkan Waktu habis koneksi berdasarkan persyaratan aplikasi dan beban kerja Anda. Untuk informasi selengkapnya, lihat bagian Waktu habis dalam topik ini.

ClusterClientOption: Mode Cluster Opsi klien yang diaktifkan

Aktifkan AutoReconnectsaat koneksi terputus.

Atur CommandTimeout. Untuk detail selengkapnya, lihat bagian Waktu habis dalam topik ini.

Atur nodeFilter untuk memfilter simpul yang gagal dari topologi. Lettuce menyimpan semua simpul yang ditemukan di output 'simpul klaster' (termasuk simpul dengan status PFAIL/FAIL) di 'partisi' klien (juga dikenal sebagai serpihan). Selama proses pembuatan topologi klaster, Lettuce mencoba terhubung ke semua simpul partisi. Perilaku Lettuce yang menambahkan simpul yang gagal ini dapat menyebabkan kesalahan koneksi (atau peringatan) ketika simpul diganti karena alasan apa pun.

Misalnya, setelah failover selesai dan klaster memulai proses pemulihan, sementara clusterTopology sedang diperbarui, peta simpul bus klaster memiliki periode waktu singkat ketika simpul yang nonaktif dicantumkan sebagai simpul FAIL, sebelum sepenuhnya dihapus dari topologi. Selama periode ini, klien Lettuce Redis OSS menganggapnya sebagai simpul yang sehat dan terus terhubung dengannya. Hal ini menyebabkan kegagalan setelah percobaan kembali habis.

Sebagai contoh:

final ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder() ... // other options .nodeFilter(it -> ! (it.is(RedisClusterNode.NodeFlag.FAIL) || it.is(RedisClusterNode.NodeFlag.EVENTUAL_FAIL) || it.is(RedisClusterNode.NodeFlag.HANDSHAKE) || it.is(RedisClusterNode.NodeFlag.NOADDR))) .validateClusterNodeMembership(false) .build(); redisClusterClient.setOptions(clusterClientOptions);
catatan

Pemfilteran node paling baik digunakan dengan DynamicRefreshSources set ke true. Sebaliknya, jika tampilan topologi diambil dari satu simpul seed yang bermasalah, yang melihat simpul primer dari serpihan tertentu sebagai simpul yang mengalami kegagalan, pemfilteran tersebut akan memfilter simpul primer ini, sehingga akan mengakibatkan slot tidak tercakup. Memiliki beberapa node benih (kapan DynamicRefreshSources benar) mengurangi kemungkinan masalah ini, karena setidaknya beberapa node benih harus memiliki tampilan topologi yang diperbarui setelah failover dengan primer yang baru dipromosikan.

ClusterTopologyRefreshOptions: Opsi untuk mengontrol penyegaran topologi cluster dari klien Cluster Mode Enabled

catatan

Klaster dengan mode klaster dinonaktifkan tidak mendukung perintah penemuan klaster dan tidak kompatibel dengan semua fungsionalitas penemuan topologi dinamis klien.

Mode cluster dinonaktifkan dengan ElastiCache tidak kompatibel dengan Lettuce's. MasterSlaveTopologyRefresh Sebagai gantinya, untuk mode klaster dinonaktifkan, Anda dapat mengonfigurasi StaticMasterReplicaTopologyProvider dan menyediakan titik akhir baca dan tulis klaster.

Untuk informasi selengkapnya tentang menghubungkan ke klaster dengan mode klaster dinonaktifkan, lihat Menemukan Titik Akhir Cluster Redis OSS (Mode Cluster Dinonaktifkan) (Konsol).

Jika Anda ingin menggunakan fungsionalitas penemuan topologi dinamis Lettuce, Anda dapat membuat klaster dengan mode klaster diaktifkan dengan konfigurasi serpihan yang sama dengan klaster yang ada. Namun, untuk klaster dengan mode klaster diaktifkan, sebaiknya konfigurasi setidaknya 3 serpihan dengan minimal 1 replika untuk mendukung failover cepat.

Aktifkan enablePeriodicRefresh. Opsi ini memungkinkan pembaruan topologi klaster berkala sehingga klien memperbarui topologi klaster dalam interval refreshPeriod (default: 60 detik). Ketika opsi ini dinonaktifkan, klien memperbarui topologi klaster hanya ketika kesalahan terjadi ketika klien tersebut mencoba menjalankan perintah terhadap klaster.

Dengan mengaktifkan opsi ini, Anda dapat mengurangi latensi yang terkait dengan penyegaran topologi klaster dengan menambahkan pekerjaan ini ke tugas latar belakang. Saat penyegaran topologi dilakukan dalam pekerjaan latar belakang, prosesnya bisa agak lambat untuk klaster yang memiliki banyak simpul. Hal ini karena semua simpul sedang dikueri untuk mendapatkan tampilan klaster yang paling terbaru. Jika Anda menjalankan klaster dalam jumlah besar, Anda sebaiknya menambah periodenya.

Aktifkan enableAllAdaptiveRefreshTriggers. Hal ini memungkinkan penyegaran topologi adaptif yang menggunakan semua pemicu: MOVED_REDIRECT, ASK_REDIRECT, PERSISTENT_RECONNECTS, UNCOVERED_SLOT, UNKNOWN_NODE. Pemicu penyegaran adaptif memulai pembaruan tampilan topologi berdasarkan peristiwa yang terjadi selama operasi klaster Redis OSS. Mengaktifkan opsi ini akan membuat penyegaran topologi langsung dilakukan ketika salah satu pemicu sebelumnya terjadi. Penyegaran yang dipicu secara adaptif dibatasi lajunya menggunakan waktu habis karena peristiwa dapat terjadi dalam skala besar (waktu habis default di antara pembaruan: 30).

Aktifkan closeStaleConnections. Hal ini memungkinkan penutupan koneksi yang sudah tidak berlaku saat menyegarkan topologi klaster. Itu hanya berlaku jika ClusterTopologyRefreshOptions. isPeriodicRefreshEnabled () benar. Ketika diaktifkan, klien dapat menutup koneksi yang tidak berlaku dan membuat yang baru di latar belakang. Hal ini mengurangi kebutuhan untuk menangani koneksi yang gagal selama runtime perintah.

Aktifkan dynamicRefreshResources. Kami merekomendasikan dynamicRefreshResources untuk mengaktifkan cluster kecil, dan menonaktifkannya untuk cluster besar. dynamicRefreshResourcesmemungkinkan menemukan node cluster dari node benih yang disediakan (misalnya, titik akhir konfigurasi cluster). Ia menggunakan semua simpul yang ditemukan sebagai sumber untuk menyegarkan topologi klaster.

Menggunakan dynamic refresh akan mengueri semua simpul yang ditemukan untuk topologi klaster dan mencoba memilih tampilan klaster yang paling akurat. Jika diatur ke false, hanya simpul seed awal yang digunakan sebagai sumber untuk penemuan topologi, dan jumlah klien diperoleh hanya untuk simpul seed awal. Saat dinonaktifkan, jika titik akhir konfigurasi klaster diresolusi ke simpul yang gagal, percobaan untuk menyegarkan tampilan klaster akan gagal dan menyebabkan pengecualian. Skenario ini dapat terjadi karena dibutuhkan beberapa waktu hingga entri simpul yang gagal dihapus dari titik akhir konfigurasi klaster. Oleh karena itu, titik akhir konfigurasi masih dapat diresolusi secara acak ke simpul yang gagal untuk waktu yang singkat.

Namun, ketika diaktifkan, kita menggunakan semua simpul klaster yang diterima dari tampilan klaster untuk mengueri tampilannya saat ini. Karena kita memfilter simpul yang gagal dari tampilan tersebut, penyegaran topologi akan berhasil. Namun, kapan dynamicRefreshSources benar, Lettuce menanyakan semua node untuk mendapatkan tampilan cluster, dan kemudian membandingkan hasilnya. Jadi, klaster dengan banyak simpul bisa menghabiskan banyak daya komputasi. Sebaiknya nonaktifkan fitur ini untuk klaster dengan banyak simpul.

final ClusterTopologyRefreshOptions topologyOptions = ClusterTopologyRefreshOptions.builder() .enableAllAdaptiveRefreshTriggers() .enablePeriodicRefresh() .dynamicRefreshSources(true) .build();

ClientResources

Konfigurasikan DnsResolverdengan DirContextDnsResolver. DNS resolver didasarkan pada com.sun.jndi.dns Java. DnsContextFactory.

Konfigurasikan reconnectDelay dengan backoff eksponensial dan jitter penuh. Lettuce memiliki mekanisme percobaan ulang bawaan berdasarkan strategi backoff eksponensial. Untuk detailnya, lihat Exponential Backoff dan Jitter di Blog Arsitektur. AWS Untuk informasi lebih lanjut tentang pentingnya memiliki strategi backoff coba lagi, lihat bagian logika backoff dari posting blog Praktik Terbaik di Blog Database. AWS

ClientResources clientResources = DefaultClientResources.builder() .dnsResolver(new DirContextDnsResolver()) .reconnectDelay( Delay.fullJitter( Duration.ofMillis(100), // minimum 100 millisecond delay Duration.ofSeconds(10), // maximum 10 second delay 100, TimeUnit.MILLISECONDS)) // 100 millisecond base .build();

Batas Waktu

Gunakan nilai waktu habis koneksi yang lebih rendah daripada waktu habis perintah Anda. Lettuce menggunakan pembuatan lazy connection. Jadi, jika waktu habis koneksi lebih tinggi dari waktu habis perintah, Anda dapat mengalami periode kegagalan persisten setelah penyegaran topologi jika Lettuce mencoba terhubung ke simpul yang tidak berkondisi baik dan waktu habis perintah selalu terlampaui.

Gunakan waktu habis perintah dinamis untuk perintah yang berbeda-beda. Sebaiknya tetapkan waktu habis perintah berdasarkan durasi perintah yang diharapkan. Misalnya, gunakan waktu habis yang lebih lama untuk perintah yang mengulangi beberapa kunci, seperti skrip FLUSHDB, FLUSHALL, KEYS, SMEMBERS, atau Lua. Gunakan waktu habis yang lebih pendek untuk perintah kunci tunggal, seperti SET, GET, dan HSET.

catatan

Waktu habis yang dikonfigurasi dalam contoh berikut adalah untuk pengujian yang menjalankan perintah SET/GET dengan kunci dan nilai hingga 20 byte. Waktu pemrosesan bisa lebih lama jika perintahnya kompleks atau kunci dan nilainya lebih besar. Anda harus mengatur waktu habis berdasarkan kasus penggunaan aplikasi Anda.

private static final Duration META_COMMAND_TIMEOUT = Duration.ofMillis(1000); private static final Duration DEFAULT_COMMAND_TIMEOUT = Duration.ofMillis(250); // Socket connect timeout should be lower than command timeout for Lettuce private static final Duration CONNECT_TIMEOUT = Duration.ofMillis(100); SocketOptions socketOptions = SocketOptions.builder() .connectTimeout(CONNECT_TIMEOUT) .build(); class DynamicClusterTimeout extends TimeoutSource { private static final Set<ProtocolKeyword> META_COMMAND_TYPES = ImmutableSet.<ProtocolKeyword>builder() .add(CommandType.FLUSHDB) .add(CommandType.FLUSHALL) .add(CommandType.CLUSTER) .add(CommandType.INFO) .add(CommandType.KEYS) .build(); private final Duration defaultCommandTimeout; private final Duration metaCommandTimeout; DynamicClusterTimeout(Duration defaultTimeout, Duration metaTimeout) { defaultCommandTimeout = defaultTimeout; metaCommandTimeout = metaTimeout; } @Override public long getTimeout(RedisCommand<?, ?, ?> command) { if (META_COMMAND_TYPES.contains(command.getType())) { return metaCommandTimeout.toMillis(); } return defaultCommandTimeout.toMillis(); } } // Use a dynamic timeout for commands, to avoid timeouts during // cluster management and slow operations. TimeoutOptions timeoutOptions = TimeoutOptions.builder() .timeoutSource( new DynamicClusterTimeout(DEFAULT_COMMAND_TIMEOUT, META_COMMAND_TIMEOUT)) .build();