国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

基于 Golang 和 Redis 解決分布式系統下的并發問題

云計算 分布式
Redis 提供了多種解決并發問題的方案,包括原子操作、事務、LUA 腳本和分布式鎖等。在實際應用中,需要根據具體場景選擇合適的方案。

在分布式系統和數據庫的交互中,并發問題如同暗流般潛伏,稍有不慎就會掀起應用的驚濤駭浪。試想一下,我們正在構建一個股票交易平臺,允許不同用戶同時購買公司股票。每個公司都有一定數量的可用股票,用戶只能在剩余股票充足的情況下進行購買。

Golang 與 Redis 的解決方案:構建穩固的交易系統

為了解決這個問題,我們可以借助 Golang 和 Redis 的強大功能,構建一個安全可靠的交易系統。

數據層搭建:GoRedis 助力高效交互

首先,我們使用 goredis 客戶端庫創建一個數據層(Repository),用于與 Redis 數據庫進行交互:

type Repository struct {
 client *redis.Client
}

var _ go_redis_concurrency.Repository = (*Repository)(nil)

func NewRepository(address, password string) Repository {
 return Repository{
  client: redis.NewClient(&redis.Options{
   Addr:     address,
   Password: password,
  }),
 }
}

購買股票功能實現:并發問題初現端倪

接下來,我們實現 BuyShares 函數,模擬用戶購買股票的操作:

func (r *Repository) BuyShares(ctx context.Context, userId, companyId string, numShares int, wg *sync.WaitGroup) error {
 defer wg.Done()

 companySharesKey := BuildCompanySharesKey(companyId)

 // --- (1) ----
 // 獲取當前可用股票數量
 currentShares, err := r.client.Get(ctx, companySharesKey).Int()
 if err != nil {
  fmt.Print(err.Error())
  return err
 }

 // --- (2) ----
 // 驗證剩余股票是否充足
 if currentShares < numShares {
  fmt.Print("error: 公司剩余股票不足\n")
  return errors.New("error: 公司剩余股票不足")
 }
 currentShares -= numShares

 // --- (3) ----
 // 更新公司可用股票數量
 _, err = r.client.Set(ctx, companySharesKey, currentShares, 0).Result()
 return err
}

該函數包含三個步驟:

  1. 獲取公司當前可用股票數量。
  2. 驗證剩余股票是否足以滿足用戶購買需求。
  3. 更新公司可用股票數量。

看似邏輯清晰,但當多個用戶并發執行 BuyShares 函數時,問題就出現了。

模擬并發場景:問題暴露無遺

為了模擬并發場景,我們創建多個 Goroutine 同時執行 BuyShares 函數:

const (
 total_clients = 30
)

func main() {
 // --- (1) ----
 // 初始化 Repository
 repository := redis.NewRepository(fmt.Sprintf("%s:%d", config.Redis.Host, config.Redis.Port), config.Redis.Pass)

 // --- (2) ----
 // 并發執行 BuyShares 函數
 companyId := "TestCompanySL"
 var wg sync.WaitGroup
 wg.Add(total_clients)

 for idx := 1; idx <= total_clients; idx++ {
  userId := fmt.Sprintf("user%d", idx)
  go repository.BuyShares(context.Background(), userId, companyId, 100, &wg)
 }
 wg.Wait()

 // --- (3) ----
 // 獲取公司剩余股票數量
 shares, err := repository.GetCompanyShares(context.Background(), companyId)
 if err != nil {
  panic(err)
 }
 fmt.Printf("公司 %s 剩余股票數量: %d\n", companyId, shares)
}

假設公司 TestCompanySL 初始擁有 1000 股可用股票,每個用戶購買 100 股。我們期望的結果是,只有 10 個用戶能夠成功購買股票,剩余用戶會因為股票不足而收到錯誤信息。

然而,實際運行結果卻出乎意料,公司剩余股票數量可能出現負數,這意味著多個用戶在讀取可用股票數量時,獲取到的是同一個未更新的值,導致最終結果出現偏差。

Redis 并發解決方案:精準打擊,逐個擊破

為了解決上述并發問題,Redis 提供了多種解決方案,讓我們來一一剖析。

原子操作:簡單場景下的利器

原子操作能夠在不加鎖的情況下,保證對數據的修改操作具有原子性。在 Redis 中,可以使用 INCRBY 命令對指定 key 的值進行原子遞增或遞減。

func (r *Repository) BuyShares(ctx context.Context, userId, companyId string, numShares int, wg *sync.WaitGroup) error {
 defer wg.Done()

 // ... (省略部分代碼) ...

 // 使用 INCRBY 命令原子更新股票數量
 _, err = r.client.IncrBy(ctx, companySharesKey, int64(-numShares)).Result()
 return err
}

然而,在我們的股票交易場景中,原子操作并不能完全解決問題。因為在更新股票數量之前,還需要進行剩余股票數量的驗證。如果多個用戶同時讀取到相同的可用股票數量,即使使用原子操作更新,最終結果仍然可能出現錯誤。

事務:保證操作的原子性

Redis 事務可以將多個命令打包成一個原子操作,要么全部執行成功,要么全部回滾。通過 MULTI、EXEC、DISCARD 和 WATCH 命令,可以實現對數據的原子性操作。

  • MULTI:標記事務塊的開始。
  • EXEC:執行事務塊中的所有命令。
  • DISCARD:取消事務塊,放棄執行所有命令。
  • WATCH:監視指定的 key,如果 key 在事務執行之前被修改,則事務執行失敗。

在我們的例子中,可以使用 WATCH 命令監視公司可用股票數量的 key。如果 key 在事務執行之前被修改,則說明有其他用戶并發修改了數據,當前事務執行失敗,從而保證數據的一致性。

func (r *Repository) BuyShares(ctx context.Context, userId, companyId string, numShares int, wg *sync.WaitGroup) error {
 defer wg.Done()

 companySharesKey := BuildCompanySharesKey(companyId)

 // 使用事務保證操作的原子性
 tx := r.client.TxPipeline()
 tx.Watch(ctx, companySharesKey)

 // ... (省略部分代碼) ...

 _, err = tx.Exec(ctx).Result()
 return err
}

然而,在高并發場景下,使用事務可能會導致大量事務執行失敗,影響系統性能。

LUA 腳本:將邏輯移至 Redis 服務端執行

為了避免上述問題,可以借助 Redis 的 LUA 腳本功能,將業務邏輯移至 Redis 服務端執行。LUA 腳本在 Redis 中以原子方式執行,可以有效避免并發問題。

local sharesKey = KEYS[1]
local requestedShares = ARGV[1]

local currentShares = redis.call("GET", sharesKey)
if currentShares < requestedShares then
 return {err = "error: 公司剩余股票不足"}
end

currentShares = currentShares - requestedShares
redis.call("SET", sharesKey, currentShares)

該 LUA 腳本實現了與 BuyShares 函數相同的邏輯,包括獲取可用股票數量、驗證剩余股票是否充足以及更新股票數量。

在 Golang 中,可以使用 goredis 庫執行 LUA 腳本:

var BuyShares = redis.NewScript(`
 local sharesKey = KEYS[1]
 local requestedShares = ARGV[1]

 local currentShares = redis.call("GET", sharesKey)
 if currentShares < requestedShares then
  return {err = "error: 公司剩余股票不足"}
 end

 currentShares = currentShares - requestedShares
 redis.call("SET", sharesKey, currentShares)
`)

func (r *Repository) BuyShares(ctx context.Context, userId, companyId string, numShares int, wg *sync.WaitGroup) error {
 defer wg.Done()

 keys := []string{BuildCompanySharesKey(companyId)}
 err := BuyShares.Run(ctx, r.client, keys, numShares).Err()
 if err != nil {
  fmt.Println(err.Error())
 }
 return err
}

使用 LUA 腳本可以有效解決并發問題,并且性能優于事務機制。

分布式鎖:靈活控制并發訪問

除了 LUA 腳本,還可以使用分布式鎖來控制對共享資源的并發訪問。Redis 提供了 SETNX 命令,可以實現簡單的分布式鎖機制。

在 Golang 中,可以使用 redigo 庫的 Lock 函數獲取分布式鎖:

func (r *Repository) BuyShares(ctx context.Context, userId, companyId string, numShares int, wg *sync.WaitGroup) error {
 defer wg.Done()

 companySharesKey := BuildCompanySharesKey(companyId)

 // 獲取分布式鎖
 lockKey := "lock:" + companySharesKey
 lock, err := r.client.Lock(ctx, lockKey, redislock.Options{
  RetryStrategy: redislock.ExponentialBackoff{
   InitialDuration: time.Millisecond * 100,
   MaxDuration:     time.Second * 3,
  },
 })
 if err != nil {
  return fmt.Errorf("獲取分布式鎖失敗: %w", err)
 }
 defer lock.Unlock(ctx)

 // ... (省略部分代碼) ...

 return nil
}

使用分布式鎖可以靈活控制并發訪問,但需要謹慎處理鎖的釋放和超時問題,避免出現死鎖情況。

總結

Redis 提供了多種解決并發問題的方案,包括原子操作、事務、LUA 腳本和分布式鎖等。在實際應用中,需要根據具體場景選擇合適的方案。

  • 原子操作適用于簡單場景,例如計數器等。
  • 事務可以保證多個操作的原子性,但性能較低。
  • LUA 腳本可以將業務邏輯移至 Redis 服務端執行,性能較高,但需要熟悉 LUA 語法。
  • 分布式鎖可以靈活控制并發訪問,但需要謹慎處理鎖的釋放和超時問題。

希望本文能夠幫助你更好地理解和解決 Redis 并發問題,構建更加穩定可靠的分布式系統。

責任編輯:武曉燕 來源: 源自開發者
相關推薦

2021-10-25 09:50:57

Redis分布式技術

2021-10-26 00:38:10

Redis分布式

2021-06-03 00:02:43

RedisRedlock算法

2021-07-30 00:09:21

Redlock算法Redis

2021-12-01 10:13:48

場景分布式并發

2022-03-08 15:24:23

BitMapRedis數據

2023-05-18 14:02:00

分布式系統冪等性

2019-06-19 15:40:06

分布式鎖RedisJava

2017-12-12 14:51:15

分布式緩存設計

2020-02-17 16:05:17

系統演進過程時間問題

2021-12-14 08:19:59

系統分布式網絡

2021-12-15 07:24:56

分布式系統時鐘

2017-06-05 15:51:54

分布式Logical Tim算法

2023-05-12 08:23:03

分布式系統網絡

2020-10-19 07:30:57

Java Redis 開發

2022-03-08 07:22:48

Redis腳本分布式鎖

2013-12-20 09:43:13

分布式

2020-09-23 09:52:01

分布式WebSocketMQ

2023-02-11 00:04:17

分布式系統安全

2019-12-26 08:59:20

Redis主從架構
點贊
收藏

51CTO技術棧公眾號

精品视频在线看| 欧美精品制服第一页| 蜜桃导航-精品导航| 91九色porny在线| 亚洲欧美综合久久久| 亚洲男人天堂视频| 偷拍自拍在线| 国产一区二区在线看| 欧美视频三区在线播放| 亚洲欧美日韩国产成人| 91久久精品国产性色| 激情偷拍久久| 综合av色偷偷网| 伊人色综合网| 日本在线不卡视频一二三区| 精品国产乱码久久久久久影片| 成人三级黄色免费网站| 亚洲美女视频一区| 亚洲黄色网址在线观看| 国语一区二区三区| 亚洲欧洲自拍偷拍| 激情小说 在线视频| 精品一区二区三区日韩| 欧美激情精品久久久久久黑人| 亚洲女同av| 精品国产免费一区二区三区香蕉| caoporn超碰97| 国产自产v一区二区三区c| 丰满白嫩尤物一区二区| 日本精品视频一区| 狠狠干夜夜操| 欧美日韩破处视频| 91成人观看| 中文字幕在线视频一区| 日韩丝袜美女视频| 日本国产一区二区三区| 国产偷人视频免费| 一级欧美视频| 亚洲国产激情av| 一区二区三区四区在线观看视频| 96精品久久久久中文字幕| 99热在线免费观看| 国产精品中文字幕制服诱惑| 日韩精品国产精品| 欧美日韩免费观看一区二区三区| 国产精品视频yy9099| av片在线免费| 日韩大片在线永久免费观看网站| 久久中文视频| 在线一区二区视频| 欧美精品无码一区二区三区| 欧美精品国产一区| 亚洲字幕一区二区| 天天综合久久| 青青青国产精品一区二区| 蜜桃视频一区二区三区在线观看 | 最近2019中文字幕在线高清 | 欧美日韩性生活| 日本一二三区视频免费高清| 午夜精品久久久久99热蜜桃导演| 精品高清视频| 国产一区视频网站| 偷拍视频一区二区| 国产精品一二一区| 久久久噜噜噜www成人网| 国产91在线|亚洲| 草莓福利社区在线| 色综合久久88色综合天天看泰| 手机在线电影一区| 懂色av一区二区三区四区五区| 99国产精品久| 宅男深夜视频| 欧美三级乱人伦电影| 99福利在线观看| 精品久久人人做人人爰| 欧美成人a交片免费看| 91av在线播放视频| 激情欧美一区二区三区| 国产成人免费电影| 日韩精品一区二区三区四区视频 | 亚洲精选91| 日韩精品欧美在线| 欧美巨大另类极品videosbest | 国产精品一线二线三线| 国内久久精品视频| 蜜桃臀av在线| 这里只有精品在线播放| 93在线视频精品免费观看| 一区二区三区四区久久| 国产成人精品综合在线观看| 日本欧美电影在线观看| 久久综合久久美利坚合众国| 亚洲系列另类av| 视频一区不卡| 欧美黄色性视频| 亚洲成av人片在www色猫咪| 成人午夜sm精品久久久久久久| 国产欧美韩日| 久久久久国色av免费看影院| av在线天堂播放| 天堂av一区二区| 日韩一区二区久久久| 香蕉亚洲视频| 免费在线a视频| 久久久精品一区二区三区| 向日葵视频成人app网址| 爽爽爽爽爽爽爽成人免费观看| av毛片在线免费看| 91精品国产综合久久精品app| 在线手机福利影院| 国产视频在线一区二区| 亚洲夜夜综合| 国产午夜精品视频一区二区三区| 欧美久久免费观看| 免费一级片91| www.亚洲视频| 欧美一级视频一区二区| 新67194成人永久网站| 欧美日韩中文在线视频| 欧美一二三区精品| 最新日韩一区| 日本欧美黄网站| 韩国av一区| 亚洲色精品三区二区一区| 在线观看欧美日本| www.在线视频| 999在线观看免费大全电视剧| 国产精品欧美日韩一区| 亚洲精品在线免费| 中文字幕日韩精品一区| 日韩美女一级视频| 亚洲一级黄色av| 久久国产精品99精品国产 | 精品视频国内| 亚洲欧美电影| 男人最爱成人网| 欧美videossex另类| 在线观看完整版免费| 91传媒免费视频| 黄色污污在线观看| 国产中文字幕二区| 日本va中文字幕| www.激情小说.com| 男女av免费观看| 黄色国产一级视频| www.日本xxxx| 超碰影院在线观看| 诱受h嗯啊巨肉高潮| 成人www视频网站免费观看| 欧美黄色免费网址| 欧美人成在线观看| 天天综合天天操| 亚洲国产精品久久久久婷蜜芽| 91看片就是不一样| 在线国产一区二区三区| 日本高清视频免费在线观看| 成人免费视频网址| 国产98在线|日韩| 成人高清视频观看www| 国产日韩中文字幕| 先锋影音男人资源| 视频二区在线播放| www.99热.com| 免费在线观看麻豆视频 | 在线看片不卡| 一区二区日韩欧美| 91老司机福利 在线| 欧美日韩三级在线| 成人中文字幕+乱码+中文字幕| 黄色三级中文字幕| 色播五月综合网| 国产一区二区三区四区五区3d| 欧美极品一区二区三区| 综合自拍亚洲综合图不卡区| 欧美午夜精品一区二区蜜桃| 精品日本美女福利在线观看| 亚洲精品成人免费| 久久久国产一区二区三区| 97久久夜色精品国产九色| 国产老熟妇精品观看| 黄色电影免费在线看| 日韩电影网站| 欧美99久久| 一区二区三区免费| 中文字幕一区电影| 日本亚洲导航| 在线观看免费黄色| 成人三级视频| 久久久久久久精| 亚洲天堂第二页| 婷婷四月色综合| 日本免费在线视频| 欧美日韩调教| 图片区日韩欧美亚洲| 国产91热爆ts人妖在线| 欧美三级午夜理伦三级| 国产91在线播放精品| 蜜臀精品一区二区三区在线观看 | 一本色道婷婷久久欧美 | 麻豆电影传媒二区|