Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/DistributedLock.Redis.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ As of 1.0.1, Redis-based primitives support the use of `IDatabase.WithKeyPrefix(
In addition to specifying the name/key and database(s), some additional tuning options are available.

- `Expiry` determines how long the lock will be *initially* claimed for (because of auto-extension, locks can be held for longer). Defaults to 30s.
- `ExtensionCadence` determines how frequently the hold on the lock will be renewed to the full `Expiry`. Defaults to 1/3 of `Expiry`.
- `MinValidityTime` determines what fraction of `Expiry` still has to remain when the locking operation completes to consider it a success. This is mostly relevant when acquiring a lock across multiple databases (e. g. if we immediately succeed on database 1 and eventually succeed on database 2 after 30s have elapsed, then our hold on database 1 will have expired). Defaults to 90% of the `Expiry`.
- `ExtensionCadence` determines how frequently the hold on the lock will be renewed to the full `Expiry`. Defaults to 1/3 of `MinValidityTime`.
- `BusyWaitSleepTime` specifies a range of times that the implementation will sleep between attempts to acquire a lock that is currently held by someone else. A random number in the range will be chosen for each sleep. If you expect contention, lowering these values may increase the responsiveness (how quickly a lock detects that it can now be taken) but will increase the number of calls made to Redis. Raising the values will have the reverse effects.


Expand Down
55 changes: 1 addition & 54 deletions src/DistributedLock.MongoDB/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ sequenceDiagram
Note over PB,DB: expiresAt > now (held by A)
DB->>PB: ❌ Lock Not Acquired

PB->>PB: Wait & Retry (exponential backoff)
PB->>PB: Wait & Retry

PA->>PA: Background: ExtensionCadence timer
PA->>DB: Update: Extend expiresAt += Expiry
Expand Down Expand Up @@ -411,59 +411,6 @@ This mechanism prevents the "split brain" scenario where two processes both beli
- Under contention, adaptive backoff reduces the load on MongoDB compared to fixed random intervals
- The `expiresAt` TTL index keeps the collection clean without manual maintenance

## Adaptive Backoff Strategy

When contention is high, the adaptive backoff strategy exponentially increases the wait time between acquisition attempts:

```mermaid
graph TD
A["Attempt to Acquire"] --> B{"Lock Available?"}
B -->|Yes| C["✅ Acquired"]
B -->|No| D["Consecutive Failures: N"]

D --> E["Sleep Time = min * 1.5^N"]
E --> F["Add Random Jitter ±20%"]
F --> G["Wait: max(min, sleepTime + jitter)"]
G --> H["Retry"]
H --> A

C --> I["Reset Failure Counter"]

style C fill:#90EE90
style E fill:#FFD700
style F fill:#FFA500
```

### Backoff Comparison Chart

#### Low Contention Scenario

| Attempt # | Strategy | Sleep Duration | Notes |
| --------- | -------- | -------------- | ------------------ |
| 1st | Random | 234ms | Unpredictable |
| 2nd | Random | 567ms | Unpredictable |
| 3rd | Random | 45ms | Unpredictable |
| 4th | Random | 689ms | Unpredictable |
| 1st | Adaptive | 10ms | Responsive |
| 2nd | Adaptive | 15ms | Exponential growth |
| 3rd | Adaptive | 22ms | Controlled backoff |
| 4th | Adaptive | 33ms | Still responsive |

#### High Contention Scenario

| Attempt # | Strategy | Sleep Duration | Impact |
| --------- | -------- | -------------- | -------------------------- |
| 1st | Random | 234ms | Constant high load |
| 2nd | Random | 567ms | Constant high load |
| 3rd | Random | 45ms | Constant high load |
| 4th | Random | 689ms | Constant high load |
| 1st | Adaptive | 10ms | Starts responsive |
| 2nd | Adaptive | 15ms | Progressive backoff |
| 3rd | Adaptive | 22ms | Reduces MongoDB load |
| 4th | Adaptive | 150ms | Significantly reduces load |

**Key Advantage**: Adaptive backoff automatically adjusts to contention level, providing better resource utilization

## Framework Support

- **.NET Standard 2.1** and higher
Expand Down
55 changes: 1 addition & 54 deletions src/DistributedLock.MongoDB/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ sequenceDiagram
Note over PB,DB: expiresAt > now (由 A 持有)
DB->>PB: ❌ 未能获取锁

PB->>PB: 等待 & 重试 (指数退避)
PB->>PB: 等待 & 重试

PA->>PA: 后台: ExtensionCadence 计时器
PA->>DB: 更新: 续期 expiresAt += Expiry
Expand Down Expand Up @@ -411,59 +411,6 @@ sequenceDiagram
- 在竞争下,自适应退避相比固定随机间隔减少了对 MongoDB 的负载
- `expiresAt` TTL 索引保持集合整洁,无需手动维护

## 自适应退避策略

当竞争高时,自适应退避策略会指数级增加获取尝试之间的等待时间:

```mermaid
graph TD
A["尝试获取"] --> B{"锁可用?"}
B -->|是| C["✅ 已获取"]
B -->|否| D["连续失败: N 次"]

D --> E["睡眠时间 = min * 1.5^N"]
E --> F["添加随机抖动 ±20%"]
F --> G["等待: max(min, sleepTime + jitter)"]
G --> H["重试"]
H --> A

C --> I["重置失败计数"]

style C fill:#90EE90
style E fill:#FFD700
style F fill:#FFA500
```

### 退避对比图

#### 低竞争场景

| 尝试次数 | 策略 | 睡眠时间 | 备注 |
| -------- | ------ | -------- | ---------- |
| 第 1 次 | 随机 | 234ms | 不可预测 |
| 第 2 次 | 随机 | 567ms | 不可预测 |
| 第 3 次 | 随机 | 45ms | 不可预测 |
| 第 4 次 | 随机 | 689ms | 不可预测 |
| 第 1 次 | 自适应 | 10ms | 响应快 |
| 第 2 次 | 自适应 | 15ms | 指数增长 |
| 第 3 次 | 自适应 | 22ms | 控制退避 |
| 第 4 次 | 自适应 | 33ms | 仍然响应快 |

#### 高竞争场景

| 尝试次数 | 策略 | 睡眠时间 | 影响 |
| -------- | ------ | -------- | ----------------- |
| 第 1 次 | 随机 | 234ms | 恒定高负载 |
| 第 2 次 | 随机 | 567ms | 恒定高负载 |
| 第 3 次 | 随机 | 45ms | 恒定高负载 |
| 第 4 次 | 随机 | 689ms | 恒定高负载 |
| 第 1 次 | 自适应 | 10ms | 开始响应快 |
| 第 2 次 | 自适应 | 15ms | 逐步退避 |
| 第 3 次 | 自适应 | 22ms | 减少 MongoDB 负载 |
| 第 4 次 | 自适应 | 150ms | 显著减少负载 |

**关键优势**:自适应退避根据竞争水平自动调整,提供更好的资源利用率

## 框架支持

- **.NET Standard 2.1** 及更高版本
Expand Down
Loading