2016-01-16

Rails memcache lock (dalli)

最近在實作 cache & lock,不過這邊不寫一般的作法,單純希望有個方便的lock可以在記憶體中,要防止使用者的重複交易之類的

我可以用DB,但怕有效能影響,所以只能選擇 memory 系列,而我有 Redis & memcache(dalli) 可以選

用 Redis 的話缺點很大,因為 hash 沒有 expire 可選,只有一般的 key 有,所以會多一票垃圾 key 在列表內,非常 dirty ...,所以只剩下 memcache

而 memcache 其實無 lock 選項,而...只有一種作法之類的,叫做 increment,也就是某個變數 + 1 的意思,當 return > 1 時,就代表這個 lock 已經失效,這就非常方便了

最後實作會類似這樣的 code :

  def action_lock(kind , timer: 600 , token: nil , user: current_user)
    return false if !timer || timer < 1
    #key的格式請自己編
    return Rails.cache.increment("ACTION_LOCK_#{user.id}_#{kind}_#{token}" , 1 , :expires_in => timer) == 1
  end

有這個基本後,就可以再製作很多的東西,也就是專案的需求

  1. 封包重送問題
  2. 同BTC wallet和金額的重複交易問題
  3. 發送頻率問題

(1):封包重送問題,可以使用 random post token 來完成,類似每次 post from 都產生一個 random key 來當 token,然後 post 出去後就記錄已使用,下次再接收時則阻擋,這樣可以防止類似手機或筆電的連線中斷而封包重送且重複執行的問題,類似 "#{kind}_#{user_id}_#{random_token}"

(2):重複交易其實就很簡單,想辦法把KEY編寫一樣即可,類似 "#{kind}_#{user_id}_#{wallet}_#{amount}" 的方式,並設定過期時間,就可以輕易完成

(3):發送頻率則更簡單,因為是限制單一使用者,則直接把 user_id 當作 key即可,類似 "#{kind}_#{user_id}"

okay打完收工(rock)

沒有留言:

張貼留言