go 简单实现分布式锁

有多个客户端请求服务端,业务规定,某个任务只能单一执行

例如:有a,b,c,d 4个客户端同时访问服务端,都竞争任务执行资格,谁竞争到了这个资格,这个任务就由它执行,其它人即使执行也是无效的,如果它出故障了,服务端判断一定时间任务没有执行,就会释放这个资格,其它客户端就可以继续竞争这个任务执行资格了。

如何实现这种业务场景呢?

代码例子

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "sync"
    "time"
)

type F struct {
    Name string
    T    int64
}

var f F
var m sync.Mutex

func main() {

    //起一个go协程去检查单一任务是否离线,10秒
    go func() {
        for {
            if f.Name != "" && time.Now().Unix()-f.T > 10 {
                m.Lock()
                f.Name = ""
                m.Unlock()
            } else {
                fmt.Println("目前锁的持有者是:", f.Name)
            }
            time.Sleep(1 * time.Second)
        }

    }()

    r := gin.Default()
    r.GET("/ping", task)
    r.GET("/hello", hello)
    r.Run() // listen and serve on 0.0.0.0:8080

}

func hello(c *gin.Context) {
    c.JSON(200, gin.H{
        "message": "hello,world",
    })
}

func task(c *gin.Context) {
    if c.Query("name") != "" {
        if f.Name == "" {
            m.Lock()

            f.Name = c.Query("name")
            f.T = time.Now().Unix()
            m.Unlock()
            c.JSON(200, gin.H{
                "message": "get lock ok",
            })

        } else {
            if c.Query("name") == f.Name {
                //更新心跳时间
                f.T = time.Now().Unix()
                c.JSON(200, gin.H{
                    "message": "单一任务执行者",
                })
            } else {
                c.JSON(200, gin.H{
                    "message": "不需要额外的任务执行者",
                })
            }
        }
    } else {
        c.JSON(400, gin.H{
            "message": "miss  name query",
        })
    }

}


执行效果

jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=ee
{"message":"get lock ok"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=cc
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=ee
{"message":"单一任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=ee
{"message":"单一任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"get lock ok"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"单一任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=bb
{"message":"单一任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=ee
{"message":"不需要额外的任务执行者"}
jiangyd:fenbu jiangyd$ curl http://127.0.0.1:8080/ping?name=ee
{"message":"不需要额外的任务执行者"}


应用日志

目前锁的持有者是: 
目前锁的持有者是: 
目前锁的持有者是: 
[GIN] 2021/11/18 - 14:38:11 | 200 |     166.817µs |       127.0.0.1 | GET      "/ping?name=ee"
目前锁的持有者是: ee
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:13 | 200 |      132.71µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: ee
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:16 | 200 |     156.544µs |       127.0.0.1 | GET      "/ping?name=cc"
目前锁的持有者是: ee
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:18 | 200 |      60.798µs |       127.0.0.1 | GET      "/ping?name=ee"
目前锁的持有者是: ee
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:19 | 200 |      57.979µs |       127.0.0.1 | GET      "/ping?name=ee"
目前锁的持有者是: ee
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:21 | 200 |      59.946µs |       127.0.0.1 | GET      "/ping?name=bb"
[GIN] 2021/11/18 - 14:38:22 | 200 |      53.904µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:23 | 200 |      45.606µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:23 | 200 |      46.552µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:24 | 200 |       49.45µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:25 | 200 |      76.116µs |       127.0.0.1 | GET      "/ping?name=bb"
[GIN] 2021/11/18 - 14:38:26 | 200 |      105.55µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:27 | 200 |      79.018µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:27 | 200 |      66.346µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:28 | 200 |      76.468µs |       127.0.0.1 | GET      "/ping?name=bb"
[GIN] 2021/11/18 - 14:38:29 | 200 |      50.744µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: ee
[GIN] 2021/11/18 - 14:38:30 | 200 |      96.843µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: 
[GIN] 2021/11/18 - 14:38:31 | 200 |      109.12µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: bb
目前锁的持有者是: bb
目前锁的持有者是: bb
[GIN] 2021/11/18 - 14:38:34 | 200 |     140.095µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: bb
[GIN] 2021/11/18 - 14:38:35 | 200 |      52.475µs |       127.0.0.1 | GET      "/ping?name=bb"
目前锁的持有者是: bb
目前锁的持有者是: bb
目前锁的持有者是: bb
目前锁的持有者是: bb
[GIN] 2021/11/18 - 14:38:39 | 200 |      57.742µs |       127.0.0.1 | GET      "/ping?name=ee"
目前锁的持有者是: bb
[GIN] 2021/11/18 - 14:38:40 | 200 |      61.668µs |       127.0.0.1 | GET      "/ping?name=ee"
[GIN] 2021/11/18 - 14:38:41 | 200 |      46.113µs |       127.0.0.1 | GET      "/ping?name=ee"
目前锁的持有者是: bb
目前锁的持有者是: bb
目前锁的持有者是: bb
目前锁的持有者是: bb
目前锁的持有者是: bb
目前锁的持有者是: 
目前锁的持有者是: 


这样就可以达到要求了。

上一篇:测试人员学习云原生


下一篇:测试人员怎么理解http与websocket的区别