|
79 | 79 | AUTOSCALER_PVC_SUFFIX = "-block-data" |
80 | 80 | AUTOSCALER_WAL_PVC_SUFFIX = "-pg-wal" |
81 | 81 | PITR_WAL_PVC_SIZE = "100Gi" |
| 82 | +WAL_IOPS_FRACTION = 0.25 |
82 | 83 | _LOAD_BALANCER_TIMEOUT_SECONDS = float(600) |
83 | 84 | _LOAD_BALANCER_POLL_INTERVAL_SECONDS = float(2) |
84 | 85 | _OVERLAY_IP_TIMEOUT_SECONDS = float(300) |
@@ -356,13 +357,39 @@ async def update_branch_volume_iops(branch_id: Identifier, iops: int) -> None: |
356 | 357 | namespace = deployment_namespace(branch_id) |
357 | 358 |
|
358 | 359 | 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 | + |
359 | 376 | try: |
360 | 377 | 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}) |
362 | 379 | except VelaSimplyblockAPIError as exc: |
363 | 380 | raise VelaDeploymentError("Failed to update volume") from exc |
364 | 381 |
|
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) |
366 | 393 |
|
367 | 394 |
|
368 | 395 | async def ensure_branch_storage_class(branch_id: Identifier, *, iops: int) -> str: |
@@ -399,6 +426,7 @@ def _configure_vela_values( |
399 | 426 | database_admin_password: str, |
400 | 427 | pgbouncer_admin_password: str, |
401 | 428 | storage_class_name: str, |
| 429 | + wal_iops: int, |
402 | 430 | use_existing_db_pvc: bool, |
403 | 431 | pgbouncer_config: Mapping[str, int] | None, |
404 | 432 | enable_file_storage: bool, |
@@ -454,6 +482,7 @@ def _configure_vela_values( |
454 | 482 | wal_persistence["create"] = not use_existing_db_pvc |
455 | 483 | wal_persistence["size"] = PITR_WAL_PVC_SIZE |
456 | 484 | wal_persistence["storageClassName"] = storage_class_name |
| 485 | + wal_persistence.setdefault("annotations", {})["simplybk/qos-rw-iops"] = str(wal_iops) |
457 | 486 | wal_persistence["claimName"] = wal_persistence.get("claimName") or ( |
458 | 487 | f"{_autoscaler_vm_name()}{AUTOSCALER_WAL_PVC_SUFFIX}" |
459 | 488 | ) |
@@ -521,14 +550,21 @@ async def create_vela_config( |
521 | 550 | postgresql_resource = resources.files(__package__).joinpath("postgresql.conf") |
522 | 551 | values_content = _load_chart_values(chart) |
523 | 552 |
|
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) |
525 | 560 | values_content = _configure_vela_values( |
526 | 561 | values_content, |
527 | 562 | parameters=parameters, |
528 | 563 | jwt_secret=jwt_secret, |
529 | 564 | database_admin_password=database_admin_password, |
530 | 565 | pgbouncer_admin_password=pgbouncer_admin_password, |
531 | 566 | storage_class_name=storage_class_name, |
| 567 | + wal_iops=wal_iops, |
532 | 568 | use_existing_db_pvc=use_existing_db_pvc, |
533 | 569 | pgbouncer_config=pgbouncer_config, |
534 | 570 | enable_file_storage=parameters.enable_file_storage, |
|
0 commit comments