The page has been translated by Gen AI.

Lettuce Library based Redis Cluster Development vector

Lettuce Library based Redis Cluster Development vector

Overview

Redis Cluster distributes data based on sharding, and replication is performed using a Master‑Slave structure for each shard. Therefore, it differs from the traditional Redis (DBaaS) architecture of Redis Sentinel. Client development of this type is required. The Lettuce library is widely used for Redis Cluster client development. The Lettuce library provides synchronous and asynchronous APIs, supports operations for each Redis data type, and offers various features needed for connecting to Redis Cluster, such as integration with Spring Data.

Lettuce library

Lettuce

Lettuce is based on the Netty library, utilizing TCP channels and event-driven processing for Redis. Cluster and connection are created and managed. Therefore, as a dependency, Netty and Reactor-related libraries are needed. The Lettuce library provides various features, including StandAlone as well as Cluster. Provides a connection class for Sentinel and supports ID/P assword method and SSL-based authentication. After connecting to a Redis Cluster, if a failure occurs on a Master or Slave node or when adding a node and When deleting, the Lettuce library can reflect the topology changes in real time.

[ Lettuce Maven ]

<dependency>
	<groupId>io.lettuce</groupId>
	<artifactId>lettuce core</artifactId>
	<version>${version}</version>
</dependency>

Spring-data-redis

RDBMS provides a driver based on the JDBC interface, and Spring Framework provides the corresponding. Provides an interface that easily registers drivers as Spring Beans. Lettuce is based on the Spring Data Redis library and integrates easily with the Spring Framework. It can be registered and used. Calls the Connection Pool and Redis Operation objects as Spring Beans.

[ Spring data redis Maven ]

<dependency>
	<groupId>org.springframework.data</groupId>
	<artifactId>spring data redis</artifactId>
	<version>${version}</version>
</dependency>

Redis Cluster connection settings

Redis Cluster Configuration

Manage node IP addresses, port values, and authentication information within the cluster as a Redis Cluster connection information management object. Set. It is recommended to enter all Master/Slave information within the cluster and launch the client for the first time. Refer to the documentation. If authentication is not applied to the Redis Cluster, the authentication information will not be set.

[ RedisClusterConfiguration code example ]

List<String> host;
RedisClusterConfiguration configuration = new RedisClusterConfiguration(this.host);
configuration.setUsername("username");
configuration.setPassword("password");

Cluster Topology Refresh Options

Manage the Redis Cluster state, and when a Master/Slave failure or Cluster change occurs, handle it. You can set options for actions that are reflected dynamically. Lettuce does so periodically. You can check the cluster status, or set it to check the cluster status when a trigger occurs. It is available, and you can also define the check interval.

[ ClusterTopologyRefreshOptions Settings List ]

OptionExplanationdefault
enableAllAdaptiveRefreshTriggersReconstruct the topology when a trigger occurs in Redis ClusterFalse
refreshTriggersReconnectAttemptsPerform a topology refresh when a Reconnect Attempt occurs the number of times set by RefreshTrigger.PERSISTENT_RECONNECTS.5
adaptiveRefreshTriggersTimeoutBecause triggers cause topology refreshes, frequent trigger emissions and frequent refreshes load Redis, so we avoid repeated refreshes within that time interval.30
enablePeriodicRefreshWhether to perform topology refreshFalse
refreshPeriodenablePeriodicRefresh execution interval60
dynamicRefreshSourcesIf set to true, topology information is obtained from all discovered nodes. If set to false, topology information is obtained only from the initially configured seed node.True

[ ClusterTopologyRefreshOptions code example ]

ClusterTopologyRefreshOptions topologyRefreshOptions =
ClusterTopologyRefreshOptions.builder()
.enableAllAdaptiveRefreshTriggers()
.dynamicRefreshSources(true)
.enablePeriodicRefresh(Duration.ofSeconds(60))
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30))
.refreshTriggersReconnectAttempts(3)
.build()

Lettuce Client Configuration

A class that manages overall client-related options, such as connection and command You can configure timeout and TCP-related settings. Timeout-related settings are Application Since it is related to outage and failover time, consider the Redis Cluster and topology settings when setting the value. Define

[ ClusterClientOptions configuration list ]

optionExplanationdefault
autoReconnectWhether to retry a connection that was terminated without a close eventTrue
timeoutOptionsTimeout for GET and PUT operations, same as commandTimeoutX
socketOptionsThe default timeout for the connection is 10 seconds.10
disconnectedBehaviorWhen the connection is lost, configure handling of ongoing operations: if auto reconnect is enabled, store the operation in a queue; if auto reconnect is disabled, treat it as a failure.DEFAULT

Lettuce Connection Factory

Providing a connection to the client based on the configuration classes mentioned earlier This is a class. You can set the read policy and add Netty-related options that manage TCP. It can be done. Typically, the generated LettuceConnectionFactory object is Spring Register it as a Bean so that it can be easily used in Redis-related clients.

[ LettuceConnectionFactory code example ]

LettuceConnectionFactory connectionFactory=new
LettuceConnectionFactory(configuration
,LettuceClientConfiguration.builder()
	.readFrom(ReadFrom.REPLICA_PREFERRED)
	.commandTimeout(Duration.ofMillis(${user}))
	.clientOptinos(
		ClusterClientOptions.builder()
			.autoReconnect(true)
			.disconnectedBehavior(ClientOptions.DisconnectedBehavior.DEFAULT)
		.topologyRefreshOptions(topologyRefreshOptions)
		.build())
	.clientResources(clientResource)
	.build());

RedisTemplate<K,V>

A class that provides the client Operation API for businesses using Redis Cluster. The class must use RedisTemplate. RedisTemplate is Takes a LettuceConnectionFactory as a parameter, obtains a Connection, and creates RedisTemplate is registered as a Spring Bean and used.

[ RedisTemplate code example ]

//Create lettuce template for String type key and value
RedisTemplate<String, String>
template = new RedisTemplate<>();

//Set template based on lettuce ConnectionFactory
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());

Netty Epoll option configuration

Netty Epoll options

Generally, for TCP settings, the client configures only a few parameters while most are handled by the application. It is applied based on kernel parameters in the OS. The Netty Epoll library provides detailed TCP options. It provides a way to solve problems that cannot be addressed with the existing client TCP options. With the existing Lettuce library, failover does not work when there is a network outage on the read replica. There is an issue, which we resolve by applying TCP_USER_TIMEOUT in the Epoll options.

[Frequently used Epoll options]

OptionExplanation
EpollChannelOption.TCP_KEEPIDLEIf there is no load during KEEP IDLE, transition to the Idle state and perform a status check.
EpollChannelOption.TCP_KEEPCNTAfter transitioning to the idle state, perform status checks for KEEPCNT iterations.
EpollChannelOption.TCP_KEEPINTVLInterval time when performing a status check after switching to Idle state
EpollChannelOption.TCP_USER_TIMEOUTIf there is no response for USER_TIMEOUT after a TCP request, it is considered a failure and the TCP connection is terminated; if set to 0, this option is not used.

Netty Epoll library

The Epoll library includes compiled files for each OS. Therefore, the Classifier It must be specified, and the Linux environment library includes an SO file that is used whenever an Epoll option is invoked.

netty epoll pom.xml example for Linux

<dependency>
	<groupId>io.netty</groupId>
	<artifactId>netty transport native epoll</artifactId>
	<version> 1.85.Final</version>
	<classifier>linux x86_64</classifier>
</dependency>

nettyCustomizer

To apply the Netty Epoll option in Lettuce, you need the NettyCustomizer interface. Implement it and set the Epoll option in the internal method. Whether Epoll is applied You can check with the EpollProvider.isAvailable method.

[ NettyCustomizer interface implementation example ]

ClientResources clientResource = ClientResources.builder().nettyCustomizer(new
	NettyCustomizer() {
	@Override
	public void afterBootstrapInitialized(Bootstrap bootstrap) {
		bootstrap.option(EpollChannelOption.TCP_KEEPIDLE, ${user});
		bootstrap.option(EpollChannelOption.TCP_KEEPINTVL, ${user});
		bootstrap.opt ion(EpollChannelOption.TCP_KEEPCNT, ${user});
		bootstrap.option(EpollChannelOption.TCP_USER_TIMEOUT, ${user});
		bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
	}).build();

Lettuce-based Operation code example

Lettuce Configuration class example

Based on Redis Cluster connection information, configure LettuceConnectionFactory and RedisTemplate Initialize the configuration and register it as a Spring Bean. ClientResource is Netty Apply the Epoll option and set the Cluster state information option in ClusterTopology, In ClientConfiguration, detailed client options are defined.

[ Lettuce Config uration class example ]

@Configuration
public class RedisConfig{
	// Method to create ConnectionFactory bean
	@Bean
	public LettuceConnectionFactory redisConnectionFactory() {
		// Define cluster status related settings
		ClusterTopologyRefreshOptions topolo gyRefreshOptions =
		ClusterTopologyRefreshOptions.builder()
		.enableAllAdaptiveRefreshTriggers()
		.dynamicRefreshSources(true)
		.enablePeriodicRefresh(Duration.ofSeconds(60))
		.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30))
		.refres hTriggersReconnectAttempts(3)
		.build();

		// Define cluster connection information, Host information is entered in List
		RedisClusterConfiguration configuration =
		new RedisClusterConfiguration(this.host);
		configuration.setUsern ame("user");
		configuration.setPassword("password");

		// Define Netty Epoll options
		ClientResources clientResource =
		ClientResources.builder().nettyCustomizer(new NettyCustomizer() {
			@Override
			public void afterBootstrapInitialized(Bootstrap bootstrap) {
			bootstrap.option(EpollChannelOption.TCP_KEEPIDLE, 15);
			bootstrap.option(EpollChannelOption.TCP_KEEPINTVL, 5);
			bootstrap.option(EpollChannelOption.T CP_KEEPCNT, 1);
			bootstrap.option(EpollChannelOption.TCP_USER_TIMEOUT, 30000);
			bootstrap.option(ChannelOption.SO_KEEPALIVE,true);
			}).build();
		}

		// Define LettuceFactory with Topology, Cluster Info, Netty option
		LettuceConnectionFactory connectionFactory=new
		LettuceConnectionFactory(configuration
		,LettuceClientConfiguration.builder()
		.readFrom(ReadFrom.REPLICA_PREFERRED)
		.clientResources(clientResource)
		.commandTimeout(Duration.ofMillis(30000))
		.clientOptions(
			ClusterClientOptions.builder()
			.topologyRefreshOptions(topologyRefreshOptions).build()).build());

		return connectionFactory;
	}

	// Create RedisTemplate Bean in String type
	@Bean
	RedisTemplate<String, String> redisTemplate(
	@Qualifier("redisConnectionFactory") RedisConnectionFactory
	redisConnectionFactory) {
		RedisTemplate<String, String> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConne ctionFactory);
		template.setKeySerializer(new StringRedisSerializer());
		template.setValueSerializer(new StringRedisSerializer());
		return template;
	}
}

Redis Operation example

You can retrieve a RedisTemplate bean and execute GET and PUT operations against a Redis Cluster. Redis Cluster state changes or failovers are performed by the Lettuce library based on the options configured in RedisConfig.

[ Redis Operation Example ]

@Autowired
@Qualifier("redisTemplate")
private RedisTemplate<String, String> redisTemplate;
//String
type PUT operation
this.redisTemplate.opsForValue().set(key, value);
//String
type GET operation
String v = this.redisTemplate.opsForValue().get(key);