Skip to content

Instantly share code, notes, and snippets.

@hltbra
Created June 28, 2015 21:57
Show Gist options
  • Save hltbra/2fbf5310aabbecee68c5 to your computer and use it in GitHub Desktop.
Save hltbra/2fbf5310aabbecee68c5 to your computer and use it in GitHub Desktop.
Redis Essentials, chapter 3 benchmark
var redis = require("redis");
var client = redis.createClient();
if (process.argv.length < 3) {
console.log("ERROR: You need to specify a data type!");
console.log(" $ node using-timeseries.js [string|hash]");
process.exit(1);
}
var getUsedMemory = function(value) {
return parseInt(value.match(/used_memory:(\d+)/)[1], 10);
};
var dataType = process.argv[2];
var timeseries = require("./timeseries-" + dataType);
client.flushall(function(err, reply) {
client.info("memory", function(err, reply) {
var initialMemory = getUsedMemory(reply);
var multi = client.multi();
var benchmark = new timeseries.TimeSeries(multi, "benchmark");
var beginTimestamp = new Date(2015, 0, 1, 0, 0, 0) / 1000;
var endTimestamp = new Date(2015, 0, 2, 0, 0, 0) / 1000;
for (var timestamp = beginTimestamp ; timestamp < endTimestamp ; timestamp++) {
benchmark.insert(timestamp);
}
multi.exec(function(err, replies) {
client.info("memory", function(err, reply){
var totalMemory = getUsedMemory(reply);
var usedMemory = totalMemory - initialMemory;
console.log("Time Series", dataType, "approach used memory", usedMemory, "bytes");
client.quit();
});
});
});
});
/*
$ node benchmark.js string
Time Series string approach used memory 11938112 bytes
$ node benchmark.js hash
Time Series hash approach used memory 797696 bytes
*/
function TimeSeries(client, namespace) {
this.namespace = namespace;
this.client = client;
this.units = {
second: 1,
minute: 60,
hour: 60 * 60,
day: 24 * 60 * 60
};
this.granularities = { // 1
'1sec' : { name: '1sec', ttl: this.units.hour * 2, duration: 1, quantity: this.units.minute * 5 },
'1min' : { name: '1min', ttl: this.units.day * 7, duration: this.units.minute, quantity: this.units.hour * 8 },
'1hour': { name: '1hour', ttl: this.units.day * 60 , duration: this.units.hour, quantity: this.units.day * 10 },
'1day' : { name: '1day', ttl: null, duration: this.units.day, quantity: this.units.day * 30 },
};
};
TimeSeries.prototype.insert = function(timestampInSeconds) {
for (var granularityName in this.granularities) {
var granularity = this.granularities[granularityName];
var key = this._getKeyName(granularity, timestampInSeconds);
var fieldName = this._getRoundedTimestamp(timestampInSeconds, granularity.duration); // 1
this.client.hincrby(key, fieldName, 1); // 2
if (granularity.ttl !== null) {
this.client.expire(key, granularity.ttl);
}
}
};
TimeSeries.prototype._getKeyName = function(granularity, timestampInSeconds) {
var roundedTimestamp = this._getRoundedTimestamp(timestampInSeconds, granularity.quantity); // 1
return [this.namespace, granularity.name, roundedTimestamp].join(':');
};
TimeSeries.prototype._getRoundedTimestamp = function(timestampInSeconds, precision) {
return Math.floor(timestampInSeconds/precision) * precision;
};
TimeSeries.prototype.fetch = function(granularityName, beginTimestamp, endTimestamp, onComplete) {
var granularity = this.granularities[granularityName];
var begin = this._getRoundedTimestamp(beginTimestamp, granularity.duration);
var end = this._getRoundedTimestamp(endTimestamp, granularity.duration);
var fields = []; // 1
var multi = this.client.multi(); // 2
for (var timestamp = begin; timestamp <= end; timestamp += granularity.duration) {
var key = this._getKeyName(granularity, timestamp);
var fieldName = this._getRoundedTimestamp(timestamp, granularity.duration); // 3
multi.hget(key, fieldName); // 4
}
multi.exec(function(err, replies) { // 5
var results = [];
for (var i = 0 ; i < replies.length ; i++) {
var timestamp = beginTimestamp + i * granularity.duration;
var value = parseInt(replies[i], 10) || 0;
results.push({timestamp: timestamp , value: value});
}
onComplete(granularityName, results);
});
};
exports.TimeSeries = TimeSeries;
function TimeSeries(client, namespace) { // 1
this.namespace = namespace; // 2
this.client = client; // 3
this.units = { // 4
second: 1,
minute: 60,
hour: 60 * 60,
day: 24 * 60 * 60
};
this.granularities = { // 5
'1sec' : { name: '1sec', ttl: this.units.hour * 2, duration: this.units.second },
'1min' : { name: '1min', ttl: this.units.day * 7, duration: this.units.minute },
'1hour': { name: '1hour', ttl: this.units.day * 60 , duration: this.units.hour },
'1day' : { name: '1day', ttl: null, duration: this.units.day } // 9
};
};
TimeSeries.prototype.insert = function(timestampInSeconds) { // 1
for (var granularityName in this.granularities) { // 2
var granularity = this.granularities[granularityName]; // 3
var key = this._getKeyName(granularity, timestampInSeconds); // 4
this.client.incr(key); // 5
if (granularity.ttl !== null) { // 6
this.client.expire(key, granularity.ttl); // 7
}
}
};
TimeSeries.prototype._getKeyName = function(granularity, timestampInSeconds) { // 1
var roundedTimestamp = this._getRoundedTimestamp(timestampInSeconds, granularity.duration); // 2
return [this.namespace, granularity.name, roundedTimestamp].join(':'); // 3
};
TimeSeries.prototype._getRoundedTimestamp = function(timestampInSeconds, precision) { // 1
return Math.floor(timestampInSeconds/precision) * precision; // 2
};
TimeSeries.prototype.fetch = function(granularityName, beginTimestamp, endTimestamp, onComplete) { // 1
var granularity = this.granularities[granularityName]; // 2
var begin = this._getRoundedTimestamp(beginTimestamp, granularity.duration); // 3
var end = this._getRoundedTimestamp(endTimestamp, granularity.duration); // 4
var keys = []; // 5
for (var timestamp = begin; timestamp <= end; timestamp += granularity.duration) { // 6
var key = this._getKeyName(granularity, timestamp); // 7
keys.push(key); // 8
}
this.client.mget(keys, function(err, replies) { // 9
var results = []; // 10
for (var i = 0 ; i < replies.length ; i++) { // 11
var timestamp = beginTimestamp + i * granularity.duration; // 12
var value = parseInt(replies[i], 10) || 0; // 13
results.push({timestamp: timestamp , value: value}); // 14
}
onComplete(granularityName, results); // 15
});
};
exports.TimeSeries = TimeSeries; // 16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment