2016-09-30 49 views
1

我有一個應用程序(nodejs/express),需要根據一天中的時間和星期幾查找要應用的路由規則。REDIS - 創建有意義的鍵來減少查詢

因此,例如,我有以下業務規則:

    在星期一和星期二
  • 09:00 GMT和12:00 GMT之間,我需要路由對象農行「位置x」。
  • 週二13:00到13:30我需要將ABC路由到「位置y」。

(爲了這個討論的目的,真的沒關係ABC是什麼對象。)

我兩個選擇之間的辯論,據我應該如何設計我的Redis數據庫我的鑰匙

選項1

讓天信息中的對象數據的一部分,是這樣的:

HMSET routing_rules:objectABC_09:00_12:00 days 'mon tues' location X 
HMSET routing_rules:objectABC_13:00_13:30 days 'tues' location Y 
這種方法的

優勢 - 當它的時間來更新天名單我可以簡單地這樣做:

HMSET routing_rules:objectABC_09:00_12:00 days 'mon tues thu' 

這裏的缺點是,爲了找到合適的規則,我必須讓兩個查詢.. ..首先做一個SCAN命令來找到合適的時間範圍......然後如果有匹配的話......做另一個查詢來查找天數值。

選項2

包括周信息的一天的關鍵

HMSET routing_rules:objectABC_09:00_12:00_mt location X 
HMSET routing_rules:objectABC_13:00_13:30_t location Y 

的一部分,我會用像

m = monday 
t = tuesday 
w = wed 
r = thursday 
etc. 

優點命名約定來選擇2是爲了根據當前時間和日期找到正確的路由規則,我只需要運行一個SCAN命令(我們可以假設我的掃描命令將返回一杆的結果)

但缺點選項2的是,當我需要一個新的一天增加的關鍵,我認爲我需要刪除鍵和值。 ..然後重新創建它。它是否正確?

而現在,我知道如何刪除的唯一方法是對對象中的每個值做一個HDEL,然後刪除該鍵。 因此,舉例來說,我一直在做這樣的事情:

127.0.0.1:6379> HDEL routing_rules:objectABC_00:00_00:00 days 'mon tues' location x 

,我必須列出的所有對象的值刪除整個鍵/值對。 在這個例子中,它並沒有那麼糟糕,因爲我只有兩個值 - 這個鍵 - 位置和天數字段。但是如果有更多的數據,它會有點麻煩。除了與此關鍵字相關的字段數外,我不確定是否還有其他因素需要考慮。

如果您對如何設計此按鍵以獲得最佳性能和維護方面有任何建議,我完全理解。我看到它的方式,至少有一次無法避免運行掃描。但這是我的第一個redis數據庫嘗試,所以我提前爲補救性問題/ noob錯誤道歉。

編輯1

假設我有足夠的內存,並假設我只需要保存一個字段/每鍵值,讓我們說我創造了我的鑰匙是這樣的:

SET routing_rules:objectABC_09:00_12:00_m X 
SET routing_rules:objectABC_09:00_12:00_t X 
SET routing_rules:objectABC_13:00_13:30_t Y 

而且現在請求進入對象ABC,星期一在UTC 11。因爲我的鍵表示開始時間和結束時間(又名範圍),所以我沒有看到如何在沒有執行掃描的情況下找到正確的鍵/值對。

我錯過了什麼嗎?

回答

0

我不會在這種情況下(以及在大多數情況下)使用任何SCAN命令。您可能必須多次調用它才能掃描整個密鑰空間,而有其他替代方法可以直接訪問您正在查找的數據 - 這就是K/V存儲性能的原因。

舉例來說,在您的第一個解決方案中,將所有值放在散列中,並在HGETALL的一個請求中獲取所有路由。然後,您將不得不遍歷應用程序中的值以選擇正確的值。

另一種解決方案,不需要在應用程序方面的任何迭代,是創建每天,每小時範圍內的航線:

SET routing_rules:objectABC_09:00_12:00_m location X SET routing_rules:objectABC_13:00_13:30_t location Y ...

在一個 GET請求

然後你有你正在尋找的價值對於。 添加一天只需要一個SET。 與您的解決方案相比的缺點是內存使用量:它將條目數量倍增。你沒有提供關於條目數量的任何線索,但是如果它非常高,這可能是一個問題。要減少所需的內存,可以使用較短的鍵名開始,如r:objectABC_09001200m而不是routing_rules:objectABC_09:00_12:00_m)。

更新

鑑於時間範圍似乎沒有恆定,並假設沒有算法來推斷出當前時間的時間範圍內,第一個解決方案,基於使用哈希,似乎基於GET/SET,比第二個更好。不過,我會根據時間命名域範圍:

HSET routing_rules:objectABC 09:00_12:00 X HSET routing_rules:objectABC 12:00_12:30是

然後,我會得到所有的字段對於給定對象使用HGETALL routing_rules:objectABC並迭代成員鍵以找到正確的。

+0

帕斯卡,什麼會被視爲條目數「高」值? – Happydevdays

+0

與服務器上的可用內存相比,它取決於每個鍵+值的內存大小。 –

+0

我認爲我將有大約15 GB使用...和50,000個對象,每個對象最多有5個路由規則。 – Happydevdays

0

我會使用排序集解決方案,爲每個對象設置一個值,值應該是位置*,並且分數應該是該規則到期的一週內的分鐘數。

例如(周開始於週一00:00)

在09:00 GMT和12:00 GMT之間的週一和週二,我需要的路線 對象農行「位置x」。

週一12:00 => 720 週二12:00 => 2160

ZADD ABC_rules 720 x 2160 x

有兩個問題在這裏,你的第一個例子顯示時間,有沒有規則,因此必須應予以考慮。第二個和更主要的設置對象必須是唯一的,並且x不能被存儲兩次。兩者同時是上面的*原因,解決它是通向apped /前面加上本週一分鐘規則開始值:

週一9:00 => 540 週二9:00 => 1980年

ZADD ABC_rules 720 x:540 2160 x:1980

要查詢,所有你需要的是使用ZRANGEBYSCORE在本週分鐘,並確保你得到追加到位置的時間是你送的時間之前。

查詢週一10:00(600):

ZRANGEBYSCORE ABC_rules 600 +inf LIMIT 1

其結果將是x:540既然540是低於600,你知道x是一個有效的答案。

查詢週一13:00(780):

ZRANGEBYSCORE ABC_rules 780 +inf LIMIT 1

結果將是x:1980,並且自1980年以來比你大的查詢(780)這個結果是無效的,你應該把你的默認路由(或任何你的解決方案是在你的時間表未映射的時間)。

要刪除規則,你必須刪除與開始時附加的位置:

ZREM ABC_rules x:540

您還可以使用ZRANGEBYSCORE獲得在特定的一天應用所有的規則,你可以寫一個LUA清除它們的腳本。