Improve data distribution: solve LP task on failure domains instead of individual OSDs
This greatly speeds up PG placement and makes it more uniform both because the LP task becomes simpler and because the distribution of individual OSDs is optimised manually
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
const assert = require('assert');
|
||||
const { fold_failure_domains, unfold_failure_domains, adjust_distribution } = require('./fold.js');
|
||||
const DSL = require('./dsl_pgs.js');
|
||||
const LPOptimizer = require('./lp_optimizer.js');
|
||||
const stableStringify = require('../stable-stringify.js');
|
||||
|
||||
async function run()
|
||||
{
|
||||
// Test run adjust_distribution
|
||||
console.log('adjust_distribution');
|
||||
const rand = [];
|
||||
for (let i = 0; i < 100; i++)
|
||||
{
|
||||
rand.push(1 + Math.floor(10*Math.random()));
|
||||
// or rand.push(0);
|
||||
}
|
||||
const adj = adjust_distribution({ 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1, 9: 1, 10: 1 }, rand);
|
||||
//console.log(rand.join(' '));
|
||||
console.log(rand.reduce((a, c) => { a[c] = (a[c]||0)+1; return a; }, {}));
|
||||
//console.log(adj.join(' '));
|
||||
console.log(adj.reduce((a, c) => { a[c] = (a[c]||0)+1; return a; }, {}));
|
||||
console.log('Movement: '+rand.reduce((a, c, i) => a+(rand[i] != adj[i] ? 1 : 0), 0)+'/'+rand.length);
|
||||
|
||||
console.log('\nfold_failure_domains');
|
||||
console.log(JSON.stringify(fold_failure_domains(
|
||||
[
|
||||
{ id: 1, level: 'osd', size: 1, parent: 'disk1' },
|
||||
{ id: 2, level: 'osd', size: 2, parent: 'disk1' },
|
||||
{ id: 'disk1', level: 'disk', parent: 'host1' },
|
||||
{ id: 'host1', level: 'host', parent: 'dc1' },
|
||||
{ id: 'dc1', level: 'dc' },
|
||||
],
|
||||
[ [ [ 'dc' ], [ 'host' ] ] ]
|
||||
), 0, 2));
|
||||
|
||||
console.log('\noptimize_folded');
|
||||
// 5 DCs, 2 hosts per DC, 10 OSD per host
|
||||
const nodes = [];
|
||||
for (let i = 1; i <= 100; i++)
|
||||
{
|
||||
nodes.push({ id: i, level: 'osd', size: 1, parent: 'host'+(1+(0|((i-1)/10))) });
|
||||
}
|
||||
for (let i = 1; i <= 10; i++)
|
||||
{
|
||||
nodes.push({ id: 'host'+i, level: 'host', parent: 'dc'+(1+(0|((i-1)/2))) });
|
||||
}
|
||||
for (let i = 1; i <= 5; i++)
|
||||
{
|
||||
nodes.push({ id: 'dc'+i, level: 'dc' });
|
||||
}
|
||||
|
||||
// Check rules
|
||||
const rules = DSL.parse_level_indexes({ dc: '112233', host: '123456' }, [ 'dc', 'host', 'osd' ]);
|
||||
assert.deepEqual(rules, [[],[["dc","=",1],["host","!=",[1]]],[["dc","!=",[1]]],[["dc","=",3],["host","!=",[3]]],[["dc","!=",[1,3]]],[["dc","=",5],["host","!=",[5]]]]);
|
||||
|
||||
// Check tree folding
|
||||
const { nodes: folded_nodes, leaves: folded_leaves } = fold_failure_domains(nodes, rules);
|
||||
const expected_folded = [];
|
||||
const expected_leaves = {};
|
||||
for (let i = 1; i <= 10; i++)
|
||||
{
|
||||
expected_folded.push({ id: 100+i, name: 'host'+i, level: 'host', size: 10, parent: 'dc'+(1+(0|((i-1)/2))) });
|
||||
expected_leaves[100+i] = [ ...new Array(10).keys() ].map(k => ({ id: 10*(i-1)+k+1, level: 'osd', size: 1, parent: 'host'+i }));
|
||||
}
|
||||
for (let i = 1; i <= 5; i++)
|
||||
{
|
||||
expected_folded.push({ id: 'dc'+i, level: 'dc' });
|
||||
}
|
||||
assert.equal(stableStringify(folded_nodes), stableStringify(expected_folded));
|
||||
assert.equal(stableStringify(folded_leaves), stableStringify(expected_leaves));
|
||||
|
||||
// Now optimise it
|
||||
console.log('1000 PGs, EC 112233');
|
||||
const leaf_weights = folded_nodes.reduce((a, c) => { if (Number(c.id)) { a[c.id] = c.size; } return a; }, {});
|
||||
let res = await LPOptimizer.optimize_initial({
|
||||
osd_weights: leaf_weights,
|
||||
combinator: new DSL.RuleCombinator(folded_nodes, rules, 10000, false),
|
||||
pg_size: 6,
|
||||
pg_count: 1000,
|
||||
ordered: false,
|
||||
});
|
||||
LPOptimizer.print_change_stats(res, false);
|
||||
assert.equal(res.space, 100, 'Initial distribution');
|
||||
|
||||
const unfolded_res = { ...res };
|
||||
unfolded_res.int_pgs = unfold_failure_domains(res.int_pgs, null, folded_leaves);
|
||||
const osd_weights = nodes.reduce((a, c) => { if (Number(c.id)) { a[c.id] = c.size; } return a; }, {});
|
||||
unfolded_res.space = unfolded_res.pg_effsize * LPOptimizer.pg_list_space_efficiency(unfolded_res.int_pgs, osd_weights, 0, 1);
|
||||
LPOptimizer.print_change_stats(unfolded_res, false);
|
||||
assert.equal(res.space, 100, 'Initial distribution');
|
||||
}
|
||||
|
||||
run().catch(console.error);
|
||||
Reference in New Issue
Block a user