最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

生產(chǎn)環(huán)境go-redsync使用示例

 更新時間:2025年10月01日 11:34:30   作者:qinyuan15  
go-redsync是go語言實(shí)現(xiàn)分布式鎖的常用工具,但官方文檔是的入門示例并不是一個可以直接用于生產(chǎn)環(huán)境的版本,本文提供一個可以用于生產(chǎn)環(huán)境的使用示例,感興趣的可以了解一下

一、問題和意義

go-redsync是go語言實(shí)現(xiàn)分布式鎖的常用工具,但官方文檔是的入門示例并不是一個可以直接用于生產(chǎn)環(huán)境的版本。很多人將官方文檔中的入門示例使用到實(shí)際項(xiàng)目中導(dǎo)致了生產(chǎn)事故。故文本提供一個可以用于生產(chǎn)環(huán)境的使用示例。

二、官方入門示例存在的問題

官方示例代碼為:

package main

import (
	goredislib "github.com/redis/go-redis/v9"
	"github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v9"
)

func main() {
	// Create a pool with go-redis (or redigo) which is the pool redisync will
	// use while communicating with Redis. This can also be any pool that
	// implements the `redis.Pool` interface.
	client := goredislib.NewClient(&goredislib.Options{
		Addr: "localhost:6379",
	})
	pool := goredis.NewPool(client) // or, pool := redigo.NewPool(...)

	// Create an instance of redisync to be used to obtain a mutual exclusion
	// lock.
	rs := redsync.New(pool)

	// Obtain a new mutex by using the same name for all instances wanting the
	// same lock.
	mutexname := "my-global-mutex"
	mutex := rs.NewMutex(mutexname)

	// Obtain a lock for our given mutex. After this is successful, no one else
	// can obtain the same lock (the same mutex name) until we unlock it.
	if err := mutex.Lock(); err != nil {
		panic(err)
	}

	// Do your work that requires the lock.

	// Release the lock so other processes or threads can obtain a lock.
	if ok, err := mutex.Unlock(); !ok || err != nil {
		panic("unlock failed")
	}
}

接下來,我們開兩個協(xié)程實(shí)測一下。

// 這里省去創(chuàng)建redis連接的操作

mutexname := "my-global-mutex"
var wg sync.WaitGroup // 用于實(shí)現(xiàn)主函數(shù)等待所有子協(xié)程執(zhí)行完畢之后再退出
wg.Add(2)
go func() {
   defer wg.Done()
   mutex := rs.NewMutex(mutexname)
   // 開始嘗試獲得分布式鎖
   if err := mutex.Lock(); err != nil {
      log.Errorf("failed to acquire lock in task1: %v", err)
      return
   }

   // 執(zhí)行一些任務(wù)
   log.Info("task1 start at ", time.Now().Format("15:04:05.000"))
   time.Sleep(time.Second * 10) // 模擬一個耗時的任務(wù)
   log.Info("task1 end at ", time.Now().Format("15:04:05.000"))

   // 執(zhí)行完任務(wù),釋放鎖
   if _, err := mutex.Unlock(); err != nil {
      log.Errorf("failed to release lock in task1: %v", err)
   }
}()
go func() {
   defer wg.Done()
   mutex := rs.NewMutex(mutexname)
   // 開始嘗試獲得分布式鎖
   if err := mutex.Lock(); err != nil {
      log.Errorf("failed to acquire lock in task2: %v", err)
      return
   }

   // 執(zhí)行一些任務(wù)
   log.Info("task2 start at ", time.Now().Format("15:04:05.000"))
   time.Sleep(time.Second * 10) // 模擬一個耗時的任務(wù)
   log.Info("task2 end at ", time.Now().Format("15:04:05.000"))

   // 執(zhí)行完任務(wù),釋放鎖
   if _, err := mutex.Unlock(); err != nil {
      log.Errorf("failed to release lock in task2: %v", err)
   }
}()
wg.Wait()

程序執(zhí)行結(jié)果如下:

INFO msg=task2 start at 02:22:00.330
INFO msg=task1 start at 02:22:08.508
INFO msg=task2 end at 02:22:10.330
ERROR msg=failed to release lock in task2: lock already taken, locked nodes: [0]
INFO msg=task1 end at 02:22:18.508
ERROR msg=failed to release lock in task1: lock already taken, locked nodes: [0]

可以看出,分布式鎖并沒有起作用,任務(wù)2還沒執(zhí)行完,任務(wù)1就已經(jīng)獲得鎖并開始。原因是go-redsync默認(rèn)的加鎖時間只有8秒鐘,如果一個任務(wù)執(zhí)行時間超過8秒,則分布式鎖會在任務(wù)執(zhí)行結(jié)束前釋放。

三、生產(chǎn)環(huán)境可用的版本

生產(chǎn)環(huán)境中,任務(wù)沒結(jié)束時需要調(diào)用mutex.Extend()方法延長鎖的時間

mutexname := "my-global-mutex"
var wg sync.WaitGroup // 用于實(shí)現(xiàn)主函數(shù)等待所有子協(xié)程執(zhí)行完畢之后再退出
wg.Add(2)
go func() {
   defer wg.Done()
   mutex := client.NewMutex(mutexname)
   // 開始嘗試獲得分布式鎖
   if err := mutex.Lock(); err != nil {
      log.Errorf("failed to acquire lock in task1: %v", err)
      return
   }
   var lockReleased atomic.Bool
   lockReleased.Store(false)

   go func() { // 只要當(dāng)前任務(wù)還在執(zhí)行,每過1秒就延長鎖的過期時間
      for {
         time.Sleep(time.Second)
         if lockReleased.Load() {
            return
         }
         _, err := mutex.Extend()
         if err != nil {
            log.Errorf("extend lock in task1 fail: %v", err)
         }
      }
   }()

   log.Info("task1 start at ", time.Now().Format("15:04:05.000"))
   time.Sleep(time.Second * 10) // 模擬一個耗時的任務(wù)
   log.Info("task1 end at ", time.Now().Format("15:04:05.000"))

   // 執(zhí)行完任務(wù),釋放鎖
   if _, err := mutex.Unlock(); err != nil {
      log.Errorf("failed to release lock in task1: %v", err)
   }
   lockReleased.Store(true)
}()
go func() {
   defer wg.Done()
   mutex := client.NewMutex(mutexname)
   // 開始嘗試獲得分布式鎖
   if err := mutex.Lock(); err != nil {
      log.Errorf("failed to acquire lock in task2: %v", err)
      return
   }
   var lockReleased atomic.Bool
   lockReleased.Store(false)

   go func() { // 只要當(dāng)前任務(wù)還在執(zhí)行,每過1秒就延長鎖的過期時間
      for {
         time.Sleep(time.Second)
         if lockReleased.Load() {
            return
         }
         _, err := mutex.Extend()
         if err != nil {
            log.Errorf("extend lock in task2 fail: %v", err)
         }
      }
   }()

   log.Info("task2 start at ", time.Now().Format("15:04:05.000"))
   time.Sleep(time.Second * 10) // 模擬一個耗時的任務(wù)
   log.Info("task2 end at ", time.Now().Format("15:04:05.000"))

   // 執(zhí)行完任務(wù),釋放鎖
   if _, err := mutex.Unlock(); err != nil {
      log.Errorf("failed to release lock in task2: %v", err)
   }
   lockReleased.Store(true)
}()
wg.Wait()

執(zhí)行結(jié)果如下:

INFO msg=task2 start at 02:31:06.973
INFO msg=task2 end at 02:31:16.974
INFO msg=task1 start at 02:31:17.471
INFO msg=task1 end at 02:31:27.471

這一執(zhí)行結(jié)果符合預(yù)期,任務(wù)1會在任務(wù)2執(zhí)行完之后才能獲得鎖。

四、 對go-redsync做封裝

前面的代碼示例可用于生產(chǎn),但代碼過于冗長,每次使用分布式鎖時都寫那么多代碼也太麻煩。我們可以將其封裝為了個TryLock方法:

type LockHolder interface {
    ReleaseLock()
}

type lockHolder struct {
    mutex       *redsync.Mutex
    lockReleased atomic.Bool
}

func (h *lockHolder) ReleaseLock() {
    _, err := h.mutex.Unlock()
    if err != nil {
        log.Errorf("failed to release lock: %v", err)
    }
    h.lockReleased.Store(true)
}

func TryLock(mutexName string) (LockHolder, error) {
    rs := getRedsync()
    mutex := rs.NewMutex(mutexName)
    if err := mutex.Lock(); err != nil {
        log.Errorf("failed to acquire lock: %v", err)
        return nil, err
    }

    holder := &lockHolder{
        mutex:       mutex,
        lockReleased: atomic.Bool{},
    }
    holder.lockReleased.Store(false)

    go func() {
        for {
            time.Sleep(time.Second)
            if holder.lockReleased.Load() {
                return
            }
            _, err := mutex.Extend()
            if err != nil {
                log.Errorf("extend lock fail: %v", err)
            }
        }
    }()
    return holder, nil
}

接下來使用分布式鎖的代碼可以簡化為:

mutexname := "my-global-mutex"
var wg sync.WaitGroup
wg.Add(2)
go func() {
   defer wg.Done()
   lock, err := TryLock(mutexname)
   if err != nil {
      log.Errorf("failed to acquire lock in task1: %v", err)
      return
   }
   defer lock.ReleaseLock()
   log.Info("task1 start at ", time.Now().Format("15:04:05.000"))
   time.Sleep(time.Second * 10)
   log.Info("task1 end at ", time.Now().Format("15:04:05.000"))
}()
go func() {
   defer wg.Done()
   lock, err := TryLock(mutexname)
   if err != nil {
      log.Errorf("failed to acquire lock in task2: %v", err)
      return
   }
   defer lock.ReleaseLock()
   log.Info("task2 start at ", time.Now().Format("15:04:05.000"))
   time.Sleep(time.Second * 10)
   log.Info("task2 end at ", time.Now().Format("15:04:05.000"))
}()
wg.Wait()

到此這篇關(guān)于生產(chǎn)環(huán)境go-redsync使用示例的文章就介紹到這了,更多相關(guān)生產(chǎn)環(huán)境go-redsync使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go?常見設(shè)計(jì)模式之單例模式詳解

    Go?常見設(shè)計(jì)模式之單例模式詳解

    單例模式是設(shè)計(jì)模式中最簡單的一種模式,單例模式能夠確保無論對象被實(shí)例化多少次,全局都只有一個實(shí)例存在,在Go?語言有多種方式可以實(shí)現(xiàn)單例模式,所以我們今天就來一起學(xué)習(xí)下吧
    2023-07-07
  • Go源碼分析之預(yù)分配slice內(nèi)存

    Go源碼分析之預(yù)分配slice內(nèi)存

    這篇文章主要從Go語言源碼帶大家分析一下預(yù)分配slice內(nèi)存的相關(guān)知識,文中的示例代碼簡潔易懂,對我們深入了解go有一定的幫助,需要的可以學(xué)習(xí)一下
    2023-08-08
  • 基于Go語言開發(fā)一個JSON格式校驗(yàn)工具

    基于Go語言開發(fā)一個JSON格式校驗(yàn)工具

    在日常開發(fā)中,經(jīng)常會遇到需要校驗(yàn) JSON 格式是否正確的場景,如果 JSON 格式不正確,系統(tǒng)往往會報(bào)錯甚至崩潰,因此開發(fā)一個 命令行 JSON 格式校驗(yàn)工具 非常實(shí)用,所以本文給大家介紹了如何基于Go語言開發(fā)一個JSON格式校驗(yàn)工具,需要的朋友可以參考下
    2025-09-09
  • sublime安裝支持go和html的插件

    sublime安裝支持go和html的插件

    這篇文章主要介紹了sublime安裝支持go和html的插件,需要的朋友可以參考下
    2015-01-01
  • golang中使用mongo的方法介紹

    golang中使用mongo的方法介紹

    這篇文章主要給大家介紹了關(guān)于golang中使用mongo的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • 淺談Go 語言中逃逸分析是怎么進(jìn)行的

    淺談Go 語言中逃逸分析是怎么進(jìn)行的

    Go 語言的逃逸分析是在編譯階段進(jìn)行的靜態(tài)分析過程,用于確定變量的內(nèi)存分配位置,本文就來介紹一下逃逸分析是怎么進(jìn)行的,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-10-10
  • Go中GoFrameMap轉(zhuǎn)換詳解

    Go中GoFrameMap轉(zhuǎn)換詳解

    本文詳細(xì)解析了Go語言中g(shù)conv.Map()方法的實(shí)現(xiàn)原理,該方法通過遞歸處理將各種數(shù)據(jù)類型轉(zhuǎn)換為map[string]any格式,感興趣的可以了解一下
    2026-05-05
  • Golang通道channel的源碼分析

    Golang通道channel的源碼分析

    channel(通道),顧名思義,是一種通道,一種用于并發(fā)環(huán)境中數(shù)據(jù)傳遞的通道。channel是golang中標(biāo)志性的概念之一,很好很強(qiáng)大!本文將從源碼帶大家了解一下channel的使用,希望對大家有所幫助
    2022-12-12
  • go語言字符串的拼接和切片方法總結(jié)

    go語言字符串的拼接和切片方法總結(jié)

    在go語言中,因?yàn)樽址荒鼙辉L問,不能被修改,所以進(jìn)行字符串拼接的時候,golang都需要進(jìn)行內(nèi)存拷貝,造成一定的性能消耗,這篇文章主要給大家介紹了關(guān)于go語言字符串的拼接和切片的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • Go語言排序算法之插入排序與生成隨機(jī)數(shù)詳解

    Go語言排序算法之插入排序與生成隨機(jī)數(shù)詳解

    從這篇文章開始將帶領(lǐng)大家學(xué)習(xí)Go語言的經(jīng)典排序算法,比如插入排序、選擇排序、冒泡排序、希爾排序、歸并排序、堆排序和快排,二分搜索,外部排序和MapReduce等,本文將先詳細(xì)介紹插入排序,并給大家分享了go語言生成隨機(jī)數(shù)的方法,下面來一起看看吧。
    2017-11-11

最新評論

慈利县| 嘉义市| 和平县| 盐津县| 郸城县| 讷河市| 沁源县| 修文县| 柏乡县| 平凉市| 仙桃市| 鸡西市| 长宁县| 贵南县| 襄汾县| 永修县| 敦煌市| 嫩江县| 绩溪县| 横山县| 松原市| 东乡县| 台湾省| 西城区| 新乡市| 奎屯市| 乡城县| 夏津县| 临猗县| 庄河市| 武清区| 葵青区| 伊吾县| 吕梁市| 高台县| 剑阁县| 普陀区| 定兴县| 林芝县| 新兴县| 年辖:市辖区|