forked from vitalif/vitastor
Aggregate per-pool statistics in mon
parent
30bb602681
commit
b66160a7ad
|
@ -244,6 +244,7 @@ async function optimize_change({ prev_pgs: prev_int_pgs, osd_tree, pg_size = 3,
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// FIXME: use parity_chunks with parity_space instead of pg_minsize
|
||||||
const pg_effsize = Math.min(pg_minsize, Object.keys(osd_tree).length)
|
const pg_effsize = Math.min(pg_minsize, Object.keys(osd_tree).length)
|
||||||
+ Math.max(0, Math.min(pg_size, Object.keys(osd_tree).length) - pg_minsize) * parity_space;
|
+ Math.max(0, Math.min(pg_size, Object.keys(osd_tree).length) - pg_minsize) * parity_space;
|
||||||
const pg_count = prev_int_pgs.length;
|
const pg_count = prev_int_pgs.length;
|
||||||
|
|
73
mon/mon.js
73
mon/mon.js
|
@ -36,6 +36,8 @@ const etcd_allow = new RegExp('^'+[
|
||||||
'history/last_clean_pgs',
|
'history/last_clean_pgs',
|
||||||
'inode/stats/[1-9]\\d*/[1-9]\\d*',
|
'inode/stats/[1-9]\\d*/[1-9]\\d*',
|
||||||
'stats',
|
'stats',
|
||||||
|
'index/image/.*',
|
||||||
|
'index/maxid/[1-9]\\d*',
|
||||||
].join('$|^')+'$');
|
].join('$|^')+'$');
|
||||||
|
|
||||||
const etcd_tree = {
|
const etcd_tree = {
|
||||||
|
@ -267,6 +269,16 @@ const etcd_tree = {
|
||||||
}, */
|
}, */
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
pool: {
|
||||||
|
stats: {
|
||||||
|
/* <pool_id>: {
|
||||||
|
used_raw_tb: float, // used raw space in the pool
|
||||||
|
total_raw_tb: float, // maximum amount of space in the pool
|
||||||
|
raw_to_usable: float, // raw to usable ratio
|
||||||
|
space_efficiency: float, // 0..1
|
||||||
|
} */
|
||||||
|
},
|
||||||
|
},
|
||||||
stats: {
|
stats: {
|
||||||
/* op_stats: {
|
/* op_stats: {
|
||||||
<string>: { count: uint64_t, usec: uint64_t, bytes: uint64_t },
|
<string>: { count: uint64_t, usec: uint64_t, bytes: uint64_t },
|
||||||
|
@ -289,6 +301,17 @@ const etcd_tree = {
|
||||||
history: {
|
history: {
|
||||||
last_clean_pgs: {},
|
last_clean_pgs: {},
|
||||||
},
|
},
|
||||||
|
index: {
|
||||||
|
image: {
|
||||||
|
/* <name>: {
|
||||||
|
id: uint64_t,
|
||||||
|
pool_id: uint64_t,
|
||||||
|
}, */
|
||||||
|
},
|
||||||
|
maxid: {
|
||||||
|
/* <pool_id>: uint64_t, */
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME Split into several files
|
// FIXME Split into several files
|
||||||
|
@ -363,6 +386,11 @@ class Mon
|
||||||
{
|
{
|
||||||
this.config.mon_stats_timeout = 100;
|
this.config.mon_stats_timeout = 100;
|
||||||
}
|
}
|
||||||
|
this.config.mon_stats_interval = Number(this.config.mon_stats_interval) || 5000;
|
||||||
|
if (this.config.mon_stats_interval < 100)
|
||||||
|
{
|
||||||
|
this.config.mon_stats_interval = 100;
|
||||||
|
}
|
||||||
// After this number of seconds, a dead OSD will be removed from PG distribution
|
// After this number of seconds, a dead OSD will be removed from PG distribution
|
||||||
this.config.osd_out_time = Number(this.config.osd_out_time) || 0;
|
this.config.osd_out_time = Number(this.config.osd_out_time) || 0;
|
||||||
if (!this.config.osd_out_time)
|
if (!this.config.osd_out_time)
|
||||||
|
@ -1027,6 +1055,17 @@ class Mon
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
LPOptimizer.print_change_stats(optimize_result);
|
LPOptimizer.print_change_stats(optimize_result);
|
||||||
|
const pg_effsize = Math.min(pool_cfg.pg_size, Object.keys(pool_tree).length);
|
||||||
|
this.state.pool.stats[pool_id] = {
|
||||||
|
used_raw_tb: (this.state.pool.stats[pool_id]||{}).used_raw_tb || 0,
|
||||||
|
total_raw_tb: optimize_result.space,
|
||||||
|
raw_to_usable: pg_effsize / (pool_cfg.pg_size - (pool_cfg.parity_chunks||0)),
|
||||||
|
space_efficiency: optimize_result.space/(optimize_result.total_space||1),
|
||||||
|
};
|
||||||
|
etcd_request.success.push({ requestPut: {
|
||||||
|
key: b64(this.etcd_prefix+'/pool/stats/'+pool_id),
|
||||||
|
value: b64(JSON.stringify(this.state.pool.stats[pool_id])),
|
||||||
|
} });
|
||||||
this.save_new_pgs_txn(etcd_request, pool_id, up_osds, real_prev_pgs, optimize_result.int_pgs, pg_history);
|
this.save_new_pgs_txn(etcd_request, pool_id, up_osds, real_prev_pgs, optimize_result.int_pgs, pg_history);
|
||||||
}
|
}
|
||||||
this.state.config.pgs.hash = tree_hash;
|
this.state.config.pgs.hash = tree_hash;
|
||||||
|
@ -1133,7 +1172,7 @@ class Mon
|
||||||
}, this.config.mon_change_timeout || 1000);
|
}, this.config.mon_change_timeout || 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
sum_stats()
|
sum_op_stats()
|
||||||
{
|
{
|
||||||
const op_stats = {}, subop_stats = {}, recovery_stats = {};
|
const op_stats = {}, subop_stats = {}, recovery_stats = {};
|
||||||
for (const osd in this.state.osd.stats)
|
for (const osd in this.state.osd.stats)
|
||||||
|
@ -1194,18 +1233,31 @@ class Mon
|
||||||
write: { count: 0n, usec: 0n, bytes: 0n },
|
write: { count: 0n, usec: 0n, bytes: 0n },
|
||||||
delete: { count: 0n, usec: 0n, bytes: 0n },
|
delete: { count: 0n, usec: 0n, bytes: 0n },
|
||||||
});
|
});
|
||||||
|
for (const pool_id in this.state.config.pools)
|
||||||
|
{
|
||||||
|
this.state.pool.stats[pool_id] = this.state.pool.stats[pool_id] || {};
|
||||||
|
this.state.pool.stats[pool_id].used_raw_tb = 0n;
|
||||||
|
}
|
||||||
for (const osd_num in this.state.osd.space)
|
for (const osd_num in this.state.osd.space)
|
||||||
{
|
{
|
||||||
for (const pool_id in this.state.osd.space[osd_num])
|
for (const pool_id in this.state.osd.space[osd_num])
|
||||||
{
|
{
|
||||||
|
this.state.pool.stats[pool_id] = this.state.pool.stats[pool_id] || { used_raw_tb: 0n };
|
||||||
inode_stats[pool_id] = inode_stats[pool_id] || {};
|
inode_stats[pool_id] = inode_stats[pool_id] || {};
|
||||||
for (const inode_num in this.state.osd.space[osd_num][pool_id])
|
for (const inode_num in this.state.osd.space[osd_num][pool_id])
|
||||||
{
|
{
|
||||||
|
const u = BigInt(this.state.osd.space[osd_num][pool_id][inode_num]||0);
|
||||||
inode_stats[pool_id][inode_num] = inode_stats[pool_id][inode_num] || inode_stub();
|
inode_stats[pool_id][inode_num] = inode_stats[pool_id][inode_num] || inode_stub();
|
||||||
inode_stats[pool_id][inode_num].raw_used += BigInt(this.state.osd.space[osd_num][pool_id][inode_num]||0);
|
inode_stats[pool_id][inode_num].raw_used += u;
|
||||||
|
this.state.pool.stats[pool_id].used_raw_tb += u;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const pool_id in this.state.config.pools)
|
||||||
|
{
|
||||||
|
const used = this.state.pool.stats[pool_id].used_raw_tb;
|
||||||
|
this.state.pool.stats[pool_id].used_raw_tb = Number(used)/1024/1024/1024/1024;
|
||||||
|
}
|
||||||
for (const osd_num in this.state.osd.inodestats)
|
for (const osd_num in this.state.osd.inodestats)
|
||||||
{
|
{
|
||||||
const ist = this.state.osd.inodestats[osd_num];
|
const ist = this.state.osd.inodestats[osd_num];
|
||||||
|
@ -1277,7 +1329,7 @@ class Mon
|
||||||
async update_total_stats()
|
async update_total_stats()
|
||||||
{
|
{
|
||||||
const txn = [];
|
const txn = [];
|
||||||
const stats = this.sum_stats();
|
const stats = this.sum_op_stats();
|
||||||
const object_counts = this.sum_object_counts();
|
const object_counts = this.sum_object_counts();
|
||||||
const inode_stats = this.sum_inode_stats();
|
const inode_stats = this.sum_inode_stats();
|
||||||
this.fix_stat_overflows(stats, (this.prev_stats = this.prev_stats || {}));
|
this.fix_stat_overflows(stats, (this.prev_stats = this.prev_stats || {}));
|
||||||
|
@ -1296,6 +1348,13 @@ class Mon
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const pool_id in this.state.pool.stats)
|
||||||
|
{
|
||||||
|
txn.push({ requestPut: {
|
||||||
|
key: b64(this.etcd_prefix+'/pool/stats/'+pool_id),
|
||||||
|
value: b64(JSON.stringify(this.state.pool.stats[pool_id])),
|
||||||
|
} });
|
||||||
|
}
|
||||||
if (txn.length)
|
if (txn.length)
|
||||||
{
|
{
|
||||||
await this.etcd_call('/kv/txn', { success: txn }, this.config.etcd_mon_timeout, 0);
|
await this.etcd_call('/kv/txn', { success: txn }, this.config.etcd_mon_timeout, 0);
|
||||||
|
@ -1309,11 +1368,17 @@ class Mon
|
||||||
clearTimeout(this.stats_timer);
|
clearTimeout(this.stats_timer);
|
||||||
this.stats_timer = null;
|
this.stats_timer = null;
|
||||||
}
|
}
|
||||||
|
let sleep = (this.stats_update_next||0) - Date.now();
|
||||||
|
if (sleep < this.config.mon_stats_timeout)
|
||||||
|
{
|
||||||
|
sleep = this.config.mon_stats_timeout;
|
||||||
|
}
|
||||||
this.stats_timer = setTimeout(() =>
|
this.stats_timer = setTimeout(() =>
|
||||||
{
|
{
|
||||||
this.stats_timer = null;
|
this.stats_timer = null;
|
||||||
|
this.stats_update_next = Date.now() + this.config.mon_stats_interval;
|
||||||
this.update_total_stats().catch(console.error);
|
this.update_total_stats().catch(console.error);
|
||||||
}, this.config.mon_stats_timeout || 1000);
|
}, sleep);
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_kv(kv)
|
parse_kv(kv)
|
||||||
|
|
|
@ -199,6 +199,7 @@ static int vitastor_file_open(BlockDriverState *bs, QDict *options, int flags, E
|
||||||
int64_t ret = 0;
|
int64_t ret = 0;
|
||||||
qemu_mutex_init(&client->mutex);
|
qemu_mutex_init(&client->mutex);
|
||||||
client->config_path = g_strdup(qdict_get_try_str(options, "config_path"));
|
client->config_path = g_strdup(qdict_get_try_str(options, "config_path"));
|
||||||
|
// FIXME: Rename to etcd_address
|
||||||
client->etcd_host = g_strdup(qdict_get_try_str(options, "etcd_host"));
|
client->etcd_host = g_strdup(qdict_get_try_str(options, "etcd_host"));
|
||||||
client->etcd_prefix = g_strdup(qdict_get_try_str(options, "etcd_prefix"));
|
client->etcd_prefix = g_strdup(qdict_get_try_str(options, "etcd_prefix"));
|
||||||
client->use_rdma = qdict_get_try_int(options, "use_rdma", -1);
|
client->use_rdma = qdict_get_try_int(options, "use_rdma", -1);
|
||||||
|
|
Loading…
Reference in New Issue