关于一些采集数据
很多场景下,我们只需要"采集 → 处理 → 转发",中间不落盘。本文梳理了几种主流方案,帮你根据实际需求选对路子。
---
## 一、为什么"不保存本地"?
先说清楚为什么有这个需求。不是所有数据采集都需要在本地存一份:
| 场景 | 为什么不存本地 |
|------|---------------|
| **边缘设备 / IoT** | 存储空间有限,SD 卡写入寿命短 |
| **合规要求** | 敏感数据不能在本地留存,采集完即走 |
| **实时流处理** | 数据来一条处理一条,存了反而拖慢管线 |
| **中转采集** | 本地只是"管道",最终目的地是云端 / 远端数据库 |
| **容器化环境** | 容器无状态,本地存储重启即丢,不如不存 |
核心诉求就一句话:**数据从源头采集后,直接进入处理或转发流程,不在本地磁盘留下持久化文件。**
---
## 二、方案一:内存缓冲 + 直接转发
最直接的思路——数据采到内存里,攒一批就发走,全程不碰磁盘。
```
[数据源] → 内存队列(List/RingBuffer) → HTTP/SDK 上传 → 远端存储
```
### 代码示例(Python)
```python
import threading
import queue
import requests
import time
# 内存队列,不落盘
buffer = queue.Queue(maxsize=10000)
def collector():
"""采集线程:不断往内存队列里塞数据"""
while True:
data = read_from_sensor() # 你的采集逻辑
buffer.put(data)
def uploader():
"""上传线程:攒够 100 条就批量发走"""
batch = []
while True:
item = buffer.get()
batch.append(item)
if len(batch) >= 100:
requests.post("https://your-api/ingest", json=batch)
batch.clear() # 发完即清,内存不留
threading.Thread(target=collector, daemon=True).start()
threading.Thread(target=uploader, daemon=True).start()
```
### 优缺点
- ✅ 实现简单,几行代码搞定
- ✅ 数据不碰磁盘,速度快
- ⚠️ 进程崩溃 = 数据丢失(内存里的没发出去的就没了)
- ⚠️ 上游采集速度远超下游上传速度时,队列会撑满
**适合:** 采集量不大、能容忍少量丢失、快速原型验证。
---
## 三、方案二:消息队列做中转(Kafka / RabbitMQ / DMS)
把"不存本地"这件事交给消息队列来做。采集端只管往队列里 produce,消费端从队列里拿数据往最终目的地写。
```
[数据源] → Producer → [Kafka Topic] → Consumer → 远端数据库/对象存储
```
### 为什么这比方案一靠谱?
消息队列本身有持久化能力(Kafka 的 log、RabbitMQ 的 durable queue),但这个持久化发生在**队列服务端**,不在你的采集机器本地磁盘上。对采集机器来说,数据就是"发出去就不管了"。
### 代码示例(Kafka)
```python
from kafka import KafkaProducer
import json
producer = KafkaProducer(
bootstrap_servers=['kafka-broker:9092'],
value_serializer=lambda v: json.dumps(v).encode('utf-8')
)
def collect_and_forward(data):
# 采集到数据,直接丢进 Kafka,不存本地
producer.send('sensor-data-topic', data)
# Kafka 收到后,采集端的内存就可以释放了
```
消费端(可以在另一台机器上):
```python
from kafka import KafkaConsumer
import json
consumer = KafkaConsumer(
'sensor-data-topic',
bootstrap_servers=['kafka-broker:9092'],
group_id='forwarder-group'
)
for msg in consumer:
data = json.loads(msg.value)
# 写到远端数据库或对象存储
save_to_remote(data)
```
### 优缺点
- ✅ 采集端极轻,不落盘、不阻塞
- ✅ 队列服务端有持久化,崩溃恢复能力强
- ✅ 天然支持多消费者、削峰填谷
- ⚠️ 需要额外维护一套消息队列服务
- ⚠️ 极端情况队列服务端磁盘满了也会丢(但概率远低于本地方案)
**适合:** 采集规模大、需要可靠投递、有多个下游消费方。
> **华为云对应产品:** DMS(分布式消息服务)提供 Kafka 和 RabbitMQ 的托管服务,免运维,直接用。
---
## 四、方案三:流式上传到对象存储(OBS / S3)
如果最终目的地就是对象存储,可以跳过本地文件这一步,直接用流式上传(multipart upload)把数据"边采边传"。
```
[数据源] → 流式读取 → Multipart Upload → 对象存储(OBS/S3)
```
### 代码示例(华为云 OBS)
```python
from obs import ObsClient
obs_client = ObsClient(
access_key_id='your-ak',
secret_access_key='your-sk',
server='https://obs.cn-north-4.myhuaweicloud.com'
)
# 方式1:直接上传内存中的 bytes,不生成本地文件
data_bytes = collect_data_as_bytes() # 采集到的数据在内存中
obs_client.putContent('my-bucket', 'data/2026-11/sensor.json', data_bytes)
# 方式2:流式分片上传,适合大文件
# 初始化 multipart
upload_id = obs_client.initiateMultipartUpload('my-bucket', 'big-data.bin')['body']['uploadId']
part_num = 1
for chunk in stream_from_source(chunk_size=5*1024*1024): # 每次从数据源流式读 5MB
# chunk 在内存中,不写本地文件
obs_client.uploadPart('my-bucket', 'big-data.bin', upload_id, part_num, chunk)
part_num += 1
# 完成上传
obs_client.completeMultipartUpload('my-bucket', 'big-data.bin', upload_id, parts_list)
```
### 优缺点
- ✅ 数据从内存直达对象存储,本地零落盘
- ✅ 分片上传支持大文件、断点续传
- ✅ 对象存储天然高可用、容量无限
- ⚠️ 大文件分片上传时,当前分片仍在内存中(单分片建议 5MB~100MB)
- ⚠️ 需要 AK/SK 认证(建议用环境变量传入,不要硬编码)
**适合:** 最终目的地就是对象存储、采集的是文件型数据(日志、图片、音视频)。
---
## 五、方案四:Serverless 函数做采集中转
用云函数(如华为云 FunctionGraph、AWS Lambda)做采集中转:数据源直接 HTTP 调用函数,函数内部把数据写到目标存储,函数实例本身无状态、无本地持久化。
```
[数据源] → HTTP POST → [云函数] → 远端存储(数据库/OBS)
```
### 代码示例(FunctionGraph 风格)
```python
def handler(event, context):
# 从 event 中取出采集数据
data = event.get('body', '')
# 直接写入远端,函数实例不存任何本地文件
context.getLogger().info(f"收到 {len(data)} 字节数据,开始转发")
# 写到 OBS / 数据库 / 其他服务
write_to_destination(data, context)
return {
'statusCode': 200,
'body': 'forwarded'
}
```
### 优缺点
- ✅ 完全无状态,函数实例用完即毁,天然不存本地
- ✅ 弹性伸缩,采集量突增自动扩容
- ✅ 免运维,不用管服务器
- ⚠️ 有单次执行时间限制(通常几分钟)
- ⚠️ 冷启动有延迟(几十毫秒到几秒)
- ⚠️ 高频采集下,函数调用费用需要关注
**适合:** 采集是事件驱动的(HTTP 触发、定时触发)、采集量波动大、不想维护服务器。
---
## 六、方案五:流处理框架(Flink / Spark Streaming)
如果采集的数据需要**实时处理后再转发**,用流处理框架是最专业的选择。数据在流处理管线中全程在内存/算子间流转,不需要落本地盘。
```
[数据源] → Source → [算子1: 过滤] → [算子2: 聚合] → Sink → 远端
```
### 代码示例(Flink Python API 概念示意)
```python
from pyflink.datastream import StreamExecutionEnvironment
env = StreamExecutionEnvironment.get_execution_environment()
# 从 Kafka source 读数据(不存本地)
stream = env.add_source(kafka_source("sensor-topic"))
# 过滤异常值
stream = stream.filter(lambda x: x['value'] > 0)
# 按窗口聚合
stream = stream.key_by(lambda x: x['device_id']) \
.window(TumblingEventTimeWindows.of(Time.minutes(5))) \
.aggregate(SumAggregator())
# 结果直接写到远端 sink(不落本地盘)
stream.add_sink(jdbc_sink("jdbc:postgresql://remote-db/sensor_stats"))
env.execute("sensor-stream-pipeline")
```
### 优缺点
- ✅ 全程内存流转,专业流处理能力
- ✅ 支持窗口聚合、状态管理、Exactly-Once 语义
- ✅ 高吞吐、低延迟
- ⚠️ 架构复杂度高,需要部署 Flink 集群
- ⚠️ 学习曲线陡,小项目用这个杀鸡用牛刀
**适合:** 需要实时计算/聚合后再转发的场景、大规模数据流。
---
## 七、方案对比一览
| 方案 | 复杂度 | 可靠性 | 适用规模 | 本地落盘 |
|------|--------|--------|---------|---------|
| 内存缓冲 + 转发 | ⭐ | 低 | 小 | ❌ |
| 消息队列中转 | ⭐⭐ | 高 | 中~大 | ❌(队列服务端有持久化) |
| 流式上传对象存储 | ⭐⭐ | 中~高 | 中 | ❌ |
| Serverless 函数 | ⭐⭐ | 中 | 小~中(波动型) | ❌ |
| 流处理框架 | ⭐⭐⭐ | 高 | 大 | ❌ |
---
## 八、选型建议
给你几条决策路径,按顺序问自己:
1. **数据量多大?**
- 小(每天几 MB ~ 几 GB)→ 方案一(内存缓冲)或方案四(Serverless)
- 中大(每天几十 GB ~ TB)→ 方案二(消息队列)或方案三(流式上传)
2. **能容忍丢数据吗?**
- 不能丢 → 方案二(消息队列,有 ACK 和重试机制)
- 丢一点无所谓 → 方案一(内存缓冲)就够了
3. **需要实时处理/聚合吗?**
- 需要 → 方案五(流处理框架)
- 不需要,原样转发就行 → 方案二或方案三
4. **不想运维服务器?**
- 是 → 方案四(Serverless)+ 托管消息队列(如华为云 DMS)
5. **最终目的地是什么?**
- 对象存储 → 方案三最直接
- 数据库 → 方案二 + 消费端写入
- 另一个系统/API → 方案一或方案四
---
## 九、一个容易踩的坑
**"不保存本地"不等于"不保存任何地方"。**
有些同学理解成数据采集后真的不存了,那数据不就丢了吗?我们说的"不保存本地"是指:
> **采集机器的本地磁盘上不落盘**,但数据最终要到达某个持久化目的地(远端数据库、对象存储、消息队列等)。
如果你的需求是"采集后真的什么都不存"——那通常意味着你只需要**实时计算结果**(比如实时算个平均值显示一下就完了),这种情况用方案五(流处理)的算子直接输出到前端/监控大屏即可。
---
## 十、总结
| 你想要... | 推荐方案 |
|----------|---------|
| 快速搞定,小规模,能容忍少量丢失 | 内存缓冲 + HTTP 转发 |
| 可靠投递,中大规模 | 消息队列(Kafka / DMS) |
| 目的地就是对象存储 | 流式 Multipart Upload |
| 事件驱动,免运维 | Serverless 函数 |
| 需要实时计算后再转发 | 流处理框架(Flink) |
核心原则就一条:**数据从采集到最终落地点之间,全程走内存或网络,不碰本地磁盘。** 具体用哪种方案,取决于你的数据量、可靠性要求、处理需求和运维能力。
希望这篇对你有帮助,有问题欢迎留言讨论。
- 点赞
- 收藏
- 关注作者
评论(0)