了解如何将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时,我们仅需要包括这两个依赖项,如下所示。

 <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存储库后端。 我们需要激活一个redisprofile来强制它使用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]}可用。

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

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

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

在Redis中设置键和值并使用有效的redisprofile运行Spring Cloud Config Server之后,我们需要在客户端启用分布式配置功能。为此,我们只需要将spring-cloud-starter-config依赖项包含到每个微服务的thepom.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的第二个用例——消息代理。我们将实现一个典型的异步系统,如下图所示。在创建新行程并完成当前行程后,微服务行程管理会将通知发送到Redis Pub / Sub。该通知由预订特定频道的驾驶员管理和乘客管理两者接收。

我们的申请非常简单。我们只需要添加以下依赖项即可提供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>

我们应该使用通道名称和发布者来注册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);
}
}

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

 @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");
}
}

负责处理传入通知的类需要实现MessageListenerinterface。 收到消息后,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

使用hash操作和mmap结构将实体存储在Redis中。每个实体都需要具有hash键和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 Redis简介。出于示例目的,我们可以使用Spring Data内部实现的默认方法。这是驱动程序管理中存储库接口的声明。

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

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

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

结论

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

微服务架构中的Redis的更多相关文章

  1. 微服务架构中API网关的角色

    [上海尚学堂的话]:本文主要讲述了Mashape的首席技术执行官Palladino对API网关的详细介绍,以及API网关在微服务中所起的作用,同时介绍了Mashape的一款开源API网关Kong. A ...

  2. Chris Richardson微服务翻译:微服务架构中的服务发现

    Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现(本文) 微服务之事件驱动的数据管理 微服 ...

  3. 微服务架构中APIGateway原理

    背景 我们知道在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些小系统通常以提供 Rest ...

  4. 认证鉴权与API权限控制在微服务架构中的设计与实现(四)

    引言: 本文系<认证鉴权与API权限控制在微服务架构中的设计与实现>系列的完结篇,前面三篇已经将认证鉴权与API权限控制的流程和主要细节讲解完.本文比较长,对这个系列进行收尾,主要内容包括 ...

  5. 【CHRIS RICHARDSON 微服务系列】微服务架构中的进程间通信-3

    编者的话 |本文来自 Nginx 官方博客,是微服务系列文章的第三篇,在第一篇文章中介绍了微服务架构模式,与单体模式进行了比较,并且讨论了使用微服务架构的优缺点.第二篇描述了采用微服务架构的应用客户端 ...

  6. Java生鲜电商平台-SpringCloud微服务架构中分布式事务解决方案

    Java生鲜电商平台-SpringCloud微服务架构中分布式事务解决方案 说明:Java生鲜电商平台中由于采用了微服务架构进行业务的处理,买家,卖家,配送,销售,供应商等进行服务化,但是不可避免存在 ...

  7. Java生鲜电商平台-SpringCloud微服务架构中核心要点和实现原理

    Java生鲜电商平台-SpringCloud微服务架构中核心要点和实现原理 说明:Java生鲜电商平台中,我们将进一步理解微服务架构的核心要点和实现原理,为读者的实践提供微服务的设计模式,以期让微服务 ...

  8. Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析

    Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们 ...

  9. 在微服务架构中service mesh是什么?

    在微服务架构中service mesh是什么 什么是 service mesh ? 微服务架构将软件功能隔离为多个独立的服务,这些服务可独立部署,高度可维护和可测试,并围绕特定业务功能进行组织. 这些 ...

随机推荐

  1. Git 添加远程github仓库的时候提示错误:fatal: remote origin already exists.

    1.先删除远程 Git 仓库 $ git remote rm origin 2.再添加远程 Git 仓库 $ git remote add origin git@github.com:wsydxian ...

  2. Java之字符串输入next()与nextLine()

            next():一定要读取到有效字符后才可以结束输入,对输入有效字符之前遇到的空格键.Tab键或Enter键等结束符,next()方法会自动将其去掉: 只有在输入有效字符之后,next( ...

  3. 概念理解_L2范数(欧几里得范数)

    L1范数 L1范数是指向量中各个元素绝对值之和 L2范数 L2范数.欧几里得范数一些概念. 首先,明确一点,常用到的几个概念,含义相同. 欧几里得范数(Euclidean norm) ==欧式长度 = ...

  4. 矩阵快速幂 F[n]=F[n-2]*2+F[n-1]+i^4 hdu5950

    #include<cstdio> #include<algorithm> #include<math.h> #include<string.h> usi ...

  5. LeetCode第144场周赛总结

    5117.IP地址无效化 首先计算出输入IP地址的长度,然后遍历每一个字符. 如果当前字符为'.',就在它的前后两侧分别加上'['和']'字符. 值得一提的是,C++的String类型提供了以上操作的 ...

  6. C. Grid game 思维+问题转化

    C. Grid game 思维+问题转化 题意 每当有一行或者一列方格的时候,都可以消气这一行或者这一列,一共有两种形状的方块,一种是横的两个,一种是竖着的两个,按时间顺序放在4*4的格子里面,问怎么 ...

  7. 知识图谱学习与实践(6)——从结构化数据进行知识抽取(D2RQ介绍)

    1 概述 D2RQ,含义是把关系型数据库当作虚拟的RDF图数据库进行访问.D2RQ平台是一个将关系型数据库当作虚拟的.只读的RDF图数据库进行访问的系统.提供了基于RDF访问关系数据库的内容,而无需复 ...

  8. ErgExp-lookbehind assert(后行断言)

    //先行断言:先遇到一个条件,判断后面的条件是否满足 let test = 'hello world' console.log(test.match(/hello(?=\sworld)/)) //后行 ...

  9. 安装VMware Tools和设置屏幕

    在虚拟机窗口的虚拟机-安装VMware Tools,点击安装,直到安装完成,出现以下界面 在主文件夹中新建VM文件夹,将VMware Tools中的VMwareTools-10.0.10-430167 ...

  10. 存储过程(Stored Procedure)

    存储过程中 IN,OUT,INOUT类型参数的区别 IN:输入参数:表示该参数的值必须在调用存储过程时指定赋值,在存储过程中修改该参数的值不能被返回,为默认值 OUT:在存储过程内部,该值的默认值为N ...