@fjall/components-infrastructure 15.0.0 → 16.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/patterns/aws/clickhouseDatabase.js +26 -7
- package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +20 -2
- package/dist/lib/resources/aws/database/clickhouseConstants.js +20 -2
- package/dist/lib/resources/aws/database/clickhouseUserData.js +13 -0
- package/dist/lib/resources/aws/monitoring/clickhouseAlarms.d.ts +4 -2
- package/package.json +3 -3
|
@@ -21,7 +21,7 @@ import { toPascalCase } from "../../utils/capitaliseString.js";
|
|
|
21
21
|
import { resolveAlertsTopic } from "../../utils/resolveAlertsTopic.js";
|
|
22
22
|
import { createClickHouseAlarms, validateClickHouseAlarmThresholds, BACKUP_HEARTBEAT_DEFAULT_WINDOW_HOURS, BACKUP_HEARTBEAT_MAX_WINDOW_HOURS, METRIC_NAMESPACE, stackScopedMetricNamespace } from "../../resources/aws/monitoring/index.js";
|
|
23
23
|
import { ClickHouseSchemaAdminSchema, ManagedPasswordNameSchema, ProfileSpecSchema, PROFILE_NAME_PATTERN } from "../../resources/aws/database/clickhouseSchemas.js";
|
|
24
|
-
import { deriveClickHouseDefaultProfiles
|
|
24
|
+
import { deriveClickHouseDefaultProfiles } from "../../resources/aws/database/clickhouseTuning.js";
|
|
25
25
|
import { inferAmiHardwareType } from "../../resources/aws/compute/ecsConstants.js";
|
|
26
26
|
import { CLICKHOUSE_DATABASE_NAME, DEFAULT_CLICKHOUSE_INSTANCE_TYPE, CLICKHOUSE_IMAGE, CLICKHOUSE_EBS_VOLUME_SIZE_GB, CLICKHOUSE_EBS_IOPS, CLICKHOUSE_EBS_THROUGHPUT_MBPS, clickHouseTaskMemoryMiB, CLICKHOUSE_HTTP_PORT, CLICKHOUSE_HTTPS_PORT, CLICKHOUSE_NATIVE_PORT, CLICKHOUSE_TCP_SECURE_PORT, CLICKHOUSE_TLS_CERT_MOUNT_PATH, CLICKHOUSE_PROMETHEUS_PORT, CLICKHOUSE_DATA_MOUNT_PATH, CLICKHOUSE_SECRET_OPTIONS, CLICKHOUSE_SERVER_ROLE_TAG, CLICKHOUSE_HOST_METRICS, clickHouseUserSecretName, CLICKHOUSE_HEALTH_CHECK, CLICKHOUSE_STOP_TIMEOUT_SECONDS, CLICKHOUSE_EBS_DEVICE_NAME, CLICKHOUSE_CONFIG_SUBDIR, CLICKHOUSE_USERS_SUBDIR, userPasswordEnvName, OPTIMISE_FINAL_SCHEDULE, REPLACING_MERGE_TREE_TABLES, OPTIMISE_MV_TABLES, CLICKHOUSE_CLOUDMAP_SERVICE_NAME, CLICKHOUSE_SERVER_CONTAINER_NAME, CLICKHOUSE_SERVICE_NAME, OPTIMISE_TASK_MEMORY_MIB, OPTIMISE_TASK_CPU_UNITS, BACKUP_SCHEDULE, BACKUP_TASK_MEMORY_MIB, BACKUP_TASK_CPU_UNITS, BACKUP_RETENTION_DAYS } from "../../resources/aws/database/clickhouseConstants.js";
|
|
27
27
|
import { TlsCertGenerator } from "../../resources/aws/utilities/tlsCertGenerator.js";
|
|
@@ -65,15 +65,35 @@ function resolveClickHouseDesiredCount(contextValue, propValue) {
|
|
|
65
65
|
* position cannot.
|
|
66
66
|
*/
|
|
67
67
|
const CLICKHOUSE_ERROR_LINE_PATTERN = '[w1, w2, w3, w4, w5="<Error>" || w5="<Fatal>", ...]';
|
|
68
|
+
/**
|
|
69
|
+
* Failed `executeQuery:` lines per 5 minutes before the alarm fires, sustained
|
|
70
|
+
* across 2 of 3 evaluation periods.
|
|
71
|
+
*
|
|
72
|
+
* ABSOLUTE, deliberately. This default used to be `3 x maxConcurrentQueries`,
|
|
73
|
+
* which read as principled and was not: a concurrency ceiling and a failure
|
|
74
|
+
* RATE are unrelated quantities, and scaling the threshold with the host size
|
|
75
|
+
* pointed the wrong way — a larger instance serves more tenants, so a given
|
|
76
|
+
* failure rate there is worse news, not more tolerable. On the 1-vCPU host it
|
|
77
|
+
* resolved to 24, meaning a steady 4-per-minute stream of failing queries
|
|
78
|
+
* never alarmed. That is the exact shape of the 2026-08-20 incident, where
|
|
79
|
+
* rejected queries surfaced to customers as missing data while every alarm
|
|
80
|
+
* stayed green.
|
|
81
|
+
*
|
|
82
|
+
* 10 is chosen against what the client now does rather than against the host:
|
|
83
|
+
* the webapp gates reads to its share of the per-user cap and retries a
|
|
84
|
+
* concurrency rejection before giving up, so a query that reaches the server
|
|
85
|
+
* AND fails is already exceptional. The 2-of-3 datapoint rule is what keeps a
|
|
86
|
+
* deploy blip or a single bad statement from paging.
|
|
87
|
+
*/
|
|
88
|
+
const DEFAULT_FAILED_QUERIES_PER_5_MIN = 10;
|
|
68
89
|
const CLICKHOUSE_FAILED_QUERY_PATTERN = '[w1, w2, w3, w4, w5="<Error>", w6="executeQuery:", ...]';
|
|
69
90
|
/**
|
|
70
91
|
* Server-log signal alarm specs for the ClickHouse service's declarative
|
|
71
92
|
* `logAlarms`. Three always-on signals plus a cold-tier S3 signal when the
|
|
72
93
|
* cold tier is enabled. Thresholds come from the `alarms` knob with defaults
|
|
73
|
-
* documented on `ClickHouseAlarmThresholds
|
|
74
|
-
* derives from the instance's `maxConcurrentQueries` so it tracks host size.
|
|
94
|
+
* documented on `ClickHouseAlarmThresholds`.
|
|
75
95
|
*/
|
|
76
|
-
function buildClickHouseLogAlarmSpecs(thresholds, coldTierEnabled
|
|
96
|
+
function buildClickHouseLogAlarmSpecs(thresholds, coldTierEnabled) {
|
|
77
97
|
const specs = [
|
|
78
98
|
{
|
|
79
99
|
idStem: "ClickHouseServerErrors",
|
|
@@ -90,7 +110,7 @@ function buildClickHouseLogAlarmSpecs(thresholds, coldTierEnabled, maxConcurrent
|
|
|
90
110
|
metricName: "ClickHouseFailedQueryCount",
|
|
91
111
|
description: "ClickHouse failed-query rate exceeds threshold — check system.query_log for the failing statement and error code",
|
|
92
112
|
literal: CLICKHOUSE_FAILED_QUERY_PATTERN,
|
|
93
|
-
threshold: thresholds.failedQueriesPer5Min ??
|
|
113
|
+
threshold: thresholds.failedQueriesPer5Min ?? DEFAULT_FAILED_QUERIES_PER_5_MIN,
|
|
94
114
|
period: Duration.minutes(5),
|
|
95
115
|
evaluationPeriods: 3,
|
|
96
116
|
datapointsToAlarm: 2
|
|
@@ -441,10 +461,9 @@ export class ClickHouseDatabase extends Construct {
|
|
|
441
461
|
(App.hasInstance() ? App.getInstance().getName() : undefined);
|
|
442
462
|
const alarmThresholds = typeof props.alarms === "object" ? props.alarms : {};
|
|
443
463
|
validateClickHouseAlarmThresholds(alarmThresholds);
|
|
444
|
-
const serverTuning = deriveClickHouseServerTuning(instanceType);
|
|
445
464
|
const serviceLogAlarms = alarmsDisabled
|
|
446
465
|
? undefined
|
|
447
|
-
: buildClickHouseLogAlarmSpecs(alarmThresholds, coldTierEnabled
|
|
466
|
+
: buildClickHouseLogAlarmSpecs(alarmThresholds, coldTierEnabled);
|
|
448
467
|
const ecsCompute = new EcsCompute(this, "Compute", {
|
|
449
468
|
type: "ecs",
|
|
450
469
|
vpc,
|
|
@@ -42,8 +42,26 @@ export declare const DEFAULT_CLICKHOUSE_INSTANCE_TYPE = "m7g.medium";
|
|
|
42
42
|
* that pulls once per launch. Upstream CH CI runs its full perf + stress
|
|
43
43
|
* matrix on the Ubuntu build; Alpine is community-tier coverage. */
|
|
44
44
|
export declare const CLICKHOUSE_IMAGE = "docker.io/clickhouse/clickhouse-server:26.3.17.56";
|
|
45
|
-
/** EBS volume configuration.
|
|
46
|
-
|
|
45
|
+
/** EBS volume configuration.
|
|
46
|
+
*
|
|
47
|
+
* Sized for the 30-organisation baseline the 2026-08 capacity review set,
|
|
48
|
+
* not for today's tenant count: the 80 GiB the cluster launched on binds at
|
|
49
|
+
* roughly 20-25 organisations once `log_events` and `application_metrics`
|
|
50
|
+
* carry a full retention window each, which is BELOW that baseline. 400 GiB
|
|
51
|
+
* buys the headroom to reach it without a second resize, and gp3 storage is
|
|
52
|
+
* cheap relative to an out-of-disk ClickHouse (merges stop, inserts start
|
|
53
|
+
* failing, and the recovery is a restore rather than a resize).
|
|
54
|
+
*
|
|
55
|
+
* Raising this alone is not enough — `buildClickHouseUserData` must grow the
|
|
56
|
+
* ext4 filesystem to match, because ModifyVolume resizes the block device
|
|
57
|
+
* and nothing else. The pair moves together; see the `resize2fs` step there.
|
|
58
|
+
* Applying an increase to a RUNNING cluster therefore needs the instance to
|
|
59
|
+
* relaunch (user data runs at boot), and EBS permits one modification per
|
|
60
|
+
* volume per 6 hours.
|
|
61
|
+
*
|
|
62
|
+
* IOPS and throughput stay at the gp3 baseline: they are size-independent on
|
|
63
|
+
* gp3, and the workload is merge- and scan-bound rather than IOPS-starved. */
|
|
64
|
+
export declare const CLICKHOUSE_EBS_VOLUME_SIZE_GB = 400;
|
|
47
65
|
export declare const CLICKHOUSE_EBS_IOPS = 3000;
|
|
48
66
|
export declare const CLICKHOUSE_EBS_THROUGHPUT_MBPS = 125;
|
|
49
67
|
/** Host memory reserved from the ClickHouse container: kernel + ECS agent +
|
|
@@ -42,8 +42,26 @@ export const DEFAULT_CLICKHOUSE_INSTANCE_TYPE = "m7g.medium";
|
|
|
42
42
|
* that pulls once per launch. Upstream CH CI runs its full perf + stress
|
|
43
43
|
* matrix on the Ubuntu build; Alpine is community-tier coverage. */
|
|
44
44
|
export const CLICKHOUSE_IMAGE = "docker.io/clickhouse/clickhouse-server:26.3.17.56";
|
|
45
|
-
/** EBS volume configuration.
|
|
46
|
-
|
|
45
|
+
/** EBS volume configuration.
|
|
46
|
+
*
|
|
47
|
+
* Sized for the 30-organisation baseline the 2026-08 capacity review set,
|
|
48
|
+
* not for today's tenant count: the 80 GiB the cluster launched on binds at
|
|
49
|
+
* roughly 20-25 organisations once `log_events` and `application_metrics`
|
|
50
|
+
* carry a full retention window each, which is BELOW that baseline. 400 GiB
|
|
51
|
+
* buys the headroom to reach it without a second resize, and gp3 storage is
|
|
52
|
+
* cheap relative to an out-of-disk ClickHouse (merges stop, inserts start
|
|
53
|
+
* failing, and the recovery is a restore rather than a resize).
|
|
54
|
+
*
|
|
55
|
+
* Raising this alone is not enough — `buildClickHouseUserData` must grow the
|
|
56
|
+
* ext4 filesystem to match, because ModifyVolume resizes the block device
|
|
57
|
+
* and nothing else. The pair moves together; see the `resize2fs` step there.
|
|
58
|
+
* Applying an increase to a RUNNING cluster therefore needs the instance to
|
|
59
|
+
* relaunch (user data runs at boot), and EBS permits one modification per
|
|
60
|
+
* volume per 6 hours.
|
|
61
|
+
*
|
|
62
|
+
* IOPS and throughput stay at the gp3 baseline: they are size-independent on
|
|
63
|
+
* gp3, and the workload is merge- and scan-bound rather than IOPS-starved. */
|
|
64
|
+
export const CLICKHOUSE_EBS_VOLUME_SIZE_GB = 400;
|
|
47
65
|
export const CLICKHOUSE_EBS_IOPS = 3000;
|
|
48
66
|
export const CLICKHOUSE_EBS_THROUGHPUT_MBPS = 125;
|
|
49
67
|
/** Host memory reserved from the ClickHouse container: kernel + ECS agent +
|
|
@@ -490,6 +490,19 @@ fi
|
|
|
490
490
|
mkdir -p "$MOUNT_POINT"
|
|
491
491
|
mount "$DEVICE" "$MOUNT_POINT"
|
|
492
492
|
|
|
493
|
+
# Grow the filesystem to fill the volume. Raising the CDK volume size issues a
|
|
494
|
+
# ModifyVolume against the block device only — ext4 keeps its old size until
|
|
495
|
+
# resize2fs runs, so without this line every capacity increase is INERT and the
|
|
496
|
+
# disk fills at whatever ceiling the volume was first formatted at. Online
|
|
497
|
+
# (post-mount) rather than offline: growing a mounted ext4 needs no prior
|
|
498
|
+
# e2fsck, growing an unmounted one does.
|
|
499
|
+
#
|
|
500
|
+
# Idempotent — a no-op when the filesystem already spans the device, so it is
|
|
501
|
+
# safe on every boot. Non-fatal: a resize failure leaves the previous, smaller
|
|
502
|
+
# filesystem working, and refusing to boot over it would take the server down
|
|
503
|
+
# to fix a headroom problem. The disk alarms are what escalate from here.
|
|
504
|
+
resize2fs "$DEVICE" || echo "WARN: resize2fs failed — filesystem may not span the volume" >&2
|
|
505
|
+
|
|
493
506
|
# Persist across reboots
|
|
494
507
|
if ! grep -q "$MOUNT_POINT" /etc/fstab; then
|
|
495
508
|
echo "$DEVICE $MOUNT_POINT ext4 defaults,nofail 0 2" >> /etc/fstab
|
|
@@ -29,8 +29,10 @@ export interface ClickHouseAlarmThresholds {
|
|
|
29
29
|
diskCriticalThreshold?: number;
|
|
30
30
|
/** `<Error>`/`<Fatal>` server-log lines per 5 min. Default 30. */
|
|
31
31
|
serverErrorsPer5Min?: number;
|
|
32
|
-
/** Failed `executeQuery:` error lines per 5 min. Default
|
|
33
|
-
*
|
|
32
|
+
/** Failed `executeQuery:` error lines per 5 min. Default 10 — absolute, not
|
|
33
|
+
* derived from the host's concurrency ceiling; see
|
|
34
|
+
* `DEFAULT_FAILED_QUERIES_PER_5_MIN` in `patterns/aws/clickhouseDatabase.ts`
|
|
35
|
+
* for why the size-derived default was the wrong shape. */
|
|
34
36
|
failedQueriesPer5Min?: number;
|
|
35
37
|
/** Background-backpressure lines ("Temporarily pause scheduling" /
|
|
36
38
|
* "Too many parts") per 15 min. Default 50. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/components-infrastructure",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/fjall-tech/fjall.git",
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
},
|
|
81
81
|
"dependencies": {
|
|
82
82
|
"@aws-sdk/client-organizations": "^3.1098.0",
|
|
83
|
-
"@fjall/generator": "^
|
|
84
|
-
"@fjall/util": "^
|
|
83
|
+
"@fjall/generator": "^16.0.0",
|
|
84
|
+
"@fjall/util": "^16.0.0",
|
|
85
85
|
"constructs": "^10.7.2"
|
|
86
86
|
},
|
|
87
87
|
"overrides": {
|