欢迎你们前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~html
本文经过使用Spring Boot,Spring Cloud和Docker构建的概念验证应用程序的示例,为了解常见的微服务架构模式提供了一个起点。git
该代码在Github上可用,而且能够在Docker Hub上得到图像。只需一个命令便可启动整个系统。github
做为这个系统的基础,我选择了一个旧项目,其后端曾经是一个总体。该应用程序提供了一种处理我的财务,组织收入和支出,管理储蓄,分析统计数据和建立简单预测的方法。web
总体应用程序被分解为三个核心微服务。全部这些都是可独立部署的应用程序,围绕某些业务功能组织。spring
包含通常用户输入逻辑和验证:收入/费用项目,节省和账户设置。docker
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 |
存储用户的联系信息和通知设置(如提醒和备份频率)。计划工做人员从其余服务收集所需信息,并向订阅客户发送电子邮件。bootstrap
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 | × | × |
分布式系统中有许多常见模式,能够帮助咱们使所描述的核心服务工做。Spring cloud 提供了强大的工具,能够加强Spring Boot应用程序的行为以实现这些模式。我简要介绍一下:后端
Spring Cloud Config 是分布式系统的水平可扩展集中配置服务。它使用可插入的存储库层,目前支持本地存储,Git和Subversion。
在这个项目中,我使用 native profile
,它只是从本地类路径加载配置文件。你能够在Config服务资源中查看 share 目录 。如今,当Notification-service请求它的配置时,使用shared/notification-service.yml
和 配置服务响应 shared/application.yml
(在全部客户端应用程序之间共享)。
只需构建具备spring-cloud-starter-config
依赖性的Spring Boot应用程序 ,自动配置将完成剩下的工做。
如今,你的应用程序中不须要任何嵌入属性。只需提供 bootstrap.yml
应用程序名称和配置服务URL:
spring:
application:
name: notification-service
cloud:
config:
uri: http://config:8888
fail-fast: true
复制代码
例如, EmailService bean 使用注释 @RefreshScope
。这意味着你能够更改电子邮件文本和主题行,而无需重建和从新启动Notification Service应用程序。
首先,在Config服务器中更改所需的属性。而后,对Notification服务执行刷新请求: curl -H "Authorization: Bearer #token#" -XPOST http://127.0.0.1:8000/notifications/refresh
你还可使用 webhooks自动执行此过程。
@RefreshScope
不适用于 @Configuration
类,不能影响 @Scheduled
方法。fail-fast
property表示若是Spring Boot应用程序没法链接到Config Service,则会当即失败启动。当你同时启动全部应用程序时,这很是有用 。受权职责彻底提取到单独的服务器,该服务器 为后端资源服务授予 OAuth2令牌。Auth Server用于用户受权以及周边内部的安全机器到机器通讯。
在这个项目中,我使用 Password credentials
受权类型进行用户受权(由于它仅由本机应用程序UI使用),而且 Client Credentials
用做微服务受权的受权类型。
Spring Cloud Security提供方便的注释和自动配置,使服务器和客户端都能轻松实现。你能够在文档中了解有关它的更多信息, 并检查Auth Server代码中的配置详细信息 。
从客户端来看,一切都与传统的基于会话的受权彻底相同。你能够从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暴露给客户端。在现实世界的系统中,这个数字能够很是快速地增加,而且整个系统的复杂性也会增长。实际上,渲染一个复杂的网页可能涉及数百种服务。
理论上,客户端能够直接向每一个微服务发出请求。但显然这个选项存在挑战和局限,例如必须知道全部端点地址,分别对每一个信息和平执行http请求,在客户端合并结果。另外一个问题是非网络友好协议,可能在后端使用。
一般,更好的方法是使用API网关。它是进入系统的单一入口点,用于经过将请求路由到适当的后端服务或经过调用多个后端服务并聚合结果来处理请求 。此外,它还可用于身份验证,压力测试,服务迁移,静态响应处理,主动流量管理。
Netflix开源了 这样的优质服务,如今有了Spring Cloud,咱们能够经过一个@EnableZuulProxy
注释启用它 。在这个项目中,我使用Zuul存储静态内容(UI应用程序)并将请求路由到适当的微服务。如下是Notification服务的简单基于前缀的路由配置:
zuul:
复制代码
routes:
复制代码
notification-service:
复制代码
path: /notifications/**
复制代码
serviceId: notification-service
复制代码
stripPrefix: false
复制代码
这意味着全部以请求开头的请求 /notifications
都将路由到Notification服务。能够看到,没有硬编码的地址。Zuul使用 服务发现 机制来定位Notification服务实例以及 Circuit Breaker和Load Balancer。
另外一种众所周知的架构模式是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从属于服务的每一个实例接收消息。若是故障超过可配置的时间表,则实例将从注册表中删除。
此外,Eureka提供了一个简单的界面,你能够在其中跟踪正在运行的服务和可用实例的数量: http://localhost:8761
Netflix OSS提供了另外一套很棒的工具。
Ribbon是一个客户端负载均衡器,可让你对HTTP和TCP客户端的行为进行大量控制。与传统的负载均衡器相比,每次线上调用都不须要额外的跳过 - 你能够直接联系所需的服务。
开箱即用,它自己与Spring Cloud和Service Discovery集成。 Eureka Client 提供可用服务器的动态列表,所以Ribbon能够在它们之间取得平衡。
Hystrix是Circuit Breaker模式的实现 ,它能够控制经过网络访问的依赖关系的延迟和故障。主要思想是在具备大量微服务的分布式环境中中止级联故障。这有助于快速失败并尽快恢复 - 自我修复的容错系统的重要方面。
除了断路器控制以外,使用Hystrix还能够添加一个回退方法,以便在主命令失败时获取默认值。
此外,Hystrix会为每一个命令生成执行结果和延迟的指标,咱们可使用它来 监控系统行为。
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);
}
复制代码
@RequestMapping
statistics-service
感谢Eureka的自动发现(但显然你能够访问具备特定URL的任何资源)在此项目配置中,每一个带有Hystrix的微服务都经过Spring Cloud Bus(使用AMQP代理)将指标推送到Turbine。Monitoring项目只是一个带有Turbine 和 Hystrix Dashboard的小型Spring启动应用程序 。
让咱们看看咱们在负载下的系统行为:账户服务调用统计服务,它响应模仿延迟。响应超时阈值设置为1秒。
0 ms delay | 500 ms delay | 800 ms delay | 1100 ms delay |
表现良好的系统。吞吐量约为22个请求/秒。统计服务中的活动线程数量不多。中位服务时间约为50毫秒。 | 活动线程的数量正在增加。咱们能够看到紫色线程池拒绝的数量,所以大约有30-40%的错误,但电路仍然关闭。 | 半开状态:失败命令的比例超过50%,断路器启动。睡眠窗口的时间量后,下一个请求经过。 | 100%的请求失败。电路如今永久开放。睡眠时间后重试不会再次关闭电路,由于单个请求太慢。 |
在尝试识别分布式环境中的问题时,集中日志记录很是有用。Elasticsearch,Logstash和Kibana堆栈使你能够轻松搜索和分析日志,利用率和网络活动数据。个人其余项目中描述随时可用的Docker配置 。
高级安全配置超出了此概念验证项目的范围。要更真实地模拟真实系统,请考虑使用https和JCE密钥库来加密微服务密码和配置服务器属性内容( 有关详细信息,请参阅 文档)。
与部署总体应用程序相比,部署微服务具备相互依赖性,这是一个复杂得多的过程。拥有一个彻底自动化的基础设施很是重要。咱们能够经过持续交付方法得到如下好处:
这是一个简单的Continuous Delivery工做流程,在此项目中实现:
在此 配置中,Travis CI为每一个成功的Git推送构建标记图像。所以latest
,Docker Hub上的每一个微服务始终都有一个 映像,旧的映像使用Git commit hash进行标记。若是须要,能够轻松部署其中任何一个并快速回滚。
这真的很容易,我建议你试试。请记住,你要启动8个Spring Boot应用程序,4个MongoDB实例和RabbitMq。确保4 Gb
的计算机上有 RAM。你始终能够经过网关,注册表,配置,身份验证服务和账户服务运行重要服务。
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
在本地构建映像的额外可能性,并公开全部容器端口以便于开发。
全部Spring Boot应用程序都须要运行 Config Server 才能启动。可是咱们能够同时启动全部容器,由于 fail-fast
Spring Boot属性和 restart: always
docker-compose选项。这意味着全部相关容器将尝试从新启动,直到Config Server启动并运行。
此外,Service Discovery机制在全部应用程序启动后须要一些时间。在实例,Eureka服务器和客户端在其本地缓存中都具备相同的元数据以前,客户端没法发现任何服务,所以可能须要3次侦听。默认侦听时间为30秒。
原文标题《Microservice Architectures With Spring Cloud and Docker》
做者:Alexander Lukyanchikov
译者:我就静静地看
不表明云加社区观点,更多详情请查看原文连接
问答 微服务架构的优点与不足? 相关阅读 Web应用程序开发指南 深度学习和神经网络的六大趋势 如何编写本身的jQuery插件? 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识
此文已由做者受权腾讯云+社区发布,更多原文请点击
搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!
海量技术实践经验,尽在云加社区!