Skip to content

Commit cb8de71

Browse files
committed
MB-70228: Add throttle unit consumption stat
Stat to track per-bucket consumption of write and read units separately. This can be used to estimate throttling requiremnts for bucket workloads. Change-Id: I5fa4cc94bff2082283ff2612516207cb3ecbd179 Reviewed-on: https://review.couchbase.org/c/kv_engine/+/239607 Tested-by: Faizan Alam <faizan.alam@couchbase.com> Reviewed-by: Mohammad Zaeem <mohammad.zaeem@couchbase.com>
1 parent 69edee7 commit cb8de71

File tree

6 files changed

+47
-40
lines changed

6 files changed

+47
-40
lines changed

daemon/bucket_metering_stats_test.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,6 @@ TEST_F(BucketMeteringStatsTest, MeteringMetricsPrefixed) {
150150
EXPECT_GT(metricFamilies.size(), 0);
151151

152152
for (const auto& expected : {"op_count_total",
153-
"meter_ru_total",
154-
"meter_wu_total",
155153
"meter_cu_total",
156154
"credit_ru_total",
157155
"credit_wu_total",

daemon/buckets.cc

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@ nlohmann::json Bucket::to_json() const {
9797
json["throttle_hard_limit"] =
9898
cb::throttle::limit_to_json(throttle_hard_limit.load());
9999
json["throttle_wait_time"] = throttle_wait_time.load();
100+
json["throttle_ru_total"] = read_units_used.load();
101+
json["throttle_wu_total"] = write_units_used.load();
100102
json["num_commands"] = num_commands.load();
101103
if (serverless) {
102-
json["ru"] = read_units_used.load();
103-
json["wu"] = write_units_used.load();
104104
json["num_commands_with_metered_units"] =
105105
num_commands_with_metered_units.load();
106106
json["num_metered_dcp_messages"] =
@@ -203,6 +203,9 @@ void Bucket::addHighResolutionStats(
203203

204204
collector.addStat(Key::throttle_reserved, throttle_reserved.load());
205205
collector.addStat(Key::throttle_hard_limit, throttle_hard_limit.load());
206+
207+
collector.addStat(Key::throttle_ru_total, read_units_used);
208+
collector.addStat(Key::throttle_wu_total, write_units_used);
206209
}
207210

208211
void Bucket::addLowResolutionStats(const BucketStatCollector& collector) const {
@@ -237,9 +240,6 @@ void Bucket::addMeteringMetrics(const BucketStatCollector& collector) const {
237240
// more information recorded internally to support this.
238241
auto forKV = collector.withLabel("for", "kv");
239242

240-
// metering
241-
forKV.addStat(Key::meter_ru_total, read_units_used);
242-
forKV.addStat(Key::meter_wu_total, write_units_used);
243243
// kv does not currently account for actual compute (i.e., CPU) units
244244
// but other components do. Expose it for consistency and ease of use
245245
forKV.addStat(Key::meter_cu_total, 0);
@@ -360,29 +360,30 @@ void Bucket::commandExecuted(const Cookie& cookie) {
360360
auto& settings = Settings::instance();
361361
const auto [read, write] = cookie.getDocumentRWBytes();
362362
if (read || write) {
363-
auto ru = settings.toReadUnits(read);
364-
auto wu = settings.toWriteUnits(write);
363+
size_t ru =
364+
settings.toReadUnits(read) * cookie.getReadThottlingFactor();
365+
size_t wu =
366+
settings.toWriteUnits(write) * cookie.getWriteThottlingFactor();
365367
if (cookie.isDurable()) {
366368
wu *= 2;
367369
}
370+
const size_t throttleUnits = ru + wu;
371+
const auto resourceDomain = cookie.getResourceAllocationDomain();
372+
373+
consumedUnits(throttleUnits, resourceDomain);
374+
if (resourceDomain != ResourceAllocationDomain::None) {
375+
read_units_used += ru;
376+
write_units_used += wu;
377+
if (ru || wu) {
378+
++num_commands_with_metered_units;
379+
}
380+
}
368381

369-
const auto throttleUnits =
370-
std::size_t(ru * cookie.getReadThottlingFactor()) +
371-
(wu * cookie.getWriteThottlingFactor());
372-
373-
consumedUnits(throttleUnits, cookie.getResourceAllocationDomain());
374382
throttle_wait_time += cookie.getTotalThrottleTime().count();
375383
if (cookie.getTotalThrottleTime().count() != 0) {
376384
low_resolution_stats[connection.getThread().index]
377385
.throttle_times.add(cookie.getTotalThrottleTime());
378386
}
379-
380-
const auto [nr, nw] = cookie.getDocumentMeteringRWUnits();
381-
read_units_used += nr;
382-
write_units_used += nw;
383-
if (nr || nw) {
384-
++num_commands_with_metered_units;
385-
}
386387
}
387388
}
388389

daemon/buckets_test.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ TEST(BucketTest, Reset) {
5050
num_commands_with_metered_units = 1;
5151
num_metered_dcp_messages = 1;
5252
num_rejected = 1;
53+
read_units_used = 1;
54+
write_units_used = 1;
5355
data_ingress_status = cb::mcbp::Status::Einval;
5456
pause_cancellation_source = folly::CancellationSource{};
5557

@@ -64,6 +66,8 @@ TEST(BucketTest, Reset) {
6466
EXPECT_EQ(0, num_commands_with_metered_units);
6567
EXPECT_EQ(0, num_metered_dcp_messages);
6668
EXPECT_EQ(0, num_rejected);
69+
EXPECT_EQ(0, read_units_used);
70+
EXPECT_EQ(0, write_units_used);
6771
EXPECT_EQ(0, throttle_gauge.getValue());
6872
EXPECT_EQ(cb::mcbp::Status::Success, data_ingress_status);
6973
EXPECT_FALSE(pause_cancellation_source.canBeCancelled());

statistics/stat_definitions.json

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4512,22 +4512,6 @@
45124512
"added": "7.6.0",
45134513
"stability": "internal"
45144514
},
4515-
{
4516-
"key": "meter_ru_total",
4517-
"unit": "none",
4518-
"type": "counter",
4519-
"description": "Total Read Units used by a bucket since reset",
4520-
"added": "7.6.0",
4521-
"stability": "internal"
4522-
},
4523-
{
4524-
"key": "meter_wu_total",
4525-
"unit": "none",
4526-
"type": "counter",
4527-
"description": "Total Write Units used by a bucket since reset",
4528-
"added": "7.6.0",
4529-
"stability": "internal"
4530-
},
45314515
{
45324516
"key": "meter_cu_total",
45334517
"unit": "none",
@@ -4615,6 +4599,22 @@
46154599
"description": "Current hard throttle limit for a bucket (units per second).",
46164600
"added": "8.1.0",
46174601
"stability": "internal"
4602+
},
4603+
{
4604+
"key": "throttle_ru_total",
4605+
"unit": "none",
4606+
"type": "counter",
4607+
"description": "Total Read Units used by a bucket since reset",
4608+
"added": "8.1.0",
4609+
"stability": "internal"
4610+
},
4611+
{
4612+
"key": "throttle_wu_total",
4613+
"unit": "none",
4614+
"type": "counter",
4615+
"description": "Total Write Units used by a bucket since reset",
4616+
"added": "8.1.0",
4617+
"stability": "internal"
46184618
},
46194619
{
46204620
"key": "storage",

tests/testapp/testapp_stats.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -557,12 +557,10 @@ TEST_P(StatsTest, TestBucketDetails) {
557557
for (const auto& bucket : array) {
558558
if (cb::serverless::isEnabled()) {
559559
EXPECT_EQ(18, bucket.size());
560-
EXPECT_TRUE(bucket.contains("ru"));
561-
EXPECT_TRUE(bucket.contains("wu"));
562560
EXPECT_TRUE(bucket.contains("num_commands_with_metered_units"));
563561
EXPECT_TRUE(bucket.contains("num_metered_dcp_messages"));
564562
} else {
565-
EXPECT_EQ(14, bucket.size()) << bucket.dump(2);
563+
EXPECT_EQ(16, bucket.size()) << bucket.dump(2);
566564
}
567565
EXPECT_TRUE(bucket.contains("index"));
568566
EXPECT_TRUE(bucket.contains("connections"));
@@ -576,6 +574,8 @@ TEST_P(StatsTest, TestBucketDetails) {
576574
EXPECT_TRUE(bucket.contains("throttle_reserved"));
577575
EXPECT_TRUE(bucket.contains("throttle_hard_limit"));
578576
EXPECT_TRUE(bucket.contains("throttle_wait_time"));
577+
EXPECT_TRUE(bucket.contains("throttle_ru_total"));
578+
EXPECT_TRUE(bucket.contains("throttle_wu_total"));
579579
EXPECT_TRUE(bucket.contains("num_commands"));
580580
EXPECT_EQ("Success", bucket["data_ingress_status"]);
581581
}

tests/testapp_cluster/throttling_tests.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ TEST_F(ThrottlingTests, OpsAreThrottled) {
142142
// Check that at least some ops are throttled
143143
auto stats = getThrottlingStats(conn, bucketName);
144144
ASSERT_FALSE(stats.empty());
145+
ASSERT_EQ(4096, stats["throttle_ru_total"]); // 4096 reads done
146+
ASSERT_EQ(1, stats["throttle_wu_total"]); // 1 write done
145147
ASSERT_LE(3, stats["num_throttled"]);
146148
ASSERT_NE(0, stats["throttle_wait_time"]);
147149
};
@@ -182,6 +184,8 @@ TEST_F(ThrottlingTests, OpsAreNotThrottled) {
182184
}
183185
auto stats = getThrottlingStats(conn, bucketName);
184186
ASSERT_FALSE(stats.empty());
187+
ASSERT_EQ(4096, stats["throttle_ru_total"]); // 4096 reads done
188+
ASSERT_EQ(1, stats["throttle_wu_total"]); // 1 write done
185189
ASSERT_EQ(0, stats["num_throttled"]);
186190
ASSERT_EQ(0, stats["throttle_wait_time"]);
187191
};

0 commit comments

Comments
 (0)