MIT6.824/lecture-08-zookeeper/8.3-xian-xing-yi-zhi-linearizability3.md
2022-01-25 02:41:31 +00:00

7.0 KiB
Raw Blame History

8.3 线性一致Linearizability3

这里还有另一个简单的请求历史记录的例子。假设我们先写X为1在这个请求完成之后有另一个客户端发送了写X为2的请求并收到了响应说写入完成。之后有第三个客户端发送了一个读X的请求得到了1。

这是一个很简单的例子它明显不是线性一致的因为线性一致要求生成的序列与实际时间匹配这意味着唯一可能的序列就是写X为1之后写X为2之后读X得到1。但是这个顺序明显违反了线性一致的第二个限制因为读X得到1的前一个写请求是写X为2这里读X应该返回2所以这里明显不是线性一致的。

我提出这个例子的原因是这是线性一致系统或者强一致系统不可能提供旧的数据的证据。为什么一个系统有可能会提供旧的数据呢或许你有大量的副本每一个副本或许没有看到所有的写请求或者所有的commit了的写请求。所以或许所有的副本看到第一个写请求也就是写X为1的请求但是只有部分副本看到了第二个写请求也就是写X为2的请求。所以当你向一个已经“拖后腿”的副本请求数据时它仍然只有X的值为1。然而客户端永远也不能在一个线性一致的系统中看到旧的数据也就是X=1因为一个线性一致的系统不允许读出旧的数据。

所以这里不是线性一致的,这里的教训是:对于读请求不允许返回旧的数据,只能返回最新的数据。或者说,对于读请求,线性一致系统只能返回最近一次完成的写请求写入的值。

好的我最后还有一个小的例子。现在我们有两个客户端其中一个提交了一个写X为3的请求之后是一个写X为4的请求。同时我们还有另一个客户端在这个时间点客户端发出了一个读X的请求但是客户端没有收到回复。

在一个实际的系统实现中,可能有任何原因导致这个结果,例如:

  • Leader在某个时间故障了
  • 这个客户端发送了一个读请求但是这个请求丢包了因此Leader没有收到这个请求
  • Leader收到了这个读请求并且执行了它但是回复的报文被网络丢包了
  • Leader收到了请求并开始执行在完成执行之前故障了
  • Leader执行了这个请求但是在返回响应的时候故障了

不管是哪种原因从客户端的角度来看就是发送了一个请求然后就没有回复了。在大多数系统的客户端内部实现机制中客户端将会重发请求或许发给一个不同的Leader或许发送给同一个Leader。所以客户端发送了第一个请求之后没有收到回复并且超时之后或许在这里发送了第二个请求。

之后终于收到了一个回复。这将是Lab3的一个场景。

服务器处理重复请求的合理方式是服务器会根据请求的唯一号或者其他的客户端信息来保存一个表。这样服务器可以记住我之前看过这个请求并且执行过它我会发送一个相同的回复给它因为我不想执行相同的请求两次。例如假设这是一个写请求你不会想要执行这个请求两次。所以服务器必须要有能力能够过滤出重复的请求。第一个请求的回复可能已经被网络丢包了。所以服务器也必须要有能力能够将之前发给第一个请求的回复再次发给第二个重复的请求。所以服务器记住了最初的回复并且在客户端重发请求的时候将这个回复返回给客户端。如果服务器这么做了那么因为服务器或者Leader之前执行第一个读请求的时候可能看到的是X=3那么它对于重传的请求可能还是会返回X=3。所以我们必须要决定这是否是一个合法的行为。

你可能会说客户端在这里发送的重传请求这在写X为4的请求之后所以你这里应该返回4而不是3。

这里取决于设计者但是重传本身是一个底层的行为或许在RPC的实现里面或许在一些库里面实现。但是从客户端程序的角度来说它只知道从第一条竖线的位置发送了一个请求

并在第二条竖线的位置收到了一个回复,

这是从客户端角度看到的所有事情。所以返回X为3是完全合法的因为这个读请求花费了一个很长的时间它与写X为4的请求是完全并发的而不是串行的。

因此对于这个读请求返回3或者4都是合法的。取决于这个读请求实际上是在这里执行

还是在这里执行。

所以,如果你的客户端有重传,并且你要从客户端的角度来定义线性一致,那么一个请求的区间从第一次传输开始,到最后应用程序实际收到响应为止,期间可能发生了很多次重传。

学生提问:如果客户端想要看到的是最新的数据而不是旧数据呢?

Robert教授你在这里宁愿得到最新的数据而不是老旧的数据。假设这里的请求是查询当前时间我向服务器发送个请求说现在是几点服务器返回给我一个响应。现在如果我发送了一个请求2分钟过去了因为网络问题我还没收到任何回复。或许应用程序更喜欢看到的回复是更近的时间而不是很久之前开始发送请求的时间。现在事实是如果你使用一个线性一致的系统你必须要实现能够容纳线性一致规则的程序。你必须写出正确的应用程序来容忍这样一个场景应用程序发出了一个请求过了一会才收到回复比如在这里如果我得到了一个值是3的回复这对于应用程序来说可能不能接受这个值。因为这意味着我在收到响应的时候系统中X存储的值是3这与事实不符实际上X=4。所以这里最终取决于应用程序本身。

你们在实验中会完成这样的机制,服务器发现了重复的请求,并将之前的回复重新发给客户端。这里的问题是,服务器最初在这里看到了请求,最后回复的数据是本应在之前一个时间点回复的数据,这样是否合理?我们使用线性一致的定义的一个原因是,它可以用来解释问题。例如,在这个场景里面,我们可以说,这样的行为符合线性一致的原则。

好的,这就是所有我想介绍的有关线性一致的东西。在期中测试我必然会问一个线性一致的问题。