2015-04-30 70 views
15

我正在學習Redis,並正在爲學習目的構建地理程序。我只想使用Redis來存儲數據,並試圖避免任何關係數據庫。我的問題是如何最好地爲程序設計數據庫。這就是程序如何去做的:使用Redis的地理程序設計建議

1)我將在世界各地創建數百萬隨機機器人,它們可以有不同的地理座標(有些機器人可以在完全相同的空間中)。

2)每個機器人將隨機發送一個帖子到服務器(可能平均每隔幾個小時),它將包含:a)機器人發送數據的位置(座標或geohash取決於最好的實現思路) 二)一些小的文本

3)我將與所有機器人的地圖,並希望能夠點擊一個機器人,並得到這個信息: 一)所有的職位它被張貼我剛剛點擊的機器人附近

4)由於我將在AWS上託管這一事實,我將需要刪除每個連接的帖子以保持內存使用率低,因此某些類型的過期是強制性的。

我最關心的是性能,我對如何設計Redis數據庫感興趣。

在一天之內(我會計算一下隨機帖子的數學做法),大約會產生500,000,000個帖子。

我的不完整的想法而已:

理念1

1)後會被存儲爲這樣的:

`HSET [Geohash of location] [timestamp] [small text] (<-- the value will be used in a later feature to increment the number of manual modification I make to a post). 

2)然後,我將能夠得到所有的通過發送他所在的geohash位置來發布機器人附近的帖子。這裏的失敗是我還需要包括他的8個geohash鄰居,這需要8個以上的查詢。這就是爲什麼我也在研究這個特徵的空間鄰近概念。

HGETALL [GeoHash Location of robot] 

這會返回字段([timestamp])和值(「0」);

3)舊帖子到期。由於我無法使用EXPIRE命令從哈希集中刪除字段,因此我需要定期掃描所有哈希集字段並查找舊時間戳並將其刪除。由於Redis只允許模式搜索,所以當所有時間戳不同時,這可能會很困難。

理念2:

使用Redis的-地理位置(https://matt.sh/redis-geo)。

1)保存的帖子我會跑:

geoadd globalSet [posts_long] [posts_lat] "small text"; 

2)爲了讓所有的職位信息,附近的機器人:

georadius globalSet [robots_long] [robots_lat] [X] km 

這將內歸還所有帖子機器人附近的X公里。

3)然後我現在卡住瞭如何刪除舊帖子

回答

0

讓我給你我如何理解你的問題的想法基地:

存儲在哈希值的情況下,只要存儲所有的Redis 。 構造密鑰爲GeoLocation:[機器人的地理位置]:1 [指示帖子的數量,每當有新的請求到來時這將繼續遞增]:時間戳和值將是時間戳。 同樣對於小文本GeoLocation:[機器人的地理位置]:1 [表示帖子的數量]:smallText。 使用set expire來設置值並根據需要設置到期時間。

例如:SETEX地理定位:12.31939:1:時間戳1432423232(時間戳)14400(4小時) SETEX地理定位:12.31939:1:smalltext羅納爾多14400

因此,你會得到所有機器人的任何數量的職位訪問和設置到期的明確關鍵也變得容易。

我們獲得發佈由特定機器人的所有信息,使用的密鑰地理定位:(特別是機器人的位置):*,並得到各值。

以這種方式,您不需要掃描redis中的所有密鑰。你會得到相對更快的信息,並且密鑰由它自己過期。

+0

感謝您的答覆!我不明白如何檢索密鑰。使用類似GeoLocation的東西:(特定機器人的位置):*我不需要使用SCAN命令來模式匹配?如果不是這個命令O(N)那麼我不需要掃描Redis中的所有密鑰? – user2924127

+0

讓我給你一個在java(jedis)的想法 設置 keys = jedis。鍵(「GeoLocation:」+(機器人的位置)+「*」); 這將返回與特定機器人匹配的所有密鑰。 然後通過該設置來獲取您需要的帖子和TimeStamp。 這將是O(M)而不是O(N)。因爲我們只是循環與特定機器人相匹配的按鍵。 因此,你會收到特定機器人的所有帖子。 –

+0

目的是嘗試獲取由機器人位置附近的其他機器人制作的所有帖子,而不是由特定機器人制作的帖子。 – user2924127

0

一個想法我從描述拿走的是,你會知道一個給定的「機器人」的當前位置,你想找到它附近的其他移動用戶實時,但你也想了一些一點的歷史位置信息。

我喜歡把Redis的作爲原料暴露積木製作了更高級別的數據庫。隨着在你意識到你需要建立和維護自己的更高水平的數據庫功能,如索引的頭腦,等

由於這種類型的數據將主要當你心裏有一個特定機器人訪問,我建議你存儲基於bot的唯一標識符而不是其位置的密鑰中的bot的位置歷史記錄和元數據。

然後通過管理其集合中的ID或散列來將其相對位置(或任何其他分組)保存到其他分組中。您可以使用多個集合或嵌套數據結構來實現某種級別的細節功能。

通過更新BOT記錄,並作爲Redis的transaction的部分位置信息保持數據的完整性。使用pipelining來提高效率。

你並不需要使用expire老帖子,你可以通過限制機器人的主記錄歷史條目數管理數據庫的大小。當你去更新一個機器人,當它超過一定的長度(llen,slen,hlen等)時,對它進行一些清理操作,以給你一個可預測/可調節的聚合數據大小。

如果您有任何希望可能會成爲生產,我強烈建議您考慮partitioning。任何成功的水平都需要它,所以不妨先做。相信我。對於這種情況,我會在功能上進行分區(位置與機器人狀態...不同數據庫在不同的複製組上)以及按鍵(散列或其他......將您的500M分解爲合理的塊)。

分區使交易變得艱難,但對於您的用例,我懷疑這是一個交易斷路器。將redis messaging與事務一起使用可以讓您通過以編程方式執行各種更新來保持您的完整性。

最後,我會考慮除redis之外的東西(在我假設的情況下使用elasticache)。在支持併發和支持複雜查詢的能力方面,redis對前者非常有用。出於這個原因,它非常適合跟蹤會議或類似的狀態。

你需要很多併發性,但它主要是追加而不是更新。所以不像一個發展中的狀態機。而且你至少需要一些搜索能力。

如果您需要將對象與對方(查詢)關聯起來,能夠支持500M用戶的分析等,您將能夠承受大型紅移羣集,發電機或類似產品。可以將kinesis放在前面,通過將批量加載的小消息進行批處理來幫助實現併發性。紅移和發電機都受益於kinesis的特殊加載路徑。

絕對要遠離RDS,但還有其他選擇可以更簡單地實現,並且可以幫助您避免無法避免的一天,因爲您必須迭代Redis羣集(顯然,您會使用)。

(老文章中,我知道,但有趣的問題和答案適用於很多情況。)

0

注意:隨着V3.2的Redis的支持與GEOADD命令Geosets。

0

由於systemjack指出search-redismodules.com有一個搜索模塊。它有一個隨機森林模塊來尋找最近的鄰居。

0

好吧,讓獨立的我們的任務:

  1. 我們需要包含所有我們的機器人的索引,所以我們可以在它們之間迭代
  2. 也許我們需要存儲有關我們的機器人
  3. 一些通用信息
  4. 我們需要存儲的地理歷史,每機器人
  5. 我們需要清理舊的數據每隔X

1)讓馬包含機器人ID和其SCORE的ke ZSET將成爲最後活動時間戳,將來我們將能夠使用此索引刪除非活動機器人。

ZADD ZSET:ROBOTS <timestamp> robot:17或事件更好的只是17沒有robot:,因爲Redis的將存儲整數作爲在RAM 4個字節。

2)用於存儲我們的機器人通用信息在HSET

HSET HSET:ROBOT:17 name "Best robot ever #17" model "Terminator T-800"

3)一般我們可以用幾種方式來存儲,比如我們可以利用多維度指標技術採取定期ZSET(https://redis.io/topics/indexes#multi-dimensional-indexes) ,但它很複雜,難以理解,所以讓使用更簡單的Redis GEO

GEOADD GEO:ROBOT:17 13.361389 38.115556 "<timestamp>:<message-data>" 

內部GEO使用常規ZSET,所以我們可以很容易地通過ZRANGE或ZRANGEBYSCORE命令遍歷它。

當然,我們可以根據我們的需要使用GEO命令,如GEORADIUS。

4)清理過程。我建議按時間進行清理,但是您可以按照相同的方式進行清理,只需使用ZRANGE代替ZRANGEBYSCORE

讓我們找到所有非活動機器人,至少一週不活動。

ZRANGEBYSCORE ZSET:ROBOTS -inf <timestamp-of-week-before> 

現在,我們需要遍歷這些ID和刪除聯合國需要HSET,GEO鍵,從我們的index

ZREM ZSET:ROBOTS 17 
DEL HSET:ROBOT:17 
DEL GEO:ROBOT:17 

現在我們需要刪除只老GEO-歷史記錄條目中刪除它,我上面說GEO在Redis的是引擎蓋下定期ZSET,所以讓我們使用ZRANGE

ZRANGE GEO:ROBOT:17 0 -1 

我們將獲得的項目列表,但由於地理,每個它進行排序怪將是GEO location

我們的條目格式化爲「:」,所以我們可以使用split(':')並比較時間戳,如果它比較老,我們將其刪除。例如我們的時間戳是12345678和消息是hello

ZDEL GEO:ROBOT:17 1234567:hello 

附:我強烈建議你閱讀有關ZSET在Redis的https://redis.io/topics/indexes

總之這真棒文章:Redis的排序,不僅得分,但被太多的鍵名的項目,這意味着用同樣的比分條目進行排序按字母順序排列,這是非常有用的!

ZADD key 0 ccc 0 bbb 0 aaa 
ZRANGE key 0 -1 

將返回有序設置:

  1. 「AAA」
  2. 「BBB」
  3. 「CCC」