淺談Redis在微服務架構中的幾種應用場景

本文介紹在SpringCloud中使用Redis作爲Pub/Sub異步通信、緩存或主數據庫和配置服務器的三種場景應用。小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

本文介紹在SpringCloud中使用Redis作爲Pub/Sub異步通信、緩存或主數據庫和配置服務器的三種場景應用。

Redis可以廣泛用於微服務架構。它可能是您應用程序以多種不同方式利用的少數流行軟件解決方案之一。根據要求,它可以充當主數據庫,緩存或消息代理。雖然它也是一個鍵/值存儲,但我們可以將它用作微服務體系結構中的配置服務器或發現服務器。雖然它通常被定義爲內存中的數據結構,但我們也可以在持久模式下運行它。

這裏我將向您展示一些使用Redis與Spring Boot和Spring Cloud框架之上構建的微服務的示例。這些應用程序將使用Redis Pub / Sub異步通信,使用R​​edis作爲緩存或主數據庫,最後使用Redis作爲配置服務器。

Redis作爲配置服務器

如果您已經使用Spring Cloud構建了微服務,那麼您可能對Spring Cloud Config有一些經驗。它負責爲微服務提供分佈式配置模式。

不幸的是,Spring Cloud Config不支持Redis作爲屬性源的後端存儲庫。這就是我決定分叉Spring Cloud Config項目並實現此功能的原因。

我希望我的實現很快將被包含在官方的Spring Cloud版本中,但是,現在,您可以使用我的fork repo來運行它。我們怎麼用呢?非常簡單。讓我們來看看。

Spring Boot的當前SNAPSHOT版本2.2.0.BUILD-SNAPSHOT與我們用於Spring Cloud Config的版本相同。在構建Spring Cloud Config Server時,我們只需要包含這兩個依賴項,如下所示。

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.2.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>config-service</artifactId>
<groupId>pl.piomin.services</groupId>
<version>1.0-SNAPSHOT</version>
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    <version>2.2.0.BUILD-SNAPSHOT</version>
  </dependency>
</dependencies>

默認情況下,Spring Cloud Config Server使用Git存儲庫後端。我們需要激活 redis配置文件以強制它使用Redis作爲後端。如果您的Redis實例偵聽的地址不是localhost:6379您需要使用spring.redis.*屬性覆蓋自動配置的連接設置 。這是我們的bootstrap.yml文件。

spring:
 application:
  name: config-service
 profiles:
  active: redis
 redis:
  host: 192.168.99.100

應用程序主類應註釋@EnableConfigServer:

@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
  public static void main(String[] args) {
    new SpringApplicationBuilder(ConfigApplication.class).run(args);
  }
}

在運行應用程序之前,我們需要啓動Redis實例。這是將其作爲Docker容器運行並在端口6379上公開的命令。

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

每個應用程序的配置必須在密鑰{spring.application.name}或{spring.application.name}-${spring.profiles.active[n]}。我們必須使用與配置屬性名稱對應的鍵創建哈希。

我們的示例應用程序driver-management使用三個配置屬性:server.port用於設置HTTP偵聽端口,spring.redis.host用於更改用作消息代理和數據庫的默認Redis地址,以及sample.topic.name用於設置用於我們的微服務之間的異步通信的主題的名稱。這是我們爲driver-management使用RDBTools可視化而創建的Redis哈希的結構。

在Redis CLI 中運行HGETALL ,返回:

>> HGETALL driver-management
{
  "server.port": "8100",
   "sample.topic.name": "trips",
   "spring.redis.host": "192.168.99.100"
}

在Redis中設置鍵值並使用redis配置文件運行Spring Cloud Config Server之後,我們需要在客戶端啓用分佈式配置功能。要做到這一點,我們只需要包含對每個微服務的spring-cloud-starter-config依賴pom.xml。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>

使用最新穩定的Spring Cloud:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Greenwich.SR1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

應用程序的名稱是spring.application.name在啓動時從屬性中獲取的,因此我們需要提供以下bootstrap.yml文件。

spring:
 application:
  name: driver-management

Redis作爲消息代理

現在我們可以在基於微服務的體系結構中繼續使用Redis的第二個用例 - 消息代理。我們將實現一個典型的異步系統。

微服務trip-management在創建新行程後以及完成當前行程後向Redis Pub / Sub發送通知。通知由訂閱特定頻道的driver-management和接收 。

我們的應用非常簡單。我們只需要添加以下依賴項,以便提供REST API並與Redis Pub / Sub集成。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

我們應該使用頻道channel名稱和發佈者註冊bean。TripPublisher負責向目標主題發送消息。

@Configuration
public class TripConfiguration {
  @Autowired
    RedisTemplate<?, ?> redisTemplate;
  @Bean
    TripPublisher redisPublisher() {
    return new TripPublisher(redisTemplate, topic());
  }
  @Bean
    ChannelTopic topic() {
    return new ChannelTopic("trips");
  }
}

TripPublisher使用RedisTemplate將消息發送到的話題。在發送之前,它會使用Jackson2JsonRedisSerializer對來自對象的每條消息轉換爲JSON字符串。

public class TripPublisher {
  private static final Logger LOGGER = LoggerFactory.getLogger(TripPublisher.class);
  RedisTemplate<?, ?> redisTemplate;
  ChannelTopic topic;
  public TripPublisher(RedisTemplate<?, ?> redisTemplate, ChannelTopic topic) {
    this.redisTemplate = redisTemplate;
    this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Trip.class));
    this.topic = topic;
  }
  public void publish(Trip trip) throws JsonProcessingException {
    LOGGER.info("Sending: {}", trip);
    redisTemplate.convertAndSend(topic.getTopic(), trip);
  }
}

我們已經在發佈者方面實現了邏輯。現在,我們可以繼續在消費接受方面的代碼事先。

我們有兩個微服務driver-management,passenger-management,它們監聽trip-management微服務發送的通知 。我們需要定義RedisMessageListenerContainerbean並設置消息監聽器實現類。

@Configuration
public class DriverConfiguration {
  @Autowired
    RedisConnectionFactory redisConnectionFactory;
  @Bean
    RedisMessageListenerContainer container() {
    RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    container.addMessageListener(messageListener(), topic());
    container.setConnectionFactory(redisConnectionFactory);
    return container;
  }
  @Bean
    MessageListenerAdapter messageListener() {
    return new MessageListenerAdapter(new DriverSubscriber());
  }
  @Bean
    ChannelTopic topic() {
    return new ChannelTopic("trips");
  }
}

負責處理傳入通知的類需要實現該 MessageListener接口。收到消息後, DriverSubscriber將其從JSON反序列化到對象並更改驅動程序的狀態。

@Service
public class DriverSubscriber implements MessageListener {
  private final Logger LOGGER = LoggerFactory.getLogger(DriverSubscriber.class);
  @Autowired
    DriverRepository repository;
  ObjectMapper mapper = new ObjectMapper();
  @Override
    public void onMessage(Message message, byte[] bytes) {
    try {
      Trip trip = mapper.readValue(message.getBody(), Trip.class);
      LOGGER.info("Message received: {}", trip.toString());
      Optional<Driver> optDriver = repository.findById(trip.getDriverId());
      if (optDriver.isPresent()) {
        Driver driver = optDriver.get();
        if (trip.getStatus() == TripStatus.DONE)
                  driver.setStatus(DriverStatus.WAITING); else
                  driver.setStatus(DriverStatus.BUSY);
        repository.save(driver);
      }
    }
    catch (IOException e) {
      LOGGER.error("Error reading message", e);
    }
  }
}

Redis作爲主數據庫

雖然使用Redis的主要目的是內存中緩存或作爲鍵/值存儲,但它也可以充當應用程序的主數據庫。在這種情況下,以持久模式運行Redis是值得的。

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

實體使用哈希散列操作和mmap結構存儲在Redis中。每個實體都需要一個哈希鍵和id。

@RedisHash("driver")
public class Driver {
  @Id
    private long id;
  private String name;
  @GeoIndexed
    private Point location;
  private DriverStatus status;
  // setters and getters ...
}

幸運的是,Spring Data Redis爲Redis集成提供了一個衆所周知的存儲庫模式。要啓用它,我們應該使用@EnableRedisRepositories註釋配置類或主類。使用Spring存儲庫模式時,我們不必自己構建對Redis的任何查詢。

@Configuration
@EnableRedisRepositories
public class DriverConfiguration {
  // logic ...
}

使用Spring Data存儲庫,我們不必構建任何Redis查詢,只需遵循Spring Data的約定下的名稱方法。爲了我們的示例目的,我們可以使用Spring Data中實現的默認方法。這是存儲庫接口的聲明driver-management。

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

不要忘記通過使用@EnableRedisRepositories註釋主應用程序類或配置類來啓用Spring Data存儲庫。

@Configuration
@EnableRedisRepositories
public class DriverConfiguration {
  ...
}

結論

正如我在前言中提到的,Redis在微服務架構中有各種用例。我剛剛介紹瞭如何與Spring Cloud和Spring Data一起使用它來提供配置服務器,消息代理和數據庫。Redis通常被認爲是緩存存儲,但我希望在閱讀本文之後,您將改變主意。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持神馬文庫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章