濮阳杆衣贸易有限公司

主頁 > 知識庫 > 如何使用Redis鎖處理并發(fā)問題詳解

如何使用Redis鎖處理并發(fā)問題詳解

熱門標(biāo)簽:南京手機(jī)外呼系統(tǒng)廠家 b2b外呼系統(tǒng) 高碑店市地圖標(biāo)注app 臺(tái)灣電銷 四川穩(wěn)定外呼系統(tǒng)軟件 一個(gè)地圖標(biāo)注多少錢 廊坊外呼系統(tǒng)在哪買 400電話辦理的口碑 地圖標(biāo)注工廠入駐

前言

上周“被”上線了一個(gè)緊急項(xiàng)目,周五下班接到需求,周一開始思考解決方案,周三開發(fā)完成,周四走流程上線,也算是面向領(lǐng)導(dǎo)編程了。之前的項(xiàng)目里面由于是自運(yùn)維,然后大多數(shù)又都趕時(shí)間,所以在處理定時(shí)任務(wù)上面基本都是自己在服務(wù)器上添加crontab,而不是讓多個(gè)實(shí)例自己去處理定時(shí)任務(wù)的并發(fā)鎖,并且Laravel 5.5開始自帶并發(fā)鎖,我們也快升級了。但是這次項(xiàng)目是Python項(xiàng)目,無奈只能自己實(shí)現(xiàn)一下,以下這個(gè)方案實(shí)現(xiàn)起來非常簡單且易于理解。

import redis
r = redis.Redis(...)

last_heart = 0		# 記錄上一次得到的鎖心跳
free_lock_try = 6	# 鎖無心跳的最大次數(shù) 

while not r.setnx('mylock', 1):
 now_heart = r.get('mylock')
 print(f"沒獲取到鎖,now_heart={now_heart},last_heart={last_heart},free_lock_try={free_lock_try}")
 if now_heart == last_heart:
  free_lock_try = free_lock_try - 1
  if free_lock_try == 0:	# 鎖已經(jīng)1分鐘沒有心跳了
   old_heart = r.getset('mylock', 1)	# 將lock重置為1,并返回set之前的心跳值
   if old_heart  now_heart:
    time.sleep(10)
    continue
   else:
    break	# 成功獲取到鎖,退出循環(huán)
 else:
  free_lock_try = 6	# 鎖有心跳,重置free_lock_try值
  last_heart = now_heart
 time.sleep(10)

def producer_exit():
 """程序正常退出時(shí)候自動(dòng)清理鎖"""
 r.delete('mylock')
import atexit
atexit.register(producer_exit)

# 業(yè)務(wù)代碼
while True:
 r.incr('mylock')	# 讓鎖心跳加一
 ...

我們來看看這段程序都解決了并發(fā)鎖中的哪些問題

  • 高并發(fā)下,多個(gè)進(jìn)程無法同時(shí)獲取到鎖。這里使用的是redis.setnx,如果鎖已經(jīng)存在,其他進(jìn)程是無法重置鎖并獲取到鎖的。另外當(dāng)多個(gè)進(jìn)程同時(shí)發(fā)現(xiàn)有鎖已經(jīng)沒有心跳了,使用的是redis.getset將心跳重置為1,都能set成功,但是get出來的值多個(gè)進(jìn)程是不一樣的,只有真正獲取到鎖的進(jìn)程返回的是之前進(jìn)程的心跳,而其他進(jìn)程獲取到的都是1。
  • 有鎖進(jìn)程正常退出,可以使用atexit注冊進(jìn)程退出函數(shù)刪除鎖,這里也可以不要,不過下次啟動(dòng)得等新的進(jìn)程等待幾次心跳
  • 有鎖進(jìn)程意外退出,退出后心跳不再增加,超過free_lock_try次數(shù)后,其他進(jìn)程會(huì)重新設(shè)置并獲取鎖
  • 所有進(jìn)程全都意外退出,這個(gè)問題不是鎖來關(guān)心的,可以使用supervisor進(jìn)行守護(hù)進(jìn)程。

導(dǎo)致Redis并發(fā)原因解釋

正所謂只有知其然才能知其所以然,只有弄明白問題出現(xiàn)的原因所在,才能對癥下藥,尋找解決問題的良方。眾所周知,Redis程序采用單線程模式進(jìn)行運(yùn)行,作為單線程程序,Redis客戶端的命令是逐條執(zhí)行,也叫做One by One執(zhí)行。既然是逐條命令執(zhí)行,從表面上來看Redis似乎不存在高并發(fā)的問題,這一觀點(diǎn)論也有道理,原子性的Redis命令本身也確實(shí)不存在高并發(fā)問題,這與多線程下的程序勃然不同。但是我們項(xiàng)目工作搭建Redis環(huán)境之后,通常都會(huì)是一組命令集合執(zhí)行程序,一個(gè)請求中就包含了N個(gè)Redis執(zhí)行命令,再加上多個(gè)客戶端請求,命令就更多了,導(dǎo)致連接超時(shí)、數(shù)據(jù)混亂或錯(cuò)誤、請求阻塞等多種問題。

即總結(jié)為,產(chǎn)生Redis并發(fā)誘因是程序中的業(yè)務(wù)復(fù)雜度導(dǎo)致。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • PHP實(shí)現(xiàn)Redis單據(jù)鎖以及防止并發(fā)重復(fù)寫入
  • 如何利用Redis鎖解決高并發(fā)問題詳解
  • php 使用redis鎖限制并發(fā)訪問類示例

標(biāo)簽:拉薩 伊春 河源 南寧 泰州 畢節(jié) 定州 甘南

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《如何使用Redis鎖處理并發(fā)問題詳解》,本文關(guān)鍵詞  如何,使用,Redis,鎖,處理,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《如何使用Redis鎖處理并發(fā)問題詳解》相關(guān)的同類信息!
  • 本頁收集關(guān)于如何使用Redis鎖處理并發(fā)問題詳解的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    汕头市| 九江县| 蒲城县| 上高县| 游戏| 新沂市| 延寿县| 黎平县| 大石桥市| 龙门县| 青神县| 广平县| 贵阳市| 敦煌市| 太仆寺旗| 宾川县| 句容市| 宜良县| 安平县| 衡南县| 垫江县| 纳雍县| 皋兰县| 黄陵县| 阳城县| 九龙坡区| 永丰县| 景谷| 黎川县| 卢氏县| 门源| 舞钢市| 平顶山市| 永平县| 贵阳市| 民乐县| 扶余县| 阳新县| 泰顺县| 鹤岗市| 额尔古纳市|