尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
数据处理和存储系统建设方案:从采集到查询的完整链路设计
简介这份《10数据处理和存储系统建设方案》面向智能化管控平台的项目规划人员、系统架构师及信息化建设从业者围绕用户规模测算、数据计算、存储容量与传输带宽四大维度给出可落地的资源估算与设备选型思路。方案以TPC-C基准推算数据库服务器峰值处理能力结合300个用户、50家化工企业等参数估算出约396核CPU需求与3台虚拟化服务器配置存储部分按系统数据年增500M、业务数据年约2.7TB计算规划三年8.1TB容量传输部分则覆盖用户访问、物联网感知与高清视频监控的带宽预留。资源包为1个doc文档约183KB内容涵盖信息量分析与预测、软硬件选型等完整章节结构清晰便于直接引用或二次修改。目前已有223人学习适合需要撰写同类建设方案、做容量规划或学习TPC-C测算方法的读者参考借鉴。1. 数据处理和存储系统建设方案从一堆散落日志到能查能算的底座很多团队第一次认真对待「数据处理和存储系统建设方案」都不是主动规划而是被现实逼的。业务跑了半年日志散在三台机器上报表靠人肉导出 Excel某天老板要一个「上个月每天的下单趋势」三个人翻了一下午还没对齐口径。这时候才意识到问题不是缺一个数据库而是缺一套从采集、清洗、存储到查询的完整链路。这个标题讲的不是买几台服务器、装个 MySQL 就完事而是把「数据怎么进来、放在哪、怎么被查、怎么不丢」这四件事一次性设计清楚。它适合两类人一类是中小团队里被临时指派搭数据底座的工程师另一类是已有系统但数据越攒越乱、想重构存储层的负责人。下面我按自己实际搭过的一套方案把选型理由、落地步骤和踩过的坑讲透你照着能复现一个最小可用版本。2. 先定分层再选组件数据处理和存储系统建设方案的骨架怎么搭动手写代码之前最该花时间的是把分层想清楚。我见过太多方案一上来就纠结「用 ClickHouse 还是 Doris」结果数据流都没理顺选什么都是错的。数据处理和存储系统建设方案的核心矛盾只有一个写入要快、查询要灵活、成本要可控这三者天然打架分层就是用来化解这个矛盾的。2.1 四层结构采集层、缓冲层、存储层、服务层各管什么我一般把整套系统拆成四层每层职责单一出问题好定位。采集层负责把数据从业务系统、日志文件、第三方接口里捞出来只做格式统一不做复杂计算。缓冲层通常是一个消息队列作用是削峰和解耦——业务高峰期写入量可能是平时的十倍没有缓冲层存储层会被直接打挂。存储层是重点要按数据的「冷热」和「查询模式」再分明细数据、聚合数据、归档数据放不同地方。服务层对外提供查询接口屏蔽底层存储的差异。这四层不是必须全上。小团队初期可以砍掉缓冲层采集直接写存储但要在采集端做限流。等写入量上来再加队列改动量不大。关键是分层的思想要在别把所有逻辑塞进一个脚本里。2.2 存储选型关系库、列式库、对象存储各自守哪块阵地选型不看热度看查询模式。下面这张表是我实际对比后总结的判断依据不是绝对标准但能帮你快速定位。存储类型典型组件适合的数据不适合的场景关系型PostgreSQL / MySQL维度表、配置、需要事务的小表单表上亿行的明细扫描列式ClickHouse / Doris宽表明细、聚合分析、日志高频单行更新、事务对象存储MinIO / S3 兼容原始文件、冷数据归档低延迟点查键值Redis缓存、去重、计数持久化主存储我的常见组合是PostgreSQL 存维度和元数据ClickHouse 存明细和聚合MinIO 存原始归档文件Redis 做查询缓存。这套组合覆盖了绝大多数中小规模场景成本也可控。2.3 用 Docker Compose 把最小可用底座跑起来光说架构没用先跑起来。下面这个 compose 文件是我常用的最小组合包含 PostgreSQL、ClickHouse、Redis 和 MinIO四个组件一次拉起。# docker-compose.yml version: 3.8 services: postgres: image: postgres:15 environment: POSTGRES_PASSWORD: devpass # 仅本地开发用生产必须换 POSTGRES_DB: meta ports: - 5432:5432 volumes: - pg_data:/var/lib/postgresql/data clickhouse: image: clickhouse/clickhouse-server:23.8 ports: - 8123:8123 # HTTP 接口 - 9000:9000 # 原生协议 volumes: - ch_data:/var/lib/clickhouse ulimits: nofile: soft: 262144 hard: 262144 redis: image: redis:7 ports: - 6379:6379 minio: image: minio/minio command: server /data --console-address :9001 environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin ports: - 9002:9000 - 9001:9001 volumes: - minio_data:/data volumes: pg_data: ch_data: minio_data:启动命令就一行docker compose up -d逻辑说明PostgreSQL 存元数据和维度ClickHouse 扛分析查询Redis 做缓存MinIO 存原始文件。参数上要注意 ClickHouse 的ulimits.nofile默认值在高并发写入时会报「Too many open files」这个坑后面还会细说。端口我做了区分MinIO 的 API 用 9002 避免和 ClickHouse 原生端口冲突。提示这套配置只适合本地验证和开发环境生产环境必须改密码、加资源限制、配持久化备份策略。3. 数据从业务库到分析库采集、清洗、入仓的完整链路底座跑起来只是第一步真正决定这套数据处理和存储系统建设方案能不能用是数据能不能稳定、准确地从源头流到分析库。这一章讲采集和入仓的具体做法每一步都有可复制的代码。3.1 增量采集用时间戳和自增 ID 做断点续传全量拉取只适合第一次初始化之后必须走增量。我一般用「更新时间戳 自增 ID」双字段做水位线避免同一秒内多条数据漏采。# incremental_fetch.py import psycopg2 import json from datetime import datetime def fetch_incremental(last_ts, last_id, batch1000): conn psycopg2.connect( hostlocalhost, dbnamemeta, userpostgres, passworddevpass ) cur conn.cursor() # 双字段水位线先比时间时间相同再比 id防止同秒漏数据 cur.execute( SELECT id, order_no, amount, status, updated_at FROM orders WHERE (updated_at %s) OR (updated_at %s AND id %s) ORDER BY updated_at, id LIMIT %s , (last_ts, last_ts, last_id, batch)) rows cur.fetchall() cur.close() conn.close() return rows def save_watermark(rows): if not rows: return None, None last rows[-1] return last[4], last[0] # updated_at, id逻辑说明水位线存两个值updated_at和id。查询条件用OR组合保证时间戳相同但 ID 更大的记录也能被捞到。参数batch控制单次拉取量我一般设 1000 到 5000太大内存吃紧太小网络往返多。每次拉完把最后一条的水位线持久化到 Redis 或元数据库下次从这里继续。3.2 清洗规则空值、类型、去重三件事必须在入仓前做完清洗放在入仓前别指望分析库帮你兜底。ClickHouse 对类型很严格脏数据进去要么报错要么静默变默认值后者更可怕。# clean.py from decimal import Decimal, InvalidOperation def clean_row(row): _, order_no, amount, status, updated_at row # 空值处理订单号为空直接丢弃金额为空补 0 if not order_no: return None try: amount Decimal(str(amount)) if amount is not None else Decimal(0) except InvalidOperation: amount Decimal(0) # 金额解析失败按 0 处理并打日志 status (status or unknown).strip().lower() return { order_no: order_no, amount: float(amount), status: status, updated_at: updated_at.strftime(%Y-%m-%d %H:%M:%S), } def dedup(rows): seen set() out [] for r in rows: key r[order_no] if key in seen: continue seen.add(key) out.append(r) return out逻辑说明清洗做三件事——空值兜底、类型转换、去重。金额用Decimal再转float避免浮点误差累积。去重按业务主键order_no同一批次内去重跨批次去重靠存储层的主键约束。参数上status统一小写并去空格否则「PAID」和「paid」会被当成两个状态。3.3 批量写入 ClickHouse攒批、压缩、重试三个参数怎么设ClickHouse 最怕小批量高频写入每次写入都会生成一个 partpart 多了合并跟不上就报「Too many parts」。所以必须攒批。# sink_clickhouse.py import clickhouse_connect import time client clickhouse_connect.get_client( hostlocalhost, port8123, usernamedefault, password ) def ensure_table(): client.command( CREATE TABLE IF NOT EXISTS orders ( order_no String, amount Float64, status String, updated_at DateTime ) ENGINE MergeTree() ORDER BY (status, updated_at) ) def write_batch(rows, retries3): if not rows: return data [[r[order_no], r[amount], r[status], r[updated_at]] for r in rows] for i in range(retries): try: client.insert(orders, data, column_names[order_no, amount, status, updated_at]) return except Exception as e: if i retries - 1: raise time.sleep(2 ** i) # 指数退避逻辑说明ORDER BY (status, updated_at)是排序键决定了查询时能不能走索引要按最常用的过滤字段来定。写入用insert批量提交单批建议 1 万到 10 万行。重试用指数退避2 ** i依次是 1、2、4 秒避免存储层抖动时疯狂重试把它压垮。参数retries设 3 次足够再多说明底层有问题该告警了。4. 查询性能与成本存储层参数调优和冷热分离数据进来了接下来是查询。这一章讲怎么让查询快起来、成本降下来这也是数据处理和存储系统建设方案里最容易被忽视、但长期最烧钱的部分。4.1 分区键和排序键ClickHouse 查询快慢的分水岭ClickHouse 的查询性能八成取决于分区键和排序键设计。分区键用来裁剪数据范围排序键用来加速过滤。-- 按月分区按状态和时间排序 CREATE TABLE orders_v2 ( order_no String, amount Float64, status String, updated_at DateTime, dt Date DEFAULT toDate(updated_at) ) ENGINE MergeTree() PARTITION BY toYYYYMM(dt) ORDER BY (status, updated_at) TTL dt INTERVAL 90 DAY;逻辑说明PARTITION BY toYYYYMM(dt)按月分区查询带月份条件时只扫对应分区。ORDER BY (status, updated_at)让「按状态过滤 按时间排序」的查询走索引。TTL自动删除 90 天前的数据这是冷热分离的第一道闸。参数上分区粒度别太细按天分区在数据量不大时反而增加元数据开销按月是稳妥选择。4.2 冷热分离热数据留 ClickHouse冷数据沉到对象存储超过 TTL 的数据不是删掉而是先导出到 MinIO需要时再按需加载。# 导出冷数据到对象存储 clickhouse-client --query SELECT * FROM orders_v2 WHERE dt today() - 90 FORMAT Parquet /tmp/cold_orders.parquet # 上传到 MinIO mc cp /tmp/cold_orders.parquet myminio/archive/orders/$(date %Y%m).parquet逻辑说明用 Parquet 格式导出压缩率高、列式读取快后续要重新加载回 ClickHouse 也方便。文件名带年月方便按时间定位。参数上导出前先确认 TTL 还没触发删除否则数据就真没了。我一般把导出任务放在 TTL 到期前一周跑留足缓冲。4.3 查询缓存Redis 挡掉重复的聚合请求报表类查询往往重复率极高同一个看板被不同人刷新底层查询完全一样。用 Redis 挡一层能省掉大量重复计算。# cache.py import redis, hashlib, json r redis.Redis(hostlocalhost, port6379, decode_responsesTrue) def cached_query(sql, ttl300): key q: hashlib.md5(sql.encode()).hexdigest() hit r.get(key) if hit: return json.loads(hit) result run_query(sql) # 实际查 ClickHouse r.setex(key, ttl, json.dumps(result)) return result逻辑说明缓存键用 SQL 的 MD5简单可靠。ttl设 300 秒报表场景够用太长会导致数据不新鲜。参数上要注意带实时性要求的查询别走缓存比如「当前在线人数」这种缓存了反而误导。缓存失效策略我用的是过期即失效没做主动清除简单够用。5. 避坑指南数据处理和存储系统建设方案里最容易翻车的五件事这套系统我前后搭过几次每次都会踩到相似的坑。下面五条是按「现象 → 原因 → 解决」整理的都是血泪经验。第一件ClickHouse 报「Too many parts」。现象是写入突然变慢甚至失败日志里全是 part 合并跟不上的告警。原因是小批量高频写入每次 insert 生成一个 part后台合并速度赶不上生成速度。解决是攒批单批至少 1 万行或者用 Buffer 表做缓冲。我一般直接在采集端攒够 5 万行再写简单有效。第二件增量采集漏数据。现象是报表数字对不上排查发现某些记录从没进过分析库。原因是只用时间戳做水位线同一秒内多条记录只取到了第一条。解决是加自增 ID 做双字段水位线查询条件用OR组合前面代码里已经体现。第三件时区导致数据错位。现象是「今天」的数据查出来少几个小时。原因是业务库用本地时间ClickHouse 默认 UTC两边没对齐。解决是入仓前统一转成 UTC 存储查询时再按需转换或者建表时显式指定时区。这个坑很隐蔽往往上线几天后才被发现。第四件MinIO 归档文件找不回来。现象是冷数据要恢复时发现文件名冲突被覆盖。原因是文件名只用了月份同月多次导出互相覆盖。解决是文件名加时间戳或批次号并且上传前先校验对象是否已存在。后悔药是没有的覆盖了就真没了。第五件Redis 缓存雪崩。现象是缓存集中过期那一刻ClickHouse 查询量暴涨响应变慢。原因是所有缓存 TTL 设了同一个值同一时间集体失效。解决是 TTL 加随机抖动比如300 random(0, 60)把失效时间打散。这个改动一行代码效果立竿见影。6. 让这套方案长期可维护监控指标和一次真实调优系统搭起来只是开始能不能长期稳定取决于你有没有盯住几个关键指标。我一般只监控四个数ClickHouse 的 part 数量、写入延迟、查询 P99 耗时、MinIO 存储增长速率。part 数量持续上涨说明合并跟不上写入延迟突增说明采集端或网络有问题查询 P99 变差通常是排序键设计不合理存储增长过快则要检查 TTL 是不是没生效。-- 查 part 数量和磁盘占用建议做成定时任务 SELECT table, count() AS parts, formatReadableSize(sum(bytes_on_disk)) AS size FROM system.parts WHERE active GROUP BY table ORDER BY parts DESC;逻辑说明system.parts是 ClickHouse 的系统表active过滤掉已合并的旧 part。parts超过 300 就该警惕超过 1000 基本要出问题。size帮你判断存储增长是否正常。这个查询本身很轻每分钟跑一次没负担。说一个我实际调优的例子。有段时间报表查询 P99 从 800 毫秒涨到 6 秒排查发现是排序键设成了(updated_at, status)而实际查询几乎都是先按status过滤再按时间排序导致索引用不上全表扫描。把排序键改成(status, updated_at)后P99 回到 700 毫秒以内。这个改动只动了一行建表语句但需要重建表并重灌数据所以排序键一定要在初期就想清楚后期改代价不小。我的习惯是任何存储表上线前先拿真实查询语句跑一遍EXPLAIN确认走了索引再放行。这个动作花不了几分钟但能挡掉大部分性能问题。数据处理和存储系统建设方案的价值不在于组件多新而在于每个环节都有据可查、有数可依。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

MATLAB实现SMOTE:不平衡数据过采样与插值合成详解

MATLAB实现SMOTE:不平衡数据过采样与插值合成详解

简介:面向机器学习与数据挖掘场景的SMOTE算法MATLAB实现,用于解决分类任务中因少数类样本不足导致模型偏向多数类的问题,适合正在研究不平衡数据分类、需要快速上手MATLAB实现的开发者。压缩包体积仅3KB,包含5个文件,核…

📅 2026/10/17 16:30:02
手写Transformer核心模块:从Attention到Encoder的PyTorch实战

手写Transformer核心模块:从Attention到Encoder的PyTorch实战

简介:这是一份面向深度学习初学者与进阶研究者的Transformer系统性教学PPT,聚焦NLP与CV两大核心领域的模型演进与工程实践。资源以95页高质量幻灯片形式,完整覆盖Transformer原始架构(输入/编码器/解码器/输出模块)、位…

📅 2026/10/17 16:30:02
【Bug已解决】Pytorch CUDA error: no kernel image is available for execution on the device on RTX… 解决方案

【Bug已解决】Pytorch CUDA error: no kernel image is available for execution on the device on RTX… 解决方案

【Bug已解决】Pytorch CUDA error: no kernel image is available for execution on the device on RTX 3090 with cuda 11.1 解决方案 问题描述 在使用 PyTorch 进行 GPU 训练时,特别是在使用较新的 NVIDIA GPU(如 RTX 3090、RTX 3080、A100 等 Ampere …

📅 2026/10/17 16:30:02
MORE NEWS

更多资讯

📰

CTF实战:Python实现数字水印提取与RC4解密全解析

1. 先说结论:这两道题为什么值得自己动手复现先交代一下背景。我今年备赛蓝桥杯网络安全赛的时候,把前几年的真题从头到尾过了一遍,其中“数字水印”和“RC4解密”这两道题让我印象最深。原因很简单:它们都属于“看起来高大上&…

📰

电商商品属性驱动架构:从PPT设计到可运行系统落地

简介:本资源是一份面向计算机专业本科生、电商系统开发初学者及课程设计实践者的学术型教学课件,聚焦“商品属性驱动的电子商务系统设计与优化”这一核心问题,系统阐述属性规范化、分类组织、精准搜索与个性化推荐四大设计原则及其实现路径。…

📰

蒙哥马利模乘原理与C语言实现:用移位代替除法加速RSA/ECC大整数运算

简介:《消除除法运算的蒙哥马利模乘》是一份经典算法文献,面向密码学、计算机数学方向的学生及工程开发者,尤其适合毕业设计阶段需要理解高效模乘原理的读者。蒙哥马利模乘通过引入与N互质的基数R,将模N乘法转换为无需试除的REDC运…

📰

MySQL查询结果加序号:窗口函数与用户变量的完整实践

MySQL查询结果加序号:从临时需求到窗口函数的完整实践干数据库开发的人,十有八九都遇到过这种需求:报表上要加一列序号,前端展示的时候要按顺序标上1、2、3……或者领导突然说“这个列表我要看排名”。接到这种需求时,…

📰

sqli-lab 38关之后:堆叠注入与ORDER BY注入实战拆解

从 Less-38 开始,sqli-lab 给我的感觉一下子就变了。前 37 关基本是在一条单查询里折腾:联合注入、报错、盲注、宽字节,方法没变,变的是过滤和闭合。到了 38 关,注入点后面第一次出现了分号。这个分号,让注…

📰

结构监测中频响函数漂移与时变结构分析:从异常数据到实用方法

做结构监测这些年,我遇到过不少一开始让人怀疑人生的数据。有一回在厂区设备基座上做振动测试,同样的测点、同样的设备、同样的激励方式,凌晨记录到的第一阶固有频率是6.85Hz,到了下午,同一测点居然变成了7.02Hz。一开…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬