-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add autopipeline for commands and allow multi slot pipelines.
Fixes #536. Co-Authored-By: Matteo Collina <[email protected]>
- Loading branch information
Showing
24 changed files
with
1,514 additions
and
173 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ node_modules | |
built | ||
|
||
.vscode | ||
benchmarks/fixtures/*.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { cronometro } from 'cronometro' | ||
import { readFileSync } from 'fs' | ||
import { join } from 'path' | ||
import Cluster from '../lib/cluster' | ||
|
||
const numNodes = parseInt(process.env.NODES || '3', 10) | ||
const iterations = parseInt(process.env.ITERATIONS || '10000', 10) | ||
const batchSize = parseInt(process.env.BATCH_SIZE || '1000', 10) | ||
const keys = readFileSync(join(__dirname, `fixtures/cluster-${numNodes}.txt`), 'utf-8').split('\n') | ||
const configuration = Array.from(Array(numNodes), (_, i) => ({ host: '127.0.0.1', port: 30000 + i + 1 })) | ||
let cluster | ||
|
||
function command(): string { | ||
const choice = Math.random() | ||
|
||
if (choice < 0.3) { | ||
return 'ttl' | ||
} else if (choice < 0.6) { | ||
return 'exists' | ||
} | ||
|
||
return 'get' | ||
} | ||
|
||
function test() { | ||
const index = Math.floor(Math.random() * keys.length) | ||
|
||
return Promise.all(Array.from(Array(batchSize)).map(() => cluster[command()](keys[index]))) | ||
} | ||
|
||
function after(cb) { | ||
cluster.quit() | ||
cb() | ||
} | ||
|
||
cronometro( | ||
{ | ||
default: { | ||
test, | ||
before(cb) { | ||
cluster = new Cluster(configuration) | ||
|
||
cb() | ||
}, | ||
after | ||
}, | ||
'enableAutoPipelining=true': { | ||
test, | ||
before(cb) { | ||
cluster = new Cluster(configuration, { enableAutoPipelining: true }) | ||
cb() | ||
}, | ||
after | ||
} | ||
}, | ||
{ | ||
iterations, | ||
print: { compare: true } | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { cronometro } from 'cronometro' | ||
import { readFileSync } from 'fs' | ||
import { join } from 'path' | ||
import Redis from '../lib/redis' | ||
|
||
const iterations = parseInt(process.env.ITERATIONS || '10000', 10) | ||
const batchSize = parseInt(process.env.BATCH_SIZE || '1000', 10) | ||
const keys = readFileSync(join(__dirname, 'fixtures/cluster-3.txt'), 'utf-8').split('\n') | ||
let redis | ||
|
||
function command(): string { | ||
const choice = Math.random() | ||
|
||
if (choice < 0.3) { | ||
return 'ttl' | ||
} else if (choice < 0.6) { | ||
return 'exists' | ||
} | ||
|
||
return 'get' | ||
} | ||
|
||
function test() { | ||
const index = Math.floor(Math.random() * keys.length) | ||
|
||
return Promise.all(Array.from(Array(batchSize)).map(() => redis[command()](keys[index]))) | ||
} | ||
|
||
function after(cb) { | ||
redis.quit() | ||
cb() | ||
} | ||
|
||
cronometro( | ||
{ | ||
default: { | ||
test, | ||
before(cb) { | ||
redis = new Redis() | ||
|
||
cb() | ||
}, | ||
after | ||
}, | ||
'enableAutoPipelining=true': { | ||
test, | ||
before(cb) { | ||
redis = new Redis({ enableAutoPipelining: true }) | ||
cb() | ||
}, | ||
after | ||
} | ||
}, | ||
{ | ||
iterations, | ||
print: { compare: true } | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { cronometro } from 'cronometro' | ||
import Redis from '../lib/redis' | ||
|
||
let redis | ||
|
||
cronometro( | ||
{ | ||
default: { | ||
test() { | ||
return redis.set('foo', 'bar') | ||
}, | ||
before(cb) { | ||
redis = new Redis() | ||
cb() | ||
}, | ||
after(cb) { | ||
redis.quit() | ||
cb() | ||
} | ||
}, | ||
'dropBufferSupport=true': { | ||
test() { | ||
return redis.set('foo', 'bar') | ||
}, | ||
before(cb) { | ||
redis = new Redis({ dropBufferSupport: true }) | ||
cb() | ||
}, | ||
after(cb) { | ||
redis.quit() | ||
cb() | ||
} | ||
} | ||
}, | ||
{ | ||
print: { compare: true } | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
'use strict' | ||
|
||
const start = process.hrtime.bigint() | ||
|
||
import * as calculateSlot from 'cluster-key-slot' | ||
import { writeFileSync } from 'fs' | ||
import { join } from 'path' | ||
import { v4 as uuid } from 'uuid' | ||
|
||
// Input parameters | ||
const numKeys = parseInt(process.env.KEYS || '1000000', 10) | ||
const numNodes = parseInt(process.env.NODES || '3', 10) | ||
|
||
// Prepare topology | ||
const maxSlot = 16384 | ||
const destination = join(__dirname, `cluster-${numNodes}.txt`) | ||
const counts = Array.from(Array(numNodes), () => 0) | ||
const keys = [] | ||
|
||
/* | ||
This algorithm is taken and adapted from Redis source code | ||
See: https://github.com/redis/redis/blob/d9f970d8d3f0b694f1e8915cab6d4eab9cfb2ef1/src/redis-cli.c#L5453 | ||
*/ | ||
const nodes = [] // This only holds starting slot, since the ending slot can be computed out of the next one | ||
let first = 0 | ||
let cursor = 0 | ||
const slotsPerNode = maxSlot / numNodes | ||
|
||
for (let i = 0; i < numNodes; i++) { | ||
let last = Math.round(cursor + slotsPerNode - 1) | ||
|
||
if (last > maxSlot || i === numNodes - 1) { | ||
last = maxSlot - 1 | ||
} | ||
|
||
if (last < first) { | ||
last = first | ||
} | ||
|
||
nodes.push(first) | ||
first = last + 1 | ||
cursor += slotsPerNode | ||
} | ||
|
||
// Generate keys and also track slot allocations | ||
for (let i = 0; i < numKeys; i++) { | ||
const key = uuid() | ||
const slot = calculateSlot(key) | ||
const node = nodes.findIndex((start, i) => i === numNodes - 1 || (slot >= start && slot < nodes[i + 1])) | ||
|
||
counts[node]++ | ||
keys.push(key) | ||
} | ||
|
||
// Save keys | ||
writeFileSync(destination, keys.join('\n')) | ||
|
||
// Print summary | ||
console.log(`Generated ${numKeys} keys in ${(Number(process.hrtime.bigint() - start) / 1e6).toFixed(2)} ms `) | ||
|
||
for (let i = 0; i < numNodes; i++) { | ||
const from = nodes[i] | ||
const to = (i === numNodes - 1 ? maxSlot : nodes[i + 1]) - 1 | ||
console.log( | ||
` - Generated ${counts[i]} keys for node(s) serving slots ${from}-${to} (${((counts[i] * 100) / numKeys).toFixed(2)} %)` | ||
) | ||
} |
Oops, something went wrong.