如何为微服务选择数据库

原文:How to choose a database for your microservices
作者:Jeff Carpenter, InfoWorld
译者:Jackyrong

你的微服务架构需要多种数据模型。你是应该选择混合持久化呢还是多模型数据库?

在过去的十年,大规模的分布式系统呈现爆炸式增长。这一趋势促使在数据库领域产生了一股巨大的创造力,这在软件业的历史上无疑是没有先例的。其结果是诞生了一个健康和充满竞争的数据库市场,我们可以因此在大量的平台中各取所需。但是我们应该如何抉择?

在本文中,我们将探讨如何为根据应用程序去选择核实的数据库模式。(是的,可以有一个以上的选择!),我们也会看看对数据模式的选择可以帮助确定在数据层中将选用哪些技术。

云架构,NoSQL 和微服务架构

随着开发人员开始创建可扩展的Web应用,历史上在数据架构上占主导地位的关系型数据库,开始显示出很大的压力。我们开发了非常流行的社交应用,并开始将越来越多的设备连接到物联网(IoT)。用户大量的读取和写入数据导致了必须扩展数据层,从而出现了新型的数据库来满足这些高可扩展性需求。

在许多情况下,这些新的数据库“NoSQL”或“非关系”的解决方案,所基于的数据模型和传统的关系数据库模型不同。NoSQL数据库包括有文档型、键值对型(key-value)、列式数据库甚至图数据库。通常来说,这些数据库牺牲了一些关系数据库的常见的的特性,如强一致性、ACID事务特性和join连接。

与此同时,和数据库技术的变革一样,在本世纪初的SOA(面向服务的架构),正逐渐演变为微服务架构的体系架构,许多企业也开始逐渐抛弃重量级的SOA体系架构如企业服务总线(ESB),并倾向使用“去中心化”的架构方法。微服务架构的魅力在于其开发、管理和扩展服务都是相对独立的。这给了我们很多在实施方面的灵活性,包括基础架构技术,如数据库。

举个例子,我们假设正在为微服务架构做开发工作,并期待着大规模的可扩展性的需求。无论这个项目是一个新的应用还是对现有应用的重构,我们都有机会针对数据库做出新的选择。

混合持久化(Polyglot persistence)

微服务架构风格的一个关键的好处,是持久性的封装。我们可以根据每个服务的需要,去选择不同的持久化技术。根据每种数据类型的特点而去选择数据存储的方法,被称为混合持久化,这一术语起初是由Martin Fowler等人推广起来的。混合持久化和微服务架构可谓是天作之合。

下图中,展示了一系列的微服务,以及我们如何为每个服务选择不同的数据模式。我不想在本文中,为每种类型的数据库去选择合适的用例。我的意图是要突出各类型数据库的优势,以及为什么混合持久化的方法是值得称道的.

其中,开发服务A的团队,因为该服务是基于大规模数据管理的核心应用,可能使用如Apache Cassandra这样的表格模型数据库。例如,一个零售应用库存应用,可能很适合使用Apache Cassandra。Cassandra提供了一系列协调机制工具,如可调一致,批处理和轻量级的事务机制,可以作为完整ACID事务机制的替代。

服务B支持用众所周知的关键字查找值的方式,例如针对产品目录的描述性数据。对于键值存储模型来说,这是一个很好的例子,在这里,我们通过一个众所周知的键值(如产品ID)查找一系列的数据。很多内存缓存都使用键值对数据模式去支持大规模的快速读取。

服务C可能主要关注半结构化内容,例如Web站点的表单或页面,而文档存储可能非常适合该类型数据。文档存储与键值存储有许多相似之处,但是一个关键的区别是文档型数据支持数据上增加结构,例如对特定属性进行索引以支持快速检索。

服务D可能涉及数据之间的复杂关系导航,例如客户数据和与组织中各部门的客户联系历史数据。这可能涉及其他服务所拥有的数据类型之间的关系。这是一个有趣的案例,因为它开始与上面提到的服务有各自的数据类型的约束相反。在这种情况下,你可以选择为你的服务创建一个具有对底层表的只读访问的图,然后通过这个“前门”处理所有的变化——即通过这个“前门”去调用那些“拥有”这些数据类型的其他服务的API。

最后,我们可能还有一个使用关系数据库技术的遗留系统或服务,或者我们有一个服务来管理那些数据量较少,或者不经常变更的数据。关系数据库可能完全适合于这些场景。

单个服务是否应该使用混合持久化?

也有可能的是,我们可以设计一个服务,这个服务需要多种数据库支撑。例如,我们可以创建一个使用键值存储模式作为索引的酒店服务,在酒店名称和ID之间实现映射,而存将关于酒店的描述性数据存储在Cassandra中。

注意,名称映射到ID可以在Cassandra中采用规范化的设计方法去实现,其中一个单独表去维护名称至ID的映射关系。这使用了更多的存储空间,但降低了管理单独键值存储的操作复杂性。

这是我推荐的做法- 针对某个微服务,只要可行,就应该坚持使用单一数据模型(数据库)。如果你发现一种情况,认为单个服务需要两个不同数据库支撑,那么请考虑该服务的粒度是否可能变得太大。你可能需要考虑将该服务拆分为较小的服务。

混合持久化局限性的权衡

混合持久化的主要缺点在于支持多种技术的成本,无论是在最初的开发阶段和将来的运营方面。

主要的开发成本,是在需要培训每个开发人员去掌握每个新的数据库技术。这是非常重要的,尤其是在开发人员频繁流动团队中。

另一个成本是支持多个数据库的操作成本。这会成为一个问题,尤其是当数据库是集中管理,并且团队必须在多种技术的掌握上维持高水平,但这在DevOps环境下,该问题并不会太突出,因为开发团队需要支持他们在生产环境中选择的数据库。

多模型数据库(Multi Model Databases)

作为另外的选择方案或混合持久化模式的补充, 数据库厂商已经开始建立和推广多模型的数据库。术语“模型”指的是数据存储所提供的核心抽象,如表(关系和非关系)、列存储、键值、文档或图。我们可以将一个多模型应用程序看作一个使用多个数据存储类型的应用程序,而多模型数据库是支持多个抽象模型的数据库。

DataStax企业版(DSE)是多模型数据库的典型例子,它核心支持Cassandra的分区行存储(表格)模型,同时也支持基于在其之上的图的抽象层(DSE图)。DSE在核心模型之上构建对应的键值和文档模型也是很简单的,如下图所示。这样,我们可以修改上面的混合持久化的方法,从而利用一个基础数据库引擎为我们所有的服务提供对应的服务,而使用单独的Cassandra keyspaces在不同服务拥有的数据间维护清晰的边界。

下面是它能实现的功能:

  • 表格:我们主要的应用服务A可以通过Cassandra的查询语言(CQL)直接和DSE的数据库打交道。
  • 键值对:虽然Apache和Cassandra的分布式版本DataStax都没有提供明确的键值对API,但是象服务B可以通过表设计去支持单个键值和列的方法,去访问
    Cassandra,例如:

    CREATE TABLE hotel.hotels (key uuid PRIMARY KEY,value text); // 或者选择blob类型
    
  • 文档型:Cassandra通过使用JSON文件支持文档型风格的数据,这可以用在服务C中。注意因为Cassandra需要针对表定义schema模式,所以不能插入新增任意的JSON列,这是一个可能通常和文档型数据库有关的特性。
  • 图:对于象服务D那样相关度很高的数据,DSE的图是一个高度可扩展的图形数据库,它构建于DSE数据库之上。DSE图支持来自Apache tinkerpop项目中强大的功能和表现力的Gremlin API。

多模型数据库的优点和限制

在考虑是否投资使用多模型数据库(或你已经在使用的数据库的多模型的特性)时,你要考虑我们前文讨论的关于混合持久化中,同样的开发和运营成本的问题。

使用多模型数据库可以让运营变得简单。即使不同的开发团队使用不同的API和不同的交互模式和后端数据库平台打交道,我们也只需要管理一个平台而已,从而提高了效率。

在选择多模型数据库时要考虑的一个问题是如何支持各种模型。一种常见的方法,是基于单一的原生的基础模型的数据库引擎,而其他模型都是构建在其之上。分层数据模型更能展现底层基本模型的特性。

例如,ThoughtWorks技术雷达第16期中,讨论了基于Cassandra构建的DSE图数据库的特性,并且也提到其中需要权衡的内容:

基于Cassandra 构建的DSE图数据库定位是大规模的数据集,相比之下我们长期喜爱的Neo4j开始表现出一定的局限性。这是需要取舍的;比如,你会失去了ACID的事务特性和Neo4j运行时的模式自由的特性,但却可以访问Cassandra的基础表,以及针对分析工作负载和Spark的整合,还有强大的TinkerPop/Gremlin查询语言可以使用,这的确是一个值得考虑的选择。

如果考虑Web应用中的各种数据类型,你可能会发现不同的数据类型对一致性有不同的需求,而且实际需要立即一致性的数据类型数量相对较少。

上面引用的ThoughtWorks的观点中,还提到了在考虑多模型数据库中另一个重要的因素 - 在不同的模型和数据引擎间的整合和交互问题,以及为访问数据的各种操作和分析的用例。DSE支持通过Spark(DSE分析)访问图数据以进行数据分析,并且DSE搜索引擎提供了针对DSE数据库中的数据创建各种查询索引的能力。

微服务数据模型操作的四个步骤

既然我们已经探讨混合持久化和多模型两种方式的优缺点,我们应该如何去决定哪些数据模型适用于大规模可扩展的微服务应用呢?可以按照以下步骤:

1、 识别你的应用程序中主要的数据类型,为其中每种类型创建一个服务,并让每个服务掌控相应的持久层。在可能的情况下,为所有服务都使用多模型数据库,允许服务在与数据交互的模型中是不相同的。

2 、用Tabular(例如DSE数据库)作为网络水平的可扩展性和可用性的主要模型,然后根据需要在此之上构建分层的键值对和文档数据模型。请务必考虑在操作和分析用例中访问数据的各种方法,以便提前计划如何将搜索索引和复制等特性用于数据分析中心。

3、用图的方法去表示(即DSE图)高度关联的数据,特别是在实体之间的关系有多个或多个属性,并且数量比实体自己的属性多的时候,或者需要在相同的实体之间捕捉多对多的关系的时候。

4、在不需要变更的情况下,保留关系数据库技术中的遗留投资。例如,当你的案例是需要大规模、低延迟和高可用性的时候,那就使用传统的关系型数据库吧。

我希望本文为读者提供了一个有用的框架,来考虑在应用程序中如何和怎么样去支持多数据模型,以及何时考虑使用多模型数据库。

Jeff Carpenter是在DataStax公司的技术传道者,他利用自己在系统架构、微服务和Apache Cassandra的知识去帮助开发者和运营工程师去构建可扩展的、可靠的,安全的分布式系统。Jeff是<< Cassandra:权威指南 第二版》的作者。

微服务数据库设计 单独的数据库: 单独的数据库微服务设计的⼀个关键是数据库设计,基本原则是每个服务都有⾃⼰单独的数据库,⽽且只有微服务本⾝可以访问这个数据库。它是基于下 ⾯三个原因。 优化服务接⼝:微服务之间的接⼝越⼩越好,最好只有服务调⽤接⼝(RPC或消息),没有其他接⼝。如果微服务不能独享⾃⼰的数据 库,那么数据库也变成了接⼝的⼀部分,这⼤⼤拓展了接⼝范围。 错误诊断:⽣产环境中的错误⼤部分都是和数据库有关的,要么是数据出了问题,要么是数据库的使⽤⽅式出了问题。当你不能完全控 制数据库的访问时,会有各种各样的错误发⽣。它可能是别的程序直接连到你的数据库或者是其他部门直接⽤客户端访问数据库的数 据,⽽这些都是在程序中查不到的,增加了错误排查难度。如果是程序中的问题,只要修改了代码,那么这个错误就不会再有。⽽上⾯ 提到的错误,你永远都没法预测它们什么时候还会再次发⽣。 性能调优:性能调优也是⼀样,你需要对数据库有全权控制才能保证它的性能。如果其他部门⼀定要访问数据库,⽽且只是查询的话, 那么可以另外创建⼀份只读数据库,让他们在另⼀个库中查询,这样才不会影响到你的库。 理想的设计是你的数据库只有你的服务能访问,你也只调⽤⾃⼰数据库中的数据,所有对别的微服务的访问都通过服务调⽤来实现。当然, 在实际应⽤中,单纯的服务调⽤可能不能满⾜性能或其他要求,不同的微服务都多少需要共享⼀些数据。 共享数据: 共享数据微服务之间的数据共享可以有下四种⽅式。 静态表: 静态表: 有⼀些静态的数据库表,例如国家,可能会被很多程序⽤到,⽽且程序内部需要对国家这个表做连接(join)⽣成最终⽤户展⽰数据,这样 ⽤微服务调⽤的⽅式就效率不⾼,影响性能。⼀个办法是在每个微服务中配置⼀个这样的表,它是只读的,这样就可以做数据库连接了。当 然你需要保证数据同步。这个⽅案在多数情况下都是可以接受的,因为以下两点: 1. 静态的数据库表结构基本不变:因为⼀旦表结构变了,你不但要更改所有微服务数据库表,还要修改所有微服务的程序。 2. 数据库表中的数据变化不频繁:这样数据同步的⼯作量不⼤。另外当你同步数据库时总会有延迟,如果数据变化不频繁那么你有很多 同步⽅式可供选择。 只读业务数据访问: 只读业务数据访问: 如果你需要读取别的数据库⾥的动态业务数据, 理想的⽅式是服务调⽤。如果你只是调⽤其他微服务做⼀些计算,⼀般情况下性能都是可 以接受的。如果你需要做数据的连接,那么你可以⽤程序代码来做,⽽不是⽤SQL语句。如果测试之后性能不能满⾜要求,那你可以考虑在 ⾃⼰的数据库⾥建⼀套只读数据表。数据同步⽅式⼤致有两种。如果是事件驱动⽅式,就⽤发消息的⽅式进⾏同步,如果是RPC⽅式,就⽤ 数据库本⾝提供的同步⽅式或者第三⽅同步软件。 通常情况下,你可能只需要其他数据库的⼏张表,每张表只需要⼏个字段。这时,其他数据库数据的最终来源,控制所有写操作以及相应 的业务验证逻辑,我们叫它主表。你的只读库可以叫从表。 当⼀条数据写⼊主表后,会发⼀条⼴播消息,所有拥有从表的微服务监听消息 并更新只读表中的数据。但这时你要特别⼩⼼,因为它的危险性要⽐静态表⼤得多。第⼀它的表结构变更会更频繁,⽽且它的变更完全不受 你控制。第⼆业务数据不像静态表,它是经常更新的,这样对数据同步的要求就⽐较⾼。要根据具体的业务需求来决定多⼤的延迟是可以接 受的。 另外它还有两个问题: 1. 数据的容量:数据库中的数据量是影响性能的主要因素。因为这个数据是外来的,不利于掌握它的流量规律,很难进⾏容量规划,也 不能更好地进⾏性能调优。 2. ** 接⼝外泄**:微服务之间的接⼝本来只有服务调⽤接⼝,这时你可以对内部程序和数据库做任何更改,⽽不影响其他服务。现在数 据库表结构也变成了接⼝的⼀部分。接⼝⼀旦发布之后,基本是不能更改的,这⼤⼤限制了你的灵活性。幸运的是因为另外建了⼀套 表,有了⼀个缓冲,当主表修改时,从表也许不需要同步更新。 除⾮你能⽤服务调⽤(没有本地只读数据库)的⽅式完成所有功能,不然不管你是⽤RPC⽅式还是事件驱动⽅式进⾏微服务集成,上⾯提到 的问题都是不可避免的。但是你可以通过合理规划数据库更改,来减少上⾯问题带来的影响,下⾯将会详细讲解。 读写业务数据访问: 读写业务数据访问: 这是最复杂的⼀种情况。⼀般情况下,你有⼀个表是主表,⽽其他表是从表。主表包含主要信息,⽽且这些主要信息被复制到从表,但微服 务会有额外字段需要写⼊从表。这样本地微服务对从表就既有读也有写的操作。⽽且主表和从表有⼀个先后次序的关系。从表的主键来源于 主表,因此⼀定先有主表,再有从表。 上图是例⼦。假设我们有两个与电影有关的微服务,⼀个是电影论坛,⽤户可以发表对电影的评论。另⼀个是电影商店。"movie"是共享
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值