# 数据的读取 Lease Read

![center](./student-guide/diagram/03-Lease-Read-01-01.png)
-------------------------------------------------------------
我们回顾一下刚才介绍的 ReadIndex Read，发现其中有一个步骤（第 2 步）就是当读取请求到达当前节点后，需要本节点向其他节点发起一次 heartbeat，如果大多数节点返回了对应的 heartbeat 回应（  heartbeat response ），那么 leader 就能够确定现在自己仍然是 leader。这个步骤需要耗费一定的网络开销，虽然单个 heartbeat 的开销比较低。Lease Read / Local Read 的优化也正是基于这个步骤开展的，它是这样进行的：

首先，在 “Raft - Leader 选举” 中我们介绍了一个概念，就是  heartbeat time interval ( leader 发送心跳间隔时间 )，要求 heartbeat time interval 小于 min ( election timeout )。也就是 leader 会每隔一个 heartbeat time interval 发送 heartbeat，我们记录这个时间点为 start，如果多数派 follower 都给了 heartbeat response（ 此时可以去确定 leader 还是此节点 ）， 由于 Raft 的选举机制，follower 会在至少 election timeout 的时间之后，才发起重新选举，所以说，就算是发生了选举，新 leader 也要在 election timeout / clock drift bound 这段时间被选举出来。那么，从 start 到 election timeout / clock drift bound，这段时间 leader 依然是本节点，我们管这段时间叫做 lease，也可以叫做租期。那么在一个 lease （租期）内，节点不需要通过发出 heartbeat 就可以确定自己依然是 leader 节点。这样一来，我们没有必要再去像 ReadIndex Read  那样，通过发送 heartbeat 来确定当前是否为 leader 了，从而提高了效率。

其次，这里我们有 2 个点需要我们注意到：
  - 各个 TiKV 服务器的 CPU clock 的时间是准的，误差不能太大，如果各个服务器的 clock 频率不同，lease 机制就会出现问题。如果这种情况，我们还可以使用 ReadIndex。
  - TiKV 实际并没有通过 heartbeat 来更新 lease，而是通过写操作。由于对于任何的写入操作，都会走一次 Raft log，所以我们在发起 （ propose ） 这次 write 请求的时候，记录下当前的时间戳 start，然后等到对应的请求 apply 之后，我们就可以续约 leader 的 lease。

最后，IndexRead 和 Lease Read 目前在 TiKV 都是支持的。