@@ -141,31 +141,128 @@ TiDB 在悲观事务模式下支持了 2 种隔离级别:
141141
142142# # 悲观事务提交流程
143143
144- TiDB 悲观锁复用了乐观锁的两阶段提交逻辑,重点在 DML 执行时做了改造 。
144+ 在事务提交流程中,悲观事务和乐观事务的逻辑相同。两者都采用两阶段提交(2PC)模式。悲观事务的重要适配点在于 DML 执行 。
145145
146- 
147-
148- 在两阶段提交之前增加了 Acquire Pessimistic Lock 阶段,简要步骤如下。
146+ ` ` ` mermaid
147+ ---
148+ config:
149+ themeCSS: |
150+ /* workaround for https://github.com/mermaid-js/mermaid/issues/523 */
151+ /* mark the two "Lock" arrows as red, by restyling the dashed arrows */
152+ line.messageLine1 {
153+ stroke: #d32f2f;
154+ stroke-dasharray: none !important;
155+ }
156+ /* make sure the arrow heads inherit the stroke color (another bug in mermaid) */
157+ #arrowhead path {
158+ fill: context-stroke;
159+ stroke: context-stroke;
160+ }
161+ ---
162+ sequenceDiagram
163+ participant Client
164+ participant TiDB
165+ participant TiKV
166+
167+ Client->>TiDB: BEGIN
168+ rect rgba(255, 0, 0, 0.08)
169+ Client->>TiDB: DML
170+ TiDB-->>TiKV: Lock
171+ TiDB-->>TiKV: Lock
172+ end
173+ rect rgba(0, 0, 0, 0.04)
174+ Client->>TiDB: COMMIT
175+ TiDB->>TiKV: Prewrite
176+ TiDB->>TiKV: Commit
177+ end
178+ ` ` `
149179
150- 1 . (同乐观锁)TiDB 收到来自客户端的 begin 请求,获取当前时间戳作为本事务的 StartTS。
151- 2 . TiDB 收到来自客户端的更新数据的请求:TiDB 向 TiKV 发起加悲观锁请求,该锁持久化到 TiKV。
152- 3 . (同乐观锁)客户端发起 commit ,TiDB 开始执行与乐观锁一样的两阶段提交。
180+ 悲观事务在 2PC 之前增加了 ` Acquire Pessimistic Lock` 阶段。该阶段包括以下步骤:
153181
154- 
182+ 1 . (同乐观事务模式)TiDB 收到来自客户端的 ` begin` 请求,当前时间戳即为该事务的 start_ts。
183+ 2 . 当 TiDB 服务器收到来自客户端的写请求时,TiDB 服务器会向 TiKV 服务器发起悲观锁请求,并将该锁持久化到 TiKV 服务器。
184+ 3 . (同乐观事务模式)当客户端发送 commit 请求时,TiDB 开始执行与乐观事务模式类似的两阶段提交。
155185
156- 相关细节本节不再赘述,详情可阅读 [TiDB 悲观锁实现原理](https:// pingkai .cn / tidbcommunity/ blog/ 7730ed79)。
186+ ` ` ` mermaid
187+ ---
188+ title: Pessimistic Transaction in TiDB
189+ ---
190+ sequenceDiagram
191+ participant client
192+ participant TiDB
193+ participant PD
194+ participant TiKV
195+
196+ client->>TiDB: begin
197+ TiDB->>PD: get ts as start_ts
198+ loop execute SQL
199+ rect rgba(0, 0, 0, 0.04)
200+ alt do read
201+ TiDB->>TiKV: get data from TiKV with start_ts
202+ TiDB->>client: return read result
203+ else do write
204+ rect rgba(255, 0, 0, 0.08)
205+ loop if has write conflict
206+ TiDB->>PD: get ts as for_update_ts
207+ TiDB->>TiDB: write in cache
208+ TiDB->>TiKV: acquire pessimistic locks parallelly
209+ end
210+ end
211+ TiDB->>client: return write result
212+ end
213+ end
214+ end
215+ client->>TiDB: commit
216+ opt start 2PC
217+ rect rgba(0, 0, 0, 0.04)
218+ par prewrite
219+ TiDB->>TiKV: prewrite each key in cache with start_ts parallelly
220+ end
221+ end
222+ rect rgba(0, 0, 0, 0.04)
223+ par commit
224+ TiDB->>PD: get ts as commit_ts
225+ TiDB->>TiKV: commit primary_key with commit_ts first
226+ TiDB->>client: success
227+ TiDB->>TiKV: commit each secondary_key with commit_ts parallelly
228+ end
229+ end
230+ end
231+ ` ` `
157232
158233# # Pipelined 加锁流程
159234
160- 加悲观锁需要向 TiKV 写入数据,要经过 Raft 提交并 apply 后才能返回,相比于乐观事务,不可避免的会增加部分延迟。为了降低加锁的开销,TiKV 实现了 pipelined 加锁流程:当数据满足加锁要求时,TiKV 立刻通知 TiDB 执行后面的请求,并异步写入悲观锁,从而降低大部分延迟,显著提升悲观事务的性能。但当 TiKV 出现网络隔离或者节点宕机时,悲观锁异步写入有可能失败,从而产生以下影响:
235+ 加悲观锁需要向 TiKV 写入数据。只有在经过 Raft 提交并 apply 后,TiKV 才能向 TiDB 返回加锁成功的响应。因此,相比乐观事务,悲观事务模式不可避免地具有更高的延迟。
236+
237+ 为了降低加锁的开销,TiKV 实现了 pipelined 加锁流程:当数据满足加锁要求时,TiKV 立刻通知 TiDB 执行后续请求,并异步写入悲观锁。该流程降低了大部分延迟,显著提升了悲观事务的性能。但是,当 TiKV 发生网络隔离或者 TiKV 节点宕机时,悲观锁的异步写入可能失败,并产生以下影响:
161238
162- * 无法阻塞修改相同数据的其他事务。如果业务逻辑依赖加锁或等锁机制,业务逻辑的正确性将受到影响 。
239+ * 无法阻塞修改相同数据的其他事务。如果应用逻辑依赖加锁或等锁机制,应用逻辑的正确性将受到影响 。
163240
164- * 有较低概率导致事务提交失败,但不会影响事务正确性 。
241+ * 有较低概率导致事务提交失败,但不会影响事务的正确性 。
165242
166- 如果业务逻辑依赖加锁或等锁机制,或者即使在集群异常情况下也要尽可能保证事务提交的成功率,应关闭 pipelined 加锁功能。
243+ < CustomContent platform = " tidb " >
167244
168- 
245+ 如果应用逻辑依赖加锁或等锁机制,或者你希望即使在 TiKV 集群异常的情况下也尽可能保证事务提交的成功率,则应关闭 pipelined 加锁功能。
246+
247+ ` ` ` mermaid
248+ ---
249+ title: pipelined pessimistic lock
250+ ---
251+ sequenceDiagram
252+ participant Client
253+ participant TiDB
254+ participant TiKV1
255+ participant TiKV2
256+ participant TiKV3
257+
258+ loop
259+ Client->>TiDB: DML
260+ TiDB->>TiKV1: Acquire pessimistic locks
261+ TiKV1->>TiDB: OK
262+ TiKV1--)TiKV2: Log replication
263+ TiKV1--)TiKV3: Log replication
264+ end
265+ ` ` `
169266
170267该功能默认开启,可修改 TiKV 配置关闭:
171268
@@ -174,14 +271,22 @@ TiDB 悲观锁复用了乐观锁的两阶段提交逻辑,重点在 DML 执行
174271pipelined = false
175272` ` `
176273
177- 若集群是 v4 .0 .9 及以上版本,也可通过[在线修改 TiKV 配置](/ dynamic- config .md # 在线修改-tikv-配置)功能动态关闭该功能:
274+ 若 TiKV 集群为 v4 .0 .9 及以上版本,也可通过[在线修改 TiKV 配置](/ dynamic- config .md # 在线修改-tikv-配置)功能动态关闭该功能:
178275
179276{{< copyable " sql" > }}
180277
181278` ` ` sql
182279set config tikv pessimistic-txn.pipelined='false';
183280` ` `
184281
282+ < / CustomContent>
283+
284+ < CustomContent platform= " tidb-cloud" >
285+
286+ 如果应用逻辑依赖加锁或等锁机制,或者你希望即使在 TiKV 集群异常的情况下也尽可能保证事务提交的成功率,可以[联系 TiDB Cloud 支持](/ tidb- cloud/ tidb- cloud- support .md )关闭 pipelined 加锁功能。
287+
288+ < / CustomContent>
289+
185290# # 内存悲观锁
186291
187292TiKV 在 v6 .0 .0 中引入了内存悲观锁功能。开启内存悲观锁功能后,悲观锁通常只会被存储在 Region leader 的内存中,而不会将锁持久化到磁盘,也不会通过 Raft 协议将锁同步到其他副本,因此可以大大降低悲观事务加锁的开销,提升悲观事务的吞吐并降低延迟。
0 commit comments