Improve calculation by using birthday paradox formulae, describe logic in readme
parent
ff74045d1e
commit
3f52f73608
53
README.md
53
README.md
|
@ -12,25 +12,50 @@ https://yourcmc.ru/git/vitalif/vitastor/
|
||||||
|
|
||||||
## Логика расчёта
|
## Логика расчёта
|
||||||
|
|
||||||
Начнём с варианта, в котором не учитываются отказы серверов:
|
|
||||||
|
|
||||||
- Вероятность потери данных равна вероятности того, что в течение года выйдет из строя любой 1 диск
|
- Вероятность потери данных равна вероятности того, что в течение года выйдет из строя любой 1 диск
|
||||||
и при этом в течение времени, которое восстанавливается недостающая копия данных, выйдут из строя
|
и при этом в течение времени, которое восстанавливается недостающая копия данных, выйдут из строя
|
||||||
все оставшиеся диски любой из PG, бывших на указанном диске.
|
все оставшиеся диски любой из PG, бывших на указанном диске...
|
||||||
|
- ...Либо из строя выйдет целый хост и в течение времени его восстановления выйдут из строя оставшиеся
|
||||||
|
диски любой из PG, бывших на одном из его дисков.
|
||||||
- Вероятность выхода из строя одной PG = (вероятность выхода из строя диска = P) ^ (N-1),
|
- Вероятность выхода из строя одной PG = (вероятность выхода из строя диска = P) ^ (N-1),
|
||||||
где N - фактор репликации.
|
где N - фактор репликации. Либо вероятность выхода из строя любых K из N-1 дисков в случае EC.
|
||||||
- Все PG, бывшие на указанном диске, для упрощения мы считаем не имеющими других общих OSD. Это,
|
- Все PG, бывшие на указанном диске, для упрощения мы считаем не имеющими других общих OSD. Это,
|
||||||
естественно, не совсем корректно, так как в Ceph они, наоборот, почти гарантированно пересекаются,
|
естественно, не совсем корректно, так как в Ceph они, наоборот, почти гарантированно пересекаются.
|
||||||
однако учесть степень их пересечения в расчётах слишком сложно, а также, теоретически,
|
Однако, теоретически, вероятность выхода из строя любой из непересекающихся PG всегда выше, чем
|
||||||
вероятность выхода из строя любой из непересекающихся PG всегда выше, чем если бы какие-то из них пересекались.
|
если бы какие-то из них пересекались, то есть у нас будет оценка сверху.
|
||||||
|
- Степень пересечения мы попробуем учесть через парадокс дней рождений, см. ниже.
|
||||||
- В таком случае события выхода из строя разных PG независимы и вероятность выхода из строя любой
|
- В таком случае события выхода из строя разных PG независимы и вероятность выхода из строя любой
|
||||||
из K PG, имевших в своём составе отказавший диск, равна единице минус вероятность того, что ни
|
из K PG, имевших в своём составе отказавший диск, равна единице минус вероятность того, что ни
|
||||||
одна из K PG не выйдет из строя, то есть, (1 - (1 - P^(N-1)) ^ K).
|
одна из K PG не выйдет из строя, то есть, (1 - (1 - P^(N-1)) ^ K).
|
||||||
- "Фатальное событие" в каждый момент времени равно тому, что из строя выйдет любой диск и одновременно
|
- Итого (Умерло) = (1 - (не умерло ни из-за диска, ни из-за хоста)) =
|
||||||
ПОСЛЕ него, на протяжении времени восстановления L (выраженного в годах), также выйдет из строя любая
|
(1 - (1 - (умерло из-за диска))^(общее число дисков) * (1 - (умерло из-за хоста))^(число хостов)).
|
||||||
из PG, бывших на этом диске. Так как это "мгновенная вероятность", а выход из строя других дисков
|
- (Умерло из-за диска) = (Умер диск) * (1 - (не умерла ни одна из его PG)) =
|
||||||
учитывается "после" этого мгновения, события мы опять-таки посчитаем независимыми и вычислим
|
(Умер диск) * (1 - (1 - умерла PG)^(число PG)).
|
||||||
вероятность наступления любого из них как `1 - (1 - AFR * (1 - (1 - (AFR*L)^(N-1)) ^ K)) ^ D`,
|
- (Умерла PG) = ((AFR диска) + (AFR сервера)/(число дисков)) * (Время восстановления в годах).
|
||||||
где D - общее число дисков.
|
AFR сервера эмпирически поделен на число дисков, чтобы "размазать" вероятность отказа сервера
|
||||||
|
по его дискам.
|
||||||
|
|
||||||
Аргументация остальных вариантов - coming soon... :)
|
Парадоксы дней рождений:
|
||||||
|
|
||||||
|
- PG почти гарантированно пересекаются, особенно в небольших кластерах. Степень их пересечения
|
||||||
|
очень полезно учитывать.
|
||||||
|
- Из задачи о парадоксе дней рождения мы знаем, что если в году N дней, а в группе K человек,
|
||||||
|
то среднее число дней, являющихся хоть чьим-то днём рождения равно `U(N,K) = N*(1 - (1 - 1/N)^K)`.
|
||||||
|
Это даёт нам возможность узнать, сколько в среднем уникальных элементов при K случайных выборах из N.
|
||||||
|
- На 1 диске в среднем размещается (число PG) групп чётности по (размер PG) дисков.
|
||||||
|
- 1 диск в среднем имеет примерно U((число хостов-1) * (число дисков), (число PG) * (размер PG - 1)) дисков,
|
||||||
|
которые работают с ним в паре. Поделим это число на (размер PG - 1) и получим среднее число PG на диск с учётом пересечений.
|
||||||
|
- 1 хост в среднем имеет примерно U((число хостов-1) * (число дисков), (число дисков) * (число PG) * (размер PG - 1)) дисков,
|
||||||
|
которые работают с ним в паре. Поделим это число на (размер PG - 1) и получим среднее число PG на сервер с учётом пересечений.
|
||||||
|
- При выходе из строя 1 диска и его мгновенной замене на другой все данные восстанавливаются на единственном
|
||||||
|
новом заменном диске. В этом случае число дисков, участвующих в процессе восстановления - 1.
|
||||||
|
- При выходе из строя 1 диска без замены в Ceph по умолчанию его данные восстанавливаются на других дисках
|
||||||
|
того же хоста. В этом случае число дисков, участвующих в процессе восстановления - U(число дисков-1, число PG).
|
||||||
|
- При выходе из строя 1 диска без замены в Vitastor или гипотетической иной системе его данные
|
||||||
|
восстанавливаются на любых других дисках в кластере. В этом случае число дисков, участвующих в
|
||||||
|
процессе восстановления - U((число хостов-1) * (число дисков), (число PG)).
|
||||||
|
- При выходе из строя целого хоста без возврата его дисков в строй в других хостах в восстановлении
|
||||||
|
участвует U((число хостов-1) * (число дисков), (число дисков) * (число PG)) дисков.
|
||||||
|
- Зная число участвующих в восстановлении дисков, среднюю скорость восстановления в пересчёте на 1 диск,
|
||||||
|
оцениваемую с учётом пропускной способности сети, а также объём дисков, мы можем рассчитать
|
||||||
|
ожидаемое время восстановления данных одного диска или одного хоста.
|
||||||
|
|
25
afr.js
25
afr.js
|
@ -58,11 +58,16 @@ function failure_rate_fullmesh(n, a, f)
|
||||||
function cluster_afr({ n_hosts, n_drives, afr_drive, afr_host, capacity, speed, ec, ec_data, ec_parity, replicas, pgs = 1, osd_rm, degraded_replacement, down_out_interval = 600 })
|
function cluster_afr({ n_hosts, n_drives, afr_drive, afr_host, capacity, speed, ec, ec_data, ec_parity, replicas, pgs = 1, osd_rm, degraded_replacement, down_out_interval = 600 })
|
||||||
{
|
{
|
||||||
const pg_size = (ec ? ec_data+ec_parity : replicas);
|
const pg_size = (ec ? ec_data+ec_parity : replicas);
|
||||||
pgs = Math.min(pgs, (n_hosts-1)*n_drives/(pg_size-1));
|
// <peers> is a number of non-intersecting PGs that a single OSD/drive has on average
|
||||||
const host_pgs = Math.min(pgs*n_drives, (n_hosts-1)*n_drives/(pg_size-1));
|
const peers = avg_distinct((n_hosts-1)*n_drives, pgs*(pg_size-1))/(pg_size-1);
|
||||||
const resilver_disk = n_drives == 1 || osd_rm ? pgs : (n_drives-1);
|
// <host_peers> is a number of non-intersecting PGs that a single host has on average
|
||||||
const disk_heal_time = (down_out_interval + capacity/(degraded_replacement ? 1 : resilver_disk)/speed)/86400/365;
|
const host_peers = avg_distinct((n_hosts-1)*n_drives, pgs*(pg_size-1)*n_drives)/(pg_size-1);
|
||||||
const host_heal_time = (down_out_interval + n_drives*capacity/pgs/speed)/86400/365;
|
// <resilver_peers> other drives participate in resilvering of a single failed drive
|
||||||
|
const resilver_peers = n_drives == 1 || osd_rm ? avg_distinct((n_hosts-1)*n_drives, pgs) : avg_distinct(n_drives-1, pgs);
|
||||||
|
// <host_resilver_peers> other drives participate in resilvering of a failed host
|
||||||
|
const host_resilver_peers = avg_distinct((n_hosts-1)*n_drives, n_drives*pgs);
|
||||||
|
const disk_heal_time = (down_out_interval + capacity/(degraded_replacement ? 1 : resilver_peers)/speed)/86400/365;
|
||||||
|
const host_heal_time = (down_out_interval + n_drives*capacity/host_resilver_peers/speed)/86400/365;
|
||||||
const disk_heal_fail = ((afr_drive+afr_host/n_drives)*disk_heal_time);
|
const disk_heal_fail = ((afr_drive+afr_host/n_drives)*disk_heal_time);
|
||||||
const host_heal_fail = ((afr_drive+afr_host/n_drives)*host_heal_time);
|
const host_heal_fail = ((afr_drive+afr_host/n_drives)*host_heal_time);
|
||||||
const disk_pg_fail = ec
|
const disk_pg_fail = ec
|
||||||
|
@ -71,8 +76,8 @@ function cluster_afr({ n_hosts, n_drives, afr_drive, afr_host, capacity, speed,
|
||||||
const host_pg_fail = ec
|
const host_pg_fail = ec
|
||||||
? failure_rate_fullmesh(ec_data+ec_parity-1, host_heal_fail, ec_parity)
|
? failure_rate_fullmesh(ec_data+ec_parity-1, host_heal_fail, ec_parity)
|
||||||
: host_heal_fail**(replicas-1);
|
: host_heal_fail**(replicas-1);
|
||||||
return 1 - ((1 - afr_drive * (1-(1-disk_pg_fail)**pgs)) ** (n_hosts*n_drives))
|
return 1 - ((1 - afr_drive * (1-(1-disk_pg_fail)**peers)) ** (n_hosts*n_drives))
|
||||||
* ((1 - afr_host * (1-(1-host_pg_fail)**host_pgs)) ** n_hosts);
|
* ((1 - afr_host * (1-(1-host_pg_fail)**host_peers)) ** n_hosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******** UTILITY ********/
|
/******** UTILITY ********/
|
||||||
|
@ -87,3 +92,9 @@ function c_n_k(n, k)
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Average birthdays for K people with N total days
|
||||||
|
function avg_distinct(n, k)
|
||||||
|
{
|
||||||
|
return n * (1 - (1 - 1/n)**k);
|
||||||
|
}
|
||||||
|
|
2
main.js
2
main.js
|
@ -166,7 +166,7 @@ class Calc extends preact.Component
|
||||||
<td><input type="text" value={state.afr_drive} onchange={this.setter('afr_drive')} /> %</td>
|
<td><input type="text" value={state.afr_drive} onchange={this.setter('afr_drive')} /> %</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>AFR сервера</th>
|
<th><abbr title="Вероятность отказа сервера сразу со всеми дисками, без возвращения их в строй">AFR сервера</abbr></th>
|
||||||
<td><input type="text" value={state.afr_host} onchange={this.setter('afr_host')} /> %</td>
|
<td><input type="text" value={state.afr_host} onchange={this.setter('afr_host')} /> %</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
Loading…
Reference in New Issue