# 实时计算 **Repository Path**: nie_shoujun_admin/real-time-computing ## Basic Information - **Project Name**: 实时计算 - **Description**: 实时教育大数据平台 - 完整构建笔记 📋 项目概述 构建一个完整的实时教育数据分析平台,实现从数据生成、实时处理到结果存储的全流程。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-11-12 - **Last Updated**: 2025-11-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 实时教育大数据平台 - 完整构建笔记 📋 项目概述 构建一个完整的实时教育数据分析平台,实现从数据生成、实时处理到结果存储的全流程。 技术栈 数据采集: Python + Kafka 实时计算: Apache Flink 数据存储: MySQL 容器化: Docker + Docker Compose 🏗️ 环境搭建 1. Docker 环境准备 Windows Docker 安装 bash # 下载 Docker Desktop for Windows # 配置国内镜像源 { "registry-mirrors": [ "https://registry.docker-cn.com", "https://mirror.baidubce.com" ], "dns": ["8.8.8.8", "114.114.114.114"] } 验证安装 bash docker --version docker-compose --version docker run hello-world 2. 项目目录结构 text realtime-edu-demo/ ├── docker-compose.yml ├── data-generator/ │ └── data_generator.py ├── init-sql/ │ └── init.sql ├── flink-job/ │ ├── pom.xml │ ├── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── edu/ │ │ └── realtime/ │ │ ├── RealTimeAnalysisJob.java │ │ ├── CourseStatisticsAggregate.java │ │ ├── model/ │ │ │ ├── StudentAnswer.java │ │ │ └── CourseRanking.java │ │ └── util/ │ │ └── JsonParser.java │ └── Dockerfile └── jobs/ └── realtime-edu-job-1.0-SNAPSHOT.jar 🐳 Docker Compose 配置 docker-compose.yml yaml services: zookeeper: image: wurstmeister/zookeeper:latest ports: ["2181:2181"] networks: ["edu-network"] kafka: image: wurstmeister/kafka:latest ports: ["9092:9092"] environment: KAFKA_ADVERTISED_HOST_NAME: kafka KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_CREATE_TOPICS: "student_answers:4:1" depends_on: ["zookeeper"] networks: ["edu-network"] mysql: image: mysql:8.0 ports: ["4000:3306"] environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_DATABASE: "edu_platform" networks: ["edu-network"] jobmanager: image: apache/flink:1.17.1-scala_2.12-java11 ports: ["8081:8081"] environment: FLINK_PROPERTIES: | jobmanager.rpc.address: jobmanager rest.address: 0.0.0.0 rest.port: 8081 command: jobmanager volumes: ["./jobs:/opt/flink/jobs"] networks: ["edu-network"] taskmanager1: image: apache/flink:1.17.1-scala_2.12-java11 environment: FLINK_PROPERTIES: | jobmanager.rpc.address: jobmanager taskmanager.numberOfTaskSlots: 2 command: taskmanager depends_on: ["jobmanager"] volumes: ["./jobs:/opt/flink/jobs"] networks: ["edu-network"] data-generator: image: python:3.11-slim volumes: ["./data-generator:/app"] working_dir: /app command: > bash -c " apt-get update && apt-get install -y netcat-openbsd && while ! nc -z kafka 9092; do sleep 5; done && pip install kafka-python && python data_generator.py " depends_on: ["kafka"] networks: ["edu-network"] db-init: image: mysql:8.0 volumes: ["./init-sql:/docker-entrypoint-initdb.d"] environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" command: > bash -c " counter=0 max_retries=30 while [ $$counter -lt $$max_retries ]; do if mysql -h mysql -P 3306 -u root -e 'SELECT 1' 2>/dev/null; then mysql -h mysql -P 3306 -u root < /docker-entrypoint-initdb.d/init.sql echo '✅ 数据库初始化完成!' tail -f /dev/null exit 0 else counter=$$((counter + 1)) sleep 5 fi done echo '❌ 等待MySQL服务超时' tail -f /dev/null " depends_on: ["mysql"] networks: ["edu-network"] networks: edu-network: driver: bridge 📊 数据生成器 data-generator/data_generator.py python from kafka import KafkaProducer import json import time import random from datetime import datetime def generate_answer_event(): student_id = random.randint(1, 4) course_id = random.randint(1, 3) question_id = random.randint(1, 1000) is_correct = random.random() > 0.3 return { 'student_id': student_id, 'course_id': course_id, 'question_id': question_id, 'is_correct': is_correct, 'answer_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'timestamp': int(time.time() * 1000) } def main(): producer = KafkaProducer( bootstrap_servers=['kafka:9092'], value_serializer=lambda v: json.dumps(v).encode('utf-8'), retries=5 ) print("开始生成模拟学生答题数据...") try: while True: event = generate_answer_event() producer.send('student_answers', value=event) print(f"发送事件: {event}") time.sleep(random.uniform(0.1, 2)) except Exception as e: print(f"发生错误: {e}") finally: producer.close() if __name__ == "__main__": main() 🗄️ 数据库初始化 init-sql/init.sql sql CREATE DATABASE IF NOT EXISTS edu_platform; USE edu_platform; CREATE TABLE IF NOT EXISTS dim_students ( student_id INT PRIMARY KEY, student_name VARCHAR(100), class_id INT, grade VARCHAR(50), created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS dim_courses ( course_id INT PRIMARY KEY, course_name VARCHAR(100), teacher_name VARCHAR(100), created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS course_ranking ( window_end TIMESTAMP, course_id INT, course_name VARCHAR(100), total_answers BIGINT, correct_answers BIGINT, accuracy_rate DECIMAL(5,2), PRIMARY KEY (window_end, course_id) ); INSERT IGNORE INTO dim_students VALUES (1, '张三', 101, '高三(1)班'), (2, '李四', 101, '高三(1)班'), (3, '王五', 102, '高三(2)班'), (4, '赵六', 102, '高三(2)班'); INSERT IGNORE INTO dim_courses VALUES (1, '数学', '张老师'), (2, '英语', '李老师'), (3, '物理', '王老师'); ⚡ Flink 实时作业 1. Maven 配置 (pom.xml) xml org.apache.flink flink-streaming-java 1.17.1 org.apache.flink flink-connector-kafka 1.17.1 org.apache.flink flink-connector-jdbc 3.1.0-1.17 mysql mysql-connector-java 8.0.33 2. 数据模型 StudentAnswer.java java public class StudentAnswer { private int studentId; private int courseId; private int questionId; private boolean isCorrect; private String answerTime; private long timestamp; // getters/setters } CourseRanking.java java public class CourseRanking { private Timestamp windowEnd; private int courseId; private String courseName; private long totalAnswers; private long correctAnswers; private double accuracyRate; // getters/setters } 3. 核心处理逻辑 RealTimeAnalysisJob.java java public class RealTimeAnalysisJob { public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); // Kafka Source KafkaSource kafkaSource = KafkaSource.builder() .setBootstrapServers("kafka:9092") .setTopics("student_answers") .setGroupId("flink-edu-group") .setStartingOffsets(OffsetsInitializer.earliest()) .setValueOnlyDeserializer(new SimpleStringSchema()) .build(); // 数据处理流水线 env.fromSource(kafkaSource, WatermarkStrategy.noWatermarks(), "Kafka Source") .flatMap((String value, Collector out) -> { StudentAnswer answer = JsonParser.parseStudentAnswer(value); if (answer != null) out.collect(answer); }) .assignTimestampsAndWatermarks( WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(5)) .withTimestampAssigner((event, timestamp) -> event.getTimestamp()) ) .keyBy(StudentAnswer::getCourseId) .window(TumblingEventTimeWindows.of(Time.minutes(5))) .aggregate(new CourseStatisticsAggregate()) .addSink(JdbcSink.sink( "INSERT INTO course_ranking VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE ...", // JDBC 配置 )); env.execute("Real-time Education Analysis Job"); } } 🚀 部署运行 1. 启动所有服务 bash # 启动所有服务 docker-compose up -d # 检查服务状态 docker-compose ps # 查看服务日志 docker-compose logs -f data-generator 2. 构建和提交 Flink 作业 bash # 进入项目目录 cd flink-job # 构建项目 mvn clean package -DskipTests # 复制 JAR 文件 cp target/realtime-edu-job-1.0-SNAPSHOT.jar ../jobs/ # 提交作业到 Flink docker-compose exec jobmanager /opt/flink/bin/flink run -d /opt/flink/jobs/realtime-edu-job-1.0-SNAPSHOT.jar 3. 验证系统运行 bash # 检查作业状态 docker-compose exec jobmanager /opt/flink/bin/flink list # 查看 MySQL 结果 docker-compose exec mysql mysql -h 127.0.0.1 -P 3306 -u root -e "USE edu_platform; SELECT * FROM course_ranking;" # 查看实时数据流 docker-compose exec kafka kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic student_answers --from-beginning --timeout-ms 3000 🔧 故障排除 常见问题解决 Docker 镜像拉取失败 配置国内镜像源 检查网络连接 服务启动顺序问题 使用 depends_on 控制依赖 在命令中添加等待逻辑 Flink Web UI 无法访问 检查端口映射 验证服务是否正常启动 使用命令行替代管理 作业提交失败 检查 JAR 文件路径 验证卷挂载配置 手动创建目录并复制文件 有用的诊断命令 bash # 检查容器日志 docker-compose logs [service-name] # 进入容器调试 docker-compose exec [service-name] bash # 检查网络 docker network inspect realtime-edu-demo_edu-network # 查看端口映射 docker-compose port jobmanager 8081 📈 预期结果 成功运行指标 ✅ Flink 作业状态: RUNNING ✅ MySQL 数据表正常更新 ✅ 实时统计结果持续产生 ✅ 数据流水线完整运行 示例输出 text +---------------------+-----------+-------------+---------------+-----------------+---------------+ | window_end | course_id | course_name | total_answers | correct_answers | accuracy_rate | +---------------------+-----------+-------------+---------------+-----------------+---------------+ | 2025-11-12 07:25:06 | 1 | 数学 | 96 | 81 | 84.38 | | 2025-11-12 07:25:06 | 2 | 英语 | 87 | 61 | 70.11 | | 2025-11-12 07:25:06 | 3 | 物理 | 93 | 61 | 65.59 | +---------------------+-----------+-------------+---------------+-----------------+---------------+ 🎯 项目总结 技术成就 完整大数据流水线: 数据生成 → 消息队列 → 实时处理 → 结果存储 容器化部署: 使用 Docker 实现环境隔离和快速部署 实时计算: 基于 Flink 的窗口聚合和流式处理 生产就绪: 包含错误处理、重试机制、监控验证 业务价值 实时监控课堂互动情况 分析课程学习效果 为教学改进提供数据支持 构建了可扩展的数据分析基础平台 这个项目成功演示了从零开始构建实时大数据平台的完整流程,涵盖了现代数据工程的核心技术和最佳实践。