产品文档已发布
RAILWISE-OS 性能优化指南
RAILWISE-OS 系统性能优化策略,包含数据库优化、缓存策略、前端优化与监控告警
产品文档
RAILWISE-OS 性能优化指南
Section titled “RAILWISE-OS 性能优化指南”AI语义标签:
#性能优化#数据库调优#缓存策略#监控告警#PostgreSQL#Redis#前端优化
RAILWISE-OS 面向工程监测业务,需要处理大量时序监测数据、高频写入与复杂查询。本指南提供系统性能优化的最佳实践,帮助运维团队与开发者提升系统响应速度与吞吐量。
1.1 性能指标基准
Section titled “1.1 性能指标基准”| 指标 | 目标值 | 说明 |
|---|---|---|
| API 响应时间 (P95) | < 200ms | 常规查询 |
| 数据写入吞吐量 | > 1000 条/秒 | 批量写入 |
| 报告生成时间 | < 30 秒 | 100页以内报告 |
| 页面首屏加载 | < 2 秒 | Web 管理端 |
| 并发用户数 | > 500 | 单实例 |
| 数据库查询 (P95) | < 100ms | 索引查询 |
2. 数据库优化
Section titled “2. 数据库优化”2.1 PostgreSQL 配置优化
Section titled “2.1 PostgreSQL 配置优化”根据服务器内存调整 PostgreSQL 参数:
# postgresql.conf - 32GB 内存服务器示例
# 共享缓冲区(建议 25% 内存)shared_buffers = 8GB
# 有效缓存大小(建议 50-75% 内存)effective_cache_size = 24GB
# 工作内存(复杂查询)work_mem = 64MB
# 维护工作内存(VACUUM, CREATE INDEX)maintenance_work_mem = 2GB
# 自动 Vacuum 工作内存autovacuum_work_mem = 512MB连接与并发配置
Section titled “连接与并发配置”# 最大连接数max_connections = 200
# 并发维护操作max_parallel_maintenance_workers = 4max_parallel_workers_per_gather = 4max_parallel_workers = 8
# WAL 配置wal_buffers = 64MBmax_wal_size = 8GBmin_wal_size = 2GBwal_compression = on查询优化配置
Section titled “查询优化配置”# 随机页成本(SSD 建议 1.1)random_page_cost = 1.1
# 有效 IO 并发数(SSD 建议 200)effective_io_concurrency = 200
# 启用 JIT 编译(PostgreSQL 11+)jit = on
# 查询计划缓存plan_cache_mode = auto2.2 索引优化
Section titled “2.2 索引优化”监测数据表索引策略
Section titled “监测数据表索引策略”-- 监测数据表(假设已存在)-- CREATE TABLE monitoring_data (...);
-- 1. 复合索引:项目 + 监测点 + 时间(最常用查询)CREATE INDEX CONCURRENTLY idx_monitoring_project_point_time ON monitoring_data (project_id, point_id, measured_at DESC);
-- 2. 时间范围查询索引CREATE INDEX CONCURRENTLY idx_monitoring_time ON monitoring_data (measured_at DESC) WHERE measured_at > '2025-01-01';
-- 3. 状态查询索引(部分索引)CREATE INDEX CONCURRENTLY idx_monitoring_abnormal ON monitoring_data (project_id, point_id, measured_at) WHERE status IN ('warning', 'alarm');
-- 4. BRIN 索引(大块数据,时间序列)CREATE INDEX CONCURRENTLY idx_monitoring_time_brin ON monitoring_data USING BRIN (measured_at) WITH (pages_per_range = 128);
-- 5. GIN 索引(JSONB 字段查询)CREATE INDEX CONCURRENTLY idx_monitoring_values_gin ON monitoring_data USING GIN (values);-- 查看索引使用情况SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read, idx_tup_fetchFROM pg_stat_user_indexesWHERE schemaname = 'public'ORDER BY idx_scan DESC;
-- 重建低效索引REINDEX INDEX CONCURRENTLY idx_monitoring_project_point_time;
-- 分析表(更新统计信息)ANALYZE monitoring_data;2.3 分区策略
Section titled “2.3 分区策略”对于大规模监测数据,建议使用表分区:
-- 按时间范围分区(每月一个分区)CREATE TABLE monitoring_data ( id UUID DEFAULT gen_random_uuid(), project_id VARCHAR(64) NOT NULL, point_id VARCHAR(64) NOT NULL, sensor_type VARCHAR(32) NOT NULL, values JSONB NOT NULL, measured_at TIMESTAMPTZ NOT NULL, status VARCHAR(16) DEFAULT 'normal', created_at TIMESTAMPTZ DEFAULT NOW(), PRIMARY KEY (id, measured_at)) PARTITION BY RANGE (measured_at);
-- 创建分区CREATE TABLE monitoring_data_2026_01 PARTITION OF monitoring_data FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE monitoring_data_2026_02 PARTITION OF monitoring_data FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
-- 自动创建未来分区(使用 pg_partman 扩展)SELECT partman.create_parent( 'public.monitoring_data', 'measured_at', 'native', 'monthly');2.4 查询优化
Section titled “2.4 查询优化”-- 启用慢查询日志log_min_duration_statement = 1000; -- 记录超过 1 秒的查询
-- 查看当前慢查询SELECT query, calls, total_exec_time, mean_exec_time, rows, shared_blks_hit, shared_blks_readFROM pg_stat_statementsORDER BY mean_exec_time DESCLIMIT 20;查询优化示例
Section titled “查询优化示例”-- 优化前:全表扫描SELECT * FROM monitoring_dataWHERE project_id = 'proj_abc123' AND measured_at BETWEEN '2026-07-01' AND '2026-07-08';
-- 优化后:使用索引 + 限制返回字段SELECT point_id, values->>'dx' as dx, values->>'dy' as dy, values->>'dz' as dz, measured_atFROM monitoring_dataWHERE project_id = 'proj_abc123' AND measured_at BETWEEN '2026-07-01' AND '2026-07-08'ORDER BY measured_at DESCLIMIT 1000;3. 缓存策略
Section titled “3. 缓存策略”3.1 Redis 缓存架构
Section titled “3.1 Redis 缓存架构”┌─────────────────────────────────────────────────────────────┐│ 缓存分层架构 │├─────────────────────────────────────────────────────────────┤│ ││ L1: 本地缓存 (Caffeine) ││ ├── 项目基础信息(TTL: 5分钟) ││ ├── 用户权限(TTL: 10分钟) ││ └── 字典数据(TTL: 30分钟) ││ ││ L2: 分布式缓存 (Redis) ││ ├── 监测数据热点(TTL: 1小时) ││ ├── 报告生成结果(TTL: 24小时) ││ └── 会话状态(TTL: 2小时) ││ ││ L3: 数据库查询缓存 ││ └── PostgreSQL 共享缓冲区 ││ │└─────────────────────────────────────────────────────────────┘3.2 Redis 配置优化
Section titled “3.2 Redis 配置优化”# redis.conf 优化配置
# 内存配置maxmemory 4gbmaxmemory-policy allkeys-lru
# 持久化配置save 900 1save 300 10save 60 10000
# AOF 配置appendonly yesappendfsync everysecno-appendfsync-on-rewrite yesauto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb
# 连接配置tcp-keepalive 300timeout 300maxclients 10000
# 慢查询日志slowlog-log-slower-than 10000slowlog-max-len 1283.3 缓存使用模式
Section titled “3.3 缓存使用模式”// 监测数据查询缓存示例class MonitoringDataService { private localCache = new Map<string, any>(); private readonly LOCAL_TTL = 5 * 60 * 1000; // 5分钟
async getMonitoringData( projectId: string, pointId: string, startTime: string, endTime: string ) { const cacheKey = `monitoring:${projectId}:${pointId}:${startTime}:${endTime}`;
// 1. 检查本地缓存 const localData = this.localCache.get(cacheKey); if (localData && Date.now() - localData.timestamp < this.LOCAL_TTL) { return localData.data; }
// 2. 检查 Redis 缓存 const redisData = await redis.get(cacheKey); if (redisData) { const parsed = JSON.parse(redisData); this.localCache.set(cacheKey, { data: parsed, timestamp: Date.now() }); return parsed; }
// 3. 查询数据库 const data = await db.query(/* ... */);
// 4. 写入缓存 await redis.setex(cacheKey, 3600, JSON.stringify(data)); // 1小时TTL this.localCache.set(cacheKey, { data, timestamp: Date.now() });
return data; }
// 数据写入后清除缓存 async invalidateCache(projectId: string, pointId: string) { const pattern = `monitoring:${projectId}:${pointId}:*`; const keys = await redis.keys(pattern); if (keys.length > 0) { await redis.del(...keys); } // 清除本地缓存 for (const key of this.localCache.keys()) { if (key.startsWith(`monitoring:${projectId}:${pointId}`)) { this.localCache.delete(key); } } }}3.4 缓存预热
Section titled “3.4 缓存预热”// 系统启动时预热热点数据async function warmupCache() { // 1. 预热活跃项目列表 const activeProjects = await db.query(` SELECT id FROM projects WHERE status = 'active' ORDER BY updated_at DESC LIMIT 100 `);
for (const project of activeProjects) { // 缓存项目基本信息 const projectInfo = await projectService.getById(project.id); await redis.setex( `project:info:${project.id}`, 300, JSON.stringify(projectInfo) );
// 缓存最近7天监测数据摘要 const summary = await monitoringService.getRecentSummary(project.id, 7); await redis.setex( `monitoring:summary:${project.id}:7d`, 600, JSON.stringify(summary) ); }
console.log(`缓存预热完成: ${activeProjects.length} 个项目`);}4. 前端优化
Section titled “4. 前端优化”4.1 Vue3 应用优化
Section titled “4.1 Vue3 应用优化”// 路由懒加载const routes = [ { path: '/projects', component: () => import('./views/ProjectList.vue'), }, { path: '/projects/:id', component: () => import('./views/ProjectDetail.vue'), }, { path: '/data/monitoring', component: () => import('./views/MonitoringData.vue'), },];
// 组件异步加载const ChartComponent = defineAsyncComponent(() => import('./components/Chart.vue'));
// 虚拟列表(大数据量表格)import { VirtualList } from 'vue-virtual-scroller';
<template> <VirtualList :items="monitoringData" :item-height="48" :buffer="200" > <template #default="{ item }"> <DataRow :data="item" /> </template> </VirtualList></template>4.2 数据可视化优化
Section titled “4.2 数据可视化优化”// ECharts 大数据量优化const chartOption = { // 使用 dataZoom 实现数据区域缩放 dataZoom: [ { type: 'inside', start: 0, end: 10 }, { type: 'slider', start: 0, end: 10 }, ],
// 大数据量使用 sampling series: [{ type: 'line', data: largeDataSet, sampling: 'lttb', // Largest Triangle Three Buckets 算法 showSymbol: false, // 不显示数据点标记 lineStyle: { width: 1 }, }],
// 启用 progressive 渲染 progressive: 1000, progressiveThreshold: 5000,};
// 数据降采样(服务端或客户端)function lttbDownsample(data: DataPoint[], threshold: number): DataPoint[] { const sampled = []; sampled.push(data[0]);
const a = (data.length - 2) / (threshold - 2); let maxAreaPoint = null; let maxArea = -1;
for (let i = 0; i < threshold - 2; i++) { const avgRangeStart = Math.floor((i + 1) * a) + 1; const avgRangeEnd = Math.floor((i + 2) * a) + 1; const avgRange = data.slice(avgRangeStart, avgRangeEnd); const avgPoint = avgRange.reduce((sum, p) => sum + p.value, 0) / avgRange.length;
const rangeOffs = Math.floor(i * a) + 1; const rangeTo = Math.floor((i + 1) * a) + 1;
for (let j = rangeOffs; j < rangeTo; j++) { const area = Math.abs( (data[0].value - avgPoint) * (data[j].time - data[avgRangeStart].time) - (data[0].time - data[avgRangeStart].time) * (data[j].value - avgPoint) ); if (area > maxArea) { maxArea = area; maxAreaPoint = data[j]; } }
sampled.push(maxAreaPoint); }
sampled.push(data[data.length - 1]); return sampled;}4.3 网络请求优化
Section titled “4.3 网络请求优化”// 请求合并(防抖)class RequestBatcher { private pendingRequests = new Map<string, Promise<any>>();
async batchRequest<T>(key: string, fn: () => Promise<T>): Promise<T> { if (this.pendingRequests.has(key)) { return this.pendingRequests.get(key)!; }
const promise = fn().finally(() => { this.pendingRequests.delete(key); });
this.pendingRequests.set(key, promise); return promise; }}
// 使用示例const batcher = new RequestBatcher();
// 多个组件同时请求同一数据,只发送一次请求const data = await batcher.batchRequest('project:123', () => api.getProject('123'));5. 报告生成优化
Section titled “5. 报告生成优化”5.1 异步生成
Section titled “5.1 异步生成”// 报告异步生成 + 轮询class ReportGenerator { async generateReport(config: ReportConfig): Promise<string> { // 1. 提交生成任务 const job = await api.reports.submit(config);
// 2. 轮询状态 return this.pollJobStatus(job.id, { maxAttempts: 60, interval: 5000, // 5秒 }); }
private async pollJobStatus( jobId: string, options: { maxAttempts: number; interval: number } ): Promise<string> { for (let i = 0; i < options.maxAttempts; i++) { const status = await api.reports.getStatus(jobId);
if (status.status === 'completed') { return status.downloadUrl; }
if (status.status === 'failed') { throw new Error(`报告生成失败: ${status.error}`); }
await new Promise(r => setTimeout(r, options.interval)); }
throw new Error('报告生成超时'); }}5.2 模板编译缓存
Section titled “5.2 模板编译缓存”# Python 模板编译缓存from jinja2 import Environment, FileSystemLoaderimport hashlib
class CachedTemplateEngine: def __init__(self, template_dir: str): self.env = Environment( loader=FileSystemLoader(template_dir), cache_size=100, # 缓存100个编译后的模板 auto_reload=False, # 生产环境关闭自动重载 ) self._compiled_cache = {}
def get_template(self, template_name: str): # 使用模板内容哈希作为缓存键 template_source = self.env.loader.get_source(self.env, template_name) cache_key = hashlib.md5(template_source[0].encode()).hexdigest()
if cache_key not in self._compiled_cache: template = self.env.get_template(template_name) self._compiled_cache[cache_key] = template
return self._compiled_cache[cache_key]6. 监控与告警
Section titled “6. 监控与告警”6.1 性能监控指标
Section titled “6.1 性能监控指标”# 监控指标配置metrics: - name: api_response_time type: histogram labels: [endpoint, method, status] buckets: [0.01, 0.05, 0.1, 0.2, 0.5, 1, 2, 5]
- name: db_query_time type: histogram labels: [query_type, table] buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1]
- name: cache_hit_ratio type: gauge labels: [cache_layer]
- name: active_connections type: gauge labels: [service]
- name: memory_usage type: gauge labels: [service, type]6.2 告警规则
Section titled “6.2 告警规则”# 告警规则配置alerts: - name: api_latency_high condition: api_response_time_p95 > 500ms duration: 5m severity: warning labels: team: backend annotations: summary: "API 响应延迟过高" description: "{{ $labels.endpoint }} P95 延迟超过 500ms"
- name: db_slow_queries condition: rate(db_slow_query_count[5m]) > 10 duration: 5m severity: warning labels: team: dba annotations: summary: "慢查询数量增加"
- name: cache_hit_ratio_low condition: cache_hit_ratio < 0.8 duration: 10m severity: warning labels: team: backend annotations: summary: "缓存命中率过低"
- name: memory_usage_high condition: memory_usage > 0.85 duration: 5m severity: critical labels: team: ops annotations: summary: "内存使用率过高"6.3 性能诊断工具
Section titled “6.3 性能诊断工具”# PostgreSQL 性能诊断# 1. 查看当前连接SELECT * FROM pg_stat_activity WHERE state = 'active';
# 2. 查看锁等待SELECT * FROM pg_locks WHERE NOT granted;
# 3. 查看表膨胀SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size, n_live_tup, n_dead_tup, round(n_dead_tup::numeric/nullif(n_live_tup,0)*100, 2) as dead_pctFROM pg_stat_user_tablesORDER BY n_dead_tup DESC;
# 4. 查看缓存命中率SELECT sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) * 100 as cache_hit_ratioFROM pg_statio_user_tables;
# Redis 性能诊断# 1. 查看内存使用redis-cli INFO memory
# 2. 查看慢查询redis-cli SLOWLOG GET 10
# 3. 查看大 Keyredis-cli --bigkeys
# 4. 查看连接数redis-cli INFO clients7. 相关文档
Section titled “7. 相关文档”文档版本: v3.2.0 | 最后更新: 2026-07-08
