JavaRush /Java 博客 /Random-ZH /Java 微服务指南。第 1 部分:微服务基础知识和架构

Java 微服务指南。第 1 部分:微服务基础知识和架构

已在 Random-ZH 群组中发布
在本指南中,您将了解什么是 Java 微服务以及如何设计和创建它们。它还涵盖了有关 Java 微服务库以及使用微服务的可行性的问题。《Java微服务:实用指南》的翻译和改编。

Java 微服务:基础知识

要理解微服务,您必须首先定义它们不是什么。它不是一个“整体” - Java 整体:它是什么以及它的优点或缺点是什么? Java 微服务指南。 第 1 部分:微服务基础知识和架构 - 1

什么是 Java 整体架构?

想象一下您在一家银行或一家金融科技初创公司工作。您为用户提供一个移动应用程序,他们可以用它来开设新的银行账户。在 Java 代码中,这将导致控制器类的出现。简化后,它看起来像这样:
@Controller
class BankController {

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        riskCheck(form);
        openBankAccount(form);
        // etc..
    }
}
您需要控制器来:
  1. 确认登记表。
  2. 检查用户地址的风险,以决定是否向其提供银行账户。
  3. 开设了银行账户。
该类BankController将与其余源一起打包到bank.jar 或bank.war 文件中进行部署——这是一个很好的旧整体,包含运行银行所需的所有代码。粗略估计,.jar(或.war)文件的初始大小范围为 1 到 100 MB。现在您只需在服务器上运行 .jar 文件...这就是部署 Java 应用程序所需要做的全部工作。 Java 微服务指南。 第 1 部分:微服务基础知识和架构 - 2图片,左上角矩形:部署单一(单片)银行 java -jar Bank.jar(cp .war/.ear 到 appserver)。右侧矩形:打开浏览器。

Java 单体应用有什么问题?

Java 单体并没有本质上的错误。然而,经验表明,如果在您的项目中:
  • 有很多程序员/团队/顾问在工作......
  • ...在来自需求非常模糊的客户的压力下,在同一个整体上...
  • 几年之内...
...那么在这种情况下,您的小bank.jar 文件就变成了巨大的千兆字节代码,这甚至令人恐惧,更不用说部署了。

如何减小 Java 整体的大小?

一个自然的问题出现了:如何使整体变得更小?现在您的bank.jar 正在一个JVM 上运行,即一台服务器上的一个进程。不多也不少。现在你可能会想到一个逻辑想法:“但是风险验证服务可以被我公司的其他部门使用!” 它与我的整体银行应用程序没有直接关系!也许它应该从整体中分离出来并作为单独的产品部署?也就是说,从技术上讲,将其作为单独的 Java 进程运行。”

什么是 Java 微服务?

实际上,这句话意味着现在riskCheck()不再从 BankController 进行方法调用:该方法或 bean 组件及其所有辅助类将被移至其自己的 Maven 或 Gradle 项目。它还将独立于银行整体进行部署和置于版本控制之下。但是,整个提取过程不会将新的 RiskCheck 模块本身转变为微服务,因为微服务的定义可以解释。这导致团队和公司内部频繁讨论。
  • 一个项目中有 5-7 个类是微型项目还是什么?
  • 100 或 1000 节课……还是微课?
  • 微服务一般和类的数量有没有关系?
让我们抛开理论推理,坚持务实的考虑,这样做:
  1. 我们将所有单独部署的服务称为微服务,无论其大小或域边界如何。
  2. 我们来思考如何安排服务间的通信。我们的微服务需要相互通信的方式。
所以,总结一下:以前您有一个 JVM 进程,一个用于运行银行的坚实的整体。现在,您拥有一个银行业整体 JVM 进程和一个在其自己的 JVM 进程中运行的单独的 RiskCheck 微服务。现在,为了检查风险,您的整体架构必须调用此微服务。这个怎么做?

Java微服务之间如何建立通信?

一般来说,有两种选择——同步和异步通信。

同步通信:(HTTP)/REST

通常,微服务之间的同步通信通过返回 XML 或 JSON 的 HTTP 和类似 REST 的服务进行。当然,可能还有其他选择 - 至少采用Google Protocol Buffers。如果您需要立即响应,最好使用 REST 通信。在我们的示例中,这正是需要做的,因为在开户之前需要进行风险验证。如果没有风险检查,就没有账户。我们将在“哪些库最适合同步 Java REST 调用”部分中讨论下面的工具。

消息传递 - 异步通信

异步微服务通信通常通过与 JMS 实现交换消息和/或使用AMQP等协议来完成。我们在这里写“通常”是有原因的:假设电子邮件/SMTP 集成的数量不可低估。当您不需要立即回复时使用它。例如,用户单击“立即购买”按钮,而您又想要生成发票。这个过程当然不应该发生在用户的购买请求-响应周期内。下面我们将描述哪些工具最适合异步 Java 消息传递

示例:Java 中的 REST API 调用

假设我们选择同步微服务通信。在这种情况下,我们的 Java 代码(我们上面介绍的代码)在低级别上将如下所示。(这里所说的低级是指对于微服务通信,通常会创建客户端库来将您从实际的 HTTP 调用中抽象出来)。
@Controller
class BankController {

    @Autowired
    private HttpClient httpClient;

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        httpClient.send(riskRequest, responseHandler());
        setupAccount(form);
        // etc..
    }
}
根据代码,很明显我们现在需要部署两个 Java(微)服务:Bank 和 RiskCheck。结果,我们将运行两个 JVM 进程。 Java 微服务指南。 第 1 部分:微服务基础知识和架构 - 3这就是开发 Java 微服务项目所需的全部内容:只需构建和部署较小的块(.jar 或 .war 文件),而不是一个整体的块。这个问题的答案尚不清楚:我们应该如何将单体应用切割成微服务?这些碎片应该有多小,如何确定正确的尺寸?让我们检查。

Java微服务架构

在实践中,公司以不同的方式开发微服务项目。该方法取决于您是尝试将现有的整体项目转变为微服务项目还是从头开始该项目。

从整体架构到微服务

最合乎逻辑的想法之一是从现有的整体中提取微服务。请注意,这里的前缀“micro”实际上并不意味着提取的服务确实很小;情况不一定如此。我们来看看理论背景。

想法:将整体分解为微服务

微服务方法可以应用于遗留项目。这就是为什么:
  1. 大多数情况下,此类项目很难维护/更改/扩展。
  2. 从开发人员到管理层,每个人都希望简化。
  3. 您拥有(相对)清晰的领域边界,这意味着您确切地知道您的软件应该做什么。
回到我们的示例,这意味着您可以查看 Java 银行业整体并尝试跨域边界将其分解。
  • 因此,将用户数据(例如姓名、地址、电话号码)的处理分离到单独的微服务“帐户管理”中是合理的。
  • 或者前面提到的“风险检查模块”,它检查用户的风险级别,可以被许多其他项目甚至公司的部门使用。
  • 或者以 PDF 格式或通过邮件发送发票的发票模块。

实施一个想法:让别人去做

上述方法在纸面和类似 UML 的图表上看起来很棒。然而,一切并没有那么简单。它的实际实施需要认真的技术准备:我们对从整体中提取什么内容的理解与提取过程本身之间存在巨大差距。大多数企业项目都会达到这样一个阶段:开发人员不敢将已有 7 年历史的 Hibernate 版本升级到较新的版本。库将随之更新,但确实存在破坏某些内容的危险。那么这些开发人员现在必须挖掘数据库事务边界不明确的古老遗留代码并提取定义明确的微服务吗?通常,这个问题非常复杂,无法在白板上或架构会议上“解决”。 Java 微服务指南。 第 1 部分:微服务基础知识和架构 - 4引用 Twitter 开发人员 @simonbrown 的话: 我会一遍又一遍地说……如果人们无法正确构建单体,微服务将无济于事。 西蒙·布朗

基于微服务架构的从头开始项目

对于新的 Java 项目,前一部分中的三个编号点看起来略有不同:
  1. 您从头开始,因此无需维护任何“包袱”。
  2. 开发人员希望将来事情变得简单。
  3. 问题:您对领域边界的了解更加模糊:您不知道您的软件实际上应该做什么(提示:敏捷;))
这导致公司尝试使用 Java 微服务的新项目。

技术微服务架构

第一点对于开发人员来说似乎是最明显的,但也有人强烈反对。Hadi Hariri 建议在 IntelliJ 中进行“提取微服务”重构。尽管下面的示例非常简化,但不幸的是,在实际项目中观察到的实现并没有离它太远。 微服务出现之前
@Service
class UserService {

    public void register(User user) {
        String email = user.getEmail();
        String username =  email.substring(0, email.indexOf("@"));
        // ...
    }
}
带有子串Java微服务
@Service
class UserService {

    @Autowired
    private HttpClient client;

    public void register(User user) {
        String email = user.getEmail();
        //теперь вызываем substring microservice via http
        String username =  httpClient.send(substringRequest(email), responseHandler());
        // ...
    }
}
因此,您实际上是将 Java 方法调用包装在 HTTP 调用中,而这样做的原因并没有明显的原因。然而,原因之一是:缺乏经验并试图强制采用 Java 微服务方法。建议:不要这样做。

面向工作流的微服务架构

下一个常见的方法是将 Java 微服务划分为基于工作流的模块。现实生活中的例子:在德国,当您去看(公立)医生时,他必须在他的医疗 CRM 系统中记录您的就诊情况。为了从保险中获得付款,他将通过 XML 向中介发送有关您的治疗(以及其他患者的治疗)的数据。代理将查看此 XML 文件并(简化):
  1. 将检查是否收到正确的 XML 文件。
  2. 它将检查程序的合理性:例如,一个一岁的孩子一天内从妇科医生处接受了三次牙齿清洁程序,看起来有些可疑。
  3. 将 XML 与其他一些官僚数据结合起来。
  4. 将 XML 文件转发给保险公司以发起付款。
  5. 它将结果发送给医生,向他提供“成功”或“请在有意义时尽快重新发送此录音”的消息。
笔记。在此示例中,微服务之间的通信不起作用,但很可能由消息代理(例如 RabbitMQ)异步完成,因为医生无论如何都不会收到即时反馈。 Java 微服务指南。 第 1 部分:微服务基础知识和架构 - 5同样,这在纸面上看起来很棒,但自然会出现问题:
  • 是否需要部署六个应用程序来处理一个 XML 文件?
  • 这些微服务真的彼此独立吗?它们可以相互独立部署吗?有不同的版本和API方案?
  • 如果验证微服务不起作用,可信度微服务会做什么?系统还能用吗?
  • 这些微服务是否共享同一个数据库(它们当然需要数据库表中的一些公共数据),还是每个微服务都有自己的数据库?
  • … 以及更多。
有趣的是,上图看起来更简单,因为每个服务现在都有自己精确的、明确定义的目的。它曾经看起来像这个可怕的巨石: Java 微服务指南。 第 1 部分:微服务基础知识和架构 - 6虽然您可以争论这些图表的简单性,但您现在肯定需要解决这些额外的操作挑战。
  • 您不仅需要部署一个应用程序,而且至少需要部署六个应用程序。
  • 您甚至可能需要部署多个数据库,具体取决于您想要进入微服务架构的程度。
  • 您需要确保每个系统都在线并正常工作。
  • 您需要确保微服务之间的调用真正具有弹性(请参阅如何使 Java 微服务具有弹性?)。
  • 以及此设置所暗示的所有其他内容 - 从本地开发设置到集成测试。
所以建议是:
  • 如果您不是 Netflix(很可能您不是 Netflix)...
  • 除非你有超强的工作技能,当你打开开发环境时,它会导致一个混乱的猴子,扔掉你的生产数据库,5秒内轻松恢复。
  • 或者您感觉像 @monzo 并且愿意尝试 1500 个微服务,只是因为您可以。
→ 不要这样做。现在它不再那么夸张了。尝试跨域边界建模微服务似乎相当合理。但这并不意味着您需要采用一个工作流程并将其拆分为微小的单独部分(接收 XML、验证 XML、转发 XML)。因此,每当您使用 Java 微服务启动一个新项目并且领域边界仍然非常模糊时,请尝试将微服务的大小保持在较低水平。您以后随时可以添加更多模块。并确保您的团队/公司/部门拥有先进的 DevOps 来支持您的新基础设施。

多语言或面向团队的微服务架构

还有第三种几乎是自由主义的微服务开发方法:允许团队甚至个人使用任意数量的语言或微服务来实现用户故事(营销人员将这种方法称为“多语言编程”)。因此,上述 XML 验证服务可以用 Java 编写,同时验证微服务可以用 Haskell 编写(以使其在数学上合理)。对于保险转发微服务,您可以使用 Erlang(因为它确实需要扩展;))。从开发人员的角度来看,看似有趣的事情(在隔离环境中用完美的语言开发完美的系统)实际上从来都不是组织想要的:同质化和标准化。这意味着一套相对标准化的语言、库和工具,以便其他开发人员将来在您转向更有利的领域时可以继续支持您的 Haskell 微服务。 Java 微服务指南。 第 1 部分:微服务基础知识和架构 - 8历史表明,标准化通常变得根深蒂固。例如,大型财富 500 强公司的开发人员有时甚至不被允许使用 Spring,因为它“不是公司技术路线图的一部分”。然而,完全过渡到多语言方法几乎是同一件事,即同一枚硬币的另一面。建议:如果您打算使用多语言编程,请尝试在同一编程语言生态系统中减少多样性。因此,最好一起使用 Kotlin 和 Java(两种语言都基于 JVM,并且彼此 ​​100% 兼容),而不是 Java 和 Haskell。在下一部分中,您将了解如何部署和测试 Java 微服务。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION