Spring certified China Education Management Center - Spring Data Redis framework tutorial III

Original title: Spring certified China Education Management Center - Spring Data Redis framework tutorial III

10.15. Support

Packageorg.springframework.data.redis.support provides various reusable components that rely on Redis as backup storage. At present, the package includes various JDK based interface implementations based on Redis, such as atomic counter and JDK set.

Atomic counters can easily package Redis key increments, while collections can easily manage Redis keys while minimizing storage exposure or API leakage. In particular, RedisSet and RedisZSet interfaces provide easy access to Redis supported collection operations, such as intersection and union. RedisList implements the top of Redis on List, Queue and Deque contracts (and their equivalent blocking siblings), exposing the storage as a collection of FIFO (first in first out), LIFO (last in first out) or end closure with minimal configuration. The following example shows the configuration of the bean used RedisList:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="
  http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="queue" class="org.springframework.data.redis.support.collections.DefaultRedisList">
    <constructor-arg ref="redisTemplate"/>
    <constructor-arg value="queue-key"/>
  </bean>

</beans>

The following example shows a Java configuration example Deque:

public class AnotherExample {

  // injected
  private Deque<String> queue;

  public void addTag(String tag) {
    queue.push(tag);
  }
}

As the previous example shows, the consumption code is separated from the actual storage implementation. In fact, there is no indication that Redis is used below. This makes the transition from development environment to production environment transparent and greatly improves testability (Redis implementation can be replaced by in memory implementation).

1. Responsive Redis support

This section describes reactive Redis support and how to get started. Reactive Redis support naturally overlaps with imperative Redis support.

11.1.Redis requirements

Spring Data Redis is currently integrated with lattice as the only reactive Java connector. Project Reactor is used as a reactive composition library.

11.2. Connect to Redis using a responsive driver

One of the first tasks when using Redis and Spring is to connect to the storage through the IoC container. To do this, you need a Java connector (or binding). Whatever library you choose, you must use org.springframework.data.redis.connection package and its reactivereedisconnection and reactivereedisconnectionfactory interfaces work and obtain positive connections for Redis.

11.2.1.Redis operation mode

Redis can be run as an independent server, using Redis Sentinel or in redis cluster mode. Lettue supports all the previously mentioned connection types.

11.2.2.reactivededisconnection and reactivededisconnectionfactory

Reactive redisconnection is the core of Redis communication because it handles the communication with the back end of Redis. It also automatically converts the underlying driver exceptions into a Spring consistent DAO exception hierarchy, so you can switch connectors without changing any code, because the operation semantics remain the same.

Reactivededisconnectionfactory creates an active reactivededisconnection instance. In addition, factories act as PersistenceExceptionTranslator instances, which means that once declared, they allow you to do transparent exception conversion -- for example, by using @ Repository annotations and AOP. For more information, see the dedicated section in the Spring Framework documentation.

Depending on the underlying configuration, the factory can return new or existing connections (if using pooled or shared native connections).

The easiest way to use a Reactivededisconnectionfactory configures the appropriate connector through the IoC container and injects it into the using class.

11.2.3. Configure lettuce connector

Spring Data Redis The org.springframework.data.redis.connection.lettuce package supports Lettuce.

You can Reactivereedisconnectionfactory sets lettuce as follows:

@Bean
public ReactiveRedisConnectionFactory connectionFactory() {
  return new LettuceConnectionFactory("localhost", 6379);
}

The following example shows a more complex configuration, including SSL and timeout, which uses LettuceClientConfigurationBuilder:

@Bean
public ReactiveRedisConnectionFactory lettuceConnectionFactory() {

  LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
    .useSsl().and()
    .commandTimeout(Duration.ofSeconds(2))
    .shutdownTimeout(Duration.ZERO)
    .build();

  return new LettuceConnectionFactory(new RedisStandaloneConfiguration("localhost", 6379), clientConfig);
}

For more detailed client configuration tuning, see LettuceClientConfiguration.

11.3. Processing objects through reactivereredistemplate

Most users may use ReactiveRedisTemplate and its corresponding package, org.springframework.data.redis.core. Due to its rich function set, the template is actually the central class of Redis module. This template provides high-level abstraction for Redis interaction. Although reactivededisconnection provides low-level methods to accept and return binary values (ByteBuffer), the template is responsible for serialization and connection management, so you don't need to deal with such details.

In addition, the template provides an operation view (following the grouping in Redis Command Reference) and provides rich general interfaces for specific types of work, as described in the following table:

After configuration, the template is thread safe and can be reused across multiple instances.

Reactivereredistemplate most operations use Java based serializers. This means that any object written or read by the template is serialized or deserialized through RedisElementWriter or RedisElementReader. The serialization context is passed to the template during construction, and the Redis module is Several implementations are available in the org.springframework.data.redis.serializer package. For more information, see serializer.

The following example shows the a Mono used by reactivereredistemplate to return a:

@Configuration
class RedisConfiguration {

  @Bean
  ReactiveRedisTemplate<String, String> reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
    return new ReactiveRedisTemplate<>(factory, RedisSerializationContext.string());
  }
}
public class Example {

  @Autowired
  private ReactiveRedisTemplate<String, String> template;

  public Mono<Long> addLink(String userId, URL url) {
    return template.opsForList().leftPush(userId, url.toExternalForm());
  }
}

11.4. String centered convenience courses

Because it is stored in Redis and is a common java.lang.String key and value, Redis module provides an extended reactivereredistemplate based on string: ReactiveStringRedisTemplate. It is a convenient one-stop solution for intensive String operations. In addition to binding to String keys, the template also uses String based redisserializationcontext, which means that the stored keys and values are human readable (assuming the same encoding is used in Redis and your code). The following example shows the reactivestringredistemplate in use:

@Configuration
class RedisConfiguration {

  @Bean
  ReactiveStringRedisTemplate reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
    return new ReactiveStringRedisTemplate<>(factory);
  }
}
public class Example {

  @Autowired
  private ReactiveStringRedisTemplate redisTemplate;

  public Mono<Long> addLink(String userId, URL url) {
    return redisTemplate.opsForList().leftPush(userId, url.toExternalForm());
  }
}

11.5.Redis messaging / publish subscribe

Spring Data provides Redis with special messaging integration, which is very similar to JMS integration in Spring Framework in terms of function and naming; In fact, users familiar with JMS support in spring should feel at home.

Redis messaging can be roughly divided into two functional areas, namely, message production or publishing and consumption or subscription. Therefore, there is a shortcut pubsub (publish / subscribe). The ReactiveRedisTemplate class is used for message generation. For asynchronous reception, Spring Data provides a dedicated message listener container for consuming message flows. For subscription purposes only, the reactivereredistemplate provides a thin alternative to using a listener container.

package org.springframework.data.redis.connection and org.springframework.data.redis.listener provide the core functions of using Redis messaging.

11.5.1. Send / publish message

To publish a message, like other operations, you can use low-level ReactiveRedisConnection or high-level ReactiveRedisTemplate. Both entities provide a publishing method that accepts the message to be sent and the target channel as parameters. Although the reactivereredisconnection requires raw data, the reactivereredistemplate allows any object to be passed in as a message:

// send message through ReactiveRedisConnection
ByteBuffer msg = ...
ByteBuffer channel = ...
Mono<Long> publish = con.publish(msg, channel);

// send message through ReactiveRedisTemplate
ReactiveRedisTemplate template = ...
Mono<Long> publish = template.convertAndSend("channel", "message");

11.5.2. Receive / subscribe messages

At the receiving end, one or more channels can be subscribed by direct naming or using pattern matching. The latter method is useful because it not only allows you to create multiple subscriptions with one command, but also listens for channels that were not created at the time of the subscription (as long as they match the pattern).

At the bottom, reactivereedisconnection provides subscribe and pSubscribe methods to map Redis commands to subscribe by mode and channel respectively. Note that you can use multiple channels or modes as parameters. To change the subscription, simply query the channel and mode ReactiveSubscription.

The responsive subscription command in Spring Data Redis is non blocking and may end without issuing elements.

As mentioned above, once subscribed, the connection starts waiting for messages. You cannot call commands on an existing subscription other than adding a new subscription or modifying / canceling an existing subscription. The command unsubscribe other than subscribe, pSubscribe, unsubscribe, or is illegal and will cause an exception.

In order to receive messages, you need to get the message flow. Note that a subscription publishes only messages for channels and modes registered in that particular subscription. The message flow itself is a hot sequence that generates elements regardless of requirements. Ensure that enough requirements are registered to avoid running out of message buffers.

Message listener container

Spring Data provides Reactivededismessagelistenercontainer, which completes all heavy conversion and subscription status management on behalf of users.

The reactivereredismessagelistenercontainer acts as a message listener container. It is used to receive messages from the Redis channel and expose a message flow that sends channel messages through application deserialization. Be responsible for registering and receiving messages, resource acquisition and release, exception conversion, etc. This allows you, as an application developer, to write (potentially complex) business logic related to receiving messages (and responding to them) and delegate template Redis infrastructure issues to the framework. The message flow registers the subscription in Redis when the publisher subscribes. If the subscription is cancelled, the registration will be cancelled.

In addition, to minimize application footprint, The reactivereredismessagelistenercontainer allows multiple listeners to share a connection and a thread, even if they do not share subscriptions. Therefore, no matter how many listeners or channels the application tracks, the runtime cost will remain the same throughout its life cycle. In addition, the container allows runtime configuration changes, so listeners can be added or removed while the application is running without restarting. In addition, the container uses the lazy subscription method, and the ReactiveRedisConnection is used only when needed - if all listeners are unsubscribed, cleanup is performed automatically.

The message listener container itself does not require external thread resources. It uses driver threads to publish messages.

ReactiveRedisConnectionFactory factory = ...
ReactiveRedisMessageListenerContainer container = new ReactiveRedisMessageListenerContainer(factory);

Flux<ChannelMessage<String, String>> stream = container.receive(ChannelTopic.of("my-channel"));

To wait and ensure the correct subscription, you can use receiveLater to return Mono < flux < channelmessage > >. The resulting Mono completion has an internal publisher as the result of completing the subscription to a given topic. By intercepting the onNext signal, you can synchronize server-side subscriptions.

ReactiveRedisConnectionFactory factory = ...
ReactiveRedisMessageListenerContainer container = new ReactiveRedisMessageListenerContainer(factory);

Mono<Flux<ChannelMessage<String, String>>> stream = container.receiveLater(ChannelTopic.of("my-channel"));

stream.doOnNext(inner -> // notification hook when Redis subscriptions are synchronized with the server)
    .flatMapMany(Function.identity())
    ....;

Subscribe via template API

As mentioned above, you can directly subscribe to channels / modes using reactivereredistemplate. This approach provides a direct but limited solution because you cannot add subscriptions after the initial subscription. Nevertheless, you can still control the message flow by using the returned Flux, for example. take(Duration). When reading, error or cancellation is completed, all bound resources will be released again.

redisTemplate.listenToChannel("channel1", "channel2").doOnNext(msg -> {
    // message processing ...
}).subscribe();

11.6. Reactive script

You can run Redis scripts using a responsive infrastructure, and the reactivescript executor should preferably use the ReactiveRedisTemplate

public class Example {

  @Autowired
  private ReactiveRedisTemplate<String, String> template;

  public Flux<Long> theAnswerToLife() {

    DefaultRedisScript<Long> script = new DefaultRedisScript<>();
    script.setLocation(new ClassPathResource("META-INF/scripts/42.lua"));
    script.setResultType(Long.class);

    return reactiveTemplate.execute(script);
  }
}

For more details on script commands, see the script section.

12.Redis cluster

Redis server version 3.0 + is required to use redis cluster. For more information, see the clustering tutorial.

12.1. Enable Redis cluster

Cluster support is based on the same building blocks as non cluster communication. RedisClusterConnection is an extension of RedisConnection, which handles communication with Redis clusters and converts errors into Spring DAO exception hierarchy. RedisClusterConnection instance is a RedisConnectionFactory created using. RedisClusterConfiguration must be set using the associated, as shown in the following example:

Example 5. Redis connectionfactory configuration of redis cluster

@Component
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class ClusterConfigurationProperties {

    /*
     * spring.redis.cluster.nodes[0] = 127.0.0.1:7379
     * spring.redis.cluster.nodes[1] = 127.0.0.1:7380
     * ...
     */
    List<String> nodes;

    /**
     * Get initial collection of known cluster nodes in format {@code host:port}.
     *
     * @return
     */
    public List<String> getNodes() {
        return nodes;
    }

    public void setNodes(List<String> nodes) {
        this.nodes = nodes;
    }
}

@Configuration
public class AppConfig {

    /**
     * Type safe representation of application.properties
     */
    @Autowired ClusterConfigurationProperties clusterProperties;

    public @Bean RedisConnectionFactory connectionFactory() {

        return new JedisConnectionFactory(
            new RedisClusterConfiguration(clusterProperties.getNodes()));
    }
}

RedisClusterConfiguration can also define PropertySource and have the following properties:

Configuration properties

spring.redis.cluster.nodes: comma separated host: port pair list.

spring.redis.cluster.max-redirects: number of cluster redirects allowed.

The initial configuration points the driver library to a set of initial cluster nodes. Changes resulting from real-time cluster reconfiguration remain only in the native driver and will not be written back to the configuration.

12.2. Connect using Redis cluster

As mentioned earlier, the behavior of Redis Cluster is different from the primary replica environment monitored by single node Redis and even Sentinel. This is because automatic sharding maps the key to one of 16384 slots, which are distributed on the node. Therefore, commands involving multiple KEYS must assert that all KEYS map to exactly the same slot to avoid cross slot errors. A single cluster node provides only one set of private KEYS. Commands issued against a particular server return only the results of those KEYS provided by that server. As a simple example, consider the KEYS command. When it is sent to the server in the cluster environment, it only returns the key served by the node to which the request is sent, not necessarily all the KEYS in the cluster. Therefore, to obtain all KEYS in a clustered environment, you must read the KEYS from all known master nodes.

Although redirecting a specific key to the corresponding slot service node is handled by the driver library, higher-level functions, such as collecting information across nodes or sending commands to all nodes in the cluster, are handled by RedisClusterConnection. Taking the previous key example as an example, this means that the keys(pattern) method will obtain each master node in the cluster, At the same time, KEYS runs commands on each master node, obtains the results and returns the accumulated keyset. RedisClusterConnection, which only requests the key of a single node, provides overloading for these methods (for example, keys(node, pattern)).

Aredis clusternode can be accessed from RedisClusterConnection.clusterGetNodes get or build from host and port or node Id.

The following example shows a set of commands running in a cluster:

Example 6. Example of running commands across clusters

redis-cli@127.0.0.1:7379 > cluster nodes

6b38bb... 127.0.0.1:7379 master - 0 0 25 connected 0-5460                      
7bb78c... 127.0.0.1:7380 master - 0 1449730618304 2 connected 5461-10922       
164888... 127.0.0.1:7381 master - 0 1449730618304 3 connected 10923-16383      
b8b5ee... 127.0.0.1:7382 slave 6b38bb... 0 1449730618304 25 connected          
RedisClusterConnection connection = connectionFactory.getClusterConnnection();

connection.set("thing1", value);                                               
connection.set("thing2", value);                                               

connection.keys("*");                                                          

connection.keys(NODE_7379, "*");                                               
connection.keys(NODE_7380, "*");                                               
connection.keys(NODE_7381, "*");                                               
connection.keys(NODE_7382, "*");                  

Primary node service slots 0 through 5460 replicate to replica 7382

Master node service slots 5461 to 10922

Master node service slots 10923 to 16383

The replica node holds a replica of the master node at 7379

The request is routed to the node at 7381 service slot 12182

The request is routed to the node at 7379 service slot 5061

Requests are routed to nodes 7379, 7380, 7381 → [thing1, thing2]

The request is routed to node 7379 → [thing2]

The request is routed to node 7380 → []

The request is routed to node 7381 → [thing1]

The request is routed to node 7382 → [thing2]

When all keys are mapped to the same slot, the native driver library will automatically provide cross slot requests, such as MGET. However, if this is not the case, RedisClusterConnection will run multiple parallel commands for the slot service node and return the cumulative results again. This has lower performance than the single slot method, so it should be used with caution. If in doubt, consider securing the key to the same slot {my prefix}. Thing2 by providing prefixes in braces (for example, {my prefix}. Thing1 and), which will map to the same slot number. The following example shows cross slot request processing:

Example 7. Cross slot request processing example

redis-cli@127.0.0.1:7379 > cluster nodes

6b38bb... 127.0.0.1:7379 master - 0 0 25 connected 0-5460                      
7bb...
RedisClusterConnection connection = connectionFactory.getClusterConnnection();

connection.set("thing1", value);           // slot: 12182
connection.set("{thing1}.thing2", value);  // slot: 12182
connection.set("thing2", value);           // slot:  5461

connection.mGet("thing1", "{thing1}.thing2");                                  

connection.mGet("thing1", "thing2");                  

The configuration is the same as in the previous example.

Key mapped to the same slot → 127.0.0.1:7381 MGET thing1 {thing1}.thing2

The key is mapped to different slots and split into a single slot routed to the corresponding node

→ 127.0.0.1:7379 GET thing2

→ 127.0.0.1:7381 GET thing1

The previous example demonstrates the general policy followed by Spring Data Redis. Note that some operations may require a large amount of data to be loaded into memory to calculate the required commands. In addition, not all cross slot requests can be safely migrated to multiple single slot requests, and errors will occur if misused (for example, PFCOUNT).

12.3. With RedisTemplate and ClusterOperations

See the section dealing with objects through RedisTemplate for information about RedisTemplate

When RedisTemplate#keySerializer is set with any JSON, be careful with RedisSerializers, because changing the JSON structure will have a direct impact on Hash slot calculation.

RedisTemplate provides access to cluster specific operations through the ClusterOperations interface, which can be accessed from RedisTemplate.opsForCluster(). This allows you to explicitly run commands on a single node in the cluster while retaining the serialization and deserialization capabilities configured for the template. It also provides administrative commands (such as CLUSTER MEET) or more advanced operations (such as re sharding).

The following example demonstrates how to access RedisClusterConnection and use RedisTemplate:

Embodiment 8. Accessing RedisClusterConnection and RedisTemplate

ClusterOperations clusterOps = redisTemplate.opsForCluster();
clusterOps.shutdown(NODE_7379);                                 

At the 7379 close node, the cross finger has a copy that can be taken over.

Posted by VirusDoctor on Tue, 30 Nov 2021 02:47:52 -0800