DAG账本项目学习总结(十):项目启动与 Docker 部署流程解析
1. 上期回顾
在第九期中,我们分析了并发实验结果和性能指标设计。
可以简单概括为:
register-results.csv:记录设备注册结果
telemetry-results.csv:记录遥测上报结果
success:表示请求是否成功
duration_ms:表示单次请求耗时
terminal_id:表示请求被分配到哪个融合终端
前几期我们已经从源码层面理解了设备注册、遥测上报、DAG 账本、云端广播、MySQL 持久化、Redis 缓存和并发实验。
这一期回到最基础但也很重要的问题:如何把这个项目真正跑起来?
2. 本期学习目标
本期重点解决四个问题:
1. 项目启动前需要哪些环境?
2. MySQL 和 Redis 如何准备?
3. Spring Boot 服务如何启动?
4. 如何从零跑通一次设备注册和遥测上报?
需要说明的是,我在仓库中没有看到现成的 docker-compose.yml。所以这里采用一种更适合学习的方式:
MySQL 和 Redis 用 Docker 启动;
Spring Boot 项目用 Maven 在本地启动。
这样既能利用 Docker 快速准备依赖服务,又方便在本地调试 Java 代码。
3. 项目运行需要哪些环境
根据 README,项目技术栈包括:
Java 11
Maven
Spring Boot 2.7
Spring Web
Spring Data JPA
MySQL 8
Spring Data Redis
项目本身是一个 Spring Boot 后端,MySQL 用来保存账本交易和设备会话,Redis 用来缓存高频查询接口。
所以启动前至少需要:
1. JDK 11
2. Maven
3. MySQL 8
4. Redis
5. 项目源码
如果本机没有安装 MySQL 和 Redis,可以直接用 Docker 启动它们。
4. 项目配置文件 application.yml
项目默认配置在:
src/main/resources/application.yml
其中 MySQL 默认连接为:
spring:
datasource:
url: ${MYSQL_URL:jdbc:mysql://localhost:3306/dag_docker_sim?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8}
username: ${MYSQL_USERNAME:root}
password: ${MYSQL_PASSWORD:1}
Redis 默认连接为:
spring:
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:}
服务端口默认是:
server:
port: ${SERVER_PORT:8080}
也就是说,如果不设置环境变量,项目默认会连接:
MySQL:localhost:3306
数据库:dag_docker_sim
用户名:root
密码:1
Redis:localhost:6379
Spring Boot:localhost:8080
这些配置都可以通过环境变量覆盖。
5. 用 Docker 启动 MySQL
如果本机没有 MySQL,可以使用 Docker 启动一个 MySQL 8 容器。
PowerShell 命令如下:
docker run -d `
--name dag-mysql `
-e MYSQL_ROOT_PASSWORD=1 `
-e MYSQL_DATABASE=dag_docker_sim `
-p 3306:3306 `
mysql:8 `
--character-set-server=utf8mb4 `
--collation-server=utf8mb4_unicode_ci
这个命令做了几件事:
创建一个名为 dag-mysql 的容器;
root 密码设置为 1;
自动创建 dag_docker_sim 数据库;
把容器 3306 端口映射到本机 3306;
设置字符集为 utf8mb4。
启动后可以查看容器状态:
docker ps
如果看到 dag-mysql 正在运行,说明 MySQL 已经启动。
6. 手动创建数据库
如果 MySQL 已经存在,但没有创建数据库,可以执行仓库中的 SQL 文件:
CREATE DATABASE IF NOT EXISTS dag_docker_sim
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
这个 SQL 文件位于:
sql/init-database.sql
它的作用就是创建 dag_docker_sim 数据库,并设置字符集和排序规则。
如果使用命令行进入 MySQL,可以这样执行:
docker exec -it dag-mysql mysql -uroot -p1
进入后执行:
CREATE DATABASE IF NOT EXISTS dag_docker_sim
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
如果前面 docker run 时已经用了 MYSQL_DATABASE=dag_docker_sim,这一步通常可以省略。
7. 用 Docker 启动 Redis
Redis 启动更简单:
docker run -d `
--name dag-redis `
-p 6379:6379 `
redis:7-alpine
查看容器状态:
docker ps
如果看到 dag-redis 正在运行,说明 Redis 已经启动。
可以进入 Redis 测试:
docker exec -it dag-redis redis-cli ping
如果返回:
PONG
说明 Redis 正常。
8. 设置环境变量
如果 MySQL 和 Redis 都使用默认配置,其实可以不设置环境变量。
但为了启动过程更清晰,可以在 PowerShell 中手动设置:
$env:MYSQL_URL="jdbc:mysql://localhost:3306/dag_docker_sim?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8"
$env:MYSQL_USERNAME="root"
$env:MYSQL_PASSWORD="1"
$env:REDIS_HOST="localhost"
$env:REDIS_PORT="6379"
$env:REDIS_PASSWORD=""
$env:SERVER_PORT="8080"
这些变量会覆盖 application.yml 中的默认值。README 中也给出了类似的环境变量配置方式。
9. 编译项目
项目使用 Maven 构建。pom.xml 中可以看到,项目依赖了:
spring-boot-starter-web
spring-boot-starter-data-jpa
spring-boot-starter-data-redis
spring-boot-starter-validation
mysql-connector-j
并且 Java 版本为 11,Spring Boot 版本为 2.7.18。
编译命令为:
mvn -s maven-settings.xml -q -DskipTests compile
如果没有使用自定义 Maven settings,也可以尝试:
mvn -q -DskipTests compile
编译成功说明依赖基本正常。
10. 启动 Spring Boot 服务
启动命令为:
mvn -s maven-settings.xml spring-boot:run
README 中也给出了这个启动方式。
启动成功后,默认访问地址是:
http://localhost:8080/api/health
可以用浏览器打开,也可以用命令行测试:
curl.exe http://localhost:8080/api/health
如果返回正常 JSON,说明服务启动成功。
11. 启动后的系统状态
服务启动时,系统会初始化这些角色:
cloud
fusion1
fusion2
fusion3
也就是:
1 个云端节点;
3 个融合终端。
可以访问:
curl.exe http://localhost:8080/api/topology
这个接口可以查看当前系统拓扑。
也可以访问:
curl.exe http://localhost:8080/api/fusions
查看所有融合终端状态。
12. 查看云端账本
启动后可以查看 cloud 账本:
curl.exe http://localhost:8080/api/cloud/ledger
也可以查看某个融合终端账本:
curl.exe http://localhost:8080/api/fusions/fusion1/ledger
如果是第一次启动,账本里通常只有初始 genesis 相关交易。
这一步的意义是确认:
Spring Boot 服务正常;
MySQL 连接正常;
Redis 连接正常;
cloud 和 fusion 运行时对象已经初始化。
13. 注册一个设备
接下来跑通第一个核心流程:设备注册。
请求接口是:
POST /api/fusions/{terminalId}/devices/register
例如向 fusion1 注册一个设备:
curl.exe -X POST "http://localhost:8080/api/fusions/fusion1/devices/register" `
-H "Content-Type: application/json" `
-d "{\"deviceName\":\"device41\",\"useBootstrapIdentity\":false,\"autoConfirm\":true}"
请求体含义如下:
deviceName:设备名称
useBootstrapIdentity:是否使用预置身份
autoConfirm:注册后是否自动确认
README 中也给出了相同结构的注册请求示例。
如果注册成功,返回结果中会包含 deviceId。这个 deviceId 后续提交遥测数据时要用。
14. 查看设备列表
注册成功后,可以查看设备列表:
curl.exe http://localhost:8080/api/devices
如果能看到刚刚注册的设备,说明设备会话已经保存到系统中。
这一步对应前几期分析过的流程:
设备注册请求
↓
创建 DeviceSimulator
↓
生成 register 交易
↓
写入 fusion1 本地账本
↓
广播到 cloud 和其他 fusion
↓
保存 device session
↓
异步持久化账本快照
15. 查看 fusion1 账本变化
注册设备后,可以再次查看 fusion1 账本:
curl.exe http://localhost:8080/api/fusions/fusion1/ledger
这时应该可以看到新的 register 类型交易。
也可以查看 cloud 账本:
curl.exe http://localhost:8080/api/cloud/ledger
如果广播正常,cloud 账本中也应该包含这笔注册交易。
这一步可以验证:
本地融合终端写账本成功;
交易广播到 cloud 成功;
账本查询接口正常;
Redis 缓存失效和重新查询正常。
16. 提交遥测数据
设备注册成功后,可以提交遥测数据。
接口是:
POST /api/fusions/{terminalId}/devices/{deviceId}/telemetry
这里的 deviceId 要替换成前面注册接口返回的设备 ID。
示例:
curl.exe -X POST "http://localhost:8080/api/fusions/fusion1/devices/{deviceId}/telemetry" `
-H "Content-Type: application/json" `
-d "{\"dataPayload\":{\"sequence\":1,\"device_name\":\"device41\",\"captured_at\":1773821000.0,\"metrics\":{\"voltage_v\":228.4,\"current_a\":16.2,\"temperature_c\":33.8,\"active_power_kw\":3.701}}}"
README 中给出的遥测 payload 也包含 sequence、device_name、captured_at 和 metrics 等字段。
如果提交成功,系统会生成一笔 business 类型交易。
17. 遥测上报成功说明了什么
一条遥测数据成功提交,说明系统至少完成了这些步骤:
1. 找到了 deviceId 对应的设备会话;
2. 确认设备属于 fusion1;
3. 设备模拟器使用私钥对数据签名;
4. fusion1 使用注册交易中的设备公钥验签;
5. 确认 register 交易已经 confirmed;
6. 创建 business 交易;
7. business 交易引用 register 交易作为身份锚点;
8. business 交易写入 fusion1 DAG 账本;
9. 交易广播到 cloud 和其他 fusion;
10. 账本快照异步写入 MySQL。
所以,遥测接口能跑通,说明项目核心链路基本正常。
18. 跑完整并发场景
如果单个注册和遥测都正常,可以继续运行完整并发实验:
powershell -ExecutionPolicy Bypass -File .\tools\concurrency-lab\Full-Scenario.ps1 `
-DeviceCount 90 `
-RegisterConcurrency 20 `
-MessagesPerDevice 4 `
-TelemetryConcurrency 20
这个脚本会执行:
并发注册 90 个设备;
每个设备提交 4 条遥测数据;
注册并发度为 20;
遥测并发度为 20。
README 中也给出了这个完整场景脚本示例。
运行后结果会输出到:
tools/concurrency-lab/output/register-results.csv
tools/concurrency-lab/output/telemetry-results.csv
这两个文件就是第九期分析的实验结果来源。
19. 查看 MySQL 中的数据
项目启动后,JPA 会根据实体自动更新表结构。application.yml 中配置的是:
spring:
jpa:
hibernate:
ddl-auto: update
这表示 Hibernate 会根据实体类自动创建或更新数据库表。
可以进入 MySQL 查看表:
docker exec -it dag-mysql mysql -uroot -p1 dag_docker_sim
然后执行:
SHOW TABLES;
正常情况下可以看到类似:
ledger_transactions
device_sessions
这两个表分别保存账本交易快照和设备会话。
20. 查看 Redis 缓存
可以进入 Redis:
docker exec -it dag-redis redis-cli
查看 key:
KEYS *
访问过查询接口后,Redis 中会出现一些缓存相关 key。
不过实际学习时,不建议频繁使用 KEYS * 查询大规模 Redis。当前只是本地小项目测试,可以用来直观看缓存是否生效。
21. 常见问题一:MySQL 连接失败
如果启动 Spring Boot 时出现 MySQL 连接失败,优先检查四点:
1. dag-mysql 容器是否启动;
2. 3306 端口是否被占用;
3. MYSQL_PASSWORD 是否和 application.yml 一致;
4. dag_docker_sim 数据库是否存在。
查看容器:
docker ps
查看日志:
docker logs dag-mysql
如果容器已经存在但状态异常,可以删除后重建:
docker rm -f dag-mysql
然后重新执行 MySQL 启动命令。
22. 常见问题二:Redis 连接失败
如果 Redis 连接失败,检查:
1. dag-redis 容器是否启动;
2. 6379 端口是否被占用;
3. REDIS_HOST 是否是 localhost;
4. REDIS_PASSWORD 是否为空。
测试 Redis:
docker exec -it dag-redis redis-cli ping
如果返回 PONG,说明 Redis 本身正常。
23. 常见问题三:8080 端口被占用
如果 Spring Boot 启动失败,提示 8080 端口被占用,可以换一个端口:
$env:SERVER_PORT="8081"
mvn -s maven-settings.xml spring-boot:run
然后访问:
http://localhost:8081/api/health
项目端口支持通过 SERVER_PORT 环境变量覆盖。
24. 常见问题四:遥测提交失败
遥测提交失败时,重点看错误信息。
如果是:
device_not_registered
说明 deviceId 不存在,可能是没有成功注册,或者复制错了设备 ID。
如果是:
device_terminal_mismatch
说明设备注册在一个 fusion,却向另一个 fusion 提交了遥测数据。
例如设备注册在 fusion1,就必须提交到:
POST /api/fusions/fusion1/devices/{deviceId}/telemetry
如果提交到 fusion2,就会失败。
如果是:
device_identity_not_confirmed
说明注册交易还没有确认。测试时可以把注册请求中的:
"autoConfirm": true
打开,这样注册后可以直接提交遥测。
25. 一次完整启动流程总结
从零启动项目,可以按照这个顺序:
1. 启动 MySQL 容器
2. 启动 Redis 容器
3. 设置环境变量
4. 编译项目
5. 启动 Spring Boot
6. 访问 /api/health
7. 注册设备
8. 查看 /api/devices
9. 提交遥测数据
10. 查看 fusion 和 cloud 账本
11. 运行并发实验
12. 查看 CSV 结果
对应命令可以浓缩为:
docker run -d --name dag-mysql -e MYSQL_ROOT_PASSWORD=1 -e MYSQL_DATABASE=dag_docker_sim -p 3306:3306 mysql:8 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
docker run -d --name dag-redis -p 6379:6379 redis:7-alpine
$env:MYSQL_URL="jdbc:mysql://localhost:3306/dag_docker_sim?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8"
$env:MYSQL_USERNAME="root"
$env:MYSQL_PASSWORD="1"
$env:REDIS_HOST="localhost"
$env:REDIS_PORT="6379"
$env:REDIS_PASSWORD=""
mvn -s maven-settings.xml spring-boot:run
26. 本期小结
这一期主要分析了项目启动与 Docker 依赖部署流程。
可以总结为五点:
第一,项目运行依赖 Java 11、Maven、MySQL 8 和 Redis。
第二,当前更适合用 Docker 启动 MySQL 和 Redis,用 Maven 本地启动 Spring Boot。
第三,application.yml 中已经配置了 MySQL、Redis 和服务端口的默认值,也支持通过环境变量覆盖。
第四,单设备注册和单条遥测上报是验证项目是否启动成功的最小闭环。
第五,并发实验需要在单请求链路跑通后再执行,否则错误排查会更困难。
更多推荐




所有评论(0)