2011-04-15 110 views
12

我使用redis以每個哈希約100k記錄存儲哈希。我想實現給定散列內的記錄過濾(構造)。注意一個哈希條目可以屬於n個過濾器。篩選Redis哈希條目

閱讀thisthis之後,它看起來像我應該:

  1. 實現每一個過濾器有序集合。 SET內的值對應於HASH中的鍵。
  2. 從給定的過濾器SET中檢索HASH鍵。
  3. 一旦我有SET的HASH鍵從HASH中獲取相應的條目。這應該給我屬於過濾器的所有條目。

首先是上述方法在高水平正確嗎?

假設方法正常,我缺少的是檢索HASH條目的最有效實現是什麼?當我有了HASH鍵之後,我是否應該使用PIPELINE排隊多個HGETALL命令,並通過每個HASH鍵?有更好的方法嗎?

我對使用PIPELINE的擔憂是我相信它會在服務命令時阻塞所有其他客戶端。我將分頁過濾結果,每頁有500個結果。在多個基於瀏覽器的客戶端執行過濾的情況下,更不用說填充SET和HASH的後端進程,聽起來像PIPELINE阻塞會引發大量爭用。任何人都可以提供一個觀點嗎?

如果有幫助,我使用2.2.4 redis,predis爲web客戶端和servicestack爲後端。

感謝, 保羅

+0

我試圖做類似的過濾器,但我有大集(1萬條記錄)進行過濾。你有沒有找到更好的方式來過濾redis? – 2016-02-12 06:14:33

回答

4

Redis是一個無鎖的非阻塞異步服務器,因此在使用流水線時不會添加爭用。一收到Redis,Redis就會高興地處理每個操作,因此實際上可以處理多個流水線操作。本質上,redis-server確實不在乎操作是否是流水線操作,它只是在接收它們時處理每個操作。

流水線的好處是減少客戶端延遲,而不是在發送下一個操作之前等待來自redis-server的每個操作的響應,客戶端只需一次寫入即可將所有操作一次抽出,然後全部讀回在一次閱讀中的迴應。

在這一行動的一個例子是我Redis mini StackOverflow clone每次點擊使以ToQuestionResults()調用它,因爲操作流水線發送1個插槽寫調用的所有操作,並讀取結果1插槽阻塞讀這是更有效的替代每次通話讀取阻塞:

https://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/RedisStackOverflow/RedisStackOverflow.ServiceInterface/IRepository.cs#L180

我對使用管道值得關注的是 ,我相信它會阻止其他所有 客戶在維修命令。

這不是一個值得關注的問題,我不會想到Redis是如何在這裏工作的,假設它在Pipelining不阻止處理其他客戶端命令的情況下效率最高。從概念上講,你可以認爲Redis的服務器進程在FIFO順序中的每個命令(流水線與否)(即沒有時間在等待/讀取整個管道浪費)。

你所描述的東西更加接近其作爲Redis的服務器讀取EXEC(即EOF Transaction)的所有操作都在一次儘快完成MULTI/EXEC(即Redis的交易)。這不是一個問題,或者和Redis的服務器仍然沒有浪費任何時間等待接收你的整個事務,它只是直到接收到最終EXEC,然後處理一次全部在排隊臨時隊列部分命令集。

這是如何通過redis的處理每個命令,一次一個實現原子性,只要它接收它們。由於沒有其他線程,所以沒有線程上下文切換,沒有鎖定,也沒有多線程問題。它通過非常快速地處理每個命令來基本實現併發性。

因此,在這種情況下,我會用流水,因爲它總是一個勝利,越是這樣,命令你管線(爲你減少阻塞讀計數)。

5

個人業務做塊,但不要緊,因爲他們不應該長時間運行。這聽起來像你正在檢索的信息比你真正需要的更多 - 當你只需要500時,HGETALL將返回100,000個項目。

發送500個HGET操作可以工作(假設集合存儲散列和鍵)儘管有可能使用散列根本就是一個過早優化的例子 - 使用常規密鑰和MGET可能會更好。

+2

謝謝你回覆湯姆。你是對的,我誤解了HGETALL的目的。雖然你的回答很有用,但我不會接受它,因爲我不覺得它真的讓我更接近原始問題。我聽到你在說什麼過早的優化,但似乎有序集合是實現過濾的接受的方式和哈希值存儲的「對象」的最佳方式。我覺得我只是遵循最佳實踐而不是做任何不尋常的事情。 – Paul 2011-04-19 09:05:59

2

我想你誤會做什麼流水線。當所有的命令都被髮送時它不會阻塞。它所做的只是緩衝命令,然後在最後一次執行它們,這樣它們就像是一個命令一樣執行。在任何時候都不會發生阻塞。這同樣適用於Redis的multi/exec如此。你能阻止最接近/在Redis的鎖定是使用watch,這將導致exec如果Redis的密鑰已經被寫入,因爲你叫watch失敗樂觀鎖。

在管道塊內調用hget 500次的效率更高,只需調用hmget('hash-key',*keys),其中keys是您正在查找的500個哈希鍵的數組。這將導致一個調用Redis的,這是一樣的,如果它是流水線,但因爲你不是在紅寶石循環應該更快執行。