作者: Alexsandro Souza
几乎每个人都在关注微服务架构,我们也不例外。作为一个与时俱进的程序员,我一直在努力了解这一架构,希望寻找一种通过Spring在Java中实现微服务架构的方法。
我们公司虽然很棒,但技术堆栈略显过时,至今还没有使用Java 8或微服务,因此我需要从外部了解更多关于微服务架构的经验和方法。我决定通过创建一个“to-do system”项目来梳理经验以供将来参考。
概览
本文的目标是为不同的微服务提供源代码walkthrough,因此我不打算深入概念和工具,而是提出一个包含用于开发微服务的模式、工具、技术的应用示例。
“to-do system”将由8个应用组成:
Reminder
User
Service Discovery System
Mailer
OAuth Server
System Integration Test
API Gateway
Web Application Client
系统如何工作
上图未系统与微服务的交互。用户访问Angular2编写的应用,该应用链接OAuth Authorization server,通过OAuth Authorization server分配用户和权限。此server将返回一个Jason Web Token,其中包含有关客户端及其权限的信息以及格式的范围。当用户认证通过并拥有token之后,Web应用可以与API Gateway通信。API Gateway将利用JWT验证请求是否来自授权server,而后调用微服务并构建响应。
OAuth server通过User service获取用户权鉴细节,API Gateway从OAuth server获取用户信息。
Reminder service是安置ToDo功能的地方,ToDo服务按计划检查reminders并通过电子邮件通知用户,电子邮件由Mail service发送,该事件由使用Kafka的事件提醒服务触发。
System Integration Test是负责联络Reminder Service endpoints的Java应用。
连接微服务
在微服务架构中,我们需要处理许多在不同IP和端口上运行的微服务。因此有必要找到一种无需硬编码的方式来管理每个地址。
Netflix Eureka是一种很好的解决方案,作为客户端服务发现,Eureka允许服务自动查找和相互通信。我们有必要理解eureka的工作原理,一边了解REST服务在不同微服务之间的通信。利用eureka来管理服务运行位置,我们可以添加instance,并通过负载均衡实现在微服务之间分配incoming application traffic。】
在我们的系统中,使用Netflix Ribbon作为客户端负载均衡器,实现容错并通过冗余增加可靠性和可用性。我们使用Netflix Feign编写声明性REST客户端,并集成Ribbon和Eureka来提供负载平衡HTTP客户端。
我们正在使用Netflix Hystrix断路器将我们的应用程序与依赖性故障隔离开来。它有助于阻止cascading failure,并允许我们快速恢复或添加fallbacks。Hystrix为每个依赖关系提供一个thread-pool。当thread-pool耗尽,hystrix将拒绝请求。Hystrix同时提供断路器功能,可以停止对依赖关系的所有请求,在请求失败、拒绝或超时时,还可以实现备用逻辑。
Authentication
对于任何系统来说,安全性都是非常重要的,微服务架构也一样。我们通过OAuth2来保持微服务的安全性。OAuth2作为一项知名Authorization,早已广泛应用于Google,Facebook和Github。
在我们的这个项目中,同时还应用了Spring Security,并在安全问题上增加了一个元素:JSON Web Token(JWT)。
如果我们仅使用OAuth,我们将需要一个OAuth授权服务器来验证用户,生成令牌并充当资源服务器的endpoints,询问该令牌是否有效以及授权的权限。与Authorization Server相比,这需要两倍的请求。而JWT提供了一种在access token中传输权限和用户数据的简单方法。一旦所有数据都已经存在于token string中,资源服务器就不需要再请求令牌检查。所有信息都被序列化为JSON,用base64编码,最后用私有RSA密钥签名。它假设所有资源服务器都将有一个公钥,以检查令牌是否为适当的私钥签名,并对令牌进行反序列化以获取信息。
REST
在我们的系统中,我们有两种交互方式:同步和异步。对于异步风格,我们使用分布式事件与Kafka,遵循模型发布/订阅。对于同步,我们有支持JSON和XML的REST风格。
对于RESTful,有四个成熟级别。我们的微服务处于2级,为了简单起见,我决定不使用HATEOAS设计模式实现超媒体控件。
因为我们正在使用Spring Cloud,所以我们要“out-of-box“一些可扩展性模式,把它们放在HTTP连接中,如断路器、bulkhead、负载均衡、连接池、超时和重试。
分布式事件
如上所述,我们通过使用Kafka将Reminder服务和Mailer服务之间的通信异步地与其他微服务进行通信。在Reminder中,我们有一个计划任务来检查提醒时间并发布RemainderFound事件。Mailer服务中将会有一个订阅的事件,它将开始向用户发送电子邮件的过程。我邀请您看看我们如何进行这种整合,以及我如何在Kafka事件模块中写入发送到Kafka的数据的序列化/反序列化。
Event sourcing及CQRS
一体化应用通畅具有单个关系数据库。我们可以使用ACID transaction。因此,如果出现问题,我们的应用程序可以简单地开始一个transaction、更改多个行并提交transaction。但处理微服务架构中的数据访问要复杂得多,这是因为数据分布在不同的数据库中。跨多个服务实施业务transactions是一个很大的挑战。
在我们的“To-Do system“中,我们正在使用事件来处理跨多个服务的业务事务。您可以查看在Mailer服务中应用的CQRS实施事件采购。您可以看到如何分离读和写,使我们能够轻松地缩放每个部分。我们使用关系数据库作为事件存储,然后使用Kafka分发事件。我们将需要使这两个动作为Atomic并避免存储事件,这样就不会发布最终的JVM崩溃。我不使用Kafka作为事件存储,因为从关系数据库构建聚合更简单。我们正在努力使事情变得容易!
下一步
在To-Do-System已经包含许多微服务架构涉及到的方方面面,另一方面也仍然存在诸多挑战。我们未来计划在此项目基础上增加更多东西,例如Spring云配置、Docker容器、与Jenkins的持续集成、Spring Sleuth分布式跟踪、ELK日志管理等等。
推荐阅读
[开源项目:[云框架]基于Spring Cloud的微服务架构](https://github.com/cloudframe...,提供Spring Cloud微服务架构最佳实践,即插即用
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。