Skip to content

Commit

Permalink
docs: update rueidislock/README.md and add a benchmark result to it
Browse files Browse the repository at this point in the history
Signed-off-by: Rueian <[email protected]>
  • Loading branch information
rueian committed Jun 8, 2024
1 parent 6af9676 commit 0124d4a
Showing 1 changed file with 79 additions and 9 deletions.
88 changes: 79 additions & 9 deletions rueidislock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import (

func main() {
locker, err := rueidislock.NewLocker(rueidislock.LockerOption{
ClientOption: rueidis.ClientOption{InitAddress: []string{"node1:6379", "node2:6380", "node3:6379"}},
KeyMajority: 2, // please make sure that all your `Locker`s share the same KeyMajority
ClientOption: rueidis.ClientOption{InitAddress: []string{"localhost:6379"}},
KeyMajority: 1, // Use KeyMajority=1 if you have only one Redis instance. Also make sure that all your `Locker`s share the same KeyMajority.
NoLoopTracking: true, // Enable this to have better performance if all your Redis are >= 7.0.5.
})
if err != nil {
panic(err)
Expand All @@ -37,21 +38,90 @@ func main() {

## Features backed by the Redis Client Side Caching
* The returned `ctx` will be canceled automatically and immediately once the `KeyMajority` is not held anymore, for example:
* Redis down.
* Related keys has been deleted by other program or administrator.
* The waiting `Locker.WithContext` will try acquiring the lock again automatically and immediately once it has been released by someone even from other program.
* Redis are down.
* Acquired keys has been deleted by other programs or administrators.
* The waiting `Locker.WithContext` will try acquiring the lock again automatically and immediately once it has been released by someone or by another program.

## How it works

When the `locker.WithContext` is invoked, it will:

1. Try acquiring 3 keys (given that `KeyMajority` is 2), which are `rueidislock:0:my_lock`, `rueidislock:1:my_lock` and `rueidislock:2:my_lock`, by sending redis command `SET NX PXAT` or `SET NX PX` if `FallbackSETPX` is set.
1. Try acquiring 3 keys (given that the default `KeyMajority` is 2), which are `rueidislock:0:my_lock`, `rueidislock:1:my_lock` and `rueidislock:2:my_lock`, by sending redis command `SET NX PXAT` or `SET NX PX` if `FallbackSETPX` is set.
2. If the `KeyMajority` is satisfied within the `KeyValidity` duration, the invocation is successful and a `ctx` is returned as the lock.
3. If the invocation is not successful, it will wait for client-side caching notification to retry again.
4. If the invocation is successful, the `Locker` will extend the `ctx` validity periodically and also watch client-side caching notification for canceling the `ctx` if the `KeyMajority` is not held anymore.
3. If the invocation is not successful, it will wait for client-side caching notifications to retry again.
4. If the invocation is successful, the `Locker` will extend the `ctx` validity periodically and also watch client-side caching notifications for canceling the `ctx` if the `KeyMajority` is not held anymore.

### Disable Client Side Caching

Some Redis provider doesn't support client-side caching, ex. Google Cloud Memorystore.
You can disable client-side caching by setting `ClientOption.DisableCache` to `true`.
Please note that when the client-side caching is disabled, rueidislock will only try to re-acquire locks for every ExtendInterval.
Please note that when the client-side caching is disabled, rueidislock will only try to re-acquire locks for every ExtendInterval.

## Benchmark

```bash
▶ go test -bench=. -benchmem -run=.
goos: darwin
goarch: arm64
pkg: rueidis-benchmark/locker
Benchmark/rueidislock-10 20103 57842 ns/op 1849 B/op 29 allocs/op
Benchmark/redislock-10 13209 86285 ns/op 8083 B/op 225 allocs/op
PASS
ok rueidis-benchmark/locker 3.782s
```

```go
package locker

import (
"context"
"testing"
"time"

"github.com/bsm/redislock"
"github.com/redis/go-redis/v9"
"github.com/redis/rueidis"
"github.com/redis/rueidis/rueidislock"
)

func Benchmark(b *testing.B) {
b.Run("rueidislock", func(b *testing.B) {
l, _ := rueidislock.NewLocker(rueidislock.LockerOption{
ClientOption: rueidis.ClientOption{InitAddress: []string{"127.0.0.1:6379"}},
KeyMajority: 1,
NoLoopTracking: true,
})
defer l.Close()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, cancel, err := l.WithContext(context.Background(), "mylock")
if err != nil {
panic(err)
}
cancel()
}
})
b.StopTimer()
})
b.Run("redislock", func(b *testing.B) {
client := redis.NewUniversalClient(&redis.UniversalOptions{Addrs: []string{"127.0.0.1:6379"}})
locker := redislock.New(client)
defer client.Close()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
retry:
lock, err := locker.Obtain(context.Background(), "mylock", time.Minute, nil)
if err == redislock.ErrNotObtained {
goto retry
} else if err != nil {
panic(err)
}
lock.Release(context.Background())
}
})
b.StopTimer()
})
}
```

0 comments on commit 0124d4a

Please sign in to comment.