【问题标题】:Two clients acquiring the same lock in Consul两个客户端在 Consul 中获得相同的锁
【发布时间】:2016-11-29 19:50:48
【问题描述】:

我有以下代码:

package publicservice

import (
    "time"
    "github.com/hashicorp/consul/api"
    "github.com/hashicorp/consul/testutil"
    "testing"
)

func TestAcquireLock(t *testing.T) {
    consul := testutil.NewTestServer(t)
    defer consul.Stop()

    firstClient, err := api.NewClient(&api.Config{
        Address: consul.HTTPAddr,
    })

    if err != nil {
        t.Fatalf("failed to create first client with %v", err)
    }

    secondClient, err := api.NewClient(&api.Config{
        Address: consul.HTTPAddr,
    })

    if err != nil {
        t.Fatalf("failed to create second client with %v", err)
    }

    lockKey := "sample-lock-key"

    firstLock, err := firstClient.LockOpts(&api.LockOptions{
        Key: lockKey,
    })

    if err != nil {
        t.Fatalf("failed to create first lock %v", err)
    }

    _, err = firstLock.Lock(nil)

    if err != nil {
        t.Fatalf("failed to acquire first lock %v", err)
    }

    defer firstLock.Unlock()

    secondLock, err := secondClient.LockOpts(&api.LockOptions{
        Key: lockKey,
        LockTryOnce: true,
        LockWaitTime: time.Second,
    })

    if err != nil {
        t.Fatalf("failed to create second lock %v", err)
    }

    _, err = secondLock.Lock(nil)

    if err == nil {
        t.Fatal("should not have acquired lock here")
    }
}

当我运行它时,第二个锁调用永远不会失败,即使它应该失败,因为锁已经被另一个客户端持有,从日志中可以看出:

2016/11/29 14:46:25 [DEBUG] http: Request GET /v1/catalog/nodes (1.115897356s) from=127.0.0.1:50492
2016/11/29 14:46:25 [DEBUG] http: Request PUT /v1/session/create (939.436µs) from=127.0.0.1:50493
2016/11/29 14:46:25 [DEBUG] http: Request GET /v1/kv/sample-lock-key?wait=15000ms (269.823µs) from=127.0.0.1:50493
2016/11/29 14:46:25 [DEBUG] http: Request PUT /v1/kv/sample-lock-key?acquire=aa8fb351-6b6e-8e17-f8d9-fb265c497a9f&flags=3304740253564472344 (899.564µs) from=127.0.0.1:50493
2016/11/29 14:46:25 [DEBUG] http: Request GET /v1/kv/sample-lock-key?consistent= (112.87µs) from=127.0.0.1:50493
2016/11/29 14:46:25 [DEBUG] http: Request PUT /v1/session/create (595.554µs) from=127.0.0.1:50494
2016/11/29 14:46:25 [DEBUG] http: Request GET /v1/kv/sample-lock-key?wait=1000ms (38.602µs) from=127.0.0.1:50494
2016/11/29 14:46:26 [DEBUG] http: Request GET /v1/kv/sample-lock-key?index=7&wait=999ms (1.007117154s) from=127.0.0.1:50494
2016/11/29 14:46:26 [DEBUG] http: Request PUT /v1/session/destroy/fd83b8f8-1757-d9d7-6f0e-5defaf26b886 (1.549558ms) from=127.0.0.1:50494
2016/11/29 14:46:26 [DEBUG] http: Request PUT /v1/kv/sample-lock-key?flags=3304740253564472344&release=aa8fb351-6b6e-8e17-f8d9-fb265c497a9f (1.56451ms) from=127.0.0.1:50495
2016/11/29 14:46:26 [DEBUG] http: Request GET /v1/kv/sample-lock-key?consistent=&index=7 (1.010637359s) from=127.0.0.1:50493

我在这里缺少什么?我还必须做些什么来确保第二个客户端没有获得锁吗?

【问题讨论】:

    标签: go locking consul


    【解决方案1】:

    问题是你必须检查从Lock返回的频道,如果已经持有锁,频道是nil

    package publicservice
    
    import (
        "time"
        "github.com/hashicorp/consul/api"
        "github.com/hashicorp/consul/testutil"
        "testing"
        "github.com/xtgo/uuid"
    )
    
    func TestAcquireLock(t *testing.T) {
        consul := testutil.NewTestServer(t)
        defer consul.Stop()
    
        firstClient, err := api.NewClient(&api.Config{
            Address: consul.HTTPAddr,
        })
    
        if err != nil {
            t.Fatalf("failed to create first client with %v", err)
        }
    
        secondClient, err := api.NewClient(&api.Config{
            Address: consul.HTTPAddr,
        })
    
        if err != nil {
            t.Fatalf("failed to create second client with %v", err)
        }
    
        lockKey := "sample-lock-key"
    
        firstLock, err := firstClient.LockOpts(&api.LockOptions{
            Key: lockKey,
            SessionName: uuid.NewRandom().String(),
        })
    
        if err != nil {
            t.Fatalf("failed to create first lock %v", err)
        }
    
        firstResult, err := firstLock.Lock(nil)
    
        t.Logf("=====> result for first lock is %v", firstResult)
    
        if err != nil {
            t.Fatalf("failed to acquire first lock %v", err)
        }
    
        defer firstLock.Unlock()
    
        secondLock, err := secondClient.LockOpts(&api.LockOptions{
            Key: lockKey,
            LockTryOnce: true,
            LockWaitTime: time.Second,
            SessionName: uuid.NewRandom().String(),
        })
    
        if err != nil {
            t.Fatalf("failed to create second lock %v", err)
        }
    
        secondResult, err := secondLock.Lock(nil)
    
        if secondResult != nil || err != nil {
            t.Fatal("should not have acquired lock here")
        }
    }
    

    【讨论】:

    • 我知道这个问题很老,但我最近才发现它。无论如何,我只是好奇检查 secondResult 为 nil 背后的逻辑是什么。 .Lock() 阻塞,所以我假设每当它解除阻塞时,您都可以假设它获得了锁。你说你需要检查 secondResult 不是 nil 的事实向我表明 .Lock() 实际上并没有阻塞?
    • 它没有,它不应该,你检查结果只是为了知道你是否真的获得了锁。
    猜你喜欢
    • 2017-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 2013-05-27
    • 2019-06-10
    相关资源
    最近更新 更多