使用redis分布式鎖解決并發(fā)線程資源共享問題
前言
眾所周知, 在多線程中,因為共享全局變量,會導致資源修改結(jié)果不一致,所以需要加鎖來解決這個問題,保證同一時間只有一個線程對資源進行操作
但是在分布式架構(gòu)中,我們的服務可能會有n個實例,但線程鎖只對同一個實例有效,就需要用到分布式鎖----redis setnx
原理
修改某個資源時, 在redis中設置一個key,value根據(jù)實際情況自行決定如何表示
我們既然要通過檢查key是否存在(存在表示有線程在修改資源,資源上鎖,其他線程不可同時操作,若key不存在,表示資源未被線程占用,允許線程搶占,然后將通過setnx設置vlaue,表示資源上鎖,其他線程不可同時操作)
圖示:
分析
我們的服務處于一個集群中,如果只是簡單的的使用線程鎖來解決以上問題,是存在問題的:因為線程是基于進程的,兩個web server處于不同的進程空間
也就是說,user1的請求發(fā)往web server1,那只能與web server1的其他請求進行鎖的操作,而不能對web server2的請求產(chǎn)生影響
上面的圖中,user1發(fā)往web server1的請求負責處理的線程為Thread1,同理負責處理user2發(fā)往web server2的請求的線程thread2
在同一時刻1,兩個線程都讀取了mysql中residue_ticket的值為100,對應上圖 (1)(2), 各自對100進行-1操作,更新到數(shù)據(jù)庫,對應(3)(4)
我們預期的情況是residue_ticket值被減少了兩次,應該為98,但是實際情況下,兩個線程都做了100-1=99的操作,并都將mysql中的值改為了99, 的這就會導致最終數(shù)據(jù)不一致,所以就要用到分布式鎖。
為什么用redis?
因為redis是單線程的,不存在多線程資源競爭,并且它真的很快
為什么用setnx 而不是set?
setnx表示只有在key不存在時才能設置成功,但是set會在key存在的情況下修改value
利用setnx的特性,我們可以這樣這樣設計:
偽代碼:
# 設置redis鎖的 redis key = 'residue_ticket_lock' # get_ticket是處理購票的邏輯 def get_ticket(): time_out = 5 # 為了防止線程過多,當前線程獲取不到鎖,長時間處于循環(huán)中而導致的性能影響,我們設置一個超時時間,如果當前線程在超時時間內(nèi)還沒有搶占到分布式鎖,就返回失敗的結(jié)果 while True: if redis.setnx('residue_ticket_lock','lock',5): # 如果setnx返回True, 表示此刻沒有其他線程在操作數(shù)據(jù)庫,當前線程可以上鎖成功,注意不僅設置了value=lock,還設置了過期時間,這是必要的,為了防止上鎖的線程異常崩掉導致不能釋放(刪除key)而導致其他所有線程永遠拿不到操作權(quán) residue_ticket = mysql.get('residue_ticket') # 從mysql中獲取當前剩余票數(shù) mysql.update('residue_ticket',residue_ticket-1) # 訂購成功,將票數(shù)-1,更新數(shù)據(jù)到mysql # 刪除key,釋放鎖 redis.del('residue_ticket') return True else: # 如果setnx返回False,表示有其他線程對在操作,當前線程等待0.01s,并繼續(xù)循環(huán) time.sleep(0.01) time_out -= 0.01 continue return False
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
kubernetes環(huán)境部署單節(jié)點redis數(shù)據(jù)庫的方法
這篇文章主要介紹了kubernetes環(huán)境部署單節(jié)點redis數(shù)據(jù)庫的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01redis中Could not get a resource from
這篇文章主要介紹了redis中Could not get a resource from the pool異常及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12Redis?延時任務實現(xiàn)及與定時任務區(qū)別詳解
這篇文章主要為大家介紹了Redis?延時任務實現(xiàn)及與定時任務區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06