为正确的案例选择正确的模式
困惑的特德恳求说:"很难相信这是不可能的。""这是2020年;当然,必须有另一种方式"。
这是Acme Widgets的教学时刻。他们技术堆栈中的数据库发生故障,并导致许多服务中断。首席技术官泰德(Ted)召集了高级技术领导人紧急会议,以制定战术和长期解决方案的行动方案。他想到的解决方案之一是将所有数据库转换为主动-主动模式,其中没有共享资产,并且在地理上分散以降低风险。但没有更改应用程序。所有人都把目光投向了新任命的首席建筑师简(Jane)的观点。令所有人大吃一惊的是,Jane平静地宣布,如果不进行应用程序重构,并非所有数据库都可以是Active-Active Shared-Nothing(AASN)。而且,她还解释说,对于某些人来说,这是不可能的,甚至对于某些人来说,甚至是不需要的。
对于简来说,这不是新情况。在加入Acme之前,作为许多组织的数据负责人,她不得不教育其他许多技术领导者关于数据弹性的细微差别,这与应用程序弹性不同。
她从过去的经验中知道,用清晰的例子说明可以做什么可以是证明对Acme最好的观点的最佳方法。
Jane宣布,首先要做的就是正确定义AASN。这意味着两个不同地理存储中的数据库的两个副本,具有相同的数据,都为在该数据中心中运行的应用程序的副本提供服务,如下图所示。
应用程序A1和A2只是在两个不同区域(R1和R2)中运行的同一应用程序的副本。数据库D1和D2是在不同区域中运行的同一数据库的副本。数据库是双向复制的,因此对一个数据库的更改会在另一个数据库中保留。A1连接到D1,而A2仅连接到D2。数据库D1和D2的副本彼此之间不共享任何内容。
Jane提醒他们,它们之间没有共享,因此诸如Oracle Real Application Clusters(https://www.oracle.com/database/technologies/rac.html)之类的系统共享存储或严重依赖于同步共享存储系统-不符合条件。从可用性的角度来看,它们可以彼此完全独立,因此带来了弹性。但是,简强调说,这并非总是可能的,而且在许多情况下甚至不是必需的。
"不需要?"困惑的Ted问道:"等等,我们必须要有数据库的高可用性,不是吗?"
"是的,我们愿意。"简回答。 " AASN数据库架构通常与高可用性混为一谈;但它们是不同的概念。"可能在不同地理区域中的"热"备用数据库在数据层中实现高可用性。当当前主数据库发生故障时,备用数据库将接管,从最后一个事务开始。使用适当的技术和良好的体系结构,可以将恢复点目标降低为0,即在主要故障期间不会丢失任何数据。不幸的是,经常会出现电力不足的可能性,即非常小的但可察觉的时间段,在此期间没有数据库可用于正常服务。使用适当的体系结构,可以将系统中断或掉电时间减少到接近零。但是,她警告说这是关键,除非在非常特殊的情况下,否则通常不可能将热备用数据库指定为也可用的活动数据库。因此,该系统具有很高的可用性。但不能称为有效/有效。
"我明白你的意思了," Ted同意。"我们可以提供高可用性,但不一定是主动/主动,没有共享资产。"
那么,在听众沉思的情况下,我们如何才能开发出一个真正的主动/主动架构,在数据库层中没有共享资产?只要我们谨慎处理这个问题,Jane就会回答,并且不要指望一种尺寸能满足所有说明性的解决方案,在许多情况下这可能是可能的。在本文中,您将学习Jane解释的各种AASN数据库系统模式,以及它们必须伴随的体系结构考虑。
"您提到AASN在许多应用中都是不可能的," Ted询问。"你能解释这些情况吗?"
Jane解释说,关键是仔细的应用程序设计,尤其是应用程序是无状态的,不需要交叉到数据库的另一个副本进行验证。在需要维护应用程序状态的地方,例如在电子商务订单更新的情况下,数据库中的AASN体系结构会带来巨大的数据完整性风险。实施AASN数据库层的理想方案是在只读数据库的情况下,其中应用程序的状态不会更改或更改,但是最终一致的状态是可以接受的。Jane警告,在后一种情况下,应用程序需要了解并且应该能够处理在数据库副本上进行相冲突的更改的可能性。
观众敦促她扩大应用程序需要做的事情。Jane继续:应用程序需要了解AASN数据库层的三个约束:
· 最终,不是立即,一致的数据存储。
· 由于两个副本中同一记录中发生更改,因此可能存在冲突。
· 由于一个更新在另一副本的更新发生冲突之后延迟更新,因此可能导致数据损坏。
简继续讲述这些方法。首先,她谈到了主动/被动无共享(APSN)架构,并强调了"被动"一词。这是数据库层中传统上公认的APSN架构视图:
在此图中,A1和A2是分别在区域R1和R2中运行的同一应用程序的两个实例,并连接到数据库D1(主数据库)和D2(备用数据库)。数据库D2是D1的热备用数据库,它通过某种类型的数据库复制技术不断更新。当区域R1发生故障时,结果数据库D1发生故障。数据库D2仅承担主要数据存储区的责任。区域R1发生故障后,D2成为主要区域,应用程序负载平衡器将流量发送到该区域。在任何时间点,主数据只有一个副本。
但是,在负载平衡器可以将流量发送到应用程序A2之前,它必须确保备用数据库已完全适应对数据库D1所做的更改。无论多么小,该时间段仍可被应用程序感知到,称为欠压期。简解释说,电力不足的持续时间完全取决于对数据库D1所做的更改,在无活动或活动较少的时间段内可能为零。
但是,观众想知道,是否可以消除掉电期?
简明确指出,可以消除数据库层的限电期。但是为了确保同步不落后,复制必须是同步的。虽然这听起来不错,但实际上它有两项惩罚,我们必须考虑:
· 由于必须使用非常低延迟的介质来传输数据,因此它通常非常昂贵,尤其是跨区域时。
· 这会增加应用程序的性能开销,因为在将提交响应发送到应用程序之前,数据库必须从D1和D2都获得确认。
因此,数据库复制通常是异步的,因此某种程度的掉电是不可避免的。
这使期望快速回答的听众的情绪受到抑制。简继续叙述。区域R1恢复后,将开始反向复制。
Jane提请观众注意以下事实:在这种体系结构中,只有一个"主"数据副本。另一个副本始终只是备用副本。这消除了数据存储之间发生冲突的任何可能性。另一方面,Active-Active Shared-Nothing数据存储区假定两个数据存储区始终都是主存储区,并且复制双向进行,而应用程序负载平衡器向这两个方向发送流量。这样,当区域R1出现故障时,负载均衡器仅停止向该负载均衡器发送流量,而D1中的所有更改都已在D2中可用,因此没有掉电期。
"太棒了!"宣布激动的特德。"为什么我们不能仅将数据存储从主动-被动共享-无转换为主动-主动共享-无?为什么我们需要更改应用程序?"
简解释道,这就是问题所在。根据应用程序打算执行的操作,它可能根本无法运行,或者可能在无提示数据损坏的情况下运行。这就是我们要提防的问题。
这两个词像空中的剑一样悬在空中,"可能无法运行"和"无声的数据损坏"。
"请解释,"特德对此很感兴趣。
但是在进一步解释之前,Jane希望读者了解数据管理的一些基础知识。
Jane提出了一个供听众思考的问题:"当我们将相同数据的多个副本存储在两个数据存储中以解决单个副本的故障时,当一个副本发生故障时会发生什么?"其他副本是否处于可以立即承担故障操作的状态?它们可能会,也可能不会,取决于架构。这就是CAP定理的规则-一致性,可用性和分区容限(https://en.wikipedia.org/wiki/CAP_theorem)—出现的地方。
一致性:如果不同数据存储中有多个数据副本,那么它们是否在任何时间点都彼此100%同步?如果这样,他们需要一个高速,低延迟的网络。但是由于现在从所有数据存储中获取提交确认的时间越来越长,因此会对应用程序的性能产生负面影响。
可用性:如果一个数据存储不可用,则其他副本可以接管该应用程序以使其获得非错误响应的方式。请记住,这仅仅是数据存储区对应用程序的响应。那里可能没有最新的更新。
分区容限:当删除数据存储副本之间的消息时,应用程序仍可以运行吗?这不能保证尚存的副本都已同步。
简解释说,CAP定理指出,在任何设计中,我们只能拥有这三个属性中的两个。不是全部三个。
她解释说,解决这个问题的另一种方法是通过下面显示的维恩图。请注意,在某些地方,三个属性中的两个重叠了。但是这三个空间都没有汇合的空间。简强调说,非常重要的一点是要理解这三者不可能完全融合。例如,如果我们追求一致性,就无法设计可用性。但是当副本丢失时会发生什么呢?恢复副本后,我们必须暂停数据存储上的操作,直到我们可以将新恢复的副本与尚存的副本同步。否则,新启动的分区将不一致,从而违反了CAP中的" C"。
因此,观众问,如果副本不一致,维护副本的意义何在?
维护副本只是意味着数据存储异步同步。因此它们最终将保持同步。但是在给定的时间点,系统无法保证数据存储100%同步。这称为最终一致性,而不是立即一致性。欣赏差异至关重要。
为了说明这一点,Jane向他们展示了一个数据系统的示例体系结构,该体系结构具有三个数据存储,这些数据存储满足CAP定理中的A和P,从而使C排除在外,即最终保持一致。
她解释了这种情况:假设数据元素的值为1,最初在所有三个数据存储区中都相同。现在,应用程序A2将值更新为2。由于该体系结构优先考虑可用性和分区容忍度而不是一致性,因此其他两个数据存储区可能尚未更新。此时,如果应用程序A3读取数据元素,则它可能会获得值1,而不是2,这是最近的值。在许多情况下,最新的价值不仅是理想的,而且是绝对必要的,这可能是不可接受的。例如在电子商务订单中。数据存储区D3最终将获得更新后的值3;但不是立即。
简解释了第二个问题。她考虑另一种情况,如下图所示。我们像以前一样从原始值1开始,应用程序A2在数据存储区D2中将其更新为2。但是在将其传播到所有其他数据存储区之前,连接到数据存储区D3的应用程序A3会将值更新为3。数据存储区D1中的值将是什么?
她警告说,由于数据复制是异步的,因此无法预测哪个更新将首先到达。如果从D2更新首先到达它,它将是2,否则将是3。在许多情况下,这种不可预测性可能是不可接受的。
对于D2,出现类似的问题。它应该忽略自己的更新并将元素更新为3吗?同样的问题也适用于D3。
Ted和听众现在对Active-Active Shared-Nothing体系结构的潜在问题有了清晰的了解。但他们大声怀疑,是否有任何技术可以避免这些问题,尤其是解决冲突?
Jane回答说,有解决冲突的方法,但是没有一种对应用程序的功能和数据准确性透明。以下是一些技术,按照从最小到最复杂的顺序实施:
· Last Man Standing:无论来源如何,都会应用最新更新。在上述情况下,假设消息以该顺序发生,则值3将同时应用于数据存储D1和D2。但是,可能存在竞争情况,其中更新将被级联多次。数据库系统通常具有内置的终止开关,以避免这些竞争情况。
· 时间戳权重:与最后一个站立的解决方案非常相似,但有一个警告。它不依赖于更新的顺序,而是检查更新的时间戳并仅沿时间戳比较更新。这要求将所有三个数据存储都与单个时间服务器同步(这在某种程度上侵蚀了"无共享"部分);但它可能更公平,并且避免了比赛条件。
· 位置权重:为每个数据存储分配一个权重。权重最高的存储的更新将获胜,并将应用于所有其他数据存储。在前面的示例中,如果D1,D2和D3的权重分别为300、200和100,则该值最终将为2,因为这是D2在权重为200时与D3在权重为100时的更新。因此,该值将在D3中更新为2,覆盖其自身的更改3。类似地,D1将重新更新为2。
· 应用程序权重:每个更新都用应用程序ID标记,并且每个应用程序也被加权。最终,权重最高的应用程序更改将被保存。
简在这里停下来指示观众思考这些技巧的影响。她说:"我们正在谈论放弃数据存储中的更改,然后将其替换为另一个。"无论选择哪种技术,对数据准确性的影响都非常大。我们必须从应用程序的设计中考虑到它;而不是数据存储架构。"
观众一直同意Jane一直以来的观点,但现在对可以做出哪种架构决定来利用ASN感到好奇。
Jane解释说,通常,数据存储根据其用途分为多种类型。
· 记录系统:数据存储区用作应用程序的记录系统。它必须是一致的,没有关于数据准确性的任何歧义或疑问。
· 参考系统:数据存储区用作数据的辅助系统,用于参考。分析存储属于此类别。机器学习,历史数据分析是在此数据存储上完成的。
· 只读:数据存储区用于只读活动,并且从未发生任何更新。
· 静态内容:数据存储区用于托管静态内容。示例包括用于网络媒体资源的托管图像和不经常更改的营销抵押品。
· 缓存:数据存储区用于在多个应用程序之间缓存数据,以加快访问速度,并且对延迟极为敏感。
· 会话状态:数据对于应用程序的特定会话而言是本地的,与该会话外部无关。例如,将用于用户交互的行为数据放入应用程序,购物车,Cookie等。
Jane继续说,数据库层中的主动-主动考虑可接受的体系结构模式取决于数据存储的使用情况。在频谱的最末端,会话状态数据存储区保存的数据仅与该会话相关,而在外部不可见。在其他位置创建数据存储的副本对应用程序无用,因为它无法从那里读取状态。因此,活动数据架构实际上不会增加任何价值,并且不相关。
读者同意甚至不需要数据库副本,更不用说主动-主动了,而是想知道它们可能与其他地方有关。Jane解释说,在其他一些情况下,例如在购物车数据存储区中,我们可能希望在数据存储区发生故障后继续保留数据。在这种情况下,辅助副本很有用,但不需要主动-主动架构。主动-被动数据库配置会有所帮助,因为该应用程序的新实例仅在其他位置停止使用该应用程序的旧实例(现在已失效)。
另一方面,"记录系统"数据存储区需要一致,明确且毫无疑问的准确数据,因此不太适合主动/主动数据存储。Jane解释说,如果使用AASN数据体系结构,则必须将应用程序设计为处理这种配置中不可避免的冲突。这些不是要解决的琐碎问题。"根据我的经验," Jane认为,"几乎所有SoR数据库都不适合AASN体系结构,而大多数都不适合。即使是那些可能的应用程序,也都需要非常激烈的应用程序重构,而且成本往往超过收益。"
现在,听众,尤其是特德,已经了解了简在这个问题上的原始沉默的本质。他表示:"很显然,诸如电子商务订单更新之类的SoR数据库不是AASN的理想选择。""另一方面,会话状态数据存储是完美的;但甚至不需要数据库的副本。但是在这两个极端之间的所有用例呢?要为所有这些人充分利用ASN,需要做什么?"
Jane解释说,介于这两种极端之间的其他模式可以受益于AASN数据存储,但必须能够解决以下两个问题:
· 解决冲突的策略是什么-上个男人站立,时间权重,地区权重或应用程序权重?
· 由于冲突解决,应用程序将如何应对数据的逻辑变化?
Acme应用程序开发负责人Debbie要求Jane在此方面做更多扩展。
Jane考虑了应用程序缓存的情况。如果两个数据存储区的更新方式不同,则在某些情况下缓存将具有不同的值。在大多数可以接受的缓存中,因为可以从记录系统确定地得出最终值。参考系统也遵循相同的模式。机器学习培训应用程序可能不受数据的微小更改的影响。大多数数据分析人员执行的汇总不会随数据的微小变化而发生重大变化。因此,在最终一致的状态下,他们可能会没事。
进一步扩展一下,Jane给出了另一个自助服务查找系统示例,以显示客户的订单历史记录。由于使用的是其他数据库,而不是记录系统的数据库,因此无论如何也无法保证数据的一致性。因此在多个副本之间发生数据漂移的可能性不会增加任何其他风险。但是,并非所有参考系统都以这种方式使用。如果该系统是记录系统的准确副本,则此条件失败。
"根据我的经验,"简认为,"除非有时间点数据可供参考,否则现实生活中不存在这样的系统。例如,想象一下在帐户查询系统的情况下,每天凌晨12:00(而不是现在)的帐户余额可用。AASN数据基础架构可以很好地处理它。"
她重申,这不仅仅是数据层的更改,AASN可能需要更改应用程序设计,甚至需要更改应用程序的业务意图。
既然Debbie理解了AASN数据层的细微差别,她想学习一些应用程序模式以利用它。
Jane解释说,设计的关键是一个问题:应用程序是无状态的还是有状态的?
通常,应用程序在单个执行线程中与数据存储进行多次交互。它需要数据库来维护应用程序的状态,还是应用程序需要对其进行跟踪?或者,应用程序是否假定每个数据库调用都独立于另一个?如果是后者,则称为无状态应用程序。使用Active-Active Shared-Nothing数据层更容易实现无状态应用程序。
简解释了这些模式:
数据存储区都是主数据库,即复制在它们之间双向进行。但是,Jane警告说,只有一个数据存储被标记为"活动"。如果失败,则可以使另一个主机处于活动状态;但在给定的时间点上只有一个处于活动状态。通过确保所有人都是主节点,我们可以改善掉电时间。通过让一位主节点成为主动,我们消除了冲突的可能性和相关的风险。
"您说过,我们改善了掉电时间,"黛比说,"并没有消除它们。为什么?"
简解释说:"那是因为复制是异步的,从而使另一个主复制可能滞后,甚至少或甚至为零。"
我们仅创建一个主节点,但创建多个副本以用于只读访问(因此不会在其中进行任何更新)。有些应用程序是纯只读的,可能会与任何读者相抵触。灾难发生后,我们可以将其中一位读者转变为一位读者,并将交易指向该位读者。由于没有主动-主动数据库,因此我们消除了冲突的可能性。但是,简警告说,激活读者需要一些时间。因此掉电时间比以前的模式要长一些。
这是上面显示的两种方法的组合,但有所不同。所有数据存储都是主数据,并且是主动-主动模式;但其中一个(数据库F)是一个超级主数据库,称为"进纸器"数据库。所有应用程序都连接到所有数据库并进行更新。为了保持一致性,为Feeder数据库分配了很高的权重,这使它自己的更新更多,并传播到其他主数据库。其他主节点也可以更新,但不那么频繁。简警告说,发生冲突的机会很小,但并未完全消除。如果存在冲突,则Feeder数据存储区中的更新将覆盖本地更改。
Jane opines,这可能是AASN的最实际用法。这里所有的数据库都是主数据库,但是我们没有使用数据库复制策略,而是使用应用程序直接更新它们。
Jane提请听众注意数据库D1和D2之间没有复制的事实。该应用程序独立更新两个数据库。由于没有数据库级别的复制,因此没有冲突的可能性,因此也没有随之而来的风险。就数据库技术而言,每个数据库都是单一的,即没有其他分区。因此CAP定理不适用。
Jane指出,模式4提出了一个不同的问题,因为数据库写入的次数很多。在获得所有数据库的确认之前,该应用程序无法继续。这可能会增加延迟问题,尤其是在应用程序是数据库聊天的情况下。为了解决这个问题,在模式5中,我们在两者之间使用了一个消息传递层。应用程序流传输到消息传递层而不是数据库。一个单独的过程从消息传递层中将其提取并写入多个主数据库。当对消息传递层的写操作完成时,应用程序将获得确认,因此它非常快。
黛比显然对这种模式感到兴奋。但是Jane警告说,虽然听起来比较简单,但是却增加了两个风险:
· 总体数据可用性有更多的延迟。当应用程序提交时,数据不会写入数据库。它是在其他进程将其拾取并写入数据库时写入的。
· 不能保证写入数据的顺序;因此可能存在数据一致性问题。
由于这些限制,Jane解释说,此模式最适合静态或不常更改的内容(缓存和参考系统),而不适合记录系统。
综上所述,Jane得出结论,"主动-主动-共享-无"数据库层体系结构的成功取决于数据库的类型,其使用情况以及应用程序处理数据更新冲突的能力和意愿。在数据库级别开启双向复制绝不是一个简单的情况,并且期望应用程序对此一无所知。通常,"记录系统"数据存储区最难实现,而"会话状态"数据存储区最容易。因此,Acme可以在许多系统上在数据库层上实现AASN,而无需更改应用程序,对于有些应用程序需要更改,而对于某些应用程序则完全不需要。对于某些类型的系统,在数据层中也不需要AASN,同时可以实现高可用性。
简在下表中对此进行了总结:
会议以紧张的音调开始;但最后对问题和可能的解决方案有了清晰的理解和赞赏。特德(Ted)非常感谢简,并宣布休会。
· AASN体系结构意味着数据存储在地理上分布,它们之间没有共享资产,并且每个数据存储都愿意为本地运行的应用程序实例提供服务。
· 在大多数情况下,没有应用程序重构就无法完成AASN数据库层。
· 数据存储分为以下几种类型:记录系统,参考系统,只读,静态内容,缓存和会话状态。
· 并非所有数据存储都具有AASN配置。通常,在上述范围内,适合性从左到右从不适合到适合。
· 单个数据元素可能被两个不同区域中的两个不同应用程序更新,从而导致数据冲突。应用程序必须意识到这种可能性。即使重构后,并不是所有的应用程序都可以处理它。
· 几乎所有复制都是异步的,这意味着延迟的更新将覆盖较新的更新,从而导致数据损坏。
· 同步复制虽然可能,但是非常昂贵,而且通常不切实际。
· 在某些数据库技术中,数据存储并不立即彼此一致,而是最终彼此不一致。这意味着应用程序将根据连接到的副本获得不同的数据。
披露声明:©2020 Capital One。观点是个别作者的观点。除非本文中另有说明,否则Capital One不与任何提及的公司有附属关系或认可。使用或显示的所有商标和其他知识产权均为其各自所有者的财产。
(本文由闻数起舞翻译自Duong Nguyen的文章《Active-Active Shared-Nothing Database Architecture》,转载请注明出处,原文链接:https://medium.com/capital-one-tech/active-active-shared-nothing-database-architecture-304957ffb89)