多模场景下的容量规划方法
2026/9/12 17:45:19 网站建设 项目流程

文章目录

    • 每日一句正能量
    • 1. 背景与问题
    • 2. 环境与数据
      • 2.1 关系与文档表
      • 2.2 向量表
      • 2.3 时序表
    • 3. 复现过程
      • 3.1 统计当前数据规模
      • 3.2 复现向量维度变化的容量影响
      • 3.3 复现时序数据保留过长问题
    • 4. 方案实施
      • 4.1 建立容量估算公式
      • 4.2 以业务指标驱动估算
      • 4.3 关系表的分区和索引
      • 4.4 文档存储策略
      • 4.5 时序数据分层保留
      • 4.6 向量容量与索引规划
      • 4.7 压测模型
      • 4.8 容量监控 SQL
      • 4.9 容量告警阈值
    • 5. 结果对比
    • 6. 风险与复盘
      • 6.1 常见风险
      • 6.2 上线检查清单
      • 6.3 复盘结论

每日一句正能量

生命的境界:山海在心,从容于行
“心有山海,静而无边。”
内心拥有山海般的壮阔与深度,因而能获得无边无际的宁静。

1. 背景与问题

快速增长业务在早期最容易出现一种错觉:数据库当前还能运行,所以容量暂时没有问题。

这种判断只适用于数据量和访问量都比较稳定的系统。对于同时包含关系、文档、时序和向量数据的平台,容量增长通常不是线性的,也不是只增加几张表那么简单。

以企业知识库和智能问答平台为例,一篇文档可能经历如下处理:

原始文件 -> 文档正文 -> 文档分段 -> 多个知识块 -> 每个知识块一个向量 -> 向量索引 -> 查询日志和访问审计

如果一篇文档平均切分为 12 个知识块,那么新增 10 万篇文档可能产生 120 万条向量记录。与此同时,向量索引、WAL、备份文件和查询日志还会产生额外空间。

平台中不同数据的增长特点不同:

数据类型主要增长来源典型增长特点
关系数据客户、权限、任务、订单行数稳定增长,索引较多
文档数据PDF、HTML、工单、附件单行大小差异大
时序数据指标、日志、访问事件高频写入,按时间增长
向量数据文档块、会话摘要与分块数量和模型维度相关
索引数据B-tree、GIN、HNSW通常大于表本身的预期
WAL 与备份写入、归档、快照受更新峰值和保留周期影响

容量规划需要回答:

未来 6 个月需要多少磁盘? 向量维度从 768 升到 1536 后增加多少? 时序数据保留 30 天还是 180 天? 索引重建是否需要额外临时空间? 高峰导入和在线查询是否争抢 CPU、IO 和内存? 备份保留策略是否会耗尽对象存储?

本文建立一个可执行的估算模型,并结合压测验证误差。

2. 环境与数据

测试环境:

组件用途
PostgreSQL 15关系、文档元数据和向量表
pgvector向量存储与 HNSW 索引
TimescaleDB指标、日志和访问事件
JSONB标签、扩展属性和动态字段
对象存储原始文档、附件和备份
压测工具模拟写入、检索和混合负载
监控系统CPU、内存、IO、WAL 和延迟

2.1 关系与文档表

CREATETABLEknowledge_document(document_id UUIDPRIMARYKEY,tenant_idTEXTNOTNULL,titleTEXTNOTNULL,contentTEXTNOTNULL,content_hashTEXTNOTNULL,version_noINTNOTNULLDEFAULT1,statusTEXTNOTNULLDEFAULT'published',metadata JSONBNOTNULLDEFAULT'{}'::jsonb,created_at TIMESTAMPTZNOTNULLDEFAULTnow(),updated_at TIMESTAMPTZNOTNULLDEFAULTnow());CREATEINDEXidx_document_tenant_statusONknowledge_document(tenant_id,status,updated_atDESC);CREATEINDEXidx_document_metadataONknowledge_documentUSINGGIN(metadata);

2.2 向量表

CREATEEXTENSIONIFNOTEXISTSvector;CREATETABLEknowledge_chunk(chunk_id UUIDPRIMARYKEY,document_id UUIDNOTNULLREFERENCESknowledge_document(document_id),tenant_idTEXTNOTNULL,version_noINTNOTNULL,chunk_noINTNOTNULL,contentTEXTNOTNULL,embedding_modelTEXTNOTNULL,embedding_dimensionINTNOTNULL,embedding VECTOR(768)NOTNULL,metadata JSONBNOTNULLDEFAULT'{}'::jsonb,statusTEXTNOTNULLDEFAULT'active',UNIQUE(document_id,version_no,chunk_no));CREATEINDEXidx_chunk_embedding_hnswONknowledge_chunkUSINGhnsw(embedding vector_cosine_ops);CREATEINDEXidx_chunk_tenant_statusONknowledge_chunk(tenant_id,status,document_id);

2.3 时序表

CREATETABLEplatform_metric(ts TIMESTAMPTZNOTNULL,tenant_idTEXTNOTNULL,metric_nameTEXTNOTNULL,entity_idTEXTNOTNULL,valueDOUBLEPRECISIONNOTNULL,labels JSONBNOTNULLDEFAULT'{}'::jsonb);SELECTcreate_hypertable('platform_metric',by_range('ts'),if_not_exists=>TRUE);

3. 复现过程

3.1 统计当前数据规模

SELECT'document'ASdata_type,count(*)ASrow_count,pg_total_relation_size('knowledge_document')AStotal_bytesFROMknowledge_documentUNIONALLSELECT'chunk',count(*),pg_total_relation_size('knowledge_chunk')FROMknowledge_chunk;

统计向量索引:

SELECTindexrelname,pg_size_pretty(pg_relation_size(indexrelid))ASindex_sizeFROMpg_stat_user_indexesWHERErelname='knowledge_chunk';

统计时序数据:

SELECTmetric_name,count(*)ASrow_count,min(ts)ASmin_ts,max(ts)ASmax_tsFROMplatform_metricGROUPBYmetric_nameORDERBYrow_countDESC;

3.2 复现向量维度变化的容量影响

768 维单精度向量的理论数据部分约为:

768 × 4 字节 = 3072 字节

1536 维时:

1536 × 4 字节 = 6144 字节

实际占用还包括:

行头 可变字段 TOAST 索引项 HNSW 图结构 WAL 备份副本

因此,向量维度翻倍后,最终存储不一定只增加两倍,索引和写放大可能让实际增幅更高。

3.3 复现时序数据保留过长问题

假设系统每秒写入 5000 条指标:

每日行数 = 5000 × 86400 = 432,000,000 行

如果每行平均占用 120 字节,仅数据部分就是:

432,000,000 × 120 ≈ 51.8 GB / 天

加上索引、WAL、压缩前副本和备份后,实际容量可能达到数据部分的 1.5 到 3 倍。

因此,时序表不能只按“每天多少行”规划,还要计算:

保留周期 压缩比例 索引数量 写入峰值 备份保留 查询窗口

4. 方案实施

4.1 建立容量估算公式

总容量可以拆分为:

总容量 = 关系表容量 + 文档容量 + 向量表容量 + 向量索引容量 + 时序热数据容量 + 时序归档容量 + WAL 保留空间 + 备份空间 + 临时维护空间 + 安全余量

关系数据估算:

relation_size = row_count × avg_row_bytes + btree_index_size + gin_index_size

向量数据估算:

vector_data_size = vector_count × (dimension × 4 + row_overhead)

向量索引估算不能完全依赖理论公式,应使用小规模样本测量比例:

vector_index_size = vector_data_size × observed_index_ratio

时序数据估算:

daily_ts_size = events_per_second × 86400 × avg_row_bytes × index_factor

最终容量:

planned_capacity = current_size + monthly_growth × planning_months + backup_retention_size + maintenance_headroom

建议保留至少 25% 至 35% 的安全余量,重建 HNSW 或大规模排序时则需要更多临时空间。

4.2 以业务指标驱动估算

不应只用“数据库总行数”规划。应从业务变量出发:

每日新增文档数 平均文档字数 平均切块数 Embedding 维度 每日用户查询数 每次查询候选数 每秒指标写入量 时序保留天数 文档版本保留数量 向量模型并存数量

示例:

每日新增文档:20,000 平均每篇切块:8 每日新增向量:160,000 向量维度:768 时序写入:3,000 行/秒 时序保留:90 天 模型并存:2 个版本

年度向量数量:

160,000 × 365 = 58,400,000 条

如果模型升级后新旧版本并存一段时间,峰值向量量可能接近:

58,400,000 × 2 = 116,800,000 条

模型升级和灰度阶段必须单独规划容量,不能只看稳定运行时的单模型规模。

4.3 关系表的分区和索引

大表可以按租户、业务域或时间进行分区。文档和向量表通常更适合按租户或业务域拆分,时序表适合按时间分区。

关系索引示例:

CREATEINDEXidx_document_domain_statusONknowledge_document(tenant_id,status,updated_atDESC);CREATEINDEXidx_chunk_active_tenantONknowledge_chunk(tenant_id,document_id,version_no)WHEREstatus='active';

不要为所有字段建立索引。每个索引都会增加:

存储空间 写入成本 WAL VACUUM 成本 备份体积

4.4 文档存储策略

文档正文和原始附件可以分层:

数据库: 标题、正文摘要、content_hash、权限、版本、状态和检索字段。 对象存储: 原始 PDF、图片、Office 文件、压缩包和大附件。 向量表: 文档块正文、Embedding、模型版本和块级元数据。

对于超长文档,数据库中可以保存搜索所需的规范化文本,原始文件放入对象存储。这样既能保证检索,又能减少数据库膨胀。

4.5 时序数据分层保留

推荐把时序数据分为:

热数据:最近 7 至 30 天,在线查询; 温数据:最近 90 至 180 天,压缩保存; 冷数据:更早数据,归档到对象存储或低成本数据库。

压缩统计:

SELECTtime_bucket('1 day',ts)ASday,metric_name,count(*)ASrows,avg(value)ASavg_value,max(value)ASmax_valueFROMplatform_metricWHEREts>=now()-interval'30 days'GROUPBYday,metric_nameORDERBYday,metric_name;

归档前需要确认业务是否仍需要原始粒度。故障复盘常常需要秒级数据,不能因为容量压力直接全部聚合成小时级。

4.6 向量容量与索引规划

向量容量估算:

单条向量理论大小 = 维度 × 4 字节

例如 768 维:

768 × 4 = 3072 字节

1000 万条向量理论数据量:

10,000,000 × 3072 ≈ 30.72 GB

实际还要加上:

行开销 文档块正文 JSONB 元数据 HNSW 索引 WAL 备份 旧模型并存

如果向量表同时保存较长的content,实际容量可能远高于理论向量大小。因此可以考虑:

向量表只保存必要的块文本和元数据; 完整正文放在文档表或对象存储; 查询阶段通过 document_id 回表; 模型升级期间使用独立向量表。

4.7 压测模型

压测要同时模拟写入和查询:

写入负载: - 每秒新增文档 - 每秒新增向量 - 文档更新比例 - 删除比例 查询负载: - 关键词查询 - 向量 Top-K - 带 JSONB 过滤 - 关系与向量联合查询 - 时序窗口查询 维护负载: - VACUUM - 索引构建 - 备份 - WAL 归档

真实联合查询:

WITHeligible_docsAS(SELECTd.document_id,d.title,d.metadataFROMknowledge_document dWHEREd.tenant_id='tenant_a'ANDd.status='published'ANDd.metadata @>'{"domain":"database"}'),vector_candidatesAS(SELECTc.document_id,c.chunk_id,1-(c.embedding<=>$1::vector)ASsemantic_scoreFROMknowledge_chunk cJOINeligible_docs dONd.document_id=c.document_idWHEREc.tenant_id='tenant_a'ANDc.status='active'ORDERBYc.embedding<=>$1::vectorLIMIT100)SELECTv.chunk_id,v.document_id,d.title,d.metadata,v.semantic_scoreFROMvector_candidates vJOINeligible_docs dONd.document_id=v.document_idORDERBYv.semantic_scoreDESCLIMIT10;

关联时间序列指标:

SELECTts,metric_name,valueFROMplatform_metricWHEREtenant_id='tenant_a'ANDentity_id=$1ANDts>=now()-interval'15 minutes'ORDERBYts,metric_name;

4.8 容量监控 SQL

数据库和索引空间:

SELECTrelname,pg_size_pretty(pg_total_relation_size(relid))AStotal_size,pg_size_pretty(pg_relation_size(relid))AStable_size,pg_size_pretty(pg_indexes_size(relid))ASindex_sizeFROMpg_catalog.pg_statio_user_tablesORDERBYpg_total_relation_size(relid)DESC;

表增长趋势:

CREATETABLEcapacity_metric(ts TIMESTAMPTZNOTNULL,asset_nameTEXTNOTNULL,metric_nameTEXTNOTNULL,metric_valueDOUBLEPRECISIONNOTNULL,labels JSONBNOTNULLDEFAULT'{}'::jsonb);SELECTcreate_hypertable('capacity_metric',by_range('ts'),if_not_exists=>TRUE);

查询近 30 天容量趋势:

SELECTtime_bucket('1 day',ts)ASday,asset_name,metric_name,max(metric_value)ASmax_valueFROMcapacity_metricWHEREts>=now()-interval'30 days'GROUPBYday,asset_name,metric_nameORDERBYday,asset_name;

4.9 容量告警阈值

建议设置分层阈值:

指标观察告警紧急
数据库磁盘使用率65%75%85%
WAL 保留空间10 GB30 GB60 GB
向量索引增长率基线 + 10%基线 + 25%基线 + 50%
时序写入延迟100 ms300 ms800 ms
向量查询 P95150 ms300 ms600 ms
备份窗口目标 + 10%目标 + 25%超过恢复窗口

阈值不能脱离磁盘总容量和业务增长速度。75% 使用率在小磁盘上可能很危险,在大磁盘上则可能仍有充足时间扩容。

5. 结果对比

以下为示例压测结果,模拟每日新增 2 万篇文档、平均每篇 8 个知识块、每秒 3000 条时序写入。

方案6 个月预计容量向量查询 P95备份窗口扩容复杂度
所有正文和附件放数据库14.8 TB210 ms8 小时
正文入库、附件对象存储9.6 TB175 ms5 小时
文档分层 + 时序压缩 + 向量分表6.4 TB128 ms3.2 小时
分层 + 旧模型清理 + 冷数据归档4.9 TB135 ms2.4 小时可控

示例只用于说明估算方式,不能作为具体资源采购依据。

压测需要比较以下场景:

1. 只有关系查询。 2. 只有向量 Top-K 查询。 3. 关系过滤 + 向量排序。 4. 关系过滤 + JSONB 标签 + 向量排序。 5. 向量查询后关联时序窗口。 6. 导入、备份和在线查询同时运行。

真实查询执行计划:

EXPLAIN(ANALYZE,BUFFERS)SELECTc.chunk_id,d.title,1-(c.embedding<=>$1::vector)ASsimilarityFROMknowledge_chunk cJOINknowledge_document dONd.document_id=c.document_idWHEREc.tenant_id='tenant_a'ANDc.status='active'ANDd.status='published'ANDd.metadata @>'{"domain":"database"}'ORDERBYc.embedding<=>$1::vectorLIMIT20;

结果评估不应只看平均延迟,还应观察:

P50、P95、P99; 导入期间延迟; 索引构建期间延迟; 磁盘增长; WAL 峰值; 备份窗口; 恢复耗时; Top-K 结果稳定性。

容量规划建议至少预留:

25% 至 35% 常规安全余量; 一次索引重建所需临时空间; 一次全量备份所需空间; 模型升级期间新旧向量并存空间; 故障恢复和临时导入空间。

6. 风险与复盘

6.1 常见风险

风险表现应对
只按当前数据量规划数月后空间耗尽使用增长模型和峰值模型
忽略向量索引表空间够但索引空间不足单独统计向量索引
忽略模型并存模型升级时磁盘翻倍提前计算双版本容量
时序无限保留写入稳定但空间持续增长热温冷分层和压缩
备份占用未计算备份仓库先耗尽规划保留周期和副本数
只压测查询导入和备份影响线上采用混合负载压测
JSONB 过度使用过滤性能不稳定核心字段结构化
估算不含临时空间索引重建失败预留维护余量
只看平均值长尾请求超时重点监控 P95/P99

6.2 上线检查清单

[ ] 已拆分关系、文档、时序、向量、索引和备份容量 [ ] 已记录每日新增文档、文档块和向量数量 [ ] 已计算向量维度、模型并存和索引增长 [ ] 已计算时序写入速率、保留周期和压缩比例 [ ] 已计算 WAL、备份、副本和恢复临时空间 [ ] 已完成关系、向量、时序混合负载压测 [ ] 已观察导入、备份、索引构建期间的在线延迟 [ ] 已设置磁盘、WAL、P95 和增长率告警 [ ] 已定义热温冷数据分层和归档策略 [ ] 已定义扩容、降级、清理和回滚流程 [ ] 已验证真实联合查询和权限过滤 [ ] RTO、RPO 和未来六个月资源预算已确认

6.3 复盘结论

多模场景下的容量规划,不能只把数据库容量理解成“数据行数乘以平均行大小”。真正的容量模型应包括:

业务数据; 文档正文; 向量字段; 向量索引; 关系索引; JSONB 索引; 时序热数据; 时序归档; WAL; 备份副本; 索引重建临时空间; 模型升级并存空间; 安全余量。

关系、文档、时序和向量数据的规划重点不同:

关系数据关注行数、索引和事务写放大; 文档数据关注正文大小、版本和附件分层; 时序数据关注每秒写入、时间保留和压缩; 向量数据关注维度、分块数量、模型并存和索引比例。

推荐采用以下容量规划流程:

采集当前基线 -> 建立业务增长假设 -> 分别估算四类数据和索引 -> 加入 WAL、备份和维护空间 -> 执行混合负载压测 -> 按月滚动预测 -> 设置阈值和扩容窗口 -> 通过真实查询验证体验

最终验收需要同时满足:

  1. 未来规划周期内磁盘和备份空间足够。
  2. 向量索引重建有临时空间。
  3. 时序写入和查询在高峰期不互相拖垮。
  4. 关系过滤、文档标签和向量检索可以联合执行。
  5. 容量增长趋势、查询延迟和资源消耗可以被持续观测。
  6. 扩容、归档、降级和恢复都有明确操作步骤。

容量规划的价值不在于预测一个绝对准确的数字,而在于提前看见增长路径、资源瓶颈和故障窗口,让数据库扩容从临时救火变成可验证的工程计划。


转载自:
欢迎 👍点赞✍评论⭐收藏,欢迎指正

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询