1. 程式人生 > >[高並發]搶紅包設計(使用redis)

[高並發]搶紅包設計(使用redis)

入隊 下一步 關系 blog 其他 web log 動作 並發

假設一個需求,在某個預告活動中準備了10w個紅包,100w人在某個時間點去開搶,每人只能搶1次,如何保證性能和準確性,下面我給出我的一個設計方案,拋磚引玉

  1. 分析瓶頸
    • 查詢用戶是否已參與過活動
    • 獲取一個可搶的紅包,保證多個人不能獲取到同一個紅包
    • 建立紅包與用戶的關系
  2. 設計數據結構解決瓶頸問題
    • 查詢用戶是否已參與過活動:可以使用Set的特性,集合中不能出現重復的數據,每個用戶發起搶的動作就將用戶標識放入Set中,如果Set中已存在這個用戶標識,則說明用戶不可再搶了
    • 獲取一個可搶的紅包:可以使用隊列的數據結構,每次獲取紅包都是一個出隊的動作,解決了多人獲取同一個紅包和超發的問題
    • 建立紅包與用戶的關系:同樣使用隊列的數據結構,每次建立都是一個入隊動作,使用單獨線程每秒嘗試出隊多個,批量存儲到數據庫中
  3. 實現功能
    • 準備工作:生成可搶紅包,入隊redis的list結構,命令為RPUSH
    • 用戶發出搶的請求:用戶標識寫入redis的Set中,命令SADD,返回1標識插入成功,可繼續獲取紅包,返回0則為已搶,直接返回
    • 獲取紅包:list出隊一條紅包數據,命令為LPOP,如果返回不為nil時,代表獲取成功,繼續下一步,反之則說明已搶完,返回
    • 建立紅包與用戶的關系:構建紅包與用戶的關系對象,入隊Redis的list,使用單獨線程每秒嘗試出隊1000個(舉例),批量存儲到數據庫中
  4. 需求擴展
    • 10w紅包不是先到先得,而是有一定隨機性
      • 可以在構建可搶紅包列表時,根據需求算法,構建一個包含無紅包item的的列表入隊,出隊判斷如果此item代表無紅包時返回,反之則進行建立紅包與用戶的關系
    • 每人可以搶N次,N>=1
      • 使用redis的string數據結構中的INCR命令,用戶發起搶的動作,則調用INCR,如果返回數據>N,說明搶的次數已達到上限
  5. 其他
    • redis並不是必須的,如果web服務器無橫向擴展需要也可以使用內存內的相關數據結構實現,同樣的如果其他中間件可提供相似的數據結構功能,也可以替換redis

[高並發]搶紅包設計(使用redis)