chore: gate production postgres tuning and taro handoff

This commit is contained in:
Codex
2026-07-01 04:27:19 +08:00
parent 6bdb2a175a
commit 69b4d3b62d
14 changed files with 702 additions and 44 deletions

View File

@@ -0,0 +1,175 @@
export const postgresTuningProfiles = {
'shared-host': {
name: 'shared-host',
label: '4c16g shared-host',
description: '4 vCPU / 16GB RAM, PostgreSQL shares the host with API, worker, Nginx and monitoring agents.',
settings: {
max_connections: {
recommended: '80',
min: 40,
max: 120,
type: 'number',
rationale: '4 vCPU should use application/pooler limits instead of many direct active connections.',
},
shared_buffers: {
recommended: '3GB',
min: '2GB',
max: '4GB',
type: 'bytes',
restart: true,
rationale: 'Keep PostgreSQL buffers large enough while leaving RAM for OS cache and sibling services.',
},
effective_cache_size: {
recommended: '10GB',
min: '8GB',
max: '12GB',
type: 'bytes',
rationale: 'Planner estimate only; reflects shared buffers plus OS cache on a 16GB shared host.',
},
work_mem: {
recommended: '16MB',
min: '8MB',
max: '32MB',
type: 'bytes',
rationale: 'This is per sort/hash operation, not a global cap.',
},
maintenance_work_mem: {
recommended: '512MB',
min: '256MB',
max: '1GB',
type: 'bytes',
rationale: 'Helps index builds, vacuum and imports without overcommitting memory.',
},
autovacuum_work_mem: {
recommended: '256MB',
min: '128MB',
max: '512MB',
type: 'bytes',
rationale: 'Avoid letting multiple autovacuum workers inherit an overly high maintenance_work_mem.',
},
wal_buffers: {
recommended: '16MB',
min: '8MB',
max: '64MB',
type: 'bytes',
restart: true,
rationale: 'Enough WAL buffering for steady learning writes and import bursts.',
},
min_wal_size: {
recommended: '1GB',
min: '1GB',
max: '4GB',
type: 'bytes',
rationale: 'Reserve WAL for short write spikes and batch jobs.',
},
max_wal_size: {
recommended: '6GB',
min: '4GB',
max: '12GB',
type: 'bytes',
rationale: 'Reduce checkpoint pressure while keeping crash recovery bounded.',
},
checkpoint_timeout: {
recommended: '10min',
min: '5min',
max: '15min',
type: 'duration',
rationale: 'Avoid overly frequent checkpoints on write bursts.',
},
checkpoint_completion_target: {
recommended: '0.9',
min: 0.8,
max: 0.95,
type: 'number',
rationale: 'Spread checkpoint I/O without pushing completion too close to the next checkpoint.',
},
effective_io_concurrency: {
recommended: '100',
min: 50,
max: 300,
type: 'number',
rationale: 'SSD cloud disk starting point; validate against the actual disk class.',
},
random_page_cost: {
recommended: '1.1',
min: 1,
max: 1.5,
type: 'number',
rationale: 'Reflect SSD random I/O and encourage reasonable index scans.',
},
jit: {
recommended: 'off',
exact: 'off',
type: 'text',
rationale: 'Question-bank API queries are mostly short OLTP requests where JIT planning cost is usually not worth it.',
},
log_min_duration_statement: {
recommended: '500ms',
min: '100ms',
max: '1000ms',
type: 'duration',
rationale: 'Capture slow SQL during launch without logging every normal request.',
},
idle_in_transaction_session_timeout: {
recommended: '60s',
min: '30s',
max: '120s',
type: 'duration',
rationale: 'Kill idle transactions before they block migrations and writes.',
},
statement_timeout: {
recommended: '30s',
min: '5s',
max: '60s',
type: 'duration',
rationale: 'API requests should fail boundedly; import jobs can override per session.',
},
lock_timeout: {
recommended: '5s',
min: '1s',
max: '10s',
type: 'duration',
rationale: 'Ordinary API requests should not wait a long time behind locks.',
},
},
},
'dedicated-db': {
name: 'dedicated-db',
label: '4c16g dedicated PostgreSQL',
description: '4 vCPU / 16GB RAM where PostgreSQL is the only heavy service on the host.',
settings: {
max_connections: { recommended: '120', min: 60, max: 150, type: 'number' },
shared_buffers: { recommended: '4GB', min: '3GB', max: '5GB', type: 'bytes', restart: true },
effective_cache_size: { recommended: '12GB', min: '10GB', max: '14GB', type: 'bytes' },
work_mem: { recommended: '16MB', min: '8MB', max: '32MB', type: 'bytes' },
maintenance_work_mem: { recommended: '768MB', min: '512MB', max: '1536MB', type: 'bytes' },
autovacuum_work_mem: { recommended: '256MB', min: '128MB', max: '512MB', type: 'bytes' },
wal_buffers: { recommended: '16MB', min: '8MB', max: '64MB', type: 'bytes', restart: true },
min_wal_size: { recommended: '2GB', min: '1GB', max: '4GB', type: 'bytes' },
max_wal_size: { recommended: '8GB', min: '4GB', max: '16GB', type: 'bytes' },
checkpoint_timeout: { recommended: '15min', min: '5min', max: '20min', type: 'duration' },
checkpoint_completion_target: { recommended: '0.9', min: 0.8, max: 0.95, type: 'number' },
effective_io_concurrency: { recommended: '100', min: 50, max: 300, type: 'number' },
random_page_cost: { recommended: '1.1', min: 1, max: 1.5, type: 'number' },
jit: { recommended: 'off', exact: 'off', type: 'text' },
log_min_duration_statement: { recommended: '500ms', min: '100ms', max: '1000ms', type: 'duration' },
idle_in_transaction_session_timeout: { recommended: '60s', min: '30s', max: '120s', type: 'duration' },
statement_timeout: { recommended: '30s', min: '5s', max: '60s', type: 'duration' },
lock_timeout: { recommended: '5s', min: '1s', max: '10s', type: 'duration' },
},
},
};
export const defaultPostgresTuningProfile = 'shared-host';
export function getPostgresTuningProfile(name = defaultPostgresTuningProfile) {
const profile = postgresTuningProfiles[name];
if (!profile) {
throw new Error(`Unknown PostgreSQL tuning profile: ${name}`);
}
return profile;
}
export function getPostgresTuningSettingNames(profileName = defaultPostgresTuningProfile) {
return Object.keys(getPostgresTuningProfile(profileName).settings);
}