设计键值存储(第二部分)

原文:Design a Key-Value Store (Part II)

译者:飞龙

协议:CC BY-NC-SA 4.0

自豪地采用谷歌翻译

这是设计键值存储系列文章的第二篇文章。 如果你还没有阅读第一篇文章,请查看它。

在我们之前的文章中,我们主要关注的是键值存储的基本概念,特别是单机场景。 当涉及扩展问题时,我们需要通过一些规则将所有数据分配到多台机器,协调机可以将客户机引导到拥有所请求资源的机器。

设计分布式系统时需要考虑很多事情。 在将数据分到多台机器时,平衡流量很重要。 这就是最好确保键是随机分布的原因。

在这篇文章中,我们将继续讨论分布式键值存储系统。 我们将讨论系统可用性,一致性等主题。

系统可用性

要评估分布式系统,一个关键指标是系统可用性。例如,假设我们的一台计算机出于某种原因崩溃(可能是硬件问题或程序错误),这对我们的键值存储系统有什么影响?

显然,如果有人从这台机器请求资源,我们将无法返回正确的响应。建立业余项目时你可能不会考虑这个问题。但是,如果你使用大量服务器服务数百万用户,则会经常发生这种情况,你无法每次都手动重新启动服务器。这就是为什么可用性在当今每个分布式系统中都是必不可少的。那么你将如何解决这个问题呢?

当然你可以用测试用例编写更健壮的代码。但是,你的程序总会有错误。另外,硬件问题更难以保护。最常见的解决方案是冗余。通过建立带有重复资源的机器,我们可以显着减少系统停机时间。如果一台机器每个月有 10% 的几率崩溃,那么使用一台备份机器,我们将两台机器都停机的概率降低到 1%。

冗余 VS 分片

乍一看,冗余与分片非常相似。那么这两者有什么关系呢?在设计分布式键值存储时,如何在冗余和分片之间进行选择?

首先,我们需要清楚这两种技术的目的。分片基本上用来分割数据到多台机器,因为一台机器不能存储太多的数据。冗余是保护系统免于宕机的一种方式。考虑到这一点,如果一台机器不能存储所有的数据,冗余就没有用。

冗余

通过引入冗余,我们可以使系统更健壮。但是,一致性是个问题。比如存在机器 A1,我们有冗余 A2。你如何确保 A1 和 A2 具有相同的数据?例如,当插入一个新条目时,我们需要更新两台机器。但其中一个写入操作可能失败。所以随着时间的推移,A1 和 A2 可能会有很多不一致的数据,这是一个很大的问题。

这里有几个解决方案。第一种方法是将本地副本保存在协调机中。无论何时更新资源,协调机都会保留更新版本的副本。因此,如果更新失败,协调员可以重新进行操作。

另一种方法是提交日志。如果你一直在使用 Git,那么提交日志的概念对你来说应该是相当熟悉的。基本上,对于每个节点机器,它将保留每个操作的提交日志,就像所有更新的历史一样。所以当我们想要更新机器 A 中的条目时,它会首先将这个请求存储在提交日志中。然后一个单独的程序将按顺序处理所有提交日志(在队列中)。每当一个操作失败时,我们可以很容易地恢复,因为我们可以查找提交日志。

我想介绍的最后一种方法是解决读取中的冲突。假设当请求的资源位于 A1,A2 和 A3 时,协调机可以请求所有三台机器。如果数据不同,系统可以即时解决冲突。

值得一提的是,所有这些方法都不是互斥的。基于应用程序你肯定可以使用多个。

读取吞吐量

在这篇文章中,我还想简单地提一下读取吞吐量。 通常,键值存储系统应该能够支持大量的读请求。 那么你将使用什么方法来提高读取吞吐量?

为了提高读取吞吐量,常用的方法是总是利用内存。 如果数据存储在每个节点机器的磁盘中,我们可以将其中的一部分移动到内存中。更普遍的想法是使用缓存。 由于设计缓存系统的文章已经深入分析了这个话题,所以在这里我就不多说了。

总结

不要把这里的分析看作标准答案。 相反,这些常见的解决方案应该给你灵感,来帮助你想出不同的想法。

没有适用于每个系统的解决方案,你应该总是根据特定的情况调整你的方法。