• 微服务架构中的Redis


    了解如何将Redis与Spring Cloud和Spring Data一起使用以提供配置服务器,消息代理和数据库。

    Redis可以广泛用于微服务架构中。它可能是少数流行的软件解决方案之一,你的应用程序可以通过许多不同的方式来利用这些解决方案。根据要求,它可以充当主数据库,缓存或消息代理。虽然它也是键/值存储,但我们可以将其用作微服务体系结构中的配置服务器或发现服务器。尽管通常将其定义为内存中的数据结构,但我们也可以在持久模式下运行它。

    通过这篇文章,我将结合我自己所掌握的和近期在优锐课学习到的知识,向你展示一些将Redis与基于Spring Boot和Spring Cloud框架构建的微服务一起使用的示例。这些应用程序将使用Redis发布/订阅,使用Redis作为缓存或主数据库,最后使用Redis作为配置服务器,彼此之间进行异步通信。这是说明所描述体系结构的图片。

     

    Redis作为配置服务器

    如果你已经使用Spring Cloud构建了微服务,则可能对Spring Cloud Config有所了解。它负责为微服务提供分布式配置模式。 不幸的是,Spring Cloud Config不支持将Redis作为属性源的后端存储库。这就是为什么我决定派生一个Spring Cloud Config项目并实现此功能的原因。我希望我的实现将很快包含在Spring Cloud的官方发行版中,我们如何使用它?很简单的。让我们来看看。

    Spring Boot的当前SNAPSHOT版本是2.2.0.BUILD-SNAPSHOT,与用于Spring Cloud Config的版本相同。在构建Spring Cloud Config Server时,我们仅需要包括这两个依赖项,如下所示。

     1 <parent>
     2     <groupId>org.springframework.boot</groupId>
     3     <artifactId>spring-boot-starter-parent</artifactId>
     4     <version>2.2.0.BUILD-SNAPSHOT</version>
     5 </parent>
     6 <artifactId>config-service</artifactId>
     7 <groupId>pl.piomin.services</groupId>
     8 <version>1.0-SNAPSHOT</version>
     9 <dependencies>
    10     <dependency>
    11         <groupId>org.springframework.cloud</groupId>
    12         <artifactId>spring-cloud-config-server</artifactId>
    13         <version>2.2.0.BUILD-SNAPSHOT</version>
    14     </dependency>
    15 </dependencies>

    默认情况下,Spring Cloud Config Server使用一个Git存储库后端。 我们需要激活一个redisprofile来强制它使用Redis作为后端。 如果你的Redis实例侦听的地址不是localhost:6379,则需要使用spring.redis.*属性覆盖自动配置的连接设置。 这是我们的bootstrap.yml文件。

    1 spring:
    2   application:
    3     name: config-service
    4   profiles:
    5     active: redis
    6   redis:
    7     host: 192.168.99.100

    应用程序主类应使用@EnableConfigServer进行注释。

    1 @SpringBootApplication
    2 @EnableConfigServer
    3 public class ConfigApplication {
    4     public static void main(String[] args) {
    5         new SpringApplicationBuilder(ConfigApplication.class).run(args);
    6     }
    7 }

    在运行应用程序之前,我们需要启动Redis实例。这是将其作为Docker容器运行并在端口6379上公开的命令。

    1 $ docker run -d --name redis -p 6379:6379 redis

    每个应用程序的配置都必须在键${spring.application.name}${spring.application.name}-${spring.profiles.active[n]}可用。

    我们必须使用与配置属性名称相对应的键来创建hash。我们的示例应用程序驱动程序管理使用三个配置属性:server.port用于设置HTTP侦听端口,spring.redis.host用于更改用作消息代理和数据库的默认Redis地址,以及sample.topic.name用于设置名称。微服务之间用于异步通信的主题。这是我们为使用RDBTools可视化的驱动程序管理创建的Redis hash的结构。

    该可视化等效于运行Redis CLI命令HGETALL,该命令返回哈希中的所有字段和值。

    1 >> HGETALL driver-management
    2 {
    3   "server.port": "8100",
    4   "sample.topic.name": "trips",
    5   "spring.redis.host": "192.168.99.100"
    6 }

    在Redis中设置键和值并使用有效的redisprofile运行Spring Cloud Config Server之后,我们需要在客户端启用分布式配置功能。为此,我们只需要将spring-cloud-starter-config依赖项包含到每个微服务的thepom.xml中即可。

    1 <dependency>
    2 <groupId>org.springframework.cloud</groupId>
    3 <artifactId>spring-cloud-starter-config</artifactId>
    4 </dependency>

    我们使用Spring Cloud的最新稳定版本。

     1 <dependencyManagement>
     2     <dependencies>
     3         <dependency>
     4             <groupId>org.springframework.cloud</groupId>
     5             <artifactId>spring-cloud-dependencies</artifactId>
     6             <version>Greenwich.SR1</version>
     7             <type>pom</type>
     8             <scope>import</scope>
     9         </dependency>
    10     </dependencies>
    11 </dependencyManagement>

    应用程序的名称是在启动时从属性spring.application.name获取的,因此我们需要提供以下bootstrap.yml文件。

    1 spring:
    2   application:
    3     name: driver-management

    Redis作为消息代理

    现在,我们可以继续研究基于微服务的体系结构中Redis的第二个用例——消息代理。我们将实现一个典型的异步系统,如下图所示。在创建新行程并完成当前行程后,微服务行程管理会将通知发送到Redis Pub / Sub。该通知由预订特定频道的驾驶员管理和乘客管理两者接收。

    我们的申请非常简单。我们只需要添加以下依赖项即可提供REST API并与Redis Pub / Sub集成。

    1 <dependency>
    2     <groupId>org.springframework.boot</groupId>
    3     <artifactId>spring-boot-starter-web</artifactId>
    4 </dependency>
    5 <dependency>
    6     <groupId>org.springframework.boot</groupId>
    7     <artifactId>spring-boot-starter-data-redis</artifactId>
    8 </dependency>

    我们应该使用通道名称和发布者来注册bean。TripPublisher负责将消息发送到目标主题。

     1 @Configuration
     2 public class TripConfiguration {
     3     @Autowired
     4     RedisTemplate<?, ?> redisTemplate;
     5     @Bean
     6     TripPublisher redisPublisher() {
     7         return new TripPublisher(redisTemplate, topic());
     8     }
     9     @Bean
    10     ChannelTopic topic() {
    11         return new ChannelTopic("trips");
    12     }
    13 }

    TripPublisher 使用RedisTemplate将消息发送到主题。 发送之前,它将使用Jackson2JsonRedisSerializer将对象中的所有消息转换为JSON字符串。

     1 public class TripPublisher {
     2     private static final Logger LOGGER = LoggerFactory.getLogger(TripPublisher.class);
     3     RedisTemplate<?, ?> redisTemplate;
     4     ChannelTopic topic;
     5     public TripPublisher(RedisTemplate<?, ?> redisTemplate, ChannelTopic topic) {
     6         this.redisTemplate = redisTemplate;
     7         this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Trip.class));
     8         this.topic = topic;
     9     }
    10     public void publish(Trip trip) throws JsonProcessingException {
    11         LOGGER.info("Sending: {}", trip);
    12         redisTemplate.convertAndSend(topic.getTopic(), trip);
    13     }
    14 }

    我们已经在发布方实现了逻辑。现在,我们可以在订户端进行实施。我们有两个微服务驱动程序管理和乘客管理,它们侦听旅行管理微服务发送的通知。我们需要定义RedisMessageListenerContainer bean并设置消息侦听器实现类。

     1 @Configuration
     2 public class DriverConfiguration {
     3     @Autowired
     4     RedisConnectionFactory redisConnectionFactory;
     5     @Bean
     6     RedisMessageListenerContainer container() {
     7         RedisMessageListenerContainer container = new RedisMessageListenerContainer();
     8         container.addMessageListener(messageListener(), topic());
     9         container.setConnectionFactory(redisConnectionFactory);
    10         return container;
    11     }
    12     @Bean
    13     MessageListenerAdapter messageListener() {
    14         return new MessageListenerAdapter(new DriverSubscriber());
    15     }
    16     @Bean
    17     ChannelTopic topic() {
    18         return new ChannelTopic("trips");
    19     }
    20 }

    负责处理传入通知的类需要实现MessageListenerinterface。 收到消息后,DriverSubscriber会将其从JSON反序列化为对象,并更改驱动程序的状态。

     1 @Service
     2 public class DriverSubscriber implements MessageListener {
     3     private final Logger LOGGER = LoggerFactory.getLogger(DriverSubscriber.class);
     4     @Autowired
     5     DriverRepository repository;
     6     ObjectMapper mapper = new ObjectMapper();
     7     @Override
     8     public void onMessage(Message message, byte[] bytes) {
     9         try {
    10             Trip trip = mapper.readValue(message.getBody(), Trip.class);
    11             LOGGER.info("Message received: {}", trip.toString());
    12             Optional<Driver> optDriver = repository.findById(trip.getDriverId());
    13             if (optDriver.isPresent()) {
    14                 Driver driver = optDriver.get();
    15                 if (trip.getStatus() == TripStatus.DONE)
    16                     driver.setStatus(DriverStatus.WAITING);
    17                 else
    18                     driver.setStatus(DriverStatus.BUSY);
    19                 repository.save(driver);
    20             }
    21         } catch (IOException e) {
    22             LOGGER.error("Error reading message", e);
    23         }
    24     }
    25 }

    Redis作为主数据库

    尽管使用Redis的主要目的是内存中缓存或作为键/值存储,但它也可以充当应用程序的主数据库。在这种情况下,值得在持久模式下运行Redis。

    1 $ docker run -d --name redis -p 6379:6379 redis redis-server --appendonly yes

    使用hash操作和mmap结构将实体存储在Redis中。每个实体都需要具有hash键和ID。

     1 @RedisHash("driver")
     2 public class Driver {
     3     @Id
     4     private Long id;
     5     private String name;
     6     @GeoIndexed
     7     private Point location;
     8     private DriverStatus status;
     9     // setters and getters ...
    10 }

    幸运的是,Spring Data Redis为Redis集成提供了众所周知的存储库模式。要启用它,我们应该使用@EnableRedisRepositories注释配置或主类。当使用Spring仓库模式时,我们不必自己构建对Redis的任何查询。

    1 @Configuration
    2 @EnableRedisRepositories
    3 public class DriverConfiguration {
    4 // logic ...
    5 }

    使用Spring Data存储库,我们不必构建任何Redis查询,只需遵循Spring Data约定的名称方法即可。有关更多详细信息,请参阅我以前的文章Spring Data Redis简介。出于示例目的,我们可以使用Spring Data内部实现的默认方法。这是驱动程序管理中存储库接口的声明。

    1 public interface DriverRepository extends CrudRepository<Driver, Long> {}

    不要忘记通过使用@EnableRedisRepositories注释主应用程序类或配置类来启用Spring Data存储库。

    1 @Configuration
    2 @EnableRedisRepositories
    3 public class DriverConfiguration {
    4 ...
    5 }

    结论

    微服务架构中Redis的使用案例多种多样。我刚刚介绍了如何轻松地将其与Spring Cloud和Spring Data一起使用以提供配置服务器,消息代理和数据库。Redis通常被认为是缓存存储,但是我希望阅读本文后你会对此有所改变。

  • 相关阅读:
    进程的Binder线程池工作过程
    Binder系列—开篇
    shell脚本使用技巧3--调试
    shell脚本使用--sleep
    shell脚本使用技巧2
    linux添加环境变量
    shell脚本学习1(Linux脚本攻略)
    c++语言的设计和演化---在线函数
    vim常用快捷键
    git常用命令
  • 原文地址:https://www.cnblogs.com/youruike-/p/12103501.html
Copyright © 2020-2023  润新知