Hi All, Thanks for the replies. These detailed explanations are extremely useful. The are much appreciated!
One other question that came to mind with this. Is there any way I can use a TTLs to keep the old account entries around for a fixed length of time rather than deleting them immediately? That way if I had an issue I could replay the process form one of these earlier points. For the regular reads of the account table I can use a limit of 1, with the reverse comparator set I should always get the newest record without hitting an older record first. I can't do the initial account insert with a TTL as I can't guarantee when a new value would come along and so replace this account record. However when I insert the new account record, instead of deleting the old one could I reinsert it with a TTL of say 1 month. How would compaction handle this. Would the original record get compacted away after 1 month + the GC Grace period or would it hang around still? Thanks, Charlie M On Thu, Jun 5, 2014 at 5:32 PM, James Campbell <ja...@breachintelligence.com > wrote: > Thanks for creating and opening the discussion on this use case. I have > been evaluating Cassandra for a very similar problem, but with the > small twist that I'd like to roll up the ledger entries into the > aggregated 'account' information on a regular basis to ensure that even > rarely-read (but often written) data will be periodically rolled up and > ready for quick reads. There is also a larger twist that for me 'account' > is a compound key and the typical read pattern will include reading from > multiple > rows within the same partition (each of which would require separate > merging from the ledger). > > > This response prompts three questions for me about that: > > > 1. Just to clarify the requirement that only one client thread does this > at a time, I assume you mean only one thread should handle any given > 'account' at a time, right? There wouldn't be problems having multiple > clients do this data maintenance on different accounts at the same time, I > hope. > > > 2. For my use case, hadoop integration seems the natural fit, because > I'd like to batch these updates to run at night during query down-time, but > the current hadoop tools don't really support reading from or writing to > multiple tables, as is required for this implementation. I've seen a few > posts from people who have written homegrown input/output formats for > hadoop, but I haven't tried to use them or evaluate their stability. Is > there another mechanism I should be thinking about for that sort of batch > updating? > > > James Campbell > ------------------------------ > *From:* Aaron Morton <aa...@thelastpickle.com> > *Sent:* Thursday, June 5, 2014 5:26 AM > *To:* Cassandra User > *Cc:* charlie....@gmail.com > *Subject:* Re: Consolidating records and TTL > > As Tyler says, with atomic batches which are enabled by default the > cluster will keep trying to replay the insert / deletes. > > Nodes check their local batch log for failed batches, ones where the > coordinator did not acknowledge it had successfully completed, every 60 > seconds. So there is a window where it’s possible for not all mutations in > the batch to be completed. This could happen when a write timeout occurs > when processing a batch of 2 rows; the request CL will not have been > achieved on one or more of the rows. The coordinator will leave it up to > the batch log to replay the request, and the client driver will (by default > config) not retry. > > You can use a model like this. > > create table ledger ( > account int, > tx_id timeuuid, > sub_total int, > primary key (account, tx_id) > ); > > create table account ( > account int, > total int, > last_tx_id timeuuid, > primary key (account) > ); > > To get the total: > > select * from account where account = X; > > Then get the ledger entries you need > > select * from ledger where account = X and tx_id > last_tx_id; > > This query will degrade when the partition size in the ledger table gets > bigger, as it will need to read the column index > (see column_index_size_in_kb in yaml). It will use that to find the first > page that contains the rows we are interested in and then read forwards to > the end of the row. It’s not the most efficient type of read but if you are > going to delete ledger entries this *should* be able to skip over the > tombstones without reading them. > > When you want to update the total in the account write to the account > table and update both the total and the last_tx_id. You can then delete > ledger entries if needed. Don’t forget to ensure that only one client > thread is doing this at a time. > > Hope that helps. > Aaron > > > ----------------- > Aaron Morton > New Zealand > @aaronmorton > > Co-Founder & Principal Consultant > Apache Cassandra Consulting > http://www.thelastpickle.com > > On 5/06/2014, at 10:37 am, Tyler Hobbs <ty...@datastax.com> wrote: > > Just use an atomic batch that holds both the insert and deletes: > http://www.datastax.com/dev/blog/atomic-batches-in-cassandra-1-2 > > > On Tue, Jun 3, 2014 at 2:13 PM, Charlie Mason <charlie....@gmail.com> > wrote: > >> Hi All. >> >> I have a system thats going to make possibly several concurrent changes >> to a running total. I know I could use a counter for this. However I have >> extra meta data I can store with the changes which would allow me to reply >> the changes. If I use a counter and it looses some writes I can't recover >> it as I will only have its current total not the extra meta data to know >> where to replay from. >> >> What I was planning to do was write each change of the value to a CQL >> table with a Time UUID as a row level primary key as well as a partition >> key. Then when I need to read the running total back I will do a query for >> all the changes and add them up to get the total. >> >> As there could be tens of thousands of these I want to have a period >> after which these are consolidated. Most won't be any where near that but a >> few will which I need to be able to support. So I was also going to have a >> consolidated total table which holds the UUID of the values consolidated up >> to. Since I can bound the query for the recent updates by the UUID I should >> be able to avoid all the tombstones. So if the read encounters any changes >> that can be consolidated it inserts a new consolidated value and deletes >> the newly consolidated changes. >> >> What I am slightly worried about is what happens if the consolidated >> value insert fails but the deletes to the change records succeed. I would >> be left with an inconsistent total indefinitely. I have come up with a >> couple of ideas: >> >> >> 1, I could make it require all nodes to acknowledge it before deleting >> the difference records. >> >> 2, May be I could have another period after its consolidated but before >> its deleted? >> >> 3, Is there anyway I could use the TTL to allow to it to be deleted >> after a period of time? Chances are another read would come in and fix the >> value. >> >> >> Anyone got any other suggestions on how I could implement this? >> >> >> Thanks, >> >> Charlie M >> > > > > -- > Tyler Hobbs > DataStax <http://datastax.com/> > > >