You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-06 02:15:48 +03:00
update benchmarks
This commit is contained in:
1
benchmark/.gitignore
vendored
Normal file
1
benchmark/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.js.json
|
32
benchmark/lib/defaults.yml
Normal file
32
benchmark/lib/defaults.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
version: 0.1
|
||||||
|
|
||||||
|
remote:
|
||||||
|
- type: oss-standalone
|
||||||
|
- setup: redis-small
|
||||||
|
|
||||||
|
setups:
|
||||||
|
- oss-standalone
|
||||||
|
|
||||||
|
spec:
|
||||||
|
setups:
|
||||||
|
- name: oss-standalone
|
||||||
|
type: oss-standalone
|
||||||
|
redis_topology:
|
||||||
|
primaries: 1
|
||||||
|
replicas: 0
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpus: "1"
|
||||||
|
memory: "10g"
|
||||||
|
|
||||||
|
exporter:
|
||||||
|
output_path: "./*.js.json"
|
||||||
|
redistimeseries:
|
||||||
|
timemetric: "$.timestamp"
|
||||||
|
metrics:
|
||||||
|
- "$.p0"
|
||||||
|
- "$.p50"
|
||||||
|
- "$.p95"
|
||||||
|
- "$.p99"
|
||||||
|
- "$.p100"
|
||||||
|
- "$.operationsPerSecond"
|
@@ -4,6 +4,7 @@ import { promises as fs } from 'fs';
|
|||||||
import { fork } from 'child_process';
|
import { fork } from 'child_process';
|
||||||
import { URL, fileURLToPath } from 'url';
|
import { URL, fileURLToPath } from 'url';
|
||||||
import { once } from 'events';
|
import { once } from 'events';
|
||||||
|
import { extname } from 'path';
|
||||||
|
|
||||||
async function getPathChoices() {
|
async function getPathChoices() {
|
||||||
const dirents = await fs.readdir(new URL('.', import.meta.url), {
|
const dirents = await fs.readdir(new URL('.', import.meta.url), {
|
||||||
@@ -32,11 +33,23 @@ async function getName() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const runnerPath = fileURLToPath(new URL('runner.js', import.meta.url)),
|
const runnerPath = fileURLToPath(new URL('runner.js', import.meta.url)),
|
||||||
path = new URL(`${await getName()}/`, import.meta.url),
|
path = new URL(`${await getName()}/`, import.meta.url);
|
||||||
metadata = await import(new URL('index.js', path));
|
|
||||||
|
async function getMetadata() {
|
||||||
|
try {
|
||||||
|
return await import(new URL('index.js', path));
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code === 'ERR_MODULE_NOT_FOUND') return;
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadata = await getMetadata(),
|
||||||
|
timestamp = Date.now();
|
||||||
|
|
||||||
for (const file of await fs.readdir(path)) {
|
for (const file of await fs.readdir(path)) {
|
||||||
if (file === 'index.js') continue;
|
if (file === 'index.js' || extname(file) !== '.js') continue;
|
||||||
|
|
||||||
const benchmarkProcess = fork(runnerPath, [
|
const benchmarkProcess = fork(runnerPath, [
|
||||||
...argv,
|
...argv,
|
||||||
@@ -45,6 +58,9 @@ for (const file of await fs.readdir(path)) {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
await once(benchmarkProcess, 'message');
|
await once(benchmarkProcess, 'message');
|
||||||
benchmarkProcess.send(metadata);
|
benchmarkProcess.send({
|
||||||
|
metadata,
|
||||||
|
timestamp
|
||||||
|
});
|
||||||
await once(benchmarkProcess, 'close');
|
await once(benchmarkProcess, 'close');
|
||||||
}
|
}
|
||||||
|
19
benchmark/lib/ping/ioredis.js
Normal file
19
benchmark/lib/ping/ioredis.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import Redis from 'ioredis';
|
||||||
|
|
||||||
|
export default async (host) => {
|
||||||
|
const client = new Redis({
|
||||||
|
host,
|
||||||
|
lazyConnect: true
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark() {
|
||||||
|
return client.ping();
|
||||||
|
},
|
||||||
|
teardown() {
|
||||||
|
return client.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
9
benchmark/lib/ping/ping.yml
Normal file
9
benchmark/lib/ping/ping.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
name: "ping"
|
||||||
|
|
||||||
|
clientconfig:
|
||||||
|
- command: |
|
||||||
|
npm install -ws
|
||||||
|
npm run build:tests-tools
|
||||||
|
cd benchmark
|
||||||
|
npm install
|
||||||
|
npm run start -- --name ping --redis-server-host ${server_private_ip}
|
21
benchmark/lib/ping/v3.js
Normal file
21
benchmark/lib/ping/v3.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { createClient } from 'redis-v3';
|
||||||
|
import { once } from 'events';
|
||||||
|
import { promisify } from 'util';
|
||||||
|
|
||||||
|
export default async (host) => {
|
||||||
|
const client = createClient({ host }),
|
||||||
|
pingAsync = promisify(client.ping).bind(client),
|
||||||
|
quitAsync = promisify(client.quit).bind(client);
|
||||||
|
|
||||||
|
await once(client, 'connect');
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark() {
|
||||||
|
return pingAsync();
|
||||||
|
},
|
||||||
|
teardown() {
|
||||||
|
return quitAsync();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
16
benchmark/lib/ping/v4.js
Normal file
16
benchmark/lib/ping/v4.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { createClient } from '@node-redis/client';
|
||||||
|
|
||||||
|
export default async (host) => {
|
||||||
|
const client = createClient({ host });
|
||||||
|
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark() {
|
||||||
|
return client.ping();
|
||||||
|
},
|
||||||
|
teardown() {
|
||||||
|
return client.disconnect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
@@ -1,10 +1,11 @@
|
|||||||
import yargs from 'yargs';
|
import yargs from 'yargs';
|
||||||
import { hideBin } from 'yargs/helpers';
|
import { hideBin } from 'yargs/helpers';
|
||||||
import { basename } from 'path';
|
import { basename } from 'path';
|
||||||
|
import { promises as fs } from 'fs';
|
||||||
import * as hdr from 'hdr-histogram-js';
|
import * as hdr from 'hdr-histogram-js';
|
||||||
hdr.initWebAssemblySync();
|
hdr.initWebAssemblySync();
|
||||||
|
|
||||||
const { path, times, concurrency } = yargs(hideBin(process.argv))
|
const { path, times, concurrency, 'redis-server-host': host } = yargs(hideBin(process.argv))
|
||||||
.option('path', {
|
.option('path', {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
demandOption: true
|
demandOption: true
|
||||||
@@ -19,25 +20,19 @@ const { path, times, concurrency } = yargs(hideBin(process.argv))
|
|||||||
default: 100,
|
default: 100,
|
||||||
demandOption: true
|
demandOption: true
|
||||||
})
|
})
|
||||||
|
.option('redis-server-host', {
|
||||||
|
type: 'string'
|
||||||
|
})
|
||||||
.parseSync();
|
.parseSync();
|
||||||
|
|
||||||
async function setup() {
|
const [ { metadata, timestamp }, module ] = await Promise.all([
|
||||||
const module = await import(path);
|
new Promise(resolve => {
|
||||||
await module.setup();
|
process.once('message', resolve);
|
||||||
return module;
|
process.send('ready');
|
||||||
}
|
}),
|
||||||
|
import(path)
|
||||||
function getMetadata() {
|
]),
|
||||||
return new Promise(resolve => {
|
{ benchmark, teardown } = await module.default(host, metadata);
|
||||||
process.once('message', resolve);
|
|
||||||
process.send('ready');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const [ { benchmark, teardown }, metadata ] = await Promise.all([
|
|
||||||
setup(),
|
|
||||||
getMetadata()
|
|
||||||
]);
|
|
||||||
|
|
||||||
async function run(times) {
|
async function run(times) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
@@ -45,23 +40,20 @@ async function run(times) {
|
|||||||
let num = 0,
|
let num = 0,
|
||||||
inProgress = 0;
|
inProgress = 0;
|
||||||
|
|
||||||
function run() {
|
async function run() {
|
||||||
++inProgress;
|
++inProgress;
|
||||||
++num;
|
++num;
|
||||||
|
|
||||||
const start = process.hrtime.bigint();
|
const start = process.hrtime.bigint();
|
||||||
benchmark(metadata)
|
await benchmark(metadata);
|
||||||
.catch(err => console.error(err))
|
histogram.recordValue(Number(process.hrtime.bigint() - start));
|
||||||
.finally(() => {
|
--inProgress;
|
||||||
histogram.recordValue(Number(process.hrtime.bigint() - start));
|
|
||||||
--inProgress;
|
|
||||||
|
|
||||||
if (num < times) {
|
if (num < times) {
|
||||||
run();
|
run();
|
||||||
} else if (inProgress === 0) {
|
} else if (inProgress === 0) {
|
||||||
resolve(histogram);
|
resolve(histogram);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const toInitiate = Math.min(concurrency, times);
|
const toInitiate = Math.min(concurrency, times);
|
||||||
@@ -75,8 +67,20 @@ async function run(times) {
|
|||||||
await run(Math.min(times * 0.1, 10_000));
|
await run(Math.min(times * 0.1, 10_000));
|
||||||
|
|
||||||
// benchmark
|
// benchmark
|
||||||
const histogram = await run(times);
|
const benchmarkStart = process.hrtime.bigint(),
|
||||||
|
histogram = await run(times),
|
||||||
|
benchmarkNanoseconds = process.hrtime.bigint() - benchmarkStart,
|
||||||
|
json = {
|
||||||
|
timestamp,
|
||||||
|
operationsPerSecond: times / Number(benchmarkNanoseconds) * 1_000_000_000,
|
||||||
|
p0: histogram.getValueAtPercentile(0),
|
||||||
|
p50: histogram.getValueAtPercentile(50),
|
||||||
|
p95: histogram.getValueAtPercentile(95),
|
||||||
|
p99: histogram.getValueAtPercentile(99),
|
||||||
|
p100: histogram.getValueAtPercentile(100)
|
||||||
|
};
|
||||||
console.log(`[${basename(path)}]:`);
|
console.log(`[${basename(path)}]:`);
|
||||||
console.table(histogram.toJSON());
|
console.table(json);
|
||||||
|
await fs.writeFile(`${path}.json`, JSON.stringify(json));
|
||||||
|
|
||||||
await teardown();
|
await teardown();
|
||||||
|
9
benchmark/lib/set-get-delete-string/1KB.yml
Normal file
9
benchmark/lib/set-get-delete-string/1KB.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
name: "set-get-delete-string-1KB"
|
||||||
|
|
||||||
|
clientconfig:
|
||||||
|
- command: |
|
||||||
|
npm install -ws
|
||||||
|
npm run build:tests-tools
|
||||||
|
cd benchmark
|
||||||
|
npm install
|
||||||
|
npm run start -- --name set-get-delete-string --size 1024 --redis-server-host ${server_private_ip}
|
9
benchmark/lib/set-get-delete-string/1MB.yml
Normal file
9
benchmark/lib/set-get-delete-string/1MB.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
name: "set-get-delete-string-1MB"
|
||||||
|
|
||||||
|
clientconfig:
|
||||||
|
- command: |
|
||||||
|
npm install -ws
|
||||||
|
npm run build:tests-tools
|
||||||
|
cd benchmark
|
||||||
|
npm install
|
||||||
|
npm run start -- --name set-get-delete-string --size 1048576 --redis-server-host ${server_private_ip}
|
9
benchmark/lib/set-get-delete-string/8B.yml
Normal file
9
benchmark/lib/set-get-delete-string/8B.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
name: "set-get-delete-string-8B"
|
||||||
|
|
||||||
|
clientconfig:
|
||||||
|
- command: |
|
||||||
|
npm install -ws
|
||||||
|
npm run build:tests-tools
|
||||||
|
cd benchmark
|
||||||
|
npm install
|
||||||
|
npm run start -- --name set-get-delete-string --size 8 --redis-server-host ${server_private_ip}
|
@@ -1,19 +1,23 @@
|
|||||||
import Redis from 'ioredis';
|
import Redis from 'ioredis';
|
||||||
|
|
||||||
const client = new Redis({ lazyConnect: true });
|
export default async (host, { randomString }) => {
|
||||||
|
const client = new Redis({
|
||||||
|
host,
|
||||||
|
lazyConnect: true
|
||||||
|
});
|
||||||
|
|
||||||
export function setup() {
|
await client.connect();
|
||||||
return client.connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function benchmark({ randomString }) {
|
return {
|
||||||
return Promise.all([
|
benchmark() {
|
||||||
client.set(randomString, randomString),
|
return Promise.all([
|
||||||
client.get(randomString),
|
client.set(randomString, randomString),
|
||||||
client.del(randomString)
|
client.get(randomString),
|
||||||
]);
|
client.del(randomString)
|
||||||
}
|
]);
|
||||||
|
},
|
||||||
export function teardown() {
|
teardown() {
|
||||||
return client.disconnect();
|
return client.disconnect();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
import { createClient } from '@node-redis/client-local';
|
|
||||||
|
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
export function setup() {
|
|
||||||
return client.connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function benchmark({ randomString }) {
|
|
||||||
return Promise.all([
|
|
||||||
client.set(randomString, randomString),
|
|
||||||
client.get(randomString),
|
|
||||||
client.del(randomString)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function teardown() {
|
|
||||||
return client.disconnect();
|
|
||||||
}
|
|
@@ -1,19 +0,0 @@
|
|||||||
import { createClient } from '@node-redis/client-production';
|
|
||||||
|
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
export function setup() {
|
|
||||||
return client.connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function benchmark({ randomString }) {
|
|
||||||
return Promise.all([
|
|
||||||
client.set(randomString, randomString),
|
|
||||||
client.get(randomString),
|
|
||||||
client.del(randomString)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function teardown() {
|
|
||||||
return client.disconnect();
|
|
||||||
}
|
|
27
benchmark/lib/set-get-delete-string/v3.js
Normal file
27
benchmark/lib/set-get-delete-string/v3.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { createClient } from 'redis-v3';
|
||||||
|
import { once } from 'events';
|
||||||
|
import { promisify } from 'util';
|
||||||
|
|
||||||
|
export default async (host, { randomString }) => {
|
||||||
|
const client = createClient({ host }),
|
||||||
|
setAsync = promisify(client.set).bind(client),
|
||||||
|
getAsync = promisify(client.get).bind(client),
|
||||||
|
delAsync = promisify(client.del).bind(client),
|
||||||
|
quitAsync = promisify(client.quit).bind(client);
|
||||||
|
|
||||||
|
await once(client, 'connect');
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark() {
|
||||||
|
return Promise.all([
|
||||||
|
setAsync(randomString, randomString),
|
||||||
|
getAsync(randomString),
|
||||||
|
delAsync(randomString)
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
teardown() {
|
||||||
|
return quitAsync();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
20
benchmark/lib/set-get-delete-string/v4.js
Normal file
20
benchmark/lib/set-get-delete-string/v4.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { createClient } from '@node-redis/client';
|
||||||
|
|
||||||
|
export default async (host, { randomString }) => {
|
||||||
|
const client = createClient({ host });
|
||||||
|
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
return {
|
||||||
|
benchmark() {
|
||||||
|
return Promise.all([
|
||||||
|
client.set(randomString, randomString),
|
||||||
|
client.get(randomString),
|
||||||
|
client.del(randomString)
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
teardown() {
|
||||||
|
return client.disconnect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
@@ -7,8 +7,7 @@
|
|||||||
"start": "node ."
|
"start": "node ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-redis/client-local": "../packages/client",
|
"@node-redis/client": "../packages/client",
|
||||||
"@node-redis/client-production": "npm:@node-redis/client@1.0.0",
|
|
||||||
"hdr-histogram-js": "2.0.1",
|
"hdr-histogram-js": "2.0.1",
|
||||||
"ioredis": "4.28.1",
|
"ioredis": "4.28.1",
|
||||||
"redis-v3": "npm:redis@3.1.2",
|
"redis-v3": "npm:redis@3.1.2",
|
||||||
|
Reference in New Issue
Block a user