当前位置: 首页 > 科技观察

如何使用MongoDB实现高性能、高可用的双活应用架构?

时间:2023-03-16 12:01:05 科技观察

【原创.com】投资界有一句至理名言——“不要把所有的鸡蛋放在一个篮子里”。都说投资需要分解风险,才不会在孤注一掷后造成巨大损失。随着企业服务窗口的不断增加,业务中断对很多企业来说意味着毁灭性的灾难。因此,跨多个数据中心的应用部署成为当前最热门的话题之一。如今,在跨多个数据中心部署应用程序的最佳实践中,数据库通常负责处理跨多个地理区域的读写、复制数据更改,并提供尽可能高的可用性、一致性和持久性。然而,并非所有技术的选择都是平等的。例如,一种数据库技术可以提供更高的可用性保证,但同时只能提供比另一种技术更低的数据一致性和持久性保证。本文首先分析了现代多数据中心对数据库架构的需求。然后讨论了数据库架构的类型及其优缺点,最后研究了MongoDB如何适用于这些类别,最终实现了双活应用架构。双活需求当组织考虑跨多个数据中心(或区域云)部署应用时,通常希望使用“双活”架构,即所有数据中心的应用服务器同时处理所有请求。图1:“主动-主动”应用程序架构如图1所示。该架构可以实现以下目标:通过提供本地处理(具有较低的延迟)来为全局请求提供服务。即使在整个区域停机的情况下也能保持高可用性。通过并行使用多个数据中心的服务器资源,处理各种应用请求,实现平台资源的优化利用。“主动-主动”架构的替代方案是主-容灾(也称为主-被动)架构,由一个主数据中心(区域)和多个灾难恢复(DR)区域组成(如图2所示)。图2:主DR架构在正常操作条件下,主数据中心在DR站点空闲时处理请求。如果主数据中心发生故障,灾难恢复站点会立即开始处理请求(同时变为活动状态)。通常,数据从主数据中心复制到灾难恢复站点,这样如果主数据中心发生故障,可以快速进行接管。如今,双活架构的定义在业界还没有得到普遍认同,上述双活应用架构有时也算作“双活”。不同之处在于从主站点到DR站点的故障转移是否足够快(通常为秒级)并且可以自动化(无需人工干预)。在这种解释中,主动-主动架构意味着应用程序停机时间接近于零。有一个普遍的误解,认为双活应用程序架构需要多主数据库。这种理解是错误的,因为它扭曲了对多主库的数据一致性和持久化的把握。一致性保证之前写入的结果可以被读取,而数据持久化保证提交的写入数据能够完整保存,不会发生写入冲突;或由于节点故障导致数据丢失。双活应用的数据库需求在设计双活应用架构时,数据库层必须满足以下四种架构需求(当然,还必须具备标准数据库的功能,如具有丰富二级索引的查询语言功能、低延迟访问数据、本机驱动程序、综合操作工具等):性能、低延迟读写操作。这意味着:可以在本地数据中心的应用程序的节点上处理读写操作。数据持久性,通过将写入复制到多个节点来实现,以便在系统发生故障时数据保持不变。一致性,保证之前写入的结果是可以读到的,不同地域、不同节点读到的结果应该是一样的。可用性,当一个节点、数据中心或网络连接丢失时,数据库必须继续运行。另外,这类故障恢复的时间要尽量短,一般要求是几秒。分布式数据库架构对于双活应用架构,一般有以下三种数据库结构:采用两步提交的分布式事务。多主数据库模型有时被称为“无主数据库模型”。拆分(分片)数据库有多个主分片,每个分片负责一个独特的数据片。让我们来看看每种结构的优缺点。两步提交的分布式事务方法是在单个事务中更新所有包含记录的节点,而不是在写入一个节点后(异步)复制到其他节点。该事务保证所有节点都将收到更新,否则如果事务失败,所有节点都将恢复到之前的状态。两步提交协议虽然可以保证持久性和多节点一致性,但是牺牲了性能。两步提交协议要求事务中所有参与节点之间进行两步通信。即在操作的每个阶段,发送请求和确认以确保每个节点同时完成了相同的写入。当数据库节点分布在多个数据中心时,查询延迟将从毫秒级延长到秒级。在大多数应用程序中,尤其是那些客户端是用户设备(移动设备、Web浏览器、客户端应用程序等)的应用程序,这种响应级别是不可接受的。多主数据库多主数据库是一种分布式数据库,它只允许在一个集群节点上更新记录。写入操作通常将记录复制到多个数据中心的多个节点。从表面上看,多主数据库应该是实现双活架构的理想方案。它使每个应用程序服务器都可以不受限制地读取和写入数据的本地副本。但是,它在数据一致性方面有严重的局限性。由于同一记录的两个(或更多)副本可能由不同位置的不同会话同时更新。这会导致同一记录的两个不同版本,因此数据库(有时是应用程序本身)必须通过解决冲突来解决不一致问题。常用的冲突解决策略是:最近的更新“胜”,或者修改次数较多的记录“胜”。因为如果使用其他更复杂的解析策略,性能将受到显着影响。这也意味着在写入和冲突解决机制完成之间,不同的数据中心会为同一条记录读取不同且冲突的值。分区(分片)数据库分区数据库将数据库划分为不同的分区或分片。每个分片由一组服务器实现,每个服务器包含分区数据的完整副本。这里的关键是每个分片都保持对数据分区的独占控制。对于任何给定时间的每个分片,一台服务器充当主服务器,其他服务器充当其副本。数据读写被发布到主数据库。如果主服务器由于任何原因(例如硬件或网络故障)出现故障,备份服务器会自动接管主服务器的角色。数据库中的每条记录都属于一个特定的分区,并由一个分片管理,以确保它只被主分片写入。分片内的记录被映射到每个分片的主分片以确保一致性。由于集群包含多个分片,因此会有多个主分片(多个主分区),因此可以将这些主分片分配到不同的数据中心,以保证它们在每个数据中心本地都是可用的。写入操作发生,如图3所示:图3:分区数据库分片数据库可用于通过部署至少与数据中心一样多的分片并为分片分配主次分片来实现双活应用程序架构。分片,这样每个数据中心至少有一个主分片,如图4所示:图4:带有分片数据库的双活架构有一个副本(数据的副本)。例如,图4中的图表描绘了跨三个数据中心的分布式数据库架构:纽约(NYC)伦敦(LON)悉尼(SYD)集群具有三个分片,每个分片具有三个副本:NYC分片在有一个纽约的主分片和伦敦和悉尼的副本。LON分片在伦敦有一个主分片,在纽约和悉尼有副本。SYD分片在悉尼有一个主分片,在伦敦和纽约有副本。这样,每个数据中心都有来自所有分片的副本,因此本地应用程序服务器可以读取整个数据集和一个分片的主分片以进行本地写入。分片数据库可以满足大多数使用场景的一致性和性能需求。由于读写都发生在本地服务器上,性能会非常好。从主分片读取时,一致性得到保证,因为每条记录只能分配给一个主分片。例如:我们在美国新泽西州和俄勒冈州有两个数据中心,那么我们可以按照地理区域(东部和西部)拆分数据集,将东海岸的用户流量路由到数据中心在新泽西州。因为该数据中心包含主要用于东部的分片;并将西海岸用户的流量路由到俄勒冈数据中心,因为该数据中心主要包含西部的分片。我们可以看到,分片数据库为我们提供了多个主数据库的所有好处,而没有数据不一致的复杂性。应用服务器可以从本地主服务器读写,由于每个主服务器都有自己的记录,不会出现不一致的情况。相反,多主数据库的方案可能会造成数据丢失和读取不一致。数据库架构比较图5:数据库架构比较图5提供了每种数据库架构在满足双活应用程序要求时的优缺点。在选择多主数据库和分区数据库时,决定因素是应用程序是否可以容忍可能的读取不一致和数据丢失。如果答案是肯定的,那么多主数据库可能更容易部署。如果答案是否定的,那么分片数据库是最好的选择。由于不一致和数据丢失对于大多数应用程序来说是不可接受的,因此分片数据库通常是最佳选择。MongoDB主动-主动应用程序MongoDB是分片数据库架构的一个例子。在MongoDB中,构建一组主服务器和从服务器的集合称为副本集。副本集为每个分片提供高可用性。称为区域分片的机制被配置为由每个分片管理的数据集。前面说了ZoneSharding可以实现地理分区。白皮书《MongoDB多数据中心部署》:https://www.mongodb.com/collat??eral/mongodb-multi-data-center-deployments?utm_medium=dzone-synd&utm_source=dzone&utm_content=active-application&jmp=dzone-refZoneSharding相关文档:https:///docs.mongodb.com/manual/tutorial/sharding-segmenting-data-by-location//的“分区(分片)数据库”部分//描述了MongoDB如何工作和实现它的细节。事实上,许多组织,包括:Ebay、YouGov、Ogilvy和Maher都在使用MongoDB来实现双活应用程序架构。除了标准的分片数据库功能外,MongoDB还提供对写入持久性和读取一致性的细粒度控制,使其成为多数据中心部署的理想选择。对于写入,我们可以指定写入关注点来控制写入的持久性。Writeconcern允许应用程序在MongoDB确认写入之前指定要写入的副本数,以便写入操作可以在一个或多个远程数据中心的服务器上完成。通过这样做,它可以确保在节点或数据中心发生故障时不会丢失对数据库的更改。此外,MongoDB还弥补了分片数据库的一个潜在劣势:写入可用性无法达到100%。由于每条记录只有一个主节点,如果该主节点发生故障,将在一段时间内无法写入分区。MongoDB通过多次重试写入大大减少了故障转移时间。通过多次写入尝试,MongoDB可以自动应对网络故障等临时系统错误导致的写入失败,从而大大简化了应用程序中的代码量。MongoDB另一个适合多数据中心部署的显着特点是MongoDB自动故障转移的速度。当节点或数据中心发生故障或网络中断时,MongoDB可以在2-5秒内进行故障转移(当然取决于其配置和网络本身的可靠性)。失败后,剩余的副本集会根据配置选择新的主分片和MongoDB驱动,自动识别新的主分片。一旦故障转移完成,其恢复过程将自动执行后续的写操作。对于读取,MongoDB提供了两个函数来指定所需的一致性级别。首先,当从二级数据读取时,应用程序可以指定最大陈旧值(maxStalenessSeconds)。这样就保证了从节点从主节点复制过来的滞后时间不能超过指定的老化值,从而使从节点返回的数据有它的时效性。另外,读也可以关联一个读关注点(ReadConcern)来控制查询返回数据的一致性。例如,ReadConcern可以使用一些返回值来告诉MongoDB数据已经复制到副本集中的大多数节点。这可确保查询仅读取未因节点或数据中心故障而丢失的数据,并为应用程序提供随时间推移的一致数据视图。MongoDB3.6还引入了“因果一致性”的概念,以确保客户端会话中的每个读操作始终只“关注”前一个写操作是否已完成,而不管是哪一个。副本正在为请求提供服务。这种因果一致性通过在会话中强制执行严格的操作因果顺序来确保每次读取始终在逻辑上一致,从而在分布式系统中启用单调读取。而这正是各种多节点数据库无法满足的。因果一致性不仅让开发者在传统单节点关系型数据库的实现过程中保留了数据严格一致性的优势;在数据平台上。JulianChen在IT项目、企业运维、风险管控等领域拥有十余年经验,日常工作深入系统安全的各个环节。作为CISSP证书持有者,他在各种专业期刊上发表了《IT运维的“六脉神剑”》、《律师事务所IT服务管理》、《股票交易网络系统中的安全设计》的论文。他也持续分享和更新《廉环话》系列博文和各种外文技术翻译。曾被评为“信息安全实践者”、Future-S2015中国IT治理与管理实践者。【原创稿件,合作网站转载请注明原作者和出处为.com】