2014-12-03 28 views
5

Questo comportamento in Cassandra sembra contro-intuitivo e voglio sapere perché questo sta accadendo, e forse aggirarlo.Cassandra TTL viene impostato su 0 sulla chiave primaria se non è specificato TTL su un aggiornamento, ma se lo è, il TTL sulla chiave primaria non cambia


Immaginate Ho una tabella con tre colonne: pk, la chiave primaria, un tipo text, foo, un bigint, e bar, un'altra text.

insert into keyspace.table (pk, foo, bar) values ('first', 1, 'test') using ttl 60; 

Questo crea una riga nella mia tabella che ha un tempo di vita di 60 secondi. Guardando la cosa, sembra che questo:

pk | foo | bar 
------------------ 
first | 1 | test 

Ora faccio:

update keyspace.table using ttl 10 set bar='change' where pk='first'; 

E poi, guardando la fila, lo vedo subisce le seguenti modifiche:

pk | foo | bar 
-------------------- 
first | 1 | change 
first | 1 | <<null>> // after 10 seconds 
    <<deleted>>  // after the initial 60 seconds 

Tutto buona e giusta. Quello che volevo era che il tempo di vita di bar cambiasse, ma nient'altro, soprattutto non la chiave primaria. Questo comportamento era previsto.


Tuttavia, se il mio aggiornamento non dispone di un ttl in esso, o è impostato su 0:

update keyspace.table set bar='change' where pk='first'; 

poi vedo questo comportamento nel corso del tempo, invece.

pk | foo | bar 
-------------------- 
first | 1 | change 
first | 0 | change // after the initial 60 seconds 

In altre parole, la riga non viene mai eliminata. foo non è stato modificato, quindi il suo time-to-live era ancora in vigore e dopo che è passato il valore è stato cancellato (impostato su 0). Ma pk ha avuto il suo time-to-live cambiato. Questo è totalmente inaspettato.

Perché la modifica del time-to-live della chiave primaria viene eseguita solo se non si specifica il time-to-live nell'aggiornamento? E come posso aggirare questo in modo che il tempo di vita della chiave primaria cambi solo se dico esplicitamente di farlo?

Modifica Ho anche scoperto che se uso un time-to-live che è superiore a quello iniziale, sembra anche che cambi il time-to-live sulla chiave primaria.

update keyspace.table using ttl 70 set bar='change' where pk='first'; 

    pk | foo | bar 
-------------------- 
first | 1 | change 
first | 0 | change // after the initial 60 seconds 
    <<deleted>>  // after the 70 seconds 

risposta

6

L'effetto che si sta verificando è causato dal modello di archiviazione utilizzato da Cassandra.

Nell'esempio, in cui si dispone di una tabella che non dispone di colonne di raggruppamento, ogni riga della tabella viene associata a una riga nell'archivio dati (spesso denominata "riga di risparmio", poiché questo è il modello di memoria esposto attraverso l'API Thrift). Ciascuna colonna della tabella che non fa parte della chiave primaria (quindi nell'esempio le colonne foo e bar) viene associata a una colonna nella riga Risparmio. In aggiunta a ciò, una colonna aggiuntiva che non è visibile nella riga CQL viene creata come marcatore che la riga esiste.

La scadenza TTL si verifica a livello delle colonne Deriva, non delle colonne CQL. Quando si usa la riga INSERT, tutte le colonne che si inseriscono e il marcatore speciale della stessa riga ottengono lo stesso valore TTL.

Se si UPDATE una riga, solo le colonne che si aggiornano ricevono un nuovo TTL. L'indicatore di riga non viene toccato.

Quando si esegue una query con SELECT, vengono restituite tutte le righe per le quali almeno una colonna o è presente l'indicatore di riga speciale. Ciò significa che la colonna con il valore TTL più alto definisce per quanto tempo una riga CQL è visibile, a meno che l'indicatore della riga stessa (che viene toccato solo quando si utilizza un'istruzione INSERT) abbia un TTL più lungo.

Se si desidera assicurarsi che la chiave primaria della riga venga aggiornata con lo stesso valore TTL dei nuovi valori di colonna, la soluzione è semplice: Utilizzare l'istruzione INSERT quando si aggiorna una riga. Questo avrà esattamente lo stesso effetto dell'uso di UPDATE, ma aggiornerà anche il TTL dell'indicatore di riga.

L'unico svantaggio di questa soluzione alternativa è che non funziona in combinazione con transazioni leggere (clausola IF in INSERT o UPDATE). Se hai bisogno di questi in combinazione con un TTL, devi usare una soluzione più complessa, ma questa sarebbe una domanda a parte, suppongo.

Se si desidera aggiornare alcune colonne di una riga, ma si desidera comunque che scompaia l'intera riga quando scade il TTL specificato al momento dell'inserimento, questo non è supportato direttamente da Cassandra. L'unico modo sarebbe quello di scoprire il TTL a sinistra per la riga prima interrogando il TTL di una delle colonne e quindi usando questo TTL nell'operazione UPDATE. Ad esempio, è possibile utilizzare SELECT TTL(foo) FROM table1 WHERE pk = 'first';. Tuttavia, questo ha implicazioni sulle prestazioni perché aumenta la latenza (è necessario attendere il risultato di SELECT prima di poter eseguire UPDATE).

In alternativa, è possibile aggiungere una colonna che si utilizza solo come indicatore "riga esistente" e che si tocca solo durante lo INSERT e mai in uno UPDATE. Potresti quindi semplicemente ignorare le righe per le quali questa colonna è null, ma questo filtro dovrebbe essere implementato sul lato client e non sarà di aiuto se non è possibile specificare un TTL in un UPDATE perché le colonne aggiornate non verranno mai eliminate.

+0

Se è in uso una chiave primaria composta, cosa cambia? – OrangeDog

+1

L'uso di una chiave primaria composta non dovrebbe cambiare nulla. Per quanto riguarda il modello di archiviazione di basso livello (Thrift), una chiave primaria composta è in realtà solo una tupla. Il mapping su colonne diverse a livello di CQL è solo zucchero sintattico. –

+0

E se c'è una chiave di clustering? – OrangeDog

1

Dopo alcuni test, quelli sono i risultati previsti. I TTL hanno la granularità delle colonne.

  • Quando si esegue un aggiornamento, se non viene specificato TTL, la colonna TTL è impostata su 0. Questa operazione non influisce sugli altri TTL delle colonne.
  • Impossibile aggiornare un valore di colonna e conservare il vecchio valore di colonna TTL in un singolo comando cql.
  • Una riga (o chiave primaria/partizione) viene eliminata quando TUTTI i TTL di colonna sono scaduti.La riga non verrà eliminato se una colonna ha un TTL o 0.

A partire da oggi (Cassandra 2.1), Ecco come è possibile aggiornare un valore di colonna e preservare il suo TTL:

SELECT TTL(col1) FROM table1 where pk=1; 
// read the ttl value fetched. 
UPDATE table1 USING TTL <the_ttl_value> set col1='change' where pk=1; 
+0

Questo in realtà non risponde alla domanda. Se hai una domanda diversa, puoi richiederla facendo clic su [Invia domanda] (http://stackoverflow.com/questions/ask).Puoi anche [aggiungere una taglia] (http://stackoverflow.com/help/privileges/set-bounties) per attirare maggiormente l'attenzione su questa domanda una volta che hai abbastanza [reputazione] (http://stackoverflow.com/help/ che cosa è-la reputazione). – Jordan

+0

@Jordan Qui ho modificato e ripristinato la mia precedente risposta. Era la cosa giusta da fare? –

+0

Questo non risponde alla mia domanda sul motivo per cui la riga viene cancellata a volte e non altre volte. Apprezzo che tu abbia trovato il tempo per archiviare il problema, e lo sto guardando ora. – 2rs2ts