本文通过使用Spring Boot,Spring Cloud和Docker构建的概念验证应用程序的示例,为了解常见的微服务架构模式提供了一个起点。
作为这个系统的基础,我选择了一个旧项目,其后端曾经是一个整体。该应用程序提供了一种处理个人财务,组织收入和支出,管理储蓄,分析统计数据和创建简单预测的方法。
功能服务
整体应用程序被分解为三个核心微服务。所有这些都是可独立部署的应用程序,围绕某些业务功能组织。
img帐户服务
包含一般用户输入逻辑和验证:收入/费用项目,节省和帐户设置。
METHOD | PATH | DESCRIPTION | USER AUTHENTICATED | AVAILABLE FROM UI |
---|---|---|---|---|
GET | /accounts/{account} | Get specified account data | ||
GET | /accounts/current | Get current account data | × | × |
GET | /accounts/demo | Get demo account data (pre-filled incomes/expenses items, etc) | × | |
PUT | /accounts/current | Save current account data | × | × |
POST | /accounts/ | Register new account |
统计服务
对主要统计参数执行计算并捕获每个帐户的时间序列。数据点包含标准化为基本货币和时间段的值。此数据可用于跟踪帐户生命周期中的现金流动态。
METHOD | PATH | DESCRIPTION | USER AUTHENTICATED | AVAILABLE FROM UI |
---|---|---|---|---|
GET | /statistics/{account} | Get specified account statistics | ||
GET | /statistics/current | Get current account statistics | × | × |
GET | /statistics/demo | Get demo account statistics | × | |
PUT | /statistics/{account} | Create or update time series datapoint for specified account |
通知服务
存储用户的联系信息和通知设置(如提醒和备份频率)。计划工作人员从其他服务收集所需信息,并向订阅客户发送电子邮件。
METHOD | PATH | DESCRIPTION | USER AUTHENTICATED | AVAILABLE FROM UI |
---|---|---|---|---|
GET | /notifications/settings/current | Get current account notification settings | × | × |
PUT | /notifications/settings/current | Save current account notification settings | × | × |
注意
- 每个微服务都有自己的数据库,因此无法绕过API并直接访问持久性数据。
- 对于这个项目,我使用MongoDB作为每个服务的主数据库。拥有多语言持久性体系结构(以便选择最适合服务要求的数据库类型)也是有意义的。
- 服务到服务通信非常简单:微服务仅使用同步REST API进行通信。现实世界系统中的常见做法是使用交互方式的组合。例如,执行同步GET请求以检索数据并通过Message broker使用异步方法进行创建/更新操作,以便解耦服务和缓冲消息。这带给我们 。
基建服务
img配置服务
客户端使用
只需构建具有spring-cloud-starter-config
依赖性的Spring Boot应用程序 ,自动配置将完成剩下的工作。
现在,你的应用程序中不需要任何嵌入属性。只需提供 bootstrap.yml
应用程序名称和配置服务URL:
spring:
application:
name: notification-service
cloud:
config:
uri: http://config:8888
fail-fast: true
使用Spring Cloud Config,可以动态更改应用程序配置
注意
- 动态刷新有一些限制。
@RefreshScope
不适用于@Configuration
类,不能影响@Scheduled
方法。 -
fail-fast
property表示如果Spring Boot应用程序无法连接到Config Service,则会立即失败启动。当你启动时,这非常有用 。 - 下面有重要的安全说明。
验证服务
从客户端来看,一切都与传统的基于会话的授权完全相同。你可以从Principal
请求中检索 对象,使用基于表达式的访问控制和@PreAuthorize
注释检查用户角色和其他内容 。
PiggyMetrics中的每个客户端(帐户服务,统计服务,通知服务和浏览器)都有一个范围: server
用于后端服务, ui
- 用于浏览器。因此,我们还可以保护控制器免受外部访问,例如:
@PreAuthorize("#oauth2.hasScope('server')")
@RequestMapping(value = "accounts/{name}", method = RequestMethod.GET)
public List<DataPoint> getStatisticsByAccountName(@PathVariable String name) {
return statisticsService.findByAccountName(name);
}
API网关
zuul:
routes:
notification-service:
path: /notifications/**
serviceId: notification-service
stripPrefix: false
Service Discovery
另一种众所周知的架构模式是Service Discovery。它允许自动检测服务实例的网络位置,这些服务实例可能由于自动扩展,故障和升级而动态分配地址。
服务发现的关键部分是注册表。我在这个项目中使用了Netflix Eureka。当客户端负责确定可用服务实例的位置(使用注册服务器)并在它们之间加载平衡请求时,Eureka是客户端发现模式的一个很好的例子。
使用Spring Boot,你可以轻松地使用spring-cloud-starter-eureka-server
依赖项, @EnableEurekaServer
注释和简单配置属性构建Eureka Registry 。
通过@EnableDiscoveryClient
注释和 bootstrap.yml
应用程序名称启用客户端支持 :
spring:
application:
name: notification-service
现在,在应用程序启动时,它将向Eureka Server注册并提供元数据,例如主机和端口,运行状况指示器URL,主页等.Eureka从属于服务的每个实例接收消息。如果故障超过可配置的时间表,则实例将从注册表中删除。
img负载均衡器,断路器和Http客户端
Netflix OSS提供了另一套很棒的工具。
Ribbon
Ribbon是一个客户端负载均衡器,可以让你对HTTP和TCP客户端的行为进行大量控制。与传统的负载均衡器相比,每次线上调用都不需要额外的跳过 - 你可以直接联系所需的服务。
Hystrix
除了断路器控制之外,使用Hystrix还可以添加一个回退方法,以便在主命令失败时获取默认值。
Feign
Feign是一个声明式HTTP客户端,可与Ribbon和Hystrix无缝集成。实际上,通过一个 spring-cloud-starter-feign
依赖关系和 @EnableFeignClients
注释,你可以拥有一整套负载均衡器,断路器和HTTP客户端,并具有合理的即用型默认配置。
以下是帐户服务的示例:
@FeignClient(name = "statistics-service")
public interface StatisticsServiceClient {
@RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
void updateStatistics(@PathVariable("accountName") String accountName, Account account);
}
- 你需要的只是一个界面
- 你可以在Spring MVC控制器和Feign方法之间共享
@RequestMapping
- 以上示例指定了所需的服务ID -
statistics-service
感谢Eureka的自动发现(但显然你可以访问具有特定URL的任何资源)
监控仪表板
让我们看看我们在负载下的系统行为:帐户服务调用统计服务,它响应模仿延迟。响应超时阈值设置为1秒。
img0 ms delay | 500 ms delay | 800 ms delay | 1100 ms delay |
表现良好的系统。吞吐量约为22个请求/秒。统计服务中的活动线程数量很少。中位服务时间约为50毫秒。 | 活动线程的数量正在增长。我们可以看到紫色线程池拒绝的数量,因此大约有30-40%的错误,但电路仍然关闭。 | 半开状态:失败命令的比例超过50%,断路器启动。睡眠窗口的时间量后,下一个请求通过。 | 100%的请求失败。电路现在永久开放。睡眠时间后重试不会再次关闭电路,因为单个请求太慢。 |
日志分析
安全
基建自动化
与部署整体应用程序相比,部署微服务具有相互依赖性,这是一个复杂得多的过程。拥有一个完全自动化的基础设施非常重要。我们可以通过持续交付方法获得以下好处:
- 随时发布软件的能力。
- 任何构建都可能最终成为一个版本。
- 构建工件一次,根据需要进行部署。
这是一个简单的Continuous Delivery工作流程,在此项目中实现:
img如何运行所有的东西?
这真的很容易,我建议你试试。请记住,你要启动8个Spring Boot应用程序,4个MongoDB实例和RabbitMq。确保4 Gb
的计算机上有 RAM。你始终可以通过网关,注册表,配置,身份验证服务和帐户服务运行重要服务。
在你开始之前
- 安装Docker和Docker Compose。
- 出口环境变量:
CONFIG_SERVICE_PASSWORD
,NOTIFICATION_SERVICE_PASSWORD
,STATISTICS_SERVICE_PASSWORD
,ACCOUNT_SERVICE_PASSWORD
,MONGODB_PASSWORD
生产模式
在此模式下,所有最新图像都将从Docker Hub中提取。只需复制 docker-compose.yml
并点击即可 docker-compose up -d
。
发展模式
如果你想自己构建映像(例如,在代码中进行一些更改),则必须使用Maven克隆所有存储库并构建工件。然后,运行docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
docker-compose.dev.yml
继承 docker-compose.yml
在本地构建映像的额外可能性,并公开所有容器端口以便于开发。
重要的终点
- localhost:80 - 网关
- localhost:8761 - Eureka Dashboard
- localhost:9000 - Hystrix仪表板
- localhost:8989 - Hystrix仪表板源
- localhost:15672 - RabbitMq管理
注意
此外,Service Discovery机制在所有应用程序启动后需要一些时间。在实例,Eureka服务器和客户端在其本地缓存中都具有相同的元数据之前,客户端无法发现任何服务,因此可能需要3次侦听。默认侦听时间为30秒。
原文标题《Microservice Architectures With Spring Cloud and Docker》
作者:Alexander Lukyanchikov
译者:我就静静地看
搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!