3核心 CPU、4GB 内存、60GB NVMe、vps环境 这是基本环境。
特别是 NVMe(极快) 和 60GB 硬盘(空间紧张) 这两个特点,意味着我们的调优方向必须改变:“用 CPU 和 I/O 换空间,同时严格限制内存防止死机”。
3000万行数据对于 TimescaleDB 不算大,但如果不压缩,索引+数据可能很快会占满 60GB(考虑到系统和日志也要占地)。
以下是针对这台 VPS 的 精细化调优方案:
4GB 内存跑 mod_perl + 数据库非常极限。mod_perl 极其吃内存,我们必须把 Postgres 限制得“乖”一点。
修改 postgresql.conf:
Properties
# --- 内存限制 (比之前更保守) ---
# 给 OS 和 mod_perl 留足空间。设为 768MB 比较安全。
shared_buffers = 768MB
# 你的 API 可能会有很多并发小查询,设太大容易内存溢出。
work_mem = 8MB
# 维护操作(如建索引)的内存,设小一点。
maintenance_work_mem = 128MB
# 告诉优化器系统大概有多少缓存可用 (不占用实际内存,仅用于计算代价)
effective_cache_size = 2GB
# --- CPU 并行 (3核心的限制) ---
# 3核 CPU 不适合大规模并行。
# 限制后台进程总数,避免抢占 Web 服务的 CPU。
max_worker_processes = 6
# 单个查询最多只能用 1 个额外核心(加上主进程共2核),留 1 核给 API。
max_parallel_workers_per_gather = 1
max_parallel_workers = 2
NVMe 的随机读写性能极强,我们可以大胆告诉数据库:“随机读很快,别怕”。
Properties
# --- NVMe 优化 ---
# 告诉数据库随机读和顺序读一样快,这将大大鼓励使用索引。
random_page_cost = 1.1
effective_io_concurrency = 200
# --- WAL 日志 (空间保护) ---
# 60GB 硬盘比较小,之前的 4GB WAL 可能会占用太多空间。
# 降为 2GB,既保证性能又节省空间。
max_wal_size = 2GB
min_wal_size = 512MB
checkpoint_completion_target = 0.9
# --- 写入性能 (开发/测试环境神器) ---
# 强烈建议开启,性能提升巨大,风险仅为断电丢失最近 <1秒 数据
synchronous_commit = off
# 自动清理进程
autovacuum_max_workers = 3 # 原为 10 (对于3核CPU太高了)
autovacuum_naptime = 1min # 原为 10 (10秒太频繁)
你在 grep 中看到 timescaledb.max_background_workers = 16,这对于 3核心机器太浪费了,而且会占用共享内存。
Properties
# --- TimescaleDB 调整 ---
# 你的 CPU 只有3核,不需要16个后台工人类。改为 4 个足够处理压缩和保留策略。
timescaledb.max_background_workers = 4
既然你的磁盘只有 60GB,强烈建议对 3000万遥测数据启用 列式压缩。这通常能将存储空间减少 90% - 95%,而且在做统计分析(如你的三相不平衡查询)时,查询速度会更快(因为 I/O 少了)。
操作步骤(在 psql 中执行):
启用压缩特性:
假设你的超表叫 dms_data_gzdy,按照时间分块。
SQL
-- 1. 开启压缩,按 switch_oid 分段(保证同一个设备的记录在一起)
ALTER TABLE dms_data_gzdy SET (
timescaledb.compress,
timescaledb.compress_segmentby = 'switch_oid',
timescaledb.compress_orderby = 'record_time DESC'
);
设置自动压缩策略:
压缩 7 天以前的数据(热数据不压缩,便于写入;冷数据压缩,节省空间)。
SQL
SELECT add_compression_policy('dms_data_gzdy', INTERVAL '7 days');
执行完这个,你的磁盘占用可能会瞬间从几十 GB 掉到 几 GB,非常适合你的 VPS。
既然内存只有 4GB,除了限制数据库,你必须限制 Apache/mod_perl 的进程数。否则 Apache 会不断生成子进程,直到把内存吃光,然后 Linux OOM Killer 会随机杀掉 Postgres 或 Apache。
建议检查 Apache 配置 (通常在 mpm_prefork.conf 或 mpm_event.conf):
如果每个 mod_perl 进程占 50MB-100MB(很常见),你需要严格计算:
总内存: 4096 MB
OS + 其他: -512 MB
Postgres: -1000 MB (shared_buffers + overhead)
剩余给 Apache: ~2500 MB
MaxRequestWorkers (或 MaxClients): 建议设置为 25 - 30 左右。不要设置成默认的 150,必死无疑。
修改 postgresql.conf,调低内存(shared_buffers=768MB)、调低并发(max_worker_processes=6)、调低 WAL 大小(2GB)。
启用 synchronous_commit = off 和 random_page_cost = 1.1 榨干 NVMe 性能。
在数据库中对遥测表执行 ALTER TABLE ... SET (timescaledb.compress ...) 节省宝贵的 60GB 空间。
检查 Apache 配置,限制最大连接数,防止内存爆表。
# ------------------------------------------------------------------------------
# 针对 16GB RAM / 16 Core VDS 的调整
# ------------------------------------------------------------------------------
# --- 内存分配 (大幅提升) ---
# 给数据库 4GB 专用内存,查询速度飞起
shared_buffers = 4GB
# 每个查询可以用 32MB 内存做排序,复杂统计更快
work_mem = 32MB
# 维护操作(建索引/清理)给够内存,瞬间完成
maintenance_work_mem = 512MB
# 告诉优化器系统有 10GB+ 的文件缓存可用
effective_cache_size = 10GB
# --- 并行查询 (利用 16 核心优势) ---
# 允许更多后台进程
max_worker_processes = 16
# 复杂的分析查询(如三相不平衡)可以同时调用 4 个核心并行计算
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
# --- 自动清理 (CPU核心多,可以适当放宽) ---
autovacuum_max_workers = 5
# --- 写入优化 ---
# 内存大了,WAL 缓冲区也可以大一点
wal_buffers = 64MB
# 磁盘空间如果紧张,保持 2GB;如果不紧张,可以设为 4GB 减少检查点频率
max_wal_size = 4GB
# --- 其他 ---
# 连接数可以适当增加,mod_perl 进程多也不怕
max_connections = 200