In all cases below I assume that compaction into the smallest level (from a write buffer flush) has no write-amp. This is done to reduce the size of this blog post.
tl;dr - for an LSM with L1, L2, L3 and L4 what values for per-level fanout minimizes write-amp when the total fanout is 1000?
- (10, 10, 10) for leveled
- (6.3, 12.6, 12.6) for leveled-N assuming two of the levels have 2 sorted runs
- (>1, >1, >1) for tiered
Minimizing write-amp for leveled compaction
For an LSM with 4 levels (L1, L2, L3, L4) there is a per-level fanout between L1:L2, L2:L3 and L3:L4. Assume this uses classic leveled compaction so the total fanout is size(L4) / size(L1). The product of the per-level fanouts must equal the total fanout. The total write-amp is the sum of the per-level write-amp. I assume that the per-level write amp is the same as the per-level fanout although in practice and in theory it isn't that simple. Lets use a, b and c as the variables for the per-level fanout (write-amp) then the math problem is:
- minimize a+b+c
- such that a*b*c=k and a, b, c > 1
This result uses Lagrange Multipliers for an LSM tree with 4 levels do there are 3 variables: a, b, c. But the math holds for an LSM tree with fewer levels or with more levels. If there are N levels then there are N-1 variables.
L(a, b, c) = a + b + c - lambda * (a*b*c - k)
L(a, b, c) = a + b + c - lambda * (a*b*c - k)
dL/da = 1 - lambda * bc
dL/db = 1 - lambda * ac
dL/dc = 1 - lambda * ab
then
lambda = 1/bc = 1/ac = 1/ab
bc == ac == ab
bc == ac == ab
and a == b == c to minimize the sum in #1
I wrote a Python script to discover the (almost) best values and the results match the math above.
Minimizing write-amp for tiered compaction
Assuming you can reason about tiered compaction using the notion of levels then the math changes a bit because the per-level write-amp with tiered equals 1 regardless of the per-level fanout. For tiered with 4 levels and 3 variables the problem is:
Minimizing write-amp for tiered compaction
Assuming you can reason about tiered compaction using the notion of levels then the math changes a bit because the per-level write-amp with tiered equals 1 regardless of the per-level fanout. For tiered with 4 levels and 3 variables the problem is:
- minimize 1+1+1
- such that a*b*c = k and a, b, c > 1
Any values for a, b and c are sufficient as long they satisfy the constraints in #2. But it still helps to minimize a+b+c if that is predicts read-amp because a, b and c are also the number of sorted runs in L2, L3 and L4. So my advice is to use a == b == c in most cases.
Minimizing write-amp for leveled-N compaction
I explain leveled-N compaction here and here. It is like leveled compaction but allows a level to have more than one sorted run. This reduces the per-level write-amp at the cost of more read-amp. Sometimes that is a good trade.
The math above can also be used to determine how to configure per-level fanout to minimize write-amp for leveled-N. Assume an LSM tree with 4 levels (L1, L2, L3, L4) and 2 sorted runs in L2 and L3. The problem is:
Therefore with leveled-N the per-level write-amp is b/2 for L2 to L3 and c/2 for L3 to L4 because there are 2 sorted runs in the compaction input (twice as much data) in those cases. Were there 3 sorted runs then the values would be b/3 and c/3.
Lagrange Multipliers can be used to solve this assuming we want to minimize a + b/2 + c/2.
If the total fanout is 1000 then the per-level fanout values that minimize write-amp are 10, 10, 10 for leveled and 6.30, 12.60, 12.60 for this example with leveled-N and can be computed by "bc -l"
# and for leveled
e(l(1000)/3)
9.99999999999999999992
One way to think of this result is that with leveled compaction the goal is to use the same per-level fanout between levels. This also uses the same per-level write-amp between levels because per-level write-amp == the per-level fanout for leveled.
But with leveled-N compaction we need to adjust the per-level fanout for levels to continue to get the same per-level write-amp between levels.
Minimizing write-amp for leveled-N compaction
I explain leveled-N compaction here and here. It is like leveled compaction but allows a level to have more than one sorted run. This reduces the per-level write-amp at the cost of more read-amp. Sometimes that is a good trade.
The math above can also be used to determine how to configure per-level fanout to minimize write-amp for leveled-N. Assume an LSM tree with 4 levels (L1, L2, L3, L4) and 2 sorted runs in L2 and L3. The problem is:
- minimize a + b/2 + c/2
- such that a*b*c = k and a, b, c > 1
Therefore with leveled-N the per-level write-amp is b/2 for L2 to L3 and c/2 for L3 to L4 because there are 2 sorted runs in the compaction input (twice as much data) in those cases. Were there 3 sorted runs then the values would be b/3 and c/3.
Lagrange Multipliers can be used to solve this assuming we want to minimize a + b/2 + c/2.
L(a, b, c) = a + b/2 + c/2 - lambda * (a*b*c - k)
dL/da = 1 - lambda * bc
dL/db = 1/2 - lambda * ac
dL/dc = 1/2 - lambda * ab
then
lambda = 1/bc = 1/2ac = 1/2ab
bc == 2ac -> b == 2a
bc == 2ab -> c == 2a
2ac == 2ab -> c == b
bc == 2ac -> b == 2a
bc == 2ab -> c == 2a
2ac == 2ab -> c == b
and 2a == b == c to minimize the sum
If the total fanout is 1000 then the per-level fanout values that minimize write-amp are 10, 10, 10 for leveled and 6.30, 12.60, 12.60 for this example with leveled-N and can be computed by "bc -l"
# for leveled-N
e(l(1000/4)/3)
e(l(1000/4)/3)
6.29960524947436582381
e(l(1000/4)/3) * 2
12.59921049894873164762
12.59921049894873164762
# and for leveled
e(l(1000)/3)
9.99999999999999999992
One way to think of this result is that with leveled compaction the goal is to use the same per-level fanout between levels. This also uses the same per-level write-amp between levels because per-level write-amp == the per-level fanout for leveled.
But with leveled-N compaction we need to adjust the per-level fanout for levels to continue to get the same per-level write-amp between levels.
No comments:
Post a Comment