亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Redis利用原子操作(INCR,DECR)實現(xiàn)分布式計數(shù)器

 更新時間:2025年07月31日 09:05:35   作者:冰糖心書房  
在分布式系統(tǒng)中,由于多個服務(wù)實例需要共享和修改同一個計數(shù)值,實現(xiàn)一個準確、高效的分布式計數(shù)器至關(guān)重要,下面我們就來看看具體實現(xiàn)方法吧

在分布式系統(tǒng)中,由于多個服務(wù)實例需要共享和修改同一個計數(shù)值,實現(xiàn)一個準確、高效的分布式計數(shù)器至關(guān)重要。Redis 憑借其內(nèi)存存儲的高性能和原子操作命令,成為實現(xiàn)這一功能的理想選擇。

核心原理:Redis 的原子操作

Redis 的單線程命令處理模型確保了單個命令的執(zhí)行是原子性的。 這意味著當一個命令正在執(zhí)行時,不會被其他客戶端的命令打斷。對于計數(shù)器而言,INCRDECR 這兩個命令是核心。

  • INCR key: 將存儲在 key 的數(shù)字值增一。如果 key 不存在,那么 key 的值會先被初始化為 0,然后再執(zhí)行 INCR 操作。
  • DECR key: 將 key 中儲存的數(shù)字值減一。如果 key 不存在,其值同樣會先被初始化為 0 再執(zhí)行 DECR

這兩個操作的原子性是實現(xiàn)分布式計數(shù)器的基石,它保證了即使在大量并發(fā)請求下,計數(shù)結(jié)果也是準確的,避免了“讀取-修改-寫入”模式中可能出現(xiàn)的競態(tài)條件。

基本實現(xiàn)方法

實現(xiàn)一個基本的分布式計數(shù)器非常簡單,只需要為你的計數(shù)器定義一個唯一的鍵(key),然后調(diào)用相應(yīng)的原子命令即可。

使用場景示例:

  • 文章閱讀量統(tǒng)計: 每當有用戶閱讀一篇文章,就對該文章的計數(shù)器執(zhí)行 INCR
  • 在線用戶數(shù): 用戶登錄時執(zhí)行 INCR,登出時執(zhí)行 DECR
  • 庫存管理: 用戶下單時執(zhí)行 DECR,取消訂單或補貨時執(zhí)行 INCR

Python 代碼示例 (使用redis-py)

import redis

# 連接到 Redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

def get_post_views(post_id: int) -> int:
    """獲取文章的閱讀量"""
    key = f"post:{post_id}:views"
    view_count = r.get(key)
    return int(view_count) if view_count else 0

def increment_post_views(post_id: int) -> int:
    """增加文章的閱讀量"""
    key = f"post:{post_id}:views"
    # INCR 是原子操作,返回增加后的值
    return r.incr(key)

# --- 使用示例 ---
post_id = 123
print(f"文章 {post_id} 的初始閱讀量: {get_post_views(post_id)}")

# 模擬10次并發(fā)的閱讀請求
for _ in range(10):
    new_views = increment_post_views(post_id)
    print(f"閱讀量已增加至: {new_views}")

print(f"文章 {post_id} 的最終閱讀量: {get_post_views(post_id)}")

Java 代碼示例 (使用Jedis)

import redis.clients.jedis.Jedis;

public class DistributedCounter {

    private final Jedis jedis;

    public DistributedCounter(String host, int port) {
        this.jedis = new Jedis(host, port);
    }

    public long increment(String key) {
        // incr 是原子操作
        return jedis.incr(key);
    }

    public long decrement(String key) {
        // decr 是原子操作
        return jedis.decr(key);
    }

    public long getCount(String key) {
        String value = jedis.get(key);
        return value != null ? Long.parseLong(value) : 0;
    }

    public static void main(String[] args) {
        DistributedCounter counter = new DistributedCounter("localhost", 6379);
        String counterKey = "online_users";

        System.out.println("初始在線人數(shù): " + counter.getCount(counterKey));

        // 模擬用戶登錄
        long user1_login = counter.increment(counterKey);
        System.out.println("用戶1登錄,當前在線人數(shù): " + user1_login);

        long user2_login = counter.increment(counterKey);
        System.out.println("用戶2登錄,當前在線人數(shù): " + user2_login);

        // 模擬用戶登出
        long user1_logout = counter.decrement(counterKey);
        System.out.println("用戶1登出,當前在線人數(shù): " + user1_logout);

        System.out.println("最終在線人數(shù): " + counter.getCount(counterKey));
    }
}

處理需要重置的計數(shù)器(例如每日計數(shù))

在某些場景下,計數(shù)器需要定期重置,例如統(tǒng)計每日活躍用戶或每日API調(diào)用次數(shù)。一種常見的錯誤做法是先 INCR,再用 EXPIRE 設(shè)置過期時間。這種方式存在競態(tài)條件:如果在 INCR 執(zhí)行后、EXPIRE 執(zhí)行前,服務(wù)發(fā)生故障,這個鍵就會永久存在,導致計數(shù)器無法自動重置。

正確的做法是使用 Lua 腳本將 INCREXPIRE 捆綁成一個原子操作。

Lua 腳本示例

-- increment_with_ttl.lua
local key = KEYS[1]
local ttl = ARGV[1]

local count = redis.call("INCR", key)

-- 如果是第一次增加(即增加后的值為1),則設(shè)置過期時間
if count == 1 then
    redis.call("EXPIRE", key, ttl)
end

return count

在應(yīng)用程序中,通過 EVAL 命令執(zhí)行此腳本,可以確保增加計數(shù)和設(shè)置過期時間這兩步操作的原子性。

復雜操作與事務(wù)

如果需要根據(jù)計數(shù)值執(zhí)行更復雜的操作(例如,檢查庫存是否足夠再減庫存),簡單的 DECR 可能不夠用。雖然可以使用 WATCH, MULTI, EXEC 事務(wù)來解決,但這會增加代碼的復雜性。 在這種情況下,使用 Lua 腳本通常是更簡單、更高效的選擇,因為它將整個邏輯封裝在服務(wù)器端作為一個原子單元執(zhí)行。

總結(jié)

利用 Redis 的 INCRDECR 原子操作是實現(xiàn)分布式計數(shù)器的標準且高效的方法。其核心優(yōu)勢在于 Redis 保證了單個命令的原子性,從而避免了分布式環(huán)境下的競態(tài)條件。對于需要自動重置的計數(shù)器,強烈建議使用 Lua 腳本來確保操作的原子性,防止數(shù)據(jù)不一致。

到此這篇關(guān)于Redis利用原子操作(INCR,DECR)實現(xiàn)分布式計數(shù)器的文章就介紹到這了,更多相關(guān)Redis分布式計數(shù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳談redis跟數(shù)據(jù)庫的數(shù)據(jù)同步問題

    詳談redis跟數(shù)據(jù)庫的數(shù)據(jù)同步問題

    文章討論了在Redis和數(shù)據(jù)庫數(shù)據(jù)一致性問題上的解決方案,主要比較了先更新Redis緩存再更新數(shù)據(jù)庫和先更新數(shù)據(jù)庫再更新Redis緩存兩種方案,文章指出,刪除Redis緩存后再更新數(shù)據(jù)庫的方案更優(yōu),因為它可以避免數(shù)據(jù)不一致的問題,但可能產(chǎn)生高并發(fā)問題
    2025-01-01
  • Redis 命令的詳解及簡單實例

    Redis 命令的詳解及簡單實例

    這篇文章主要介紹了Redis 命令的詳解及簡單實例的相關(guān)資料,這里提供基礎(chǔ)語法及使用實例,需要的朋友可以參考下
    2017-08-08
  • Redis集群部署Windows版本的過程詳解

    Redis集群部署Windows版本的過程詳解

    本文介紹了如何在Windows系統(tǒng)上部署Redis集群,包括從GitHub下載Windows版本的Redis、配置文件的創(chuàng)建、啟動腳本的編寫以及集群的啟動和配置過程,感興趣的朋友一起看看吧
    2025-03-03
  • Redis實現(xiàn)鎖續(xù)期的項目實踐

    Redis實現(xiàn)鎖續(xù)期的項目實踐

    本文介紹了使用Redis實現(xiàn)分布式鎖的續(xù)期,包括使用Lua腳本、Redlock算法和Redisson客戶端等方法,具有一定的參考價值,感興趣的可以了解一下
    2024-12-12
  • redis事務(wù)常用操作詳解

    redis事務(wù)常用操作詳解

    在本篇文章里小編給大家分享了關(guān)于redis事務(wù)常用操作的相關(guān)知識點內(nèi)容,有興趣的朋友們可以跟著學習參考下。
    2019-07-07
  • 大白話講解調(diào)用Redis的increment失敗原因及推薦使用詳解

    大白話講解調(diào)用Redis的increment失敗原因及推薦使用詳解

    本文主要介紹了調(diào)用Redis的increment失敗原因及推薦使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Spring?Boot?3.0x的Redis?分布式鎖的概念和原理

    Spring?Boot?3.0x的Redis?分布式鎖的概念和原理

    Redis?分布式鎖是一種基于?Redis?的分布式鎖解決方案,它的原理是利用?Redis?的原子性操作實現(xiàn)鎖的獲取和釋放,從而保證共享資源的獨占性,這篇文章主要介紹了適合?Spring?Boot?3.0x的Redis?分布式鎖,需要的朋友可以參考下
    2024-08-08
  • 淺談Redis中LFU算法源碼解析

    淺談Redis中LFU算法源碼解析

    Redis的LFU淘汰算法主要用于?maxmemory-policy?設(shè)置為allkeys-lfu或volatile-lfu時,以最少使用頻率的鍵進行淘汰,本文主要介紹了淺談Redis中LFU算法源碼解析,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2025-04-04
  • 深入理解redis分布式鎖和消息隊列

    深入理解redis分布式鎖和消息隊列

    本篇文章主要介紹了深入理解redis分布式鎖和消息隊列,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • redis緩存延時雙刪的原因分析

    redis緩存延時雙刪的原因分析

    延時雙刪就是在增刪改某實體類的時候,要對該實體類的緩存進行清空,清空的位置在數(shù)據(jù)庫操作方法的前后,這篇文章主要介紹了redis緩存為什么要延時雙刪,需要的朋友可以參考下
    2022-08-08

最新評論