分布式系统中的耦合

耦合和内聚是关键的质量指标。 我们追求的系统具有高度凝聚力和松散耦合性,但是高并不意味着纯粹。 函数式编程也是如此,我们的目标是隔离和减少副作用,但是除非需要一个无用的系统,否则我们将需要它们。 对我们的系统进行模块化是很好的,因此,只要这些模块需要互相通信,它们就会有效地相互耦合。 我们的工作是创建有凝聚力的模块,并尽可能减少耦合。

让我们提供一个例子。 我们的系统具有以下结构:

  1. 不同的可部署的又名微服务架构。
  2. 通过Kafka进行内部通信(发布-订阅消息传递)。 不涉及HTTP。
  3. 1个生产者到N个消费者的场景。
  4. Json用于数据序列化。

在此系统中发布和使用的消息都有一个模式,我们可以选择使它隐式或显式,并在编译或运行时执行时验证该模式。 在分析每种方法的权衡之前,让我们先谈谈编译与运行时方法。

尽快验证软件的正确性

在我职业生涯的大部分时间里,我一直是静态类型语言的用户,因此我对此主题确实有偏见。 我坚信精益概念是减少浪费的重要性。 同时,我喜欢敏捷,TDD或BDD背后的关于尽快揭露真相的治疗思想。 静态类型以及最终的编译器可以帮助我实现这些目标。

我宁愿花时间在提供实时文档,简化将来的重构或帮助我进行设计的动机上,而不是帮助捕获类型系统应解决的错误。 如果我们无法编写一行传递空值的代码,那么编写一个检查接收到空值时方法行为的测试就是浪费时间。

编译世界并不是完美的,因为它在开发上肯定会变慢并限制开发人员(有人会说,在这种情况下,拥有更少的自由可能是一件好事)

运行时方法

既然我对您的编译偏见已经很诚实了,那么我可以解释模式验证问题的不同方法和折衷方案。

隐式模式

第一种运行时方法是最宽松的方法:使用隐式模式并信任生产者的良好意愿。 由于没有人在将消息发布到Kafka之前检查消息的有效性,这意味着消费者可能会大吃一惊。

第一个纠正措施是确保仅中毒信息的处理将被吹散,而不是整个消费者。 例如,当消息不包含预期的隐式架构时,在Akka Streams上提供恢复监督策略。

第二种纠正措施不仅是吞下这些崩溃,还可以将它们传达给适当的参与者(包括人类或软件)。 优良作法是为中毒的邮件提供死信队列,以防万一我们想要在该级别上操纵并重试这些邮件的处理。

在进入明确的模式之前,我会说这些措施通常不够用,但是随着情况的发展,它们是一个很好的安全网,我们需要做好准备。

显式架构

如果我们想避免有害信息进入我们的主题,我们可以提供中间人服务来拦截和验证显式模式。 架构注册表就是Kafka的一个例子,其文档中充满了关于如何以分布式,高度可用和可扩展的方式来实现它的见解。

这是一个集成服务,它可能是单点故障,但同时,当我们有很多使用者时,有一个集中化的模式存储库可能很有价值,并且系统的复杂性很难理解。集中的时尚。 该服务将是无状态的,因此为了避免单点故障,我们可以使其在服务器场中冗余以实现高可用性。

编译方法

最后一种方法是创建使无法创建不包含预期架构的消息的软件。 假设Scala ,我们可以创建一个jar,其中包含案例类 ,这些案例类是模式的对象实现。

这种方法有什么好处?

  1. 早点失败。 我们不必等到测试或生产就可以验证某些生产者发布的消息是正确的。
  2. 集中的知识。

什么是可解决的问题?

  • 级联更新。 如果我们的微服务位于不同的存储库中,那么我们需要确保将对通用二进制文件的更新应用于生产者和消费者。 这很麻烦,如果不这样做,可能会导致意外的错误,因为我们对该库引入了错误的安全感。 可以使用monorepo解决

最大的问题是什么?

  • 打破部署物的隔离。 微服务的要点之一是能够独立部署其服务。 如果每次使用架构库的非向后兼容更改来升级使用者时,都被迫重新部署N个使用者服务,那么您将失去这种优势。 能够进行小批量发布是持续交付的重要推动力,因此这是一个巨大的损失。

您可能会争辩说,只有非向后兼容的更改才会迫使消费者重新部署,并且我们应该以预测和最小化此类更改的方式设计架构。

广义耦合问题

如果将问题概括化,我们将看到存在两种耦合:可避免的和强制的。

当我们努力减少代码库中的重复时,就会出现可避免的耦合。 假设我们要从HTTP请求的标头中提取一些requestId并将其放入某些MDC中,以便能够跨不同的线程或服务跟踪日志。 该代码几乎不会因服务而异,因此它很适合提取,因此在服务之间增加了一些耦合。 在这样做之前,最好考虑以下几点:

  1. 耦合是微服务的敌人,而且其影响在未来还不容易看到。
  2. 遵循Conway的法律 ,打破服务的隔离度会破坏团队的隔离度,因此请确保您的组织能够应付这种程度的沟通和集成。
  3. 关键措施是费率变化。 与某些相当静态的库相比,将要不断更新的库(可能是您的架构库)作为一个公共依赖项进行管理将更加痛苦。

当某些信息需要驻留在第三个实体中时,就会出现强制耦合,因为由一个集成实体持有该信息没有意义,或者不值得将该信息共享并复制到每个单个实体中。

结论

即使我是编译语言的坚定支持者,我也认为在分布式环境中通过二进制代码共享代码值得对系统的结构和需求进行深入分析。 我希望这篇文章提供了对该主题的一些见解。

翻译自: https://www.javacodegeeks.com/2016/02/coupling-distributed-systems.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值