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

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

内容简介:通常的分布式的锁的应用场景有如下几种方式:本文主要讨论第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 ,这样,一旦锁出现了问题,就会得到通知,这样就可以在这里进行一些锁丢失的善后工作,比如在这里停止所有的需要锁才能进行的工作,这样就不会出现锁已经失效,但是工作进程却全然不知的状况了。


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

查看所有标签

猜你喜欢:

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

程序员的英语

程序员的英语

[韩]朴栽浒、[韩]李海永 / 颜廷连 / 人民邮电出版社 / 2018-2 / 49.00元

高考以后就把英语都还给老师了? 写代码特顺溜,一到英语就卡壳? 常见的语法书太枯燥,单词书又太宽泛? 不用急,快来加入针对开发人员的英语读解能力训练项目! - 安全与黑客攻击、无人机与机器人、大数据、物联网、云计算,顺应新技术潮流! - 语法、单词、完形填空、阅读理解、翻译,多角度提升读解能力! - 英语母语技术人员审校,提供“语言和技术”双保险!一起来看看 《程序员的英语》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具