zoukankan      html  css  js  c++  java
  • 微服务架构中的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通常被认为是缓存存储,但是我希望阅读本文后你会对此有所改变。

  • 相关阅读:
    C#
    C#
    ssh学习笔记
    (已解决)Could not open '/var/lib/nova/mnt/*/volume-*': Permission denied
    RPCVersionCapError: Requested message version, 4.17 is incompatible. It needs to be equal in major version and less than or equal in minor version as the specified version cap 4.11.
    如何在linux下安装idea
    The system has no LUN copy license
    调整mysql数据库最大连接数
    mysql数据库编码问题
    cinder支持nfs快照
  • 原文地址:https://www.cnblogs.com/youruike-/p/12103501.html
Copyright © 2011-2022 走看看