找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

251

积分

0

好友

32

主题
发表于 3 天前 | 查看: 10| 回复: 0

在大数据时代,实时数据分析已成为企业决策的关键支撑——电商需要实时监控爆款库存,运维要秒级定位系统异常,营销需实时调整投放策略。传统关系型数据库如MySQL在中小规模数据存储和简单查询中表现稳定,但面对千万级以上数据量的复杂聚合分析(如多维度统计、漏斗转化)时,常出现查询超时和性能下降问题,难以满足实时需求。

Apache Doris作为高性能MPP分析型数据库应运而生,专为实时数据分析设计,完美弥补MySQL的短板。本文将实战演示Spring Boot与Apache Doris的集成方案,展示如何替代MySQL处理高并发、大数据量的实时分析场景。

Apache Doris核心解析

Apache Doris是基于MPP架构的开源分析型数据库,起源于百度,2018年开源并捐赠给Apache基金会。它专为OLAP场景设计,定位"实时、高效、易用",支持PB级数据的低延迟查询,无需复杂分库分表或预处理即可应对多维度高并发分析。

Doris架构图

关键特性对比

  1. 极致查询性能:MPP架构实现多节点并行计算,单查询响应可达毫秒级,大数据量下比MySQL快10-100倍;
  2. 实时数据接入:支持Kafka、Flink等流处理框架实时导入,同步MySQL、Hive等数据源,延迟低至秒级;
  3. 兼容MySQL协议:无需修改业务SQL语法,支持JDBC/ODBC连接,集成成本低;
  4. 高并发支持:轻松承载每秒数千次查询,适合数据看板、自助分析平台等场景;
  5. 极简运维:支持单节点到数百节点横向扩展,自动分片和负载均衡。

场景对比矩阵

特性 MySQL Apache Doris
架构类型 单机/主从复制(OLTP优化) MPP架构(OLAP优化)
数据规模 GB级以下 PB级以上
查询类型 简单CRUD、单表查询 复杂聚合、多表关联分析
响应时间 小数据快,大数据慢 大数据量仍保持毫秒级
并发支持 高(OLTP场景) 极高(OLAP场景,数千QPS)

核心结论:MySQL适合"写多查少"的业务交易场景(如订单创建),Apache Doris专攻"读多写少"的实时分析场景(如报表生成)。

集成实战详解

环境准备

  • JDK 1.8+、Spring Boot 2.3+、Maven 3.6+
  • Apache Doris部署(Docker测试或集群部署)
  • 核心依赖:MySQL JDBC驱动(兼容Doris协议)

项目初始化

  1. 通过Spring Initializr创建项目,选择:
    • Spring Boot 2.7.x稳定版
    • 依赖:Spring Web、Spring Data JPA、MySQL Driver
  2. 项目结构:
    src/
    ├── main/
    │   ├── java/com/example/dorisdemo/
    │   │   ├── controller/
    │   │   ├── entity/
    │   │   ├── repository/
    │   │   ├── service/
    │   │   └── DorisDemoApplication.java
    │   └── resources/
    │       └── application.yml
    └── pom.xml

核心配置

pom.xml依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

application.yml配置

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:9030/demo_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: none
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
        format_sql: true
    show-sql: true
logging:
  level:
    org.springframework.data.jpa: debug
    com.example.dorisdemo: info

注意:Doris默认查询端口9030,demo_db需提前创建。

数据表构建

在Doris中执行建表SQL:

CREATE DATABASE IF NOT EXISTS demo_db;
USE demo_db;
CREATE TABLE IF NOT EXISTS user_behavior (
    user_id BIGINT COMMENT '用户ID',
    product_id BIGINT COMMENT '商品ID',
    category_id INT COMMENT '商品分类ID',
    behavior_type VARCHAR(20) COMMENT '行为类型',
    create_time DATETIME COMMENT '行为时间'
) ENGINE=OLAP
DUPLICATE KEY(user_id, product_id)
PARTITION BY RANGE(create_time) (
    PARTITION p202401 VALUES LESS THAN ('2024-02-01'),
    PARTITION p202402 VALUES LESS THAN ('2024-03-01')
)
DISTRIBUTED BY HASH(user_id) BUCKETS 10
PROPERTIES (
    "storage_medium" = "HDD",
    "storage_ttl" = "30 DAY"
);

表设计采用分区和分桶优化查询性能。

代码实现

实体类定义

@Entity
@Table(name = "user_behavior")
@Data
@DynamicInsert
@DynamicUpdate
public class UserBehavior {
    @Id
    @Column(name = "user_id")
    private Long userId;
    private Long productId;
    private Integer categoryId;
    private String behaviorType;
    private LocalDateTime createTime;
}

数据访问层

@Repository
public interface UserBehaviorRepository extends JpaRepository<UserBehavior, Long> {
    List<UserBehavior> findByCreateTimeBetween(LocalDateTime start, LocalDateTime end);

    @Query(value = "SELECT COUNT(*) FROM user_behavior WHERE category_id = :categoryId AND behavior_type = 'click' AND create_time BETWEEN :start AND :end", nativeQuery = true)
    Long countClickByCategoryId(@Param("categoryId") Integer categoryId, 
                               @Param("start") LocalDateTime start, 
                               @Param("end") LocalDateTime end);
}

业务逻辑层

@Service
@RequiredArgsConstructor
public class UserBehaviorService {
    private final UserBehaviorRepository behaviorRepository;

    public UserBehavior save(UserBehavior behavior) {
        return behaviorRepository.save(behavior);
    }

    public List<UserBehavior> batchSave(List<UserBehavior> behaviors) {
        return behaviorRepository.saveAll(behaviors);
    }

    public List<UserBehavior> getBehaviorByDateRange(LocalDateTime start, LocalDateTime end) {
        return behaviorRepository.findByCreateTimeBetween(start, end);
    }

    public Long getCategoryClickCount(Integer categoryId, LocalDateTime start, LocalDateTime end) {
        return behaviorRepository.countClickByCategoryId(categoryId, start, end);
    }
}

控制层接口

@RestController
@RequestMapping("/user-behavior")
@RequiredArgsConstructor
public class UserBehaviorController {
    private final UserBehaviorService behaviorService;

    @PostMapping
    public UserBehavior save(@RequestBody UserBehavior behavior) {
        return behaviorService.save(behavior);
    }

    @PostMapping("/batch")
    public List<UserBehavior> batchSave(@RequestBody List<UserBehavior> behaviors) {
        return behaviorService.batchSave(behaviors);
    }

    @GetMapping("/range")
    public List<UserBehavior> getByRange(
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime start,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end) {
        return behaviorService.getBehaviorByDateRange(start, end);
    }

    @GetMapping("/click-count")
    public Long getClickCount(
            @RequestParam Integer categoryId,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime start,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end) {
        return behaviorService.getCategoryClickCount(categoryId, start, end);
    }
}

测试验证

启动项目后通过Postman测试:

批量插入数据

POST /user-behavior/batch
[
    {"userId":1001,"productId":2001,"categoryId":301,"behaviorType":"click","createTime":"2024-01-15 10:30:00"},
    {"userId":1002,"productId":2002,"categoryId":301,"behaviorType":"click","createTime":"2024-01-15 11:20:00"},
    {"userId":1003,"productId":2003,"categoryId":302,"behaviorType":"purchase","createTime":"2024-01-15 14:10:00"}
]

统计分类点击量

GET /user-behavior/click-count?categoryId=301&start=2024-01-01 00:00:00&end=2024-01-31 23:59:59
性能对比测试(100万数据) 查询场景 MySQL 8.0 Apache Doris
单分类点击量统计 3.2秒 80毫秒
多维度分组(分类+日期) 5.7秒 120毫秒
日期范围查询(10万条) 1.8秒 50毫秒

总结

Spring Boot与Apache Doris的集成方案通过兼容MySQL协议实现低成本迁移,同时带来分析性能的质的飞跃。该组合让开发者无需深入分布式细节即可处理PB级实时分析,特别适合电商、金融、物流等领域的多维统计和报表场景。随着实时数据需求增长,Apache Doris将成为大数据分析技术栈的重要组成,为高并发查询提供稳定支撑。

您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-1 14:51 , Processed in 0.090224 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 CloudStack.

快速回复 返回顶部 返回列表