天天看點

多線程中redistemplate不執行_一文教你了解微服務架構中的Redis

了解如何将Redis與Spring Cloud和Spring Data一起使用以提供配置伺服器,消息代理和資料庫。

多線程中redistemplate不執行_一文教你了解微服務架構中的Redis
這裡給大家分享一下我的專欄《Java 進階集中營》,每天都會給大家分享一個最新的java技術内容,有優秀的技術訊息,也歡迎分享在我的專欄裡。

JAVA 進階集中營​zhuanlan.zhihu.com

多線程中redistemplate不執行_一文教你了解微服務架構中的Redis

Redis可以廣泛用于微服務架構中。它可能是少數流行的軟體解決方案之一,你的應用程式可以通過許多不同的方式來利用這些解決方案。根據要求,它可以充當主資料庫,緩存或消息代理。雖然它也是鍵/值存儲,但我們可以将其用作微服務體系結構中的配置伺服器或發現伺服器。盡管通常将其定義為記憶體中的資料結構,但我們也可以在持久模式下運作它。

通過這篇文章,我将結合我自己所掌握的和近期在優銳課學習到的知識,向你展示一些将Redis與基于Spring Boot和Spring Cloud架構建構的微服務一起使用的示例。這些應用程式将使用Redis釋出/訂閱,使用Redis作為緩存或主資料庫,最後使用Redis作為配置伺服器,彼此之間進行異步通信。這是說明所描述體系結構的圖檔。

多線程中redistemplate不執行_一文教你了解微服務架構中的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的結構。

多線程中redistemplate不執行_一文教你了解微服務架構中的Redis

該可視化等效于運作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。該通知由預訂特定頻道的駕駛員管理和乘客管理兩者接收。

多線程中redistemplate不執行_一文教你了解微服務架構中的Redis

我們的申請非常簡單。我們隻需要添加以下依賴項即可提供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通常被認為是緩存存儲,但是我希望閱讀本文後你會對此有所改變。

最後

,分享一份進階寶典《Java核心知識點整理.pdf》,覆寫了JVM、鎖、高并發、反射、Spring原理、微服務、Zookeeper、資料庫、資料結構等等,擷取請

點選下方文檔

即可

書籍、Java進階路線、面試題,PDF文檔資料。​shimo.im

多線程中redistemplate不執行_一文教你了解微服務架構中的Redis