国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

分布式鎖實現(xiàn)(mysql,以及redis)以及分布式的概念(續(xù))redsync包使用

這篇具有很好參考價值的文章主要介紹了分布式鎖實現(xiàn)(mysql,以及redis)以及分布式的概念(續(xù))redsync包使用。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

道生一,一生二,二生三,三生萬物

這張盡量結合上一章進行使用:上一章

這章主要是講如何通過redis實現(xiàn)分布式鎖的

redis實現(xiàn)

這里我用redis去實現(xiàn):

技術:golang,redis,數(shù)據(jù)結構

這里是有一個大體的實現(xiàn)思路:主要是使用redis中這些語法

redis命令說明:

  1. setnx命令:set if not exists,當且僅當 key 不存在時,將 key 的值設為 value。若給定的 key 已經(jīng)存在,則 SETNX不做任何動作。
    • 返回1,說明該進程獲得鎖,將密鑰的值設為值
    • 返回0,說明其他進程已經(jīng)獲得了鎖,進程不能進入臨界區(qū)命令格式:設置鎖。
  2. get命令:獲取鍵的值
    • 如果存在,則返回
    • 如果不存在,則返回nil命令格式:獲取鎖
  3. getset命令:該方法是原子的,對鍵設置newvalue這個值,并且返回鍵原來的舊值。
    • 命令格式:設置鎖并設置鍵新值
  4. del命令:刪除redis中指定的key
    • 命令格式:del lock.key

看了很多博客,這里總結一些比較常用的一些方法:

方案1:

分布式鎖實現(xiàn)(mysql,以及redis)以及分布式的概念(續(xù))redsync包使用,GoLong,中間件,golang,架構,中間件,分布式,redis
原理:基于set命令的分布式鎖
使用:set命令
存在問題:可能產(chǎn)生死鎖

  • 原因:假設線程獲取了鎖之后,在執(zhí)行任務的過程中掛掉,來不及顯示地執(zhí)行del命令釋放鎖,那么競爭該鎖的線程都會執(zhí)行不了,產(chǎn)生死鎖的情況。
  • 解決辦法:設置鎖超時時間
    • 原理:可以使用expire命令設置鎖超時時間
    • 使用:setnx 的 key 必須設置一個超時時間,以保證即使沒有被顯式釋放,這把鎖也要在一定時間后自動釋放。
    • 存在問題:可能產(chǎn)生死鎖
      • 問題原因:setnx 和 expire 不是原子性的操作:
        假設某個線程執(zhí)行 setnx 命令,成功獲得了鎖,但是還沒來得及執(zhí)行expire 命令,服務器就掛掉了,這樣一來,這把鎖就沒有設置過期時間了,變成了死鎖,別的線程再也沒有辦法獲得鎖了
      • 使用:setnx 的 key 必須設置一個超時時間,以保證即使沒有被顯式釋放,這把鎖也要在一定時間后自動釋放
      • 解決辦法:redis 的 set 命令支持在獲取鎖的同時設置 key 的過期時間
      • 存在問題:鎖過期提前自動釋放,線程A刪除了線程B的鎖
        • 問題原因:鎖過期提前自動釋放
          1. 假如線程A成功得到了鎖,并且設置的超時時間是 30 秒。如果某些原因?qū)е戮€程 A 執(zhí)行的很慢,過了 30 秒都沒執(zhí)行完,這時候鎖過期自動釋放,線程 B 得到了鎖。
          2. 隨后,線程A執(zhí)行完任務,接著執(zhí)行del指令來釋放鎖。但這時候線程 B 還沒執(zhí)行完,線程A實際上刪除的是線程B加的鎖。
        • 使用:在加鎖的時候把當前的線程 ID 當做value,并在刪除之前驗證 key 對應的 value 是不是自己線程的 ID
        • 解決辦法:可以在 del 釋放鎖之前做一個判斷,驗證當前的鎖是不是自己加的鎖
        • 存在問題:get操作、判斷和釋放鎖是兩個獨立操作,非原子操作
          • 問題原因:判斷和釋放鎖是兩個獨立操作
          • 解決辦法:對于非原子性的問題,我們可以使用Lua腳本來確保操作的原子性

諾是想要更好的體驗可以通過我的飛書觀看:飛升思維導圖

方式2:

分布式鎖實現(xiàn)(mysql,以及redis)以及分布式的概念(續(xù))redsync包使用,GoLong,中間件,golang,架構,中間件,分布式,redis
這里的一些出現(xiàn)的方法是java中的。諾是需要可以改成自己的所屬語言,這張圖較為清晰我也就不做多余的說名,詳情可以看我的飛書:飛書思維導圖

具體的實現(xiàn)操作:

const (
	//解鎖,使用lua變成原子性
	unLockScript = "if redis.call('get',KEYS[1])==ARGV[1]" +
		"then redis.call('del',KEYS[1]) " +
		"return 1 " +
		"else " +
		"return 0 " +
		"end"
	//續(xù)期(看門狗)
	watchLogScript = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end"
)

type DispersedLock struct {
	key            string        //鎖
	value          string        //鎖的值,隨機值(可以用userId+requestId)
	expire         int           //鎖過期時間,單位毫秒
	lockClient     redis.Cmdable //啟用鎖的客戶端,redis目前
	unLockScript   string        //lua 腳本
	watchLogScript string        //看門狗 lua
	unlockChan     chan struct{} //通知通道
}

func (d DispersedLock) getScript(ctx context.Context, script string) string {
	result, _ := d.lockClient.ScriptLoad(ctx, script).Result()
	return result
}

var scriptMap sync.Map

func NewLockRedis(ctx context.Context, cmdable redis.Cmdable, key string, expire int, value string) *DispersedLock {
	lock := &DispersedLock{
		key:    key,
		value:  value,
		expire: expire,
	}
	lock.lockClient = cmdable
	lockScrip, _ := scriptMap.LoadOrStore("dispersed_lock", lock.getScript(ctx, unLockScript))
	lockWatch, _ := scriptMap.LoadOrStore("watch_log", lock.getScript(ctx, watchLogScript))
	lock.unLockScript = lockScrip.(string)
	lock.watchLogScript = lockWatch.(string)
	lock.unlockChan = make(chan struct{}, 0)
	return lock
}

func (d DispersedLock) Lock(ctx context.Context) bool {
	ok, _ := d.lockClient.SetNX(ctx, d.key, d.value, time.Duration(d.expire)*time.Millisecond).Result()
	if ok {
		go d.watchDog(ctx)
	}
	return ok
}
func (d DispersedLock) watchDog(ctx context.Context) {
	//創(chuàng)建一個定時器,每到工作時間的2/3就出發(fā)一次
	duration := time.Duration(d.expire*1e3*2/3) * time.Millisecond
	ticker := time.NewTicker(duration)
	//打包成原子
	for {
		select {
		case <-ticker.C:
			//腳本參數(shù)
			args := []interface{}{
				d.value,
				d.expire,
			}
			result, err := d.lockClient.Eval(ctx, d.watchLogScript, []string{d.key}, args...).Result()
			if err != nil {
				logS.LogM.ErrorF(ctx, "watchDog error %s", err)
				return
			}
			res, ok := result.(int64)
			if !ok {
				return
			}
			if res == 0 {
				return
			}
		case <-d.unlockChan:
			return
		}
	}
}

func (d DispersedLock) unlock(ctx context.Context) bool {
	//腳本參數(shù)
	args := []interface{}{
		d.value,
	}
	result, _ := d.lockClient.Eval(ctx, d.unLockScript, []string{d.key}, args...).Result()
	close(d.unlockChan)

	if result.(int64) > 0 {
		return true
	} else {
		return false
	}
}

const lockMaxLoopNum = 1000

// LoopLock 輪詢等待
func (d DispersedLock) LoopLock(ctx context.Context, sleepTime int) bool {
	cancel, cannel := context.WithCancel(context.Background())
	ticker := time.NewTicker(time.Duration(sleepTime) * time.Millisecond)
	count := 0
	status := 0

loop:
	for {
		select {
		case <-cancel.Done():
			break loop
		default:
		}
		if d.Lock(ctx) {
			ticker.Stop()
			cannel()
			break
		} else {
			<-ticker.C
		}
		count++
		//判斷是否大于最大獲取次數(shù),達到最大直接退出循環(huán)
		if count >= lockMaxLoopNum {
			status = 1
			break
		}
	}
	cannel()
	if status != 0 {

		return false
	}
	return true
}

這些就是通過redis去實現(xiàn)一個分布式鎖的具體步驟,很多實現(xiàn),估計很多其他語言的朋友們可能會有些蒙圈。但是沒有關系。go 關鍵字你就當他是一個線程就可以了,select 關鍵字,你可以理解成隊列+if的判斷

推薦使用包

golangredsync

import "github.com/go-redsync/redsync/v4"

這個包基本上滿足了市面上分布式鎖的所有需求,包括續(xù)租:(但是這里的續(xù)租需要一定的條件才能觸發(fā),這個條件要達到redis實例的最大值時才能觸發(fā))。所以為了,方便使用,建議可以自己續(xù)寫一個續(xù)租的方法。

這里獻上我的:文章來源地址http://www.zghlxwxcb.cn/news/detail-814446.html

// NewLock 實例化一個分布式鎖,用來實現(xiàn)冪等,降低重試成本
func NewLock(mutexName string) *redsync.Mutex {
	pool := goredis.NewPool(configuration.RedisClient)
	rs := redsync.New(pool)
	newString := uuid.NewString()
	lockName := "Lock:" + newString + ":" + mutexName
	mutex := rs.NewMutex(lockName)
	return mutex
}

// LockRelet 周期性續(xù)租,過去無可挽回,未來可以改變
// num定義時間:單位毫秒
// size定義續(xù)租的次數(shù)
func LockRelet(num int, size int, mutex *redsync.Mutex) chan bool {
	done := make(chan bool)
	if size <= 0 {
		return nil
	}
	go func() {
		ticker := time.NewTicker(time.Duration(num) * time.Millisecond)
		defer ticker.Stop()
		for size > 0 {
			size--
			select {
			case <-ticker.C:
				extend, err := mutex.Extend()
				if err != nil {
					logS.LogM.Panicf("Failed to extend lock:", err)
				} else if !extend {
					logS.LogM.Panicf("Failed to extend lock: not successes")
				}
			case <-done:
				return
			}
		}
	}()
	return done
}

到了這里,關于分布式鎖實現(xiàn)(mysql,以及redis)以及分布式的概念(續(xù))redsync包使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 分別使用Redis、MySQL、ZooKeeper構建分布式鎖

    本文使用Java構建三種中間件的分布式鎖,下面介紹下三種分布式鎖的優(yōu)缺點, 使用MySQL構建分布式鎖 ,因為數(shù)據(jù)庫數(shù)據(jù)存儲在磁盤中,所以IO速率相對較慢,因此構建出來的分布式鎖不適合用在高并發(fā)場景,對于一些對并發(fā)要求不高的系統(tǒng)中可以使用,進一步提高系統(tǒng)的安全

    2024年02月06日
    瀏覽(15)
  • Redis——》實現(xiàn)分布式鎖

    推薦鏈接: ????總結——》【Java】 ????總結——》【Mysql】 ????總結——》【Redis】 ????總結——》【Kafka】 ????總結——》【Spring】 ????總結——》【SpringBoot】 ????總結——》【MyBatis、MyBatis-Plus】 ????總結——》【Linux】 ????總結——》【MongoDB】 ???

    2024年02月10日
    瀏覽(24)
  • redis實現(xiàn)分布式延時隊列

    redis實現(xiàn)分布式延時隊列

    延時隊列是一種特殊的消息隊列,它允許將消息在一定的延遲時間后再進行消費。延時隊列的主要特點是可以延遲消息的處理時間,以滿足定時任務或者定時事件的需求。 總之,延時隊列通過延遲消息的消費時間,提供了一種方便、可靠的方式來處理定時任務和定時事件。它

    2024年02月08日
    瀏覽(18)
  • Redis分布式鎖實現(xiàn)原理

    Redis分布式鎖實現(xiàn)原理

    在早期互聯(lián)網(wǎng)的架構中,一個應用都是單機進行部署,這種情況下,利用JDK提供的鎖機制即可解決共享數(shù)據(jù)在多線程場景下的線程安全問題,但隨著技術的發(fā)展,分布式系統(tǒng)架構逐漸普及,在分布式架構中,由于一個應用會進行多機部署,服務器實例之間的JVM是互相獨立的,

    2024年02月16日
    瀏覽(16)
  • 使用redis實現(xiàn)分布式鎖

    使用redis實現(xiàn)分布式鎖

    在一個分布式系統(tǒng)中,也會涉及多個節(jié)點訪問同一個公共資源的情況,此時就需要通過鎖來做互斥控制,避免出現(xiàn)類似于“線程安全”的問題,而java的synchronized這樣的鎖只能在當前進程中生效,在分布式的這種多個進程多個主機的場景無能為力,此時就需要分布式鎖。 例如

    2024年02月07日
    瀏覽(36)
  • redis如何實現(xiàn)分布式鎖?

    首先,“分布式鎖”的概念,是相對“本地鎖”而言。 本地鎖比如java中的synchronized 這類 JDK 自帶的 本地鎖 ,來控制一個 JVM 進程內(nèi)的多個線程對本地共享資源的訪問。 同一時刻只有一個線程可以獲取到本地鎖訪問共享資源。 分布式系統(tǒng)下,不同的服務/客戶端通常運

    2024年02月06日
    瀏覽(21)
  • 分布式鎖之redis實現(xiàn)

    分布式鎖之redis實現(xiàn)

    需要掛在的data和redis.conf自行創(chuàng)建即可 不要忘記開放端口6379 修改redis.conf配置文件,設置 requirepass xxxxx 如果直接使用RedisTemplate使用的序列化器是jdk的,存的是二進制,使用StringRedisTemplate默認初始化序列化器就是String類型 執(zhí)行票數(shù)存入redis指令 ?編寫代碼演示超賣問題 ?500

    2024年02月10日
    瀏覽(20)
  • 分布式鎖的實現(xiàn)(redis)

    1、單機鎖 考慮在并發(fā)場景并且存在競態(tài)的狀況下,我們就要實現(xiàn)同步機制了,最簡單的同步機制就是加鎖。 加鎖可以幫我們鎖住資源,如內(nèi)存中的變量,或者鎖住臨界區(qū)(線程中的一段代碼),使得同一個時刻只有一個線程能訪問某一個區(qū)域。 如果是單實例(單進程部署),那

    2024年02月12日
    瀏覽(20)
  • Redis實現(xiàn)分布式鎖(SETNX)

    Redis實現(xiàn)分布式鎖(SETNX)

    目錄 1、什么是分布式鎖 2、分布式鎖應具備的條件???????? 3、為什么使用分布式鎖 4、SETNX介紹 5、分布式鎖實現(xiàn) 6、效果演示 7、Redisson分布式鎖詳解 8、Lua腳本實現(xiàn)可重入分布式鎖 ????????分布式鎖是控制分布式系統(tǒng)之間同步訪問共享資源的一種方式。 ????????在

    2024年02月16日
    瀏覽(24)
  • 使用注解實現(xiàn)REDIS分布式鎖

    使用注解實現(xiàn)REDIS分布式鎖

    有些業(yè)務請求,屬于耗時操作,需要加鎖,防止后續(xù)的并發(fā)操作,同時對數(shù)據(jù)庫的數(shù)據(jù)進行操作,需要避免對之前的業(yè)務造成影響。 使用 Redis 作為分布式鎖,將鎖的狀態(tài)放到 Redis 統(tǒng)一維護,解決集群中單機 JVM 信息不互通的問題,規(guī)定操作順序,保護用戶的數(shù)據(jù)正確。 梳理

    2024年02月02日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包