成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Redis事務(wù)詳解

Harpsichord1207 / 1907人閱讀

摘要:當(dāng)一個事務(wù)執(zhí)行完畢之后,才會處理其他客戶端的命令。延遲執(zhí)行事務(wù)有助于提升性能因?yàn)樵趫?zhí)行事務(wù)的過程中,會延遲執(zhí)行已入隊(duì)的命令直到客戶端發(fā)送命令為止。

Redis的基本事務(wù)(basic transaction)需要用到MULTI命令和EXEC命令,這種事務(wù)可以讓一個客戶端在不被其他客戶端打斷的情況下執(zhí)行多個命令。被NULTI命令和EXEC命令包圍的所有命令會一個接一個地執(zhí)行,直到所有命令都執(zhí)行完畢為止。當(dāng)一個事務(wù)執(zhí)行完畢之后,Redis才會處理其他客戶端的命令。

當(dāng)Redis從一個客戶端那里接收到MULTI命令時,Redis會將這個客戶端之后發(fā)送的所有命令都放入到一個隊(duì)列里面,直到這個客戶端發(fā)送EXEC命令為止,然后Redis就會在不被打斷的情況下,一個接一個地執(zhí)行存儲在隊(duì)列里面的命令。從語義上來說,Redis事務(wù)在Python客戶端上面是由流水線(pipeline)實(shí)現(xiàn)的:對連接對象調(diào)用pipeline()方法將創(chuàng)建一個事務(wù),在一切正常的情況下,客戶端會自動地使用MULTI和EXEC包裹起用戶輸入的多個命令。為了減少Redis與客戶端之間的通信往返次數(shù),提升執(zhí)行多個命令時的性能,Python的Redis客戶端會存儲起事務(wù)包含的多個命令,然后在事務(wù)執(zhí)行時一次性地將所有命令都發(fā)送給Redis。

在Python中使用事務(wù)來處理命令的并行執(zhí)行問題:

def trans():
    pipeline = conn.pipeline() # 創(chuàng)建事務(wù)型流水線對象
    pipeline.incr("trans:") # 把針對"trans:"計(jì)數(shù)器的自增操作放入隊(duì)列
    time.sleep(.1) # 等待100ms
    
    pipeline.incr("trans:", -1) # 把針對"trans:"計(jì)數(shù)器的自減操作放入隊(duì)列
    print pipeline.execute()[0] # 執(zhí)行被事務(wù)包裹的命令,并打印自增操作的執(zhí)行結(jié)果
    
if 1:
    for i in xrange(3):
        # 啟動3個線程來執(zhí)行被事務(wù)包裹的自增、休眠和自減3個操作
        threading.Thread(target=trans).start()
    time.sleep(.5) # 等待500ms,讓操作有足夠的時間完成  
          
# 打印結(jié)果:    
1
1
1  

Redis要在接收到EXEC命令之后,才會執(zhí)行哪些位于MULTI和EXEC之間的入隊(duì)命令。

上述這種簡單的事務(wù)在EXEC命令被調(diào)用之前不會執(zhí)行任何實(shí)際操作,所以用戶將沒辦法根據(jù)讀取到的數(shù)據(jù)來做決定。這種方式無法以一致的形式讀取數(shù)據(jù)將導(dǎo)致某一類型的問題變得難以解決,除此之外,因?yàn)樵诙鄠€事務(wù)同時處理同一個對象時通常需要用到二階提交(two-phase commit), 所以如果事務(wù)不能以一致的形式讀取數(shù)據(jù),那么二階提交將無法實(shí)現(xiàn),從而導(dǎo)致一些原本可以成功執(zhí)行的事務(wù)執(zhí)行失敗。

延遲執(zhí)行事務(wù)有助于提升性能
因?yàn)镽edis在執(zhí)行事務(wù)的過程中,會延遲執(zhí)行已入隊(duì)的命令直到客戶端發(fā)送EXEC命令為止。包括python客戶端在內(nèi)的很多Redis客戶端都會等到事務(wù)包含的所有命令都出現(xiàn)了之后,才一次性地將MULTI命令、要在事務(wù)中執(zhí)行的一系列命令,以及EXEC命令全部發(fā)送給Redis,然后等待直到接收到所有命令的回復(fù)為止。這種“一次性發(fā)送多個命令,然后等待所有回復(fù)出現(xiàn)”的做法通常被稱為流水線(pipeline),它可以通過減少客戶端與Redis服務(wù)器之間的網(wǎng)絡(luò)通信次數(shù)來提升Redis在執(zhí)行多個命令時的性能。

在用戶使用WATCH命令對鍵進(jìn)行監(jiān)視之后,直到用戶執(zhí)行EXEC命令的這段時間,如果有其他客戶端搶先對任何被監(jiān)視的鍵進(jìn)行了替換、更新或刪除等操作,那么當(dāng)用戶嘗試執(zhí)行EXEC命令的時候,事務(wù)將失敗并返回一個錯誤(之后選擇重試事務(wù)或者放棄事務(wù))。

UNWATCH命令可以在WATCH命令執(zhí)行之后、MULTI命令執(zhí)行之前對連接進(jìn)行重置(reset);同樣地,DISCARD命令也可以在MULTI命令執(zhí)行之后、EXEC命令執(zhí)行之前對連接進(jìn)行重置。這也就是說,用戶在使用WATCH監(jiān)視一個或多個鍵,接著使用MULTI開始一個新的事務(wù),并將多個命令入隊(duì)到事務(wù)隊(duì)列之后,仍然可以通過發(fā)送DISCARD命令來取消WATCH命令并清空所有已入隊(duì)命令。

將商品放到市場上銷售:

def list_item(conn, itemid, sellerid, price):
    inventory = "inventory:%s"%sellerid # 商家包裹
    item = "%s.%s"%(itemid, sellerid)
    end = time.time() + 5
    pipe = conn.pipeline()
    
    while time.time() < end:
        try:
            pipe.watch(inventory) # 監(jiān)視商家包裹發(fā)生的變化
            if not pipe.sismember(inventory, itemid): # 檢查商家是否仍然持有將要被銷售的商品
                pipe.unwatch()
                return None
                
            pipe.multi()
            pipe.zadd("market:",  item, price) # 將出售的商品添加到買賣市場
            pipe.srem(inventory, itemid)
            pipe.execute() # 執(zhí)行execute沒有引發(fā)WatchError異常,說明事務(wù)執(zhí)行成功,并且對包裹鍵的監(jiān)視也已經(jīng)結(jié)束
            return True
         except redis.exceptions.WatchError: # 商家的包裹已經(jīng)發(fā)生變化,重試
            pass
    return False

購買商品:

def purchase_item(conn, buyerid, itemid, sellerid, lprice):
    buyer = "users:%s"%buyerid
    seller = "users:%s"%sellerid
    item = "%s.%s"%(itemid, sellerid)
    inventory = "inventory:%s"%buyerid
    end = time.time() + 10 
    pipe = conn.pipeline()
    
    while time.time() < end:
        try:
            pipe.watch("market:", buyer) # 對商品買賣市場以及買家的個人信息進(jìn)行監(jiān)視
            # 檢查購買的商品價格是否發(fā)生變化,以及賣家是否有足夠的錢購買
            price = pipe.zscore("market:", item)
            funds = int(pipe.hget(buyer, "funds"))
            if price != lprice or price > funds:
                pipe.unwatch()
                return None
                
            pipe.multi()
            pipe.hincrby(seller, "funds", int(price))
            pipe.hincrby(buyer, "funds", int(-price))
            pipe.sadd(inventory, itemid)
            pipe.zrem("market:", item)
            pipe.execute()
            return True
        except redis.exceptions.WatchError:
            pass
            
    return False     
    
加鎖有可能造成長時間的等待,所以Redis為了盡可能地減少客戶端的等待時間,并不會在執(zhí)行WATCH命令時對數(shù)據(jù)進(jìn)行加鎖。相反,Redis只會在數(shù)據(jù)已經(jīng)被其他客戶端搶先修改了的情況下,通知執(zhí)行WATCH命令的客戶端,這種做法稱為樂觀鎖(optimistic locking),而關(guān)系型數(shù)據(jù)庫實(shí)際執(zhí)行的加鎖操作則被稱為悲觀鎖(pessimistic locking)。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/44556.html

相關(guān)文章

  • 如何使用StringRedisTemplate操作Redis詳解

    摘要:如何使用操作詳解簡介是一個開源許可的,內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲系統(tǒng),它可以用作數(shù)據(jù)庫緩存和消息中間件。解決辦法是即使查出的對象為空,也放入緩存時間設(shè)短一點(diǎn)。緩存雪崩,是指在某一個時間段,緩存集中過期失效。 如何使用StringRedisTemplate操作Redis詳解 Redis簡介 Redis 是一個開源(BSD許可)的,內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲系統(tǒng),它可以用作數(shù)據(jù)庫、緩存和消息中間件。支...

    tulayang 評論0 收藏0
  • 【推薦】最新200篇:技術(shù)文章整理

    摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...

    BicycleWarrior 評論0 收藏0
  • 【推薦】最新200篇:技術(shù)文章整理

    摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...

    tommego 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<