# 数据的读取 Lease Read

__*Lease Read*__

![`smart`](./student-guide/diagram/LeaseRead01_aa_001_2022051.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 了, 从而提高了效率。

其次, 这里有两个点需要我们注意到:

1. 各个 TiKV 服务器的 CPU clock 的时间是准的, 误差不能太大, 如果各个服务器的 clock 频率不同, lease 机制就会出现问题。如果这种情况, 我们还可以使用 ReadIndex。

2. TiKV 实际并没有通过 heartbeat 来更新 lease, 而是通过写操作。由于对于任何的写入操作, 都会走一次 Raft log, 所以我们在发起 （propose） 这种 write 请求的时候, 记录下当前的时间戳 start, 然后等到对应的请求 apply 之后, 我们就可以续约 leader 的 lease。

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