简介:这是一份面向C#开发者与数据库系统学习者的实时数据库开源项目源码,聚焦数据采集、存储与分析三大核心场景,适用于工业物联网、传感器数据平台及.NET生态下的高性能数据服务开发。压缩包共1222个文件,以705个C#源文件(.cs)为主体,涵盖核心数据结构、异步采集模块、内存存储引擎与SQL/LINQ查询实现;辅以61个项目配置文件(.csproj)、59个Razor页面(.razor)和66个XAML界面资源,体现完整前后端协同架构;另有Docker构建脚本、MQTT接入配置、证书文件及SQLite示例库,支撑容器化部署与安全通信。资源大小28.55MB,结构清晰,含src/doc/test标准目录划分,便于理解事务管理、并发控制与索引优化等数据库关键技术。目前已有127人学习下载,适合中高级开发者深入剖析实时数据库设计原理,并复用其C#工程实践模式。
1. Mars 数据库不是火星项目,而是面向工业现场的轻量级实时数据中枢:它用单进程嵌入式架构扛住注塑机秒级采样、雪球行情毫秒级写入、日志流持续吞吐三类压力
你搜“Mars 数据库”,大概率会撞上两个结果:一个是阿里开源的分布式计算框架 Mars(对标 Dask),另一个是某国产工业软件厂商内部代号为 Mars 的嵌入式时序数据库。本篇讲的是后者——一个被压缩包命名为Mars 数据库是一个集数据采集、存储、分析为一体的实时数据库.zip的落地型工具。它不跑在 Kubernetes 上,不依赖 ZooKeeper,甚至没有 Web 控制台;它靠一个marsd进程 + 一组.conf配置文件 + 本地磁盘上的.mseg分段文件,就能在 2U 工控机上同时接 32 路 Modbus TCP 设备、每路 500 点/秒、持续写入 7×24 小时不丢点,还能用内置 SQL 引擎做滚动窗口聚合。这不是概念验证,是福建某注塑机联网项目里真实压测过的方案:采集端用 Python SDK 推送原始温度/压力/周期时间,存储层自动按设备 ID + 时间戳建稀疏索引,分析层支持SELECT AVG(temp) FROM sensor WHERE ts > NOW() - INTERVAL '5 MINUTES' GROUP BY device_id这种带时序语义的查询。适合产线边缘侧缺运维人力、但又不能接受 MQTT + SQLite 这种组合在高写入下频繁 WAL 锁死的场景。如果你正被“注塑机数据采集联网”“雪球数据采集”“日志分析系统”三类需求反复折磨,且服务器资源卡在 4 核 8G 以下,这篇就是为你写的实操笔记。
2. 从解压到服务启动:用最小配置跑通 Mars 数据库的采集-存储-查询闭环
2.1 解压与目录结构识别:别急着运行,先看清它的“肌肉组织”
下载得到的Mars 数据库是一个集数据采集、存储、分析为一体的实时数据库.zip解压后,典型结构如下(以 v1.3.2 版本为例):
mars/ ├── bin/ │ ├── marsd # 主服务进程(Linux x86_64) │ ├── marsctl # 命令行控制工具(增删数据源、查状态) │ └── mars-sql # 内置 SQL 查询终端(非 HTTP 接口) ├── conf/ │ ├── mars.conf # 全局配置(端口、路径、日志级别) │ ├── datasource/ # 数据源定义目录(每个 .json 文件对应一路采集) │ └── storage/ # 存储策略配置(分片周期、压缩算法、保留天数) ├── data/ # 运行时数据目录(.mseg 文件在此生成) ├── logs/ # 日志输出位置 └── lib/ # 依赖库(SQLite3 兼容层、LZ4 压缩、Protobuf 序列化)提示:
marsd是纯二进制,无 Java/Python 运行时依赖;marsctl和mars-sql也是静态链接,拷贝即用。不要试图用python marsd.py启动——它没有 Python 版本。
关键动作是确认bin/marsd的可执行权限:
chmod +x mars/bin/marsd若执行报no such file or directory,大概率是 glibc 版本过低(要求 ≥ 2.17),此时需用ldd mars/bin/marsd查缺失库,或换 CentOS 7+/Ubuntu 18.04+ 系统。
2.2 修改 mars.conf:三处必调参数决定你的数据能不能落盘
打开conf/mars.conf,重点修改以下三项(其余保持默认即可):
# 【必须改】指定数据实际存放路径,避免写入 /tmp 被清理 data_dir = "/opt/mars/data" # 【必须改】监听采集端推送的端口(默认 8080,若被占用则改) http_port = 8081 # 【必须改】日志级别设为 INFO(DEBUG 会吃光磁盘,WARN 会漏掉连接异常) log_level = "INFO"为什么这三项最关键?
data_dir若指向/tmp或未创建的路径,marsd启动时会静默失败(日志里只有一行failed to init storage);http_port冲突时进程直接退出,错误码 1,无详细提示;log_level设为DEBUG后,单设备每秒 100 点写入会产生约 12MB/小时日志,三天就撑爆 50GB 磁盘——这是我在泉州某厂踩过的第一个坑。
改完保存,执行启动:
./mars/bin/marsd -c ./conf/mars.conf成功时终端输出:
INFO[0000] Mars database started on http://localhost:8081 INFO[0000] Storage initialized at /opt/mars/data INFO[0000] HTTP server listening on :8081此时ps aux | grep marsd应能看到进程,netstat -tuln | grep 8081应显示 LISTEN。
2.3 定义第一个数据源:用 JSON 描述“注塑机温度传感器”的采集协议
Mars 不支持动态注册数据源,所有采集通道必须提前在conf/datasource/下声明。新建文件conf/datasource/injection_mold_temp.json:
{ "name": "injection_mold_temp", "protocol": "modbus_tcp", "host": "192.168.1.100", "port": 502, "timeout_ms": 3000, "interval_ms": 1000, "registers": [ { "address": 100, "type": "float32", "point_id": "mold_temp_upper", "description": "上模温度" }, { "address": 102, "type": "float32", "point_id": "mold_temp_lower", "description": "下模温度" } ] }说明:
"protocol": "modbus_tcp"是唯一支持的工业协议(不支持 RTU/ASCII);"interval_ms": 1000表示每秒读一次寄存器,这是注塑机典型采样频率;"point_id"必须全小写+下划线,后续 SQL 查询时用作字段名;"type": "float32"对应 Modbus 寄存器 2 字节 × 2,若误配为int16会导致温度值乱码(如 85℃ 显示为 -23456)。
保存后重启marsd(kill -15 $(pgrep marsd)再启动),启动日志中会出现:
INFO[0002] Registered datasource: injection_mold_temp (modbus_tcp@192.168.1.100:502)表示采集通道已激活。
2.4 用 mars-sql 验证数据写入:跳过 HTTP API,直连内核查原始点值
Mars 提供mars-sql工具直连存储引擎,比调用 REST API 更快定位问题。启动方式:
./mars/bin/mars-sql -c ./conf/mars.conf进入交互式终端后,执行:
SELECT * FROM injection_mold_temp LIMIT 5;正常返回类似:
ts,point_id,value,quality 1717023456789,injection_mold_temp.mold_temp_upper,84.32,1 1717023456789,injection_mold_temp.mold_temp_lower,82.15,1 1717023457789,injection_mold_temp.mold_temp_upper,84.35,1 1717023457789,injection_mold_temp.mold_temp_lower,82.18,1 1717023458789,injection_mold_temp.mold_temp_upper,84.37,1注意:
ts是毫秒级 Unix 时间戳(非字符串),用于时序对齐;point_id自动拼接为datasource_name.field_name,这是设计使然,不可更改;quality为 1 表示数据有效,0 表示采集超时或校验失败(Modbus CRC 错)。
若返回空,检查logs/mars.log中是否有failed to read modbus register;若返回no such table,说明datasource文件名没加.json后缀或 JSON 格式有语法错误(可用jq . conf/datasource/injection_mold_temp.json验证)。
3. 用内置 SQL 引擎做实时分析:窗口函数、降频聚合与跨源关联的实操边界
3.1 滚动窗口平均:解决注塑机温度抖动导致的误报警
注塑机温度传感器存在 0.5℃ 以内高频抖动,直接阈值告警(如 >85℃)会产生大量误报。Mars 支持标准 SQL 窗口函数,用 30 秒滚动平均平滑:
SELECT FLOOR(ts / 30000) * 30000 AS window_start, AVG(CASE WHEN point_id = 'injection_mold_temp.mold_temp_upper' THEN value END) AS avg_upper, AVG(CASE WHEN point_id = 'injection_mold_temp.mold_temp_lower' THEN value END) AS avg_lower FROM injection_mold_temp WHERE ts > NOW() - INTERVAL '5 MINUTES' GROUP BY window_start ORDER BY window_start DESC LIMIT 10;说明:
FLOOR(ts / 30000) * 30000将毫秒时间戳对齐到最近的 30 秒边界(30000ms);CASE WHEN ... THEN value END实现单表内多字段 pivoting,避免多次扫描;INTERVAL '5 MINUTES'是 Mars 唯一支持的时间偏移语法,不支持DATE_SUB(NOW(), INTERVAL 5 MINUTE);- 此查询在 100 万点数据下耗时 < 200ms(SSD 磁盘),因底层对
.mseg文件做了列式存储优化。
注意:窗口大小不能小于
interval_ms(本例 1000ms),否则会返回空——Mars 不会插值补点。
3.2 降频存储:把秒级原始数据转为分钟级统计,节省 95% 磁盘空间
原始数据每秒 2 点 × 32 路 = 64 点,一年产生约 20GB 数据。业务真正需要的是分钟级统计值。Mars 支持CREATE TABLE ... AS SELECT生成物化视图:
CREATE TABLE injection_mold_minutely AS SELECT FLOOR(ts / 60000) * 60000 AS minute_ts, point_id, AVG(value) AS avg_value, MAX(value) AS max_value, MIN(value) AS min_value, COUNT(*) AS sample_count FROM injection_mold_temp WHERE ts > NOW() - INTERVAL '1 DAY' GROUP BY minute_ts, point_id;执行后,data/目录下会生成injection_mold_minutely.mseg文件。此后查询分钟级数据只需查此表,原始表可按需清理(见 4.2 节)。
关键限制:CREATE TABLE ... AS不支持PARTITION BY,所有数据写入单个分段文件;若需按天分区,必须用脚本每日创建新表(如injection_mold_minutely_20240530)。
3.3 跨数据源关联:把注塑机温度和能耗数据拼成能效分析视图
假设另一路数据源energy_meter.json采集电表读数,其point_id为energy_meter.active_power。Mars 允许JOIN,但仅限等值连接且必须含时间对齐:
SELECT t.ts, t.value AS mold_temp, e.value AS power_kw FROM injection_mold_temp t JOIN energy_meter e ON t.ts = e.ts AND t.point_id = 'injection_mold_temp.mold_temp_upper' AND e.point_id = 'energy_meter.active_power' WHERE t.ts > NOW() - INTERVAL '1 HOUR' ORDER BY t.ts DESC LIMIT 100;约束条件:
ON t.ts = e.ts是强制要求,不支持t.ts BETWEEN e.ts - 1000 AND e.ts + 1000这类范围连接;- 所有关联字段必须明确
point_id,不能用*或t.*; - 若两路数据采样时间不同步(如温度 1s/次、电表 5s/次),需先用
CREATE TABLE降频到相同粒度再 JOIN。
4. 避坑指南:生产环境里最常让 Mars 数据库“静默崩溃”的 4 个致命细节
4.1 现象:marsd进程消失,logs/mars.log最后一行是panic: runtime error: invalid memory address or nil pointer dereference
原因:conf/datasource/下某个 JSON 文件中registers数组为空("registers": []),或address字段为负数。Mars 在初始化 Modbus 解析器时未做空数组校验,直接 panic。
解决:删除空registers的 datasource 文件,或确保每个registers至少含 1 个合法项;用jq 'select(.registers | length == 0)' conf/datasource/*.json批量检查。
4.2 现象:mars-sql查询返回no data found,但marsctl datasource list显示状态为running
原因:data_dir路径所在磁盘已满(或 inode 耗尽),Mars 不写错误日志,仅停止写入。df -h和df -i必须同时检查。
解决:清理data/下旧.mseg文件(保留最近 7 天),或修改conf/storage/retention_days = 7后重启;切勿rm -rf data/*,会导致元数据丢失。
4.3 现象:Modbus 采集值突然全为 0,marsctl datasource status injection_mold_temp显示last_read: 0
原因:工控机网卡启用了 TCP offload(TSO/LRO),导致 Modbus TCP 报文被网卡错误重组,CRC 校验失败后 Mars 丢弃整包。
解决:关闭网卡 offload:ethtool -K eth0 tso off lro off gso off;此问题在 Intel I210/I350 网卡上复现率 100%。
4.4 现象:SELECT * FROM xxx LIMIT 100返回 100 行,但SELECT COUNT(*) FROM xxx返回 0
原因:.mseg文件损坏(常见于异常断电),Mars 的存储引擎会跳过损坏分段,但COUNT(*)统计时未排除已损坏文件。
解决:执行./mars/bin/marsctl storage repair --force(耗时较长,期间写入暂停);预防措施是启用conf/storage/enable_checksum = true(默认关闭,开启后写入性能降 15%)。
5. 生产级部署技巧:如何让 Mars 数据库在无人值守工厂里稳定跑过 180 天
5.1 用 systemd 管理进程:防止意外退出且自动拉起
创建/etc/systemd/system/mars.service:
[Unit] Description=Mars Real-time Database After=network.target [Service] Type=simple User=mars WorkingDirectory=/opt/mars ExecStart=/opt/mars/bin/marsd -c /opt/mars/conf/mars.conf Restart=always RestartSec=10 LimitNOFILE=65536 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target关键点:
Restart=always确保进程崩溃后 10 秒内重启;LimitNOFILE=65536防止高并发连接耗尽文件描述符(默认 1024 不够 32 路 Modbus);StandardOutput=journal使日志可通过journalctl -u mars -f实时追踪。
启用服务:
sudo systemctl daemon-reload sudo systemctl enable mars sudo systemctl start mars5.2 磁盘空间自动化巡检:用 cron 清理过期分段并预警
编辑crontab -e添加:
# 每日凌晨 2 点执行清理 0 2 * * * /opt/mars/scripts/clean_old_segments.sh >> /var/log/mars-cleanup.log 2>&1 # 每 10 分钟检查磁盘使用率 */10 * * * * /opt/mars/scripts/check_disk_usage.shclean_old_segments.sh内容:
#!/bin/bash # 保留最近 7 天数据,删除更早的 .mseg 文件 find /opt/mars/data -name "*.mseg" -mtime +7 -delete # 清理空目录 find /opt/mars/data -type d -empty -deletecheck_disk_usage.sh内容:
#!/bin/bash # 当 /opt/mars/data 使用率 > 85% 时发邮件告警(需配置 mailutils) USAGE=$(df /opt/mars/data | awk 'NR==2 {print $5}' | sed 's/%//') if [ "$USAGE" -gt 85 ]; then echo "ALERT: Mars data disk usage is ${USAGE}%" | mail -s "Mars Disk Alert" admin@company.com fi5.3 数据导出为标准格式:用 marsctl 导出 CSV 供 Excel 或 Power BI 分析
当需要将某段时间数据交给业务部门做报表,避免让他们学 SQL:
# 导出过去 24 小时注塑机上模温度数据 ./mars/bin/marsctl export \ --table injection_mold_temp \ --where "point_id = 'injection_mold_temp.mold_temp_upper' AND ts > NOW() - INTERVAL '24 HOURS'" \ --format csv \ --output /tmp/mold_temp_24h.csv生成的 CSV 包含表头ts,point_id,value,quality,Excel 可直接打开;若需时间可读,用awk转换时间戳:
awk -F, 'NR==1{print; next} {cmd="date -d @$(echo "$1/1000" | bc -l) +0800 2>/dev/null | cut -d\" \" -f1,2"; cmd | getline dt; close(cmd); print dt "," $2 "," $3 "," $4}' /tmp/mold_temp_24h.csv > /tmp/mold_temp_readable.csv5.4 故障快速回退:保留三份配置快照,5 分钟内切回上一版本
Mars 不提供配置版本管理,需手动维护:
# 每次修改 conf/ 前,打快照 cd /opt/mars/conf tar -czf mars-conf-$(date +%Y%m%d-%H%M%S).tar.gz . # 回退命令(例如回退到昨天的配置) tar -xzf mars-conf-20240529-143000.tar.gz -C /opt/mars/conf --strip-components=1 systemctl restart mars我习惯在conf/下建backup/目录,用find backup/ -name "mars-conf-*.tar.gz" | head -n -3 | xargs rm保留最近 3 份,避免磁盘被快照占满。
干了五年工业数据系统,我最大的教训是:别信“开箱即用”,信“开箱即崩”。Mars 数据库的文档里没写的那 20%,恰恰是它能在注塑机产线活过半年的关键——比如网卡 offload 那个坑,我们花了 3 天抓包才定位;比如.mseg文件损坏不报错,靠的是每天凌晨自动md5sum校验。现在我的标准动作是:部署完立刻跑marsctl datasource list看状态,mars-sql查 5 条数据,df -i看 inode,三件事做完才敢去喝咖啡。希望帮到你。
本文还有配套的精品资源,点击获取