Ask HN: Key-Value Store Database with Historical Lookup?
Does anyone know any key-value store database/service with ability to look up value at particular timestamp in the past? Something similar to Redis (or even simpler), but with the time dimension to it.
For example:
- At time 1: DB.set('foo', 'bar')
- At time 5: DB.set('foo', 'club')
- Then: DB.get('foo', 4) should return 'bar' (4 refers to the timestamp)
- DB.get('foo') should return 'club'
This database/service will help us with a particular problem we're facing at work. We looked around but have yet to find something similar to this.
We're thinking of writing this ourselves (a service on top of existing K-V NoSQL Database like Cassandra/Redis/LevelDB/etc). But we'd much prefer to use an existing solution.
34 comments
[ 3.7 ms ] story [ 87.7 ms ] threadSo the "current" state of any item was the result of all events happening until now applied in order, the state at any given time was just the same, with another time boundary.
Don't fear the computation, we were doing all this in CouchDB with list functions and never had huge performance problems. Range queries are present in all databases.
Constructing the events properly so that they apply conveniently to any kind of state is a different kind of story.
Or is there a better way to do this with Redis?
https://en.wikipedia.org/wiki/Temporal_database
Though, if I personally had this requirement, I would just roll my own as it sounds very basic and easy to represent in a plain RDBMS. No way am I going to base my DB choice/design or infrastructure impementation for something this small.
A log basically is a stream of changes to a DB. I found this the best introduction to it so far: http://engineering.linkedin.com/distributed-systems/log-what...
In fact, to give you a little bit more background on the problem, if you look at our data infrastructure diagram (in the posted link), the thing we're trying to improve is the hydration system (where it takes in a record in real-time and try to inject more time-sensitive information into it).
E.g. When a user watches a video (thus a video_play event sent), we want to know if it's a free user or a paid user. Since the user could be a free user today and upgrade to paid tomorrow, the only way to correctly attribute the play event to free/paid bucket is to inject that status right right into the message when it's received.
Building the system this way (using the hydration service) makes our service very prone to error and indeterministic (since you only have a short window to hydrate the message, and you can't replay a hydration).
That's why we're looking at building a historical lookup service that remembers all the different changes of a data object over time, so that replaying a hydration becomes deterministic.
At the moment we're processing around 100M records a day and growing. Not a lot but still at some scale that puts us in the position to think about scalability and performance.
As `zo1` mentions, though, this doesn't really seem like the kind of requirement that would necessitate obscure database technologies, especially because even in a relational database these are easily optimizable queries.
[0] http://blog.foundationdb.com/designing-a-schema-for-time-ser...
[1] https://foundationdb.com/layers/sql
A big question is whether you will be storing all mutations permanently or whether the database needs to provide either a time-to-live (TTL) or maximum # of maintained mutations.
If you are just keeping everything or use a keyvalue store with TTL, this can be accomplished easily with any key-value store by using fixed key sizes and appending the timestamp. In an ordered keyvalue store, you can do an efficient lookup of some time span. Some dbs like FoundationDB provide a framework to manage key space using tuples, so it's even easier to tailor and manage different key types to get the desired access speeds.
Rocksdb, a leveldb variant which is the engine beneath CockroachDB, does have TTL [3].
[1] http://cockroachdb.org
[2] https://docs.google.com/document/d/11k2EmhLGSbViBvi6_zFEiKzu...
[3] https://github.com/facebook/rocksdb/wiki/Time-to-Live
- https://code.google.com/p/kairosdb/
- https://github.com/OpenNMS/newts
- https://github.com/rackerlabs/blueflood
- https://github.com/pyr/cyanite
Edit: The lectures: http://ocw.mit.edu/courses/electrical-engineering-and-comput...
http://openmirage.org/blog/introducing-irmin
Speaking as someone who's used Apache Cassandra a ton, I'd stay the hell away. They break shit all the time to drive sales at Datastax and personally I'm over it.
Also hyperdex (hyperdex.org) is one of the better (imo) 2nd gen nosql datastores that might be worth building this on top of.
To give a little bit more context about the problem. This is related to our data analytics infrastructure that we're building (we did a technical writeup of it here - http://engineering.viki.com/blog/2014/data-warehouse-and-ana... )
If you look at our data infrastructure diagram (in the posted link), the thing we're trying to improve is the hydration system (where it takes in a record in real-time and try to inject more time-sensitive information into it).
E.g. When a user watches a video (thus a video_play event sent), we want to know if it's a free user or a paid user. Since the user could be a free user today and upgrade to paid tomorrow, the only way to correctly attribute the play event to free/paid bucket is to inject that status right right into the message when it's received.
Building the system this way (using the hydration service) makes our service very prone to error and indeterministic (since you only have a short window to hydrate the message, and you can't replay a hydration).
That's why we're looking at building a historical lookup service that remembers all the different changes of a data object over time, so that replaying a hydration becomes deterministic.
At the moment we're processing around 100M records a day and growing. That translates to about 100M read requests. The key size should be around 1M. Not a lot but still at some scale that puts us in the position to think about scalability and performance.
Before asking this question, we did look around and also looked into how we'd build it using existing database technology. We thought of 3 different ways using relational DB (PostgreSQL), simple K-V store (Redis/Riak), and Cassandra (with column family). Yet we want to get more opinions of you guys :)
http://www.garysieling.com/blog/postgres-time-travelling-deb...
SQL example: http://techblog.tilllate.com/2008/06/22/round-robin-data-sto...
Research: http://pam2012.ftw.at/TMA/papers/TMA2012paper13.pdf
The range definition looks something like this: Filter.range(name, begin, end) ) More details: http://www.aerospike.com/docs/client/java/usage/query/query....
The advantages of Aerospike is its going to be superfast as the index is co-located with the data and also the secondary indexes are always updated inline with writes. So, the indexes always reflect the current state of truth. While doing the secondary index query, its follows a scatter gather approach thereby achieving distributed parallelism of the query. More details: http://www.aerospike.com/docs/architecture/secondary-index.h...
On top of this, if at all you need to perform an aggregation on the secondary query result, you can use the Aerospike's Distributed Streaming Aggregation framework (http://www.aerospike.com/docs/guide/aggregation.html). Where you an do the aggregation on the server side itself without pulling all the data to the client. Only the final aggregation happen on the client.