2015-12-30 62 views
5

我試圖用redis實現替換Drupal 8的防洪服務的sql實現。使用redis實現防洪服務

參見https://github.com/drupal/drupal/blob/8.0.x/core/lib/Drupal/Core/Flood/DatabaseBackend.php

的要求是這樣的:

  • 動作/事件的每次發生(例如嘗試登錄)已登錄有過期,標識符和時間戳
  • 我需要能夠防止某個動作在給定的時間內可以完成N次以上
  • 我希望能夠清理過期事件
  • 如果在10分鐘內達到3的閾值,如果用戶嘗試一次,然後在5分鐘後再次嘗試兩次,他會被阻塞,並且可能會在5分鐘後再次嘗試一次。不是10.雖然第二種方法是一種有效的方法,但這不是SQL實現如何工作或測試如何工作的。
  • 正如你所看到的基於API,我也不知道什麼時候註冊事件的門檻是什麼,我只知道一個事件的到期。

我就如何落實的想法是:

  • 如果經過n次出現應該鎖定在給定的時間,那麼這將是很容易與事件的單個KEY:標識符遞增,一旦達到最大值,它將被鎖定,直到它再次到期,每個INCR也會更新(或不)。
  • 我發現許多帖子詢問列表條目到期,這是不可能的。有一些解決方法使用有序集合並按範圍刪除。大多數似乎使用一個單一的全球集,但我不能輕易計數我的事件+標識符 - 我認爲。

寫這一切下來之後,我實際上可能有一個想法,它如何能工作,所以我想我要的是是否有道理反饋或是否有更簡單的方法。

每個事件:標識符組合是一個鍵幷包含一個有序集合。它使用過期作爲分數,並將值作爲唯一值,可能創建時間以微秒爲單位。我計算未到期的記錄來檢測是否達到了閾值。我正在更新每個事件的過期:標識符到提供的過期窗口,所以它將被自動刪除,假設除非給定的標識符/客戶端不放棄並繼續嘗試,而沒有達到過期。清理集合中的記錄是否值得當做一個新的註冊?這似乎相當快,而且我也有時只能這樣做。

+0

順便說一下,我在這裏實現了第一個版本:https://github.com/md-systems/redis/blob/8.x-1.x/src/Flood/PhpRedis.php。仍然希望得到一些關於這是否是一個好方法的反饋。 – Berdir

+0

看起來像這是更多的代碼審查問題。我想你應該把它移到這裏:http://codereview.stackexchange.com/ – t1gor

+0

好點,當我創建它時沒有代碼。我更多地尋找關於我已經實現的概念的反饋,而不是關於特定代碼的反饋。但如果這很可能會導致答案,則很樂意提出。 – Berdir

回答

1

我寧願使用Redis的關鍵過期功能,而不是重新實現一個功能。

一個更簡單的替代辦法是下列之一:

  • 只是設置一個簡單的值,這是嘗試的數目;使用建立在像「標識」圖案的關鍵:「事件類型」: SETNX <identifier>:<event type> 1
  • 如果響應爲1,這是第一次嘗試,所以你對這個鍵設置超時: EXPIRE <identifier>:<event type> <timeout in seconds>

  • 否則您增加嘗試次數 INCR <identifier>:<event type> INCR的響應會給您窗口期間的嘗試次數,因此您知道您是否可以允許該操作。

你也可以使用,而不是一個簡單的值的哈希,如果你需要存儲更多的數據,就像在給定的時間窗口允許嘗試的最大數量。在這種情況下,您可能會使用HSETNX和HINCR。

+0

感謝您的回答。這基本上是「我對如何實現這個想法」的第一個要點。如第四項要求所寫,這會導致稍微不同的行爲。達到極限後,它會在給定的時間內鎖定。然而,我正在實現的界面的期望是,它只會鎖定,直到我在給定的時間範圍內低於閾值,從現在開始。 – Berdir

+0

也許我不明白你的觀點,但我不這麼認爲。 –

+0

啊,你一開始就沒有設置過期時間。真正。但是它會產生相反的效果。到期後,我可以再次使用完整的門檻。因此,如果閾值爲5,過期5分鐘,而我每1分鐘做X,那麼在您的實施中,我可以在第一次事件5分鐘後立即再次做5次,而在我的情況下,我只能做一次,那麼我已經達到了門檻。 – Berdir