architecture - 将单体服务拆分为多个服务
问题描述
我有一个实时(延迟为 10 毫秒)的整体服务,可以在一次执行中执行多项操作。由于单体架构特别是扩展团队和维护复杂的代码库,我面临很多问题。我已经确定了 3 种不同的功能服务,并计划将单体服务拆分为 3 种不同的服务。但是所有这些服务都依赖于相同的数据。
由于目前只有 1 次代码执行,我们只需要在调用中点击一次 DB(当前是它的 Redis)。拆分后有2个选项
- 从所有 3 个调用中命中 DB,但这会增加最终服务输出的延迟并增加硬件成本。
- 仅从第一个服务中访问数据库并将该数据传递给第二个和第三个服务,这里的问题是大量数据需要传递给不同的服务,并使服务更加依赖于第一个服务。
请分享您的经验,哪种方式更好,或者是否有更好的解决方案。
解决方案
我不认为有灵丹妙药,但我建议在切割巨石时要考虑一些事情。
首先,谨防“单体拆分成微服务”。单体和微服务是两种不同的野兽,每一种都需要自己的方法。微服务可以帮助您扩展团队并降低维护成本。但我们还要记住,单体架构使您无需考虑模块之间的延迟或在它们之间发送的对象的大小。架构的变化需要伴随使用模式的变化,例如:
- 使用消息而不是直接调用,使用更少的同步操作,更多的并行异步任务。查看您的数据流。
- 配料,配料,配料。如果您一次处理一个条目,跨服务延迟将杀死您的应用程序。
- 甚至更少的耦合。在单体应用中,工程师倾向于留下比需要更多的耦合,这意味着服务之间的调用更多(昂贵)。这些服务真的需要相互了解吗?
- 最终的一致性。在单体架构中,工程师倾向于使所有数据和对象状态保持一致。一旦你进入微服务世界,一致性几乎是不可能的——总会有一点延迟。追求一致性并不适合性能。但是如果你把延迟作为一个核心原则呢?您可能会突然减少服务之间的依赖关系。这是对最终一致性意味着什么的简单解释 -通俗英语的最终一致性
- 缓存。此处无需添加太多内容 - 使用缓存 :)
另一个陷阱是“逻辑分裂”。业务逻辑通常提供了一种很好且易于理解的方式来拆分代码。但这并不总是最好的延迟。因此,我建议在决定确切的切割线之前仔细考虑您的数据流。您对数据流的最低要求是什么?尝试绘制某种依赖图并在进行实际拆分之前先将其最小化。就个人而言,我更喜欢迭代方法,首先花费几个月(取决于项目规模)准备代码 - 删除依赖项并在可能的微服务中重新组织代码。每个月左右检查一次拆分。如果分裂在 3-4 个月后仍然看起来不错,那么你可能做对了(足够了)。
可能还有一些事情需要考虑,但我想你明白我的意思——确保你有正确的架构和适当的模式。但是您可能仍然会遇到最初的问题(在服务之间传递数据与多次获取)。如果是这样,我仍然认为没有通用答案,因为变量太多:
- 您只关心性能,还是关心(基础设施)成本?
- 你需要一致性吗?传递数据可能会导致数据陈旧(例如,数据在其他服务处理之前更新)
- 所有服务都需要所有数据吗?或者也许每个服务都需要一小部分(不同的)可以更快地获取的数据?
- 一个可用的只读数据库副本怎么样?
- 你为流量买单吗?流量是否受到限制(例如,如果您发送大量数据,流量是否会变慢)?
话虽如此,直接从每个服务的源中获取数据似乎更简单 - 从数据库或调用服务来提供数据。更简单的设计可能会以更低的维护成本得到回报:)
推荐阅读
- python - 将附件添加到当前的电子邮件 Python 程序中
- swift - 具有不同单元注册的 DiffableCollectionViewDataSource
- c++ - 为什么 std::codecvt 仅由文件 I/O 流使用?
- sql - 用于选择具有多列值的多行的 SQL 查询
- parallel-processing - OpenMP 是否将多个原子指令视为单个关键部分?
- c - 逻辑或:不计算第二个操作数(6.5.14.4),但编译器生成警告:违反标准?
- android - AWS 移动开发工具包库会因为 Amplify 而消失吗?
- android - 在循环中改造入队太慢
- javascript - 将值推送到数组但作为对象?JS
- r - 如何用 r 中的向量替换数据框中的字段名称?