没有明确的解决方案,因为这完全取决于您的上下文,尤其是系统应该扩展到哪个维度以及实际问题是什么。数据库真的是您的瓶颈吗?
这个(不幸的是很冗长的)答案看起来像是“微服务是坏的,是一生的巨石!”,但这不是我的意图。我的观点是,微服务和分布式数据库可以解决各种问题,但必须解决一些问题。为了对您的体系结构提出有力的论据,您必须证明这些问题不适用,可以缓解,并且该体系结构是满足您的业务需求的最佳选择。
分布式数据很困难。
可实现更好缩放的相同灵活性是较弱保证的另一面。值得注意的是,分布式系统更加多难的原因有关。
原子更新,事务,一致性/参照完整性和持久性是非常有价值的,不应轻易放弃。如果数据不完整,过时或完全错误,则毫无意义。当您将ACID作为业务需求但使用无法立即提供的数据库技术(例如,许多NoSQL数据库或每个微服务DB的数据库)时,您的应用程序必须填补空白并提供这些保证。
这不是不可能的事,但是要正确就很难。非常棘手。尤其是在分布式环境中,每个数据库都有多个作者。这种困难意味着出现错误的可能性很高,可能包括数据丢失,数据不一致等等。
例如,考虑阅读著名的分布式数据库系统的Jepsen分析,也许是从Cassandra的分析开始的。我不了解分析的一半,但TL; DR的缺点是分布式系统非常困难,以至于即使是行业领先的项目有时也会以在事后看来很明显的方式将它们弄错。
分布式系统也意味着更大的开发工作。在一定程度上,开发成本或在功能更强大的硬件上花钱之间存在直接的权衡。
示例:悬挂参考
实际上,您不应该看计算机科学,而应该看您的业务需求,以了解是否可以放松ACID以及如何放松ACID。例如,许多外键关系可能并不像看起来那样重要。考虑一个产品-类别n:m关系。在RDBMS中,我们可以使用外键约束,以便只有现有产品和现有类别才能成为该关系的一部分。如果我们引入单独的产品和类别服务,并且删除了产品或类别会怎样?
在这种情况下,这可能不是什么大问题,我们可以编写应用程序,以过滤掉不再存在的任何产品或类别。但是,这里有一些权衡!
请注意,这可能需要跨JOIN
多个数据库/微服务的应用程序级别,这仅会将处理过程从数据库服务器移至您的应用程序。这增加了总负载,并且必须通过网络移动额外的数据。
这可能会使分页混乱。例如,您请求一个类别中的下25个产品,然后从该响应中过滤出不可用的产品。现在,您的应用程序显示23个产品。从理论上讲,具有零产品的页面也是可能的!
您可能需要偶尔运行一个脚本,该脚本在每次相关更改之后或定期进行清理悬挂的引用。请注意,此类脚本非常昂贵,因为它们必须从后备数据库/微服务请求每个产品/类别,以查看其是否仍然存在。
这应该很明显,但是为了清楚起见:请勿重复使用ID。自动递增样式的ID可能正确也可能不合适。GUID或哈希为您提供了更大的灵活性,例如,可以在将项目插入数据库之前分配ID。
示例:并发订单
现在改为考虑产品-订单关系。如果产品被删除或更改,订单将如何处理?好的,我们可以简单地将相关产品数据复制到订单条目中以保持可用状态–为简化交易磁盘空间。但是,如果在订购该产品之前产品的价格发生变化或该产品不可用,该怎么办?在分布式系统中,效果需要花费时间才能传播,并且顺序可能会过时。
同样,如何解决此问题取决于您的业务需求。也许过时的订单是可以接受的,如果无法履行,您以后可以取消订单。
但这也许不是一个选择,例如对于高度并发的设置。考虑到在开始的10秒钟内有3000人争先恐后地购买音乐会门票,并且假设可用性的变化需要10毫秒才能传播。将最后一张票卖给多个人的概率是多少?取决于如何处理这些冲突,但是使用Poisson分布时,每10毫秒间隔就有一次发生冲突λ = 3000 / (10s / 10ms) = 3
的P(k > 1) = 1 - P(k = 0) - P(k = 1) = 80%
机会。是否可以在不欺诈的情况下出售并取消大多数订单,可能会导致与您的法律部门进行有趣的对话。
务实意味着选择最好的功能。
好消息是,如果不需要这样做,则不必迁移到分布式数据库模型。如果您没有“适当地”做微服务,没有人会撤销您的微服务俱乐部会员资格,因为没有这样的俱乐部-也不存在构建微服务的真正方法。
实用主义每次都会取胜,因此在解决问题时会混合使用各种方法。这甚至可能意味着具有集中式数据库的微服务。确实,如果没有必要,不要经历分布式数据库的痛苦。
您可以在没有微服务的情况下进行扩展。
微服务有两个主要好处:
- 它们可以由独立的团队独立开发和部署的组织利益(这反过来要求服务提供稳定的接口)。
- 每个微服务可以独立扩展的运营优势。
如果不需要独立扩展,微服务的吸引力将大大降低。
数据库服务器已经是一种服务,您可以独立地进行扩展(某种程度上),例如通过添加只读副本。您提到存储过程。减少它们可能会产生巨大影响,以至于其他任何可伸缩性讨论都没有意义。
而且,拥有一个包含所有服务作为库的可伸缩单块是完全可能的。然后,您可以通过启动更多的整体实例来进行扩展,这当然要求每个实例都是无状态的。
除非整体组件太大而无法合理部署,或者某些服务有特殊的资源要求,以便您可能希望独立扩展它们,否则这通常会很好地起作用。涉及额外资源的问题域可能不涉及单独的数据模型。
您有强有力的业务案例吗?
您了解组织的业务需求,因此可以根据以下分析为每个微服务数据库架构创建参数:
- 考虑到此类设置和替代解决方案的开发工作量不断增加,因此该架构是需要一定规模的,并且该架构是获得该可伸缩性的最具成本效益的方法;和
- 您的业务需求允许放宽相关的ACID保证,而不会导致上述各种问题。
相反,如果您无法证明这一点,特别是如果当前的数据库设计能够支持对未来的足够扩展(正如您的同事似乎相信的那样),那么您也有自己的答案。
YAGNI还有一个很大的可扩展性组件。面对不确定性,这是一项战略性的业务决策,即现在就构建可伸缩性(降低总成本,但涉及机会成本,可能不需要),而不是推迟一些可扩展性工作(如果需要,则需要较高的总成本,但您会有更好的选择)实际规模的想法)。这主要不是技术决定。