golang使用etcd实现分布式锁
1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "go.etcd.io/etcd/clientv3" 9 ) 10 11 func main() { 12 var ( 13 client *clientv3.Client 14 cfg clientv3.Config 15 err error 16 lease clientv3.Lease 17 ctx context.Context 18 cancelFunc context.CancelFunc 19 leaseId clientv3.LeaseID 20 leaseGrantResponse *clientv3.LeaseGrantResponse 21 leaseKeepAliveChan <-chan *clientv3.LeaseKeepAliveResponse 22 leaseKeepAliveResponse *clientv3.LeaseKeepAliveResponse 23 txn clientv3.Txn 24 txnResponse *clientv3.TxnResponse 25 kv clientv3.KV 26 ) 27 28 cfg = clientv3.Config{ 29 Endpoints: []string{"youwebsite:2379"}, 30 DialTimeout: time.Second * 5, 31 } 32 if client, err = clientv3.New(cfg); err != nil { 33 fmt.Println(err) 34 return 35 } 36 37 lease = clientv3.NewLease(client) 38 if leaseGrantResponse,err = lease.Grant(context.TODO(),5);err!=nil{ 39 fmt.Println(err) 40 return 41 } 42 leaseId = leaseGrantResponse.ID 43 44 //租约自动过期,立刻过期。//cancelfunc 取消续租,而revoke 则是立即过期 45 ctx,cancelFunc = context.WithCancel(context.TODO()) 46 defer cancelFunc() 47 defer lease.Revoke(context.TODO(),leaseId) 48 49 if leaseKeepAliveChan,err = lease.KeepAlive(ctx,leaseId);err!=nil{ 50 fmt.Println(err) 51 return 52 } 53 //启动续租协程,每秒续租一次 54 go func() { 55 for { 56 select { 57 case leaseKeepAliveResponse = <-leaseKeepAliveChan: 58 if leaseKeepAliveResponse != nil{ 59 fmt.Println("续租成功,leaseID :",leaseKeepAliveResponse.ID) 60 }else { 61 fmt.Println("续租失败") 62 } 63 64 } 65 time.Sleep(time.Second*1) 66 } 67 }() 68 //锁逻辑。 69 kv = clientv3.NewKV(client) 70 txn = kv.Txn(context.TODO()) 71 72 txn.If(clientv3.Compare(clientv3.CreateRevision("/dev/lock"),"=",0)).Then( 73 clientv3.OpPut("/dev/lock","占用",clientv3.WithLease(leaseId))).Else( 74 clientv3.OpGet("/dev/lock")) 75 if txnResponse,err = txn.Commit();err!=nil{ 76 fmt.Println(err) 77 return 78 } 79 if txnResponse.Succeeded { 80 fmt.Println("抢到锁了") 81 }else { 82 fmt.Println("没抢到锁",txnResponse.Responses[0].GetResponseRange().Kvs[0].Value) 83 } 84 time.Sleep(time.Second * 10 ) 85 }