新客領取優(yōu)惠券邏輯
判斷是否新客
若為新客 查詢數(shù)據(jù)庫是否已領取過
未領取過 給用戶發(fā)券
同一用戶并發(fā)領券的情況下 會有超領的情況 因為并發(fā)進來時查詢數(shù)據(jù)庫均沒有領取記錄
而又不能針對用戶和優(yōu)惠券做唯一索引 因為有些券允許用戶領取多張。
于是決定采用redis計數(shù)來防同一用戶并發(fā)超領 新客領券邏輯改成如下
判斷是否新客
若為新客 基于用戶ID計數(shù) incr {user_id}_receive_count
如果計數(shù)大于1 表示同一用戶并發(fā)領券 直接返回
如果計數(shù)==1 表示第一次領取
查詢數(shù)據(jù)庫是否已領取過
未領取過 給用戶發(fā)券
上述邏輯沒有問題 但糾結該如何設置計數(shù)key的過期時間
設置過期時間為1分鐘
基本上大部分并發(fā)操作都是在同一秒 過期時間1分鐘能滿足要求了
設置過期時間為1小時
萬一數(shù)據(jù)庫負載高呢 并不能在一分鐘內(nèi)完成一次領券事務操作 如雙十一這種場景 還是設的長一點 更保險一點 不管怎樣 1小時足夠完成一次領券事務操作了吧 但時間設的長了 會不會因為其他原因(如網(wǎng)絡超時)導致領券失敗回滾 用戶要等一小時后 才能重新領券
有沒其他防并發(fā)領取方案呢? 可以不用糾結這種過期時間的設置呢。
過剰同時防止の判斷と新規(guī)顧客かどうかの判斷は分けて行うことをお勧めします
同時実行防止スーパーカラーは以下を使用できます (ロック)。各操作の後にキーを削除する (ロックを解放する) ことを忘れないでください
ユーザーが新規(guī)顧客かどうか(ユーザーが以前に受信したかどうか、有効時間はイベントの終了までに設定されます)を判斷するために、受信後にユーザーの受信ステータスとして新しいKEYを設定できます。割引を受けたユーザーに直接返されます(同時実行パフォーマンスを追求する場合、データベースクエリへの接続はありません)
クーポンを取得します (クーポンを事前にキューに入れ、データベースからではなくキューから取得します。ここでの利點は、キューのデータが取得されると削除され、過剰受信が発生しないことです。狀況)、それを Redis キューに書き込みます
バックグラウンドプロセスの消費キュー、消費にはリンクリストブロックタイプを使用します(コレクション情報をデータベースに保存し、データベースに入る前にユーザーがクーポンを受け取ったかどうかをクエリして判斷します)
ビジネスに応じて具體的な計畫を?qū)g行する必要があります
ビジネスが 100% を必要としない場合、各人が受け取ることができるクーポンは 1 つだけであり、Redis クラスターの可用性が高いため、Redis
を使用してブロックするだけで十分です。アクティビティがダウンロードされた後は、特定のキーの有効期限が無効になります。これはライブラリに含まれないソリューションであるため、リクエストを繰り返すかどうかを決定する必要がある場合は、Redis のデータに依存する必要があります (Redis の場合)。ハングします。ただし、Redis の価格比較は不完全です) 永続化機能ですが、失われるデータの量は比較的少ないため、ビジネスが許可している場合はまだ許容されます)、ただし、多くのビジネス シナリオではログアウトが必要です Redis
來擋就足夠了,具體Key的失效時間,等活動下載再整體失效,因為這是一個不落庫的方案,所以如果需要判斷是否重復請求需要依賴Redis里面的數(shù)據(jù)(萬一Redis掛了呢,雖然Redis有比價不完善的持久化功能,但是丟的數(shù)據(jù)量比較少,如果如果業(yè)務上允許,還是可以接受的),但是很多場景業(yè)務都需要要求落庫
業(yè)務上要求,必須一人一券(可能券的面值很大),那么前面還是用題主的Redis
方案,在判斷完是第一次以后,直接插/更新數(shù)據(jù)庫(這里就會有異步的方案,但是異步的方案也會出現(xiàn),異步的方案也會出現(xiàn)與1類似的問題:丟數(shù)據(jù)),按照這個方案,可以保證每個人只能領一張券(由數(shù)據(jù)庫來保證數(shù)據(jù)的一致性)。如題主所說,其實你不需要把Redis里面的東西失效掉,因為如果一個用戶重復惡意請求抽券,直接走Redis來擋,不用去數(shù)據(jù)庫查詢(這里還會一個問題,該方案是先更新緩存再更新數(shù)據(jù)庫,所以需要考慮緩存更新成功,但是數(shù)據(jù)庫更新失敗的異常情況,如果數(shù)據(jù)庫異常需要清理該Key對應的緩存)
如果實在扛不住(硬件跟不上),可以用隊列來解決,用隊列來削峰
@大嗚 的方案也是可以行的,但是需要考慮某一時刻Redis
Redis
ソリューションが有効であると判斷する前に引き続き使用します。初めてです。データベースを直接挿入/更新します (ここには非同期ソリューションもありますが、非同期ソリューションにも 1: データの損失と同様の問題が発生する可能性があります)。誰もが A クーポンのみを受け取ることができることが保証されます (データの一貫性はデータベースによって保証されます)。質(zhì)問者が言ったように、実際には、ユーザーが悪意を持ってクーポンの描畫を繰り返し要求した場合、Redis はデータベースに問い合わせることなく直接ブロックできるため、Redis 內(nèi)の內(nèi)容を無効にする必要はありません (ここには別の問題があります。)解決策は、まずキャッシュを更新することです。そのため、キャッシュの更新は成功したが、データベースの更新が失敗した場合は、該當するキャッシュをクリアする必要があります。鍵)#????##????#
#????##????#本當に対処できない場合(ハードウェアが追いつかない場合)、キューを使用して問題を解決し、キューを使用してピークをカットできます#????##????#
#????##????#@Daiwoo の解決策も実現(xiàn)可能ですが、ある瞬間の Redis
の異常な狀況を考慮する必要があります #????##????#
#????#@大woo この機能は実は以前記事を書いたフラッシュセールと似ています。以下をご覧ください:
eコマース商品の必須機能: フラッシュ販売と入札
この種のことにあえて nosql データベースを使用するのは私も酔っています。
まず、トランザクションの概念、トランザクションのいくつかの分離レベル、行ロックとテーブル ロックに焦點を當ててデータベースの理論を?qū)W習し、それから従來のリレーショナル データベースを使用してこれを行うことをお勧めします。
データベース サーバーのパフォーマンスが十分でない場合は、異なるサーバーを備えた水平テーブル アーキテクチャを設計し、各サーバーがユーザー データの一部を擔當します。レベルテーブルの理論的なソースは、學部レベルのデータ構造のハッシュの章です。