一个用 etcd 作主备锁的细节问题

栏目: 后端 · 发布时间: 7年前

内容简介:通常的分布式的锁的应用场景有如下几种方式:本文主要讨论第2种场景中遇到的一个细节问题。

etcd 越来越多的被应用在分布式系统中,最典型的一个应用场景就是作为分布式锁,用于在分布式系统中保证资源的独占。

通常的分布式的锁的应用场景有如下几种方式:

etcd
etcd

本文主要讨论第2种场景中遇到的一个细节问题。

在主备切换的场景,我们希望服务一旦获取到锁,就不必主动的与 etcd 交互,而是专心的进行自己的本职工作。但是如果不主动跟 etcd 询问持有的锁的状态的话,我们又无法保证当前是确实持有锁的。正如下边的代码:

package main

import (
	"context"
	"fmt"
	"time"

	"go.etcd.io/etcd/clientv3"
	"go.etcd.io/etcd/clientv3/concurrency"
)

func main() {
	client, errClient := clientv3.New(clientv3.Config{Endpoints: []string{"http://127.0.0.1:2379"}, DialTimeout: 10 * time.Second})
	if errClient != nil {
		fmt.Errorf("client create fail - %v", errClient)
		return
	}
	session, errSession := concurrency.NewSession(client, concurrency.WithTTL(10))
	if errSession != nil {
		fmt.Errorf("create session fail - %v", errSession)
		return
	}

	mutex := concurrency.NewMutex(session, "/lock")
	if mutex == nil {
		fmt.Errorf("create mutex fail")
		return
	}
	errMutex := mutex.Lock(context.TODO())
	if errMutex != nil {
		fmt.Errorf("lock fail - %v", errMutex)
		return
	}

	fmt.Println("got lock, begin run work")

	go func() {
		// do real work here
	}()

	// prevent progress quit
	select {}
}

// do real work here 执行过程中,很可能我们的网络状态出现了问题,或者 etcd 服务出现问题导致程序已经跟网络断开,这时实际上锁很可能已经失效了。为了保证锁的有效性,我们可以在 session 的有效期内轮询锁的状态,但是这种做法很繁琐,也比较浪费资源。有没有更好的方式呢?

好在 session 提供了一个 Done 方法,该方法返回一个 channel , 一旦 session 结束,这个 channel 就会被写入内容,这样就给了我们一个简单地方法来监控锁的状态。

package main

import (
	"context"
	"fmt"
	"time"

	"go.etcd.io/etcd/clientv3"
	"go.etcd.io/etcd/clientv3/concurrency"
)

func main() {
	client, errClient := clientv3.New(clientv3.Config{Endpoints: []string{"http://127.0.0.1:2379"}, DialTimeout: 10 * time.Second})
	if errClient != nil {
		fmt.Errorf("client create fail - %v", errClient)
		return
	}
	session, errSession := concurrency.NewSession(client, concurrency.WithTTL(10))
	if errSession != nil {
		fmt.Errorf("create session fail - %v", errSession)
		return
	}

	mutex := concurrency.NewMutex(session, "/lock")
	if mutex == nil {
		fmt.Errorf("create mutex fail")
		return
	}
	errMutex := mutex.Lock(context.TODO())
	if errMutex != nil {
		fmt.Errorf("lock fail - %v", errMutex)
		return
	}

	fmt.Println("got lock, begin run work")

	go func() {
		select {
		case <-session.Done():
			// do what ever you want to process lock lost
			fmt.Println("lock lost")
		}
	}()

	go func() {
		// do real work
	}()

	// prevent progress quit
	select {}
}

如上边的代码所示,我们在一个 goroutine 中监听一个 <-session.Done()channel ,这样,一旦锁出现了问题,就会得到通知,这样就可以在这里进行一些锁丢失的善后工作,比如在这里停止所有的需要锁才能进行的工作,这样就不会出现锁已经失效,但是工作进程却全然不知的状况了。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective Java

Effective Java

Joshua Bloch / Addison-Wesley Professional / 2018-1-6 / USD 54.99

The Definitive Guide to Java Platform Best Practices—Updated for Java 9 Java has changed dramatically since the previous edition of Effective Java was published shortly after the release of Jav......一起来看看 《Effective Java》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具