Change units for tag quota enforcement from pages to bytes
This commit is contained in:
parent
73884bbfc7
commit
b442705dc7
|
@ -11,16 +11,16 @@ The global tag throttler bases throttling decisions on "quotas" provided by clie
|
|||
The global tag throttler cannot throttle tags to a throughput below the reserved quota, and it cannot allow throughput to exceed the total quota.
|
||||
|
||||
### Cost
|
||||
Internally, the units for these quotas are "page costs", computed as follows. The "page cost" of a read operation is computed as:
|
||||
Internally, the units for these quotas are bytes. The cost of an operation is rounded up to the nearest page size. The cost of a read operation is computed as:
|
||||
|
||||
```
|
||||
readCost = ceiling(bytesRead / CLIENT_KNOBS->READ_COST_BYTE_FACTOR);
|
||||
readCost = ceiling(bytesRead / CLIENT_KNOBS->READ_COST_BYTE_FACTOR) * CLIENT_KNOBS->READ_COST_BYTE_FACTOR;
|
||||
```
|
||||
|
||||
The "page cost" of a write operation is computed as:
|
||||
The cost of a write operation is computed as:
|
||||
|
||||
```
|
||||
writeCost = SERVER_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO * ceiling(bytesWritten / CLIENT_KNOBS->WRITE_COST_BYTE_FACTOR);
|
||||
writeCost = SERVER_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO * ceiling(bytesWritten / CLIENT_KNOBS->WRITE_COST_BYTE_FACTOR) * CLIENT_KNOBS->WRITE_COST_BYTE_FACTOR;
|
||||
```
|
||||
|
||||
Here `bytesWritten` includes cleared bytes. The size of range clears is estimated at commit time.
|
||||
|
@ -41,12 +41,6 @@ To set the quota through `fdbcli`, run:
|
|||
fdbcli> quota set <tag> [reserved_throughput|total_throughput] <bytes_per_second>
|
||||
```
|
||||
|
||||
Note that the quotas are specified in terms of bytes/second, and internally converted to page costs:
|
||||
|
||||
```
|
||||
page_cost_quota = ceiling(byte_quota / CLIENT_KNOBS->READ_COST_BYTE_FACTOR)
|
||||
```
|
||||
|
||||
### Limit Calculation
|
||||
The transaction budget that ratekeeper calculates and distributes to clients (via GRV proxies) for each tag is calculated based on several intermediate rate calculations, outlined in this section.
|
||||
|
||||
|
|
|
@ -63,9 +63,9 @@ ACTOR Future<Void> getQuota(Reference<IDatabase> db, TransactionTag tag, LimitTy
|
|||
} else {
|
||||
auto const quota = ThrottleApi::TagQuotaValue::fromValue(v.get());
|
||||
if (limitType == LimitType::TOTAL) {
|
||||
fmt::print("{}\n", quota.totalQuota * CLIENT_KNOBS->READ_COST_BYTE_FACTOR);
|
||||
fmt::print("{}\n", quota.totalQuota);
|
||||
} else if (limitType == LimitType::RESERVED) {
|
||||
fmt::print("{}\n", quota.reservedQuota * CLIENT_KNOBS->READ_COST_BYTE_FACTOR);
|
||||
fmt::print("{}\n", quota.reservedQuota);
|
||||
}
|
||||
}
|
||||
return Void();
|
||||
|
@ -90,9 +90,13 @@ ACTOR Future<Void> setQuota(Reference<IDatabase> db, TransactionTag tag, LimitTy
|
|||
// Internally, costs are stored in terms of pages, but in the API,
|
||||
// costs are specified in terms of bytes
|
||||
if (limitType == LimitType::TOTAL) {
|
||||
quota.totalQuota = (value - 1) / CLIENT_KNOBS->READ_COST_BYTE_FACTOR + 1;
|
||||
// Round up to nearest page size
|
||||
quota.totalQuota =
|
||||
((value - 1) / CLIENT_KNOBS->READ_COST_BYTE_FACTOR + 1) * CLIENT_KNOBS->READ_COST_BYTE_FACTOR;
|
||||
} else if (limitType == LimitType::RESERVED) {
|
||||
quota.reservedQuota = (value - 1) / CLIENT_KNOBS->READ_COST_BYTE_FACTOR + 1;
|
||||
// Round up to nearest page size
|
||||
quota.reservedQuota =
|
||||
((value - 1) / CLIENT_KNOBS->READ_COST_BYTE_FACTOR + 1) * CLIENT_KNOBS->READ_COST_BYTE_FACTOR;
|
||||
}
|
||||
ThrottleApi::setTagQuota(tr, tag, quota.reservedQuota, quota.totalQuota);
|
||||
wait(safeThreadFutureToFuture(tr->commit()));
|
||||
|
|
|
@ -5819,8 +5819,7 @@ void Transaction::clear(const KeyRangeRef& range, AddConflictRange addConflictRa
|
|||
// NOTE: The throttling cost of each clear is assumed to be one page.
|
||||
// This makes compuation fast, but can be inaccurate and may
|
||||
// underestimate the cost of large clears.
|
||||
++trState->totalCost;
|
||||
|
||||
trState->totalCost += CLIENT_KNOBS->WRITE_COST_BYTE_FACTOR;
|
||||
if (addConflictRange)
|
||||
t.write_conflict_ranges.push_back(req.arena, r);
|
||||
}
|
||||
|
|
|
@ -568,16 +568,16 @@ ACTOR Future<std::vector<CheckpointMetaData>> getCheckpointMetaData(Database cx,
|
|||
// Checks with Data Distributor that it is safe to mark all servers in exclusions as failed
|
||||
ACTOR Future<bool> checkSafeExclusions(Database cx, std::vector<AddressExclusion> exclusions);
|
||||
|
||||
// Round up to the nearest page size. Multiply by fungibility ratio
|
||||
// Measured in bytes, rounded up to the nearest page size. Multiply by fungibility ratio
|
||||
// because writes are more expensive than reads.
|
||||
inline uint64_t getWriteOperationCost(uint64_t bytes) {
|
||||
return CLIENT_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO *
|
||||
return CLIENT_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO * CLIENT_KNOBS->WRITE_COST_BYTE_FACTOR *
|
||||
((bytes - 1) / CLIENT_KNOBS->WRITE_COST_BYTE_FACTOR + 1);
|
||||
}
|
||||
|
||||
// Round up to the nearest page size.
|
||||
// Measured in bytes, rounded up to the nearest page size.
|
||||
inline uint64_t getReadOperationCost(uint64_t bytes) {
|
||||
return (bytes - 1) / CLIENT_KNOBS->READ_COST_BYTE_FACTOR + 1;
|
||||
return ((bytes - 1) / CLIENT_KNOBS->READ_COST_BYTE_FACTOR + 1) * CLIENT_KNOBS->READ_COST_BYTE_FACTOR;
|
||||
}
|
||||
|
||||
// Create a transaction to set the value of system key \xff/conf/perpetual_storage_wiggle. If enable == true, the value
|
||||
|
|
|
@ -59,7 +59,7 @@ class TransactionCostWorkload : public TestWorkload {
|
|||
return success(tr->get(workload.getKey(testNumber)));
|
||||
}
|
||||
|
||||
int64_t expectedFinalCost() const override { return 1; }
|
||||
int64_t expectedFinalCost() const override { return CLIENT_KNOBS->READ_COST_BYTE_FACTOR; }
|
||||
};
|
||||
|
||||
class ReadLargeValueTest : public ITest {
|
||||
|
@ -89,7 +89,7 @@ class TransactionCostWorkload : public TestWorkload {
|
|||
return success(tr->get(workload.getKey(testNumber)));
|
||||
}
|
||||
|
||||
int64_t expectedFinalCost() const override { return 2; }
|
||||
int64_t expectedFinalCost() const override { return 2 * CLIENT_KNOBS->READ_COST_BYTE_FACTOR; }
|
||||
};
|
||||
|
||||
class WriteTest : public ITest {
|
||||
|
@ -101,7 +101,9 @@ class TransactionCostWorkload : public TestWorkload {
|
|||
return Void();
|
||||
}
|
||||
|
||||
int64_t expectedFinalCost() const override { return CLIENT_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO; }
|
||||
int64_t expectedFinalCost() const override {
|
||||
return CLIENT_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO * CLIENT_KNOBS->READ_COST_BYTE_FACTOR;
|
||||
}
|
||||
};
|
||||
|
||||
class WriteLargeValueTest : public ITest {
|
||||
|
@ -114,7 +116,7 @@ class TransactionCostWorkload : public TestWorkload {
|
|||
}
|
||||
|
||||
int64_t expectedFinalCost() const override {
|
||||
return 2 * CLIENT_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO;
|
||||
return 2 * CLIENT_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO * CLIENT_KNOBS->READ_COST_BYTE_FACTOR;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -130,7 +132,7 @@ class TransactionCostWorkload : public TestWorkload {
|
|||
}
|
||||
|
||||
int64_t expectedFinalCost() const override {
|
||||
return 10 * CLIENT_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO;
|
||||
return 10 * CLIENT_KNOBS->GLOBAL_TAG_THROTTLING_RW_FUNGIBILITY_RATIO * CLIENT_KNOBS->READ_COST_BYTE_FACTOR;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -143,7 +145,7 @@ class TransactionCostWorkload : public TestWorkload {
|
|||
return Void();
|
||||
}
|
||||
|
||||
int64_t expectedFinalCost() const override { return 1; }
|
||||
int64_t expectedFinalCost() const override { return CLIENT_KNOBS->READ_COST_BYTE_FACTOR; }
|
||||
};
|
||||
|
||||
class ReadRangeTest : public ITest {
|
||||
|
@ -174,7 +176,7 @@ class TransactionCostWorkload : public TestWorkload {
|
|||
return success(tr->getRange(keys, 10));
|
||||
}
|
||||
|
||||
int64_t expectedFinalCost() const override { return 1; }
|
||||
int64_t expectedFinalCost() const override { return CLIENT_KNOBS->READ_COST_BYTE_FACTOR; }
|
||||
};
|
||||
|
||||
class ReadMultipleValuesTest : public ITest {
|
||||
|
@ -210,7 +212,7 @@ class TransactionCostWorkload : public TestWorkload {
|
|||
return waitForAll(futures);
|
||||
}
|
||||
|
||||
int64_t expectedFinalCost() const override { return 10; }
|
||||
int64_t expectedFinalCost() const override { return 10 * CLIENT_KNOBS->READ_COST_BYTE_FACTOR; }
|
||||
};
|
||||
|
||||
class LargeReadRangeTest : public ITest {
|
||||
|
@ -244,7 +246,7 @@ class TransactionCostWorkload : public TestWorkload {
|
|||
return success(tr->getRange(keys, 10));
|
||||
}
|
||||
|
||||
int64_t expectedFinalCost() const override { return 11; }
|
||||
int64_t expectedFinalCost() const override { return 11 * CLIENT_KNOBS->READ_COST_BYTE_FACTOR; }
|
||||
};
|
||||
|
||||
static std::unique_ptr<ITest> createRandomTest(int64_t testNumber) {
|
||||
|
|
Loading…
Reference in New Issue