Skip to content

Commit 3479752

Browse files
committed
MB-70082 Add CLI Support for rate limiting per bucket
Add two new flags to bucket-create and bucket-edit: --reserved - Set the minimum resource usage reserved for this bucket --hard-limit - If set, the bucket will be throttled at this limit Change-Id: I21de98a9fe8d3e45cb1c56c5b5d9885456402a05 Reviewed-on: https://review.couchbase.org/c/couchbase-cli/+/240608 Tested-by: Build Bot <build@couchbase.com> Reviewed-by: Matt Hall <matt.hall@couchbase.com>
1 parent 43323c9 commit 3479752

5 files changed

Lines changed: 85 additions & 4 deletions

File tree

cbmgr.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,12 @@ def __init__(self):
13541354
type=(int),
13551355
help="The number of seconds of acceptable drift at which new CAS values will be accepted")
13561356

1357+
group.add_argument("--reserved", dest="throttle_reserved", metavar="<number>", type=(int),
1358+
help="The guaranteed resource usage reserved for this bucket (units/s)")
1359+
group.add_argument("--hard-limit", dest="throttle_hard_limit", metavar="<number>", type=(int),
1360+
help="If set, the bucket will be throttled at this limit regardless of any capacity "
1361+
"left over (units/s)")
1362+
13571363
@rest_initialiser(cluster_init_check=True, version_check=True, enterprise_check=False)
13581364
def execute(self, opts):
13591365
if opts.max_ttl and not self.enterprise:
@@ -1476,7 +1482,7 @@ def execute(self, opts):
14761482
opts.history_retention_bytes, opts.history_retention_seconds,
14771483
opts.enable_history_retention, opts.rank, opts.num_vbuckets, opts.encryption_key,
14781484
dek_rotate_interval, dek_lifetime, opts.invalid_hlc_strategy,
1479-
opts.hlc_max_future_threshold)
1485+
opts.hlc_max_future_threshold, opts.throttle_reserved, opts.throttle_hard_limit)
14801486
_exit_if_errors(errors)
14811487
_success("Bucket created")
14821488

@@ -1608,6 +1614,12 @@ def __init__(self):
16081614
type=(int),
16091615
help="The number of seconds of acceptable drift at which new CAS values will be accepted")
16101616

1617+
group.add_argument("--reserved", dest="throttle_reserved", metavar="<number>", type=(int),
1618+
help="The guaranteed resource usage reserved for this bucket (units/s)")
1619+
group.add_argument("--hard-limit", dest="throttle_hard_limit", metavar="<number>", type=(int),
1620+
help="If set, the bucket will be throttled at this limit regardless of any capacity "
1621+
"left over (units/s)")
1622+
16111623
group.add_argument("--enable-cross-cluster-versioning", dest="xcluster_versioning", action='store_true')
16121624
group.add_argument("--force", dest="force", action='store_true')
16131625

@@ -1715,7 +1727,8 @@ def execute(self, opts):
17151727
opts.history_retention_bytes, opts.history_retention_seconds,
17161728
opts.enable_history_retention, opts.rank, opts.encryption_key,
17171729
dek_rotate_interval, dek_lifetime, is_couchbase_bucket, opts.invalid_hlc_strategy,
1718-
opts.hlc_max_future_threshold, opts.xcluster_versioning)
1730+
opts.hlc_max_future_threshold, opts.xcluster_versioning,
1731+
opts.throttle_reserved, opts.throttle_hard_limit)
17191732
_exit_if_errors(errors)
17201733

17211734
_success("Bucket edited")

cluster_manager.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,8 @@ def create_bucket(
11561156
dek_lifetime,
11571157
invalid_hlc_strategy,
11581158
hlc_max_future_threshold,
1159+
throttle_reserved,
1160+
throttle_hard_limit,
11591161
timeout=60):
11601162
url = f'{self.hostname}/pools/default/buckets'
11611163

@@ -1245,6 +1247,11 @@ def create_bucket(
12451247
if hlc_max_future_threshold is not None:
12461248
params["hlcMaxFutureThreshold"] = hlc_max_future_threshold
12471249

1250+
if throttle_reserved is not None:
1251+
params["throttleReserved"] = throttle_reserved
1252+
if throttle_hard_limit is not None:
1253+
params["throttleHardLimit"] = throttle_hard_limit
1254+
12481255
result, errors = self._post_form_encoded(url, params)
12491256
if errors:
12501257
return None, errors
@@ -1288,7 +1295,8 @@ def edit_bucket(self, name, memory_quota, durability_min_level, eviction_policy,
12881295
abort_outside, paralleldb_and_view_compact, purge_interval,
12891296
history_retention_bytes, history_retention_seconds, history_retention_default,
12901297
rank, encryption_key, dek_rotation_interval, dek_lifetime, couchbase_bucket: bool = True,
1291-
invalid_hlc_strategy=None, hlc_max_future_threshold=None, xcluster_versioning: bool = False):
1298+
invalid_hlc_strategy=None, hlc_max_future_threshold=None, xcluster_versioning: bool = False,
1299+
throttle_reserved=None, throttle_hard_limit=None):
12921300
url = f'{self.hostname}/pools/default/buckets/{name}'
12931301

12941302
if name is None:
@@ -1365,6 +1373,11 @@ def edit_bucket(self, name, memory_quota, durability_min_level, eviction_policy,
13651373
if xcluster_versioning:
13661374
params["enableCrossClusterVersioning"] = "true"
13671375

1376+
if throttle_reserved is not None:
1377+
params["throttleReserved"] = throttle_reserved
1378+
if throttle_hard_limit is not None:
1379+
params["throttleHardLimit"] = throttle_hard_limit
1380+
13681381
return self._post_form_encoded(url, params)
13691382

13701383
def delete_bucket(self, name):

docs/modules/cli/pages/cbcli/couchbase-cli-bucket-create.adoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ _couchbase-cli bucket-create_ [--cluster <url>] [--username <user>]
3232
[--num-vbuckets <128|1024>]
3333
[--encryption-key <key>] [--dek-rotate-every <days>] [--dek-lifetime <days>]
3434
[--invalid-hlc-strategy <error|ignore|replace>] [--hlc-max-future-threshold <seconds>]
35+
[--reserved <number>] [--hard-limit <number>]
3536

3637
== DESCRIPTION
3738

@@ -262,6 +263,14 @@ The number of days which the DEK (Data Encryption Key) should be kept for.
262263
--hlc-max-future-threshold <seconds>::
263264
The number of seconds of acceptable drift at which new CAS values will be accepted.
264265

266+
--reserved <number>::
267+
Measured in units per second. The guaranteed resource usage that is reserved for
268+
this bucket only.
269+
270+
--hard-limit <number>::
271+
Measured in units per second. If set, the bucket will be throttled at this limit
272+
regardless of any capacity left over.
273+
265274
include::{partialsdir}/cbcli/part-common-history-retention.adoc[]
266275

267276
include::{partialsdir}/cbcli/part-host-formats.adoc[]

docs/modules/cli/pages/cbcli/couchbase-cli-bucket-edit.adoc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ _couchbase-cli bucket-edit_ [--cluster <url>] [--username <user>]
3131
[--enable-history-retention-by-default <0|1>] [--rank <num>]
3232
[--encryption-key <key>] [--dek-rotate-every <days>] [--dek-lifetime <days>]
3333
[--invalid-hlc-strategy <error|ignore|replace>] [--hlc-max-future-threshold <seconds>]
34-
[--enable-cross-cluster-versioning]
34+
[--enable-cross-cluster-versioning] [--reserved <number>] [--hard-limit <number>]
3535

3636
== DESCRIPTION
3737

@@ -234,6 +234,14 @@ Run index and data compaction in parallel. Global setting only.
234234
--force::
235235
Skip any prompts asking you whether to continue.
236236

237+
--reserved <number>::
238+
Measured in units per second. The guaranteed resource usage that is reserved for this
239+
bucket only.
240+
241+
--hard-limit <number>::
242+
Measured in units per second. If set, the bucket will be throttled at this limit
243+
regardless of any capacity left over.
244+
237245
include::{partialsdir}/cbcli/part-common-history-retention.adoc[]
238246

239247
include::{partialsdir}/cbcli/part-host-formats.adoc[]

test/test_cli.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,24 @@ def test_bucket_create_hlc_threshold_invalid(self):
705705
self.assertIn("--hlc-max-future-threshold cannot be lower than 10",
706706
self.str_output)
707707

708+
def test_bucket_create_reserved(self):
709+
self.no_error_run(self.command + self.command_args + self.command_couch_args + ['--reserved', '2000'],
710+
self.server_args)
711+
expected_params = [
712+
'bucketType=couchbase', 'name=name', 'evictionPolicy=fullEviction', 'replicaNumber=0', 'ramQuotaMB=100',
713+
'storageBackend=magma', 'rank=3', 'numVBuckets=128', 'throttleReserved=2000',
714+
]
715+
self.rest_parameter_match(expected_params)
716+
717+
def test_bucket_create_hard_limit(self):
718+
self.no_error_run(self.command + self.command_args + self.command_couch_args + ['--hard-limit', '3000'],
719+
self.server_args)
720+
expected_params = [
721+
'bucketType=couchbase', 'name=name', 'evictionPolicy=fullEviction', 'replicaNumber=0', 'ramQuotaMB=100',
722+
'storageBackend=magma', 'rank=3', 'numVBuckets=128', 'throttleHardLimit=3000',
723+
]
724+
self.rest_parameter_match(expected_params)
725+
708726

709727
class TestBucketDelete(CommandTest):
710728
def setUp(self):
@@ -920,6 +938,26 @@ def test_bucket_edit_cross_cluster_versioning(self):
920938

921939
self.rest_parameter_match(expected_params)
922940

941+
def test_bucket_edit_reserved(self):
942+
self.server_args['buckets'].append(self.bucket_membase)
943+
self.no_error_run(self.command + self.command_args + self.command_couch_args + ['--reserved', '2000'],
944+
self.server_args)
945+
expected_params = [
946+
'evictionPolicy=fullEviction', 'flushEnabled=1', 'threadsNumber=8', 'replicaNumber=0', 'ramQuotaMB=100',
947+
'rank=3', 'throttleReserved=2000',
948+
]
949+
self.rest_parameter_match(expected_params)
950+
951+
def test_bucket_edit_hard_limit(self):
952+
self.server_args['buckets'].append(self.bucket_membase)
953+
self.no_error_run(self.command + self.command_args + self.command_couch_args + ['--hard-limit', '3000'],
954+
self.server_args)
955+
expected_params = [
956+
'evictionPolicy=fullEviction', 'flushEnabled=1', 'threadsNumber=8', 'replicaNumber=0', 'ramQuotaMB=100',
957+
'rank=3', 'throttleHardLimit=3000',
958+
]
959+
self.rest_parameter_match(expected_params)
960+
923961

924962
class TestBucketFlush(CommandTest):
925963
def setUp(self):

0 commit comments

Comments
 (0)