现在,“微服务架构”是编程中的流行概念。 为了跟上软件开发人员的最新发展,我一直在尝试对这种体系结构有一个很好的了解。 具体来说,我一直在寻找一种使用Spring在Java中实现微服务架构的更好方法。
一些背景:我的公司虽然很棒,但是却拥有过时的技术栈。 基本上,我们还没有使用Java 8或微服务。 因此,如果我想更多地了解这两个方面,我必须走出公司外部。 最简单的学习方法就是做到这一点,因此我决定创建一个“待办事项”系统并记录我的经验以供将来参考。
本文的目的是为不同的微服务提供源代码演练。 我不打算深入研究概念和工具。 有很多关于这些的帖子。 我的意图是提出一个包含用于开发微服务的模式,工具和技术的应用示例。
由于这是一个参考应用程序,因此我特意使它尽可能简单,从而使源代码易于理解。 您应该在家中跟随并能够在自己的计算机上运行该应用程序作为参考。
在本文中,我们将使用由8个应用程序组成的“ To Do”应用程序:
- 提醒
- 用户
- 服务发现服务器
- 邮递员
- OAuth服务器
- 系统集成测试
- API网关
- Web应用程序客户端
本文将提供整个项目的概述。 稍后,我将更深入地说明我们在每个微服务中使用什么以及如何使用这些组件。
在上图中,您可以看到我们的系统如何与所有微服务进行交互。 用户将访问使用Angular 2编写的Web应用程序。它将连接到OAuth授权服务器,这是可以分配用户和权限的中心点。 该服务器将返回一个JSON Web令牌,其中包含有关客户端的信息及其权限和切碎的范围。 在对用户进行身份验证并获得令牌之后,Web应用程序将能够与API网关进行对话。 它将使用JWT,验证它是否来自授权服务器,然后调用微服务并构建响应。
OAuth服务器使用用户服务来获取用户的身份验证详细信息。 此外,API网关使用OAuth服务器获取用户的信息。
在 剩余服务 是将被放置在待办事项功能,待办服务有计划的作业检查提醒和通过电子邮件通知用户,该邮件是由 从 提醒服务 通过使用事件 触发 卡夫卡 的 梅勒服务 发送 。
系统集成测试是一个Java应用程序,负责到达提醒服务的端点。
在微服务架构中,我们必须处理在不同IP和端口中运行的许多微服务。 因此,我们需要找到一种无需硬编码即可管理每个地址的方法。
这就是Netflix Eureka进行救援的地方。 这是一个客户端服务发现,它使服务可以自动查找并相互通信。 我们在系统中使用Spring Cloud Eureka; 您应该看看它是如何工作的,这样您就可以了解我们的REST服务如何在不同的微服务之间进行通信。 一旦Eureka关心服务在哪里运行,我们就可以添加实例并应用负载平衡以在微服务之间分配传入的应用程序流量。
在我们的系统中,我们使用Netflix Ribbon作为客户端负载平衡器。 这使我们能够实现容错能力,并通过冗余提高可靠性和可用性。 我们正在使用Netflix Foreign编写声明性REST客户端,并集成Ribbon和Eureka以提供负载平衡HTTP客户端。
我们的系统确实有一些依赖性。 我们正在尝试使用Netflix Hystrix Circuit Breaker将我们的应用程序与依赖项故障隔离。 它有助于阻止级联故障,并使我们无法快速恢复故障,或增加后备故障。 Hystrix为每个依赖项维护一个线程池。 如果线程池已用完,它将拒绝请求而不是将请求排队。 它还提供了断路器功能,可以停止对依赖项的所有请求。 当请求失败,被拒绝或超时时,您还可以实现回退逻辑。
开发任何类型的系统时,安全性都是非常重要的。 微服务架构没有什么不同。 “如何维护微服务的安全性?” 立即出现,第一个答案是OAuth2。 OAuth2绝对是一个很好的解决方案:它是一种众所周知的授权技术,已广泛用于Google,Facebook和Github。
无论如何,不提Spring Security就不可能谈论安全性。 在此项目中,我将其与OAuth2一起使用。 在谈论安全分布式系统时,Spring Security和OAuth2是显而易见的选择。
但是,我们在安全性方面又增加了一个元素:JSON Web令牌(JWT)。 如果仅使用OAuth,则需要有一个OAuth授权服务器来对用户进行身份验证,生成令牌以及充当 资源服务器 的端点, 以询问令牌是否有效以及它授予哪个权限。 这需要 比实际需要 多两倍的请求 授权服务器 。 JWT提供了一种在访问令牌中传输权限和用户数据的简单方法。 一旦所有数据都已包含在令牌字符串中,资源服务器就不需要进行令牌检查了。 首先将所有信息序列化为JSON,使用base64编码,最后使用专用RSA**签名。 假定所有资源服务器都将具有一个公用**,以检查令牌是否已为正确的专用**签名,并反序列化令牌以获取信息。
您可以查看OAuth2授权服务器(OAuth服务器)和 资源服务器(API网关) 实现,以查看代码。 该实现主要是根据此 博客文章完成的 。
在我们的系统中,我们有两种交互方式:同步和异步。 对于异步样式,我们按照模型发布/订阅将分布式事件与Kafka一起使用。 为了同步,我们有支持JSON和XML的REST样式。
有四个级别的RESTful成熟度,从0开始 的水平, 作为Martin Fowler的描述 在这里 。 我们的微服务处于 2级, 因为为简单起见 , 我决定不使用HATEOAS设计模式来实现超媒体控件。
因为我们使用的是Spring Cloud,所以我们必须开箱即用一些可伸缩性模式,这些模式放在我们的HTTP连接中,值得一提:断路器,隔板,负载平衡,连接池,超时和重试。
如上所述, Reminder服务 和 Mailer服务 之间的通信 是使用Kafka异步完成的,以便在其他微 服务 之间 分发事件。 在 Reminder服务中 ,我们有一个计划好的任务来检查提醒时间并发布事件 RemainderFound。 Mailer服务 中将有一个已订阅事件,该事件 将开始向用户发送电子邮件的过程。 我邀请您看一下我们如何进行这种集成以及如何编写在 Kafka事件模块中 发送给Kafka的数据的序列化/反序列化 。
整体应用程序通常具有单个关系数据库。 我们可以使用ACID交易。 结果,我们的应用程序可以简单地开始事务,更改多行并在一切正常的情况下提交事务,或者在出现问题的情况下回滚。 不幸的是,在微服务架构中处理数据访问要复杂得多。 这是因为数据分布在不同的数据库中。 跨多种服务实施业务交易是一个巨大的挑战。
在“ ToDo”项目中,我们使用事件来处理跨越多个服务的业务交易。 您可以查看 Mailer服务中 应用CQRS的事件源的实现 。 您可以看到如何将读取和写入分开,从而使我们能够轻松地缩放每个部分。 我们将关系数据库用作事件存储,然后使用Kafka分发事件。 我们将需要使这两个操作成为Atomic并避免存储该事件,这样它就不会发布最终的JVM崩溃。 我不使用Kafka作为事件存储,因为从关系数据库构造聚合更简单。 我们正在努力使事情变得简单!
正如您所注意到的,我们在这个项目中已经有了很多东西,仍然有许多挑战尚未解决。 但是,这是一个正在开发的项目,我们计划在其中添加更多内容,例如Spring云配置,带有Docker的Containers,与Jenkins的持续集成,与Spring Sleuth的分布式跟踪,与ELK的日志记录管理等等。 因此,请继续关注我们的 Github 存储库,以查看更多有趣的事情。
下面,我列出了很多参考资料,对我很有帮助。 因此,请看一下您是否有不清楚的地方。 祝好运!
Spring Cloud Netflix:具有功能区/功能的负载均衡器
Netflix Hystrix –复杂分布式系统的延迟和容错
翻译自: https://jaxenter.com/introduction-microservices-java-136067.html