2015-04-30 14 views
15

Sono in procinto di apprendere Redis e sto creando un programma geografico per scopi di apprendimento. Vorrei utilizzare solo Redis per archiviare i dati e sto cercando di evitare qualsiasi database relazionale. La mia domanda è come progettare al meglio il database per il programma. Ecco come procede il programma:Suggerimenti per la progettazione di programmi geografici utilizzando Redis

1) Creerò milioni di robot casuali in tutto il mondo che vagano in modo che possano avere coordinate geografiche diverse (alcuni robot possono trovarsi nello stesso identico spazio).

2) Ogni robot invierà a caso un messaggio al server (con una media di poche ore) che conterrà: a) la posizione da cui il robot ha inviato questi dati (in coordinate o geohash a seconda del idea migliore implementazione) b) qualche piccolo testo

3) avrò una mappa con tutti i robot e vorrei essere in grado di fare clic su un robot e ottenere queste informazioni: a) tutti i messaggi che sono stati postato nelle vicinanze del robot ho appena cliccato

4) A causa del fatto che lo ospiterò su AWS dovrò eliminare i post ogni coppia e di ore per mantenere basso l'utilizzo della memoria, quindi è obbligatorio un certo tipo di scadenza.

La mia preoccupazione principale è la prestazione e sono interessato a come progettare il database Redis.

In un solo giorno (eseguirò i calcoli per post casuali per eseguire questa operazione) verranno generati circa 500.000.000 di post.

Le mie idee incomplete finora:

Idea 1

1) un post saranno memorizzati in quanto tale:

`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) Ho poi sarei in grado di ottenere tutte le posti vicino a un robot inviando la posizione geohash in cui si trova. La rovina qui è che avrei anche bisogno di includere i suoi 8 vicini geohash che richiederebbero altre 8 domande. Per questo motivo sto anche esaminando il concetto di prossimità spaziale per questa funzionalità.

HGETALL [GeoHash Location of robot] 

Ciò restituirebbe quindi il campo ([timestamp]) e il valore ("0");

3) Scadenza di vecchi messaggi. Poiché non posso utilizzare il comando EXPIRE per eliminare campi da un hashset, dovrei quindi eseguire periodicamente la scansione di tutti i campi hashset e trovare vecchi timestamp e rimuoverli. Poiché Redis consente solo la ricerca di modelli, ciò potrebbe risultare difficile quando tutti i timestamp sono diversi.

Idea 2:

Uso Redis-geo (https://matt.sh/redis-geo).

1) Per memorizzare i messaggi vorrei correre:

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

2) per ottenere tutte le informazioni di posta di un robot vicina:

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

Questa sarebbero tornati tutti i messaggi in prossimità del robot all'interno X km.

3) allora io sono ora bloccati come rimuovere vecchi post

risposta

0

Lasciate che vi dia una base un'idea di come ho capito il problema:

Invece di memorizzare i valori di hash, semplicemente memorizzare tutto in Redis . Costruisci la chiave come GeoLocation: [Geohash location of robot]: 1 [che indica il numero di post, questo continuerà ad aumentare quando viene una nuova richiesta]: timestamp e value sarà il timestamp. Analogamente per il testo di piccole dimensioni. GeoLocation: [Posizione geografica del robot]: 1 [che indica il numero di post]: smallText. Utilizzare set scade per impostare i valori e impostare il tempo di scadenza come desiderato.

Es: Setex GeoLocation: 12,31,939 mila: 1: timestamp 1.432.423,232 mila (timestamp) 14400 (4 ore) Setex GeoLocation: 12,31,939 mila: 1: smallText ronaldo 14400

Così si otterrà un numero illimitato di messaggi da tutti i robot con anche una chiave distinta per accedere e impostare la scadenza è diventata facile.

Ora per ottenere tutte le informazioni inviate da un particolare robot, utilizzare i tasti GeoLocation: (posizione del robot particolare): * e ottenere i valori di ciascuno.

In questo modo non è necessario scorrere tutti i tasti in rosso. Otterrai le informazioni in modo relativamente più veloce e le chiavi scadranno per proprio.

+0

Grazie per la risposta! Non capisco però come recuperare le chiavi. Per usare qualcosa come GeoLocation: (posizione di un particolare robot): * Non avrei bisogno di usare il comando SCAN per essere in grado di riprodurre il modello? Se così non è questo comando O (N) quindi non dovrei quindi eseguire la scansione di tutti i tasti in Redis? – user2924127

+0

fammi avere un'idea in java (jedis) Set keys = jedis.keys ("GeoLocation:" + (posizione del robot) + "*"); restituirà tutte le chiavi corrispondenti per un particolare robot. Quindi passa attraverso quel set per ottenere i post e TimeStamp di cui hai bisogno. Questo sarà O (M) invece di O (N). Poiché stiamo eseguendo solo il ciclo delle chiavi corrispondenti a un determinato robot. E così riceverai tutti i messaggi da un particolare robot. –

+0

Lo scopo è cercare di ottenere tutti i post creati da altri robot vicino alla posizione del robot, non i post creati da un robot specifico. – user2924127

0

Un'idea che tolgo alla descrizione è che saprai la posizione corrente di un determinato "robot" e vorresti trovare altri utenti mobili vicino in tempo reale, ma ti piacerebbe anche che un po 'di informazioni sulla posizione storica.

Mi piace pensare ai redis come all'esposizione di blocchi grezzi per creare un database di livello superiore. Con questo in mente ti rendi conto che devi creare e mantenere le tue funzionalità di database di livello superiore come indici, ecc.

Dato che questo tipo di dati sarà principalmente accessibile quando hai in mente un robot specifico, ti consiglio di conservare la cronologia delle posizioni e i metadati per un bot in una chiave basata sull'identificatore univoco del bot e non sulla sua posizione.

Quindi mantenere la posizione relativa (o qualsiasi altro raggruppamento) agli altri gestendo il proprio ID in set o hash che raggruppano i robot in una determinata posizione. È possibile utilizzare più set o strutture di dati annidati per una sorta di livello di capacità di dettaglio.

Mantenere l'integrità dei dati aggiornando il record bot e le informazioni sulla posizione come parte di un redis transaction. Utilizzare pipelining per l'efficienza.

Non è necessario utilizzare expire per vecchi post in quanto è possibile gestire le dimensioni del database limitando il conteggio delle voci storiche nel record principale del bot. Quando vai ad aggiornare un bot, esegui solo una sorta di operazione di pulizia su di esso quando raggiunge una certa lunghezza (llen, slen, hlen, ecc.) Per darti una dimensione di dati aggregata prevedibile/regolabile.

Se c'è qualche speranza, quello che stai facendo potrebbe diventare produzione consiglio vivamente di considerare partitioning fuori dal cancello. Qualunque livello di successo lo richiederà, così potrebbe anche farlo in anticipo. Fidati di me. In questo caso, avrei partizionato in modo funzionale (posizione rispetto allo stato del robot ... diversi database su diversi gruppi di replica) e anche tramite chiave (hash o altro ... per abbattere il tuo 500M in blocchi ragionevoli).

Il partizionamento rende le transazioni difficili, ma per il tuo caso di utilizzo dubito che sia un affare. L'utilizzo di redis messaging insieme alle transazioni può consentire di mantenere l'integrità eseguendo vari aggiornamenti in modo programmatico.

Infine, considererei qualcosa oltre a redis (elasticache nel tuo caso sto assumendo). Nello spettro del supporto per la concorrenza e la capacità di fare query complesse, redis è ottimo per il primo. Per questo motivo è perfetto per tenere traccia delle sessioni o dello stato simile.

Avrete bisogno di un sacco di concorrenza, ma è in gran parte in allegato e non gli aggiornamenti. Quindi non come una macchina statale in evoluzione. E hai bisogno di almeno una certa capacità di ricerca.

Se è necessario correlare gli oggetti tra loro (query), essere in grado di supportare l'analisi, ecc., Con 500 milioni di utenti si potrebbe permettersi un grande cluster redshift, una dinamo o simili. Potrebbe mettere in primo piano il kinesis per aiutare con la concorrenza raggruppando piccoli messaggi per il caricamento di massa. Sia il redshift che la dinamo beneficiano di percorsi di caricamento speciali dal kinesis.

Sicuramente vuoi stare lontano da RDS, ma ci sono altre opzioni che sarebbero più semplici da implementare e ti aiuterebbero ad evitare quel giorno inevitabile quando devi iterare il tuo cluster redis (per il quale utilizzeresti ovviamente scan).

(vecchio post, lo so, ma interessante domanda e la risposta vale per un sacco di situazioni.)

0

notare che a partire dalla versione V3.2 supporta Redis Geosets con il comando GEOADD.

0

Come systemjack ha puntato su search- redismodules.com ha un modulo di ricerca. Ha un modulo foresta casuale per trovare anche i vicini più vicini.

0

Ok, consente di separare le nostre attività:

  1. Abbiamo bisogno di un indice che contiene tutti i nostri robot, in modo che possiamo iterare su di loro
  2. Probabilmente avremo bisogno di memorizzare alcune informazioni generiche sulla nostro robot
  3. abbiamo bisogno di memorizzare geo precedenti di ogni robot
  4. Abbiamo bisogno di pulizia vecchi dati ogni X

1) Lets ma ke ZSET che contiene l'ID del robot e il suo SCORE sarà il timestamp dell'ultima attività, in futuro saremo in grado di eliminare i robot non attivi usando questo indice.

ZADD ZSET:ROBOTS <timestamp> robot:17 o evento migliore solo 17 senza robot: a causa di redis memorizzerà numeri interi come 4 byte nella RAM.

2) consente di memorizzare il nostro robot informazioni generiche in HSET

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

3) In generale possiamo utilizzare diversi modi per conservarlo, per esempio possiamo prendere ZSET regolare con più tecnica indici dimensionali (https://redis.io/topics/indexes#multi-dimensional-indexes) , ma è molto complicato da capire, così lascia usare Redis semplici GEO

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

Internamente GEO utilizzare ZSET regolare, in modo che possiamo facilmente scorrere su di esso da ZRANGE o ZRANGEBYSCORE comandi.

E naturalmente possiamo usare comandi GEO come GEORADIUS per le nostre esigenze.

4) Il processo di pulizia. Suggerisco di ripulire per tempo, ma è possibile farlo nello stesso modo per numero di voci, basta usare ZRANGE invece ZRANGEBYSCORE

Consente di trovare tutti i nostri robot non attivi che non erano attivi almeno una settimana.

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

Ora abbiamo bisogno di iterare su quelle ID e rimuovere HSEt, chiavi GEO non necessari e rimuoverlo dalla nostra index

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

Ora abbiamo bisogno di rimuovere solo le voci vecchie GEO-storia, come ho detto sopra GEO in Redis è uno ZSET regolare sotto il cofano, così lascia usare ZRANGE

ZRANGE GEO:ROBOT:17 0 -1 

Avremo elenco di voci, ma sarà risolto strano perché di GEO, ogni 0.123.017,686 milasarà GEO location.

Le voci sono state formattate come ":" in modo che possiamo utilizzare split(':') e confrontare la data e l'ora, se è obsoleto lo rimuoviamo. Per esempio il nostro timestamp è 12345678 e il messaggio è hello

ZDEL GEO:ROBOT:17 1234567:hello 

P.S. Consiglio vivamente di leggere questo fantastico articolo su ZSET in redis https://redis.io/topics/indexes

In breve: Redis ordina gli elementi non solo per punteggio ma anche per nome chiave, ciò significa che le voci con lo stesso punteggio verranno ordinate in ordine alfabetico, il che è molto utile !

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

lo restituisca ordinati impostare:

  1. "aaa"
  2. "BBB"
  3. "CCC"