Skip to content

Commit 9a82a68

Browse files
committed
iops split for PITR branches: 25% to WAL and 75% to DATA
1 parent 08c7b5a commit 9a82a68

3 files changed

Lines changed: 54 additions & 6 deletions

File tree

src/api/organization/project/branch/__init__.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from .....deployment import (
2727
AUTOSCALER_PVC_SUFFIX,
2828
STORAGE_PVC_SUFFIX,
29+
WAL_IOPS_FRACTION,
2930
DeploymentParameters,
3031
ResizeParameters,
3132
branch_api_domain,
@@ -869,7 +870,8 @@ async def _clone_branch_environment_task(
869870
storage_class_name: str | None = None
870871
if copy_data:
871872
try:
872-
storage_class_name = await ensure_branch_storage_class(branch_id, iops=parameters.iops)
873+
data_iops = max(1, round(parameters.iops * (1 - WAL_IOPS_FRACTION))) if pitr_enabled else parameters.iops
874+
storage_class_name = await ensure_branch_storage_class(branch_id, iops=data_iops)
873875
await clone_branch_database_volume(
874876
source_branch_id=source_branch_id,
875877
target_branch_id=branch_id,
@@ -942,7 +944,8 @@ async def _restore_branch_environment_task(
942944
await _persist_branch_status(branch_id, BranchServiceStatus.CREATING)
943945
storage_class_name: str | None = None
944946
try:
945-
storage_class_name = await ensure_branch_storage_class(branch_id, iops=parameters.iops)
947+
data_iops = max(1, round(parameters.iops * (1 - WAL_IOPS_FRACTION))) if pitr_enabled else parameters.iops
948+
storage_class_name = await ensure_branch_storage_class(branch_id, iops=data_iops)
946949
await restore_branch_database_volume_from_snapshot(
947950
source_branch_id=source_branch_id,
948951
target_branch_id=branch_id,
@@ -1006,6 +1009,7 @@ async def _restore_branch_environment_in_place_task(
10061009
snapshot_namespace: str,
10071010
snapshot_name: str,
10081011
snapshot_content_name: str | None,
1012+
pitr_enabled: bool,
10091013
recovery_target_time: datetime | None = None,
10101014
) -> None:
10111015
await _persist_branch_status(branch_id, BranchServiceStatus.RESTARTING)
@@ -1022,7 +1026,8 @@ async def _restore_branch_environment_in_place_task(
10221026
return
10231027

10241028
try:
1025-
storage_class_name = await ensure_branch_storage_class(branch_id, iops=parameters.iops)
1029+
data_iops = max(1, round(parameters.iops * (1 - WAL_IOPS_FRACTION))) if pitr_enabled else parameters.iops
1030+
storage_class_name = await ensure_branch_storage_class(branch_id, iops=data_iops)
10261031
await restore_branch_database_volume_from_snapshot(
10271032
source_branch_id=source_branch_id,
10281033
target_branch_id=branch_id,
@@ -1711,6 +1716,7 @@ async def restore(
17111716
snapshot_namespace=snapshot_namespace,
17121717
snapshot_name=snapshot_name,
17131718
snapshot_content_name=snapshot_content_name,
1719+
pitr_enabled=branch.pitr_enabled,
17141720
recovery_target_time=restore_target if isinstance(restore_target, datetime) else None,
17151721
)
17161722
)

src/deployment/__init__.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
AUTOSCALER_PVC_SUFFIX = "-block-data"
8080
AUTOSCALER_WAL_PVC_SUFFIX = "-pg-wal"
8181
PITR_WAL_PVC_SIZE = "100Gi"
82+
WAL_IOPS_FRACTION = 0.25
8283
_LOAD_BALANCER_TIMEOUT_SECONDS = float(600)
8384
_LOAD_BALANCER_POLL_INTERVAL_SECONDS = float(2)
8485
_OVERLAY_IP_TIMEOUT_SECONDS = float(300)
@@ -356,13 +357,39 @@ async def update_branch_volume_iops(branch_id: Identifier, iops: int) -> None:
356357
namespace = deployment_namespace(branch_id)
357358

358359
volume, _ = await resolve_autoscaler_volume_identifiers(namespace)
360+
361+
# Only split IOPS between data and WAL when a WAL volume exists (PITR enabled).
362+
# Otherwise the full IOPS budget goes to the data volume.
363+
# Catch only VelaKubernetesError (PVC/PV not found); other failures (e.g. missing
364+
# CSI attributes) indicate corruption and must propagate.
365+
try:
366+
wal_volume, _ = await resolve_autoscaler_wal_volume_identifiers(namespace)
367+
except VelaKubernetesError:
368+
wal_volume = None
369+
370+
if wal_volume is not None:
371+
data_iops = max(1, round(iops * (1 - WAL_IOPS_FRACTION)))
372+
wal_iops = max(1, round(iops * WAL_IOPS_FRACTION))
373+
else:
374+
data_iops = iops
375+
359376
try:
360377
async with create_simplyblock_api() as sb_api:
361-
await sb_api.update_volume(volume=volume, payload={"max_rw_iops": iops})
378+
await sb_api.update_volume(volume=volume, payload={"max_rw_iops": data_iops})
362379
except VelaSimplyblockAPIError as exc:
363380
raise VelaDeploymentError("Failed to update volume") from exc
364381

365-
logger.info("Updated Simplyblock volume %s IOPS to %s", volume, iops)
382+
logger.info("Updated Simplyblock data volume %s IOPS to %s", volume, data_iops)
383+
384+
if wal_volume is not None:
385+
try:
386+
async with create_simplyblock_api() as sb_api:
387+
await sb_api.update_volume(volume=wal_volume, payload={"max_rw_iops": wal_iops})
388+
except VelaSimplyblockAPIError as exc:
389+
raise VelaDeploymentError("Failed to update WAL volume") from exc
390+
logger.info("Updated Simplyblock WAL volume %s IOPS to %s", wal_volume, wal_iops)
391+
else:
392+
logger.info("WAL volume not found for branch %s; skipping WAL IOPS update", branch_id)
366393

367394

368395
async def ensure_branch_storage_class(branch_id: Identifier, *, iops: int) -> str:
@@ -399,6 +426,7 @@ def _configure_vela_values(
399426
database_admin_password: str,
400427
pgbouncer_admin_password: str,
401428
storage_class_name: str,
429+
wal_iops: int,
402430
use_existing_db_pvc: bool,
403431
pgbouncer_config: Mapping[str, int] | None,
404432
enable_file_storage: bool,
@@ -454,6 +482,7 @@ def _configure_vela_values(
454482
wal_persistence["create"] = not use_existing_db_pvc
455483
wal_persistence["size"] = PITR_WAL_PVC_SIZE
456484
wal_persistence["storageClassName"] = storage_class_name
485+
wal_persistence.setdefault("annotations", {})["simplybk/qos-rw-iops"] = str(wal_iops)
457486
wal_persistence["claimName"] = wal_persistence.get("claimName") or (
458487
f"{_autoscaler_vm_name()}{AUTOSCALER_WAL_PVC_SUFFIX}"
459488
)
@@ -521,14 +550,21 @@ async def create_vela_config(
521550
postgresql_resource = resources.files(__package__).joinpath("postgresql.conf")
522551
values_content = _load_chart_values(chart)
523552

524-
storage_class_name = await ensure_branch_storage_class(branch_id, iops=parameters.iops)
553+
if pitr_enabled:
554+
data_iops = max(1, round(parameters.iops * (1 - WAL_IOPS_FRACTION)))
555+
wal_iops = max(1, round(parameters.iops * WAL_IOPS_FRACTION))
556+
else:
557+
data_iops = parameters.iops
558+
wal_iops = 0
559+
storage_class_name = await ensure_branch_storage_class(branch_id, iops=data_iops)
525560
values_content = _configure_vela_values(
526561
values_content,
527562
parameters=parameters,
528563
jwt_secret=jwt_secret,
529564
database_admin_password=database_admin_password,
530565
pgbouncer_admin_password=pgbouncer_admin_password,
531566
storage_class_name=storage_class_name,
567+
wal_iops=wal_iops,
532568
use_existing_db_pvc=use_existing_db_pvc,
533569
pgbouncer_config=pgbouncer_config,
534570
enable_file_storage=parameters.enable_file_storage,

src/deployment/charts/vela/templates/autoscaler/wal-pvc.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ metadata:
2222
namespace: {{ .Release.Namespace }}
2323
labels:
2424
{{- include "vela.labels" . | nindent 4 }}
25+
{{- if $pgWalPersistence.annotations }}
26+
annotations:
27+
{{- range $k, $v := $pgWalPersistence.annotations }}
28+
{{ $k }}: {{ $v | quote }}
29+
{{- end }}
30+
{{- end }}
2531
spec:
2632
{{- if $pgWalPersistence.storageClassName }}
2733
storageClassName: {{ $pgWalPersistence.storageClassName }}

0 commit comments

Comments
 (0)