欢迎光临
我们一直在努力

外卖霸王餐系统数据库分库分表策略:ShardingSphere实战案例

外卖霸王餐系统数据库分库分表策略:ShardingSphere实战案例

随着“霸王餐”活动用户量激增,单库单表的 participation_record(参与记录)表已突破千万级,写入延迟、查询超时频发。为提升系统扩展性与性能,采用 Apache ShardingSphere-JDBC 实现透明化分库分表。本文基于真实业务场景,展示按用户ID哈希分库、按活动ID范围分表的混合策略配置与代码实现。

业务场景与分片规则设计

  • 数据规模:每日新增 50 万+ 参与记录;
  • 查询模式:
    • 用户维度:查某用户所有参与记录(高频);
    • 活动维度:查某活动下所有参与者(运营后台);
  • 分片策略:
    • 分库:4 个库(ds0 ~ ds3),按 user_id % 4 路由;
    • 分表:每个库内 8 张表(t_participation_0 ~ t_participation_7),按 activity_id % 8 路由。

Maven 依赖引入

<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.3.2</version>
</dependency>

Spring Boot 配置分片规则

application.yml:

spring:
shardingsphere:
datasource:
names: ds0,ds1,ds2,ds3
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://db0.baodanbao.com.cn:3306/baodan_part_0
username: root
password: xxx
ds1:
jdbc-url: jdbc:mysql://db1.baodanbao.com.cn:3306/baodan_part_1
# … 其他配置省略
ds2:
jdbc-url: jdbc:mysql://db2.baodanbao.com.cn:3306/baodan_part_2
ds3:
jdbc-url: jdbc:mysql://db3.baodanbao.com.cn:3306/baodan_part_3

rules:
sharding:
tables:
t_participation:
actual-data-nodes: ds$>{0..3}.t_participation_$>{0..7}
database-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: dbhashmod
table-strategy:
standard:
sharding-column: activity_id
sharding-algorithm-name: tablehashmod

sharding-algorithms:
db-hash-mod:
type: HASH_MOD
props:
sharding-count: 4
table-hash-mod:
type: HASH_MOD
props:
sharding-count: 8

props:
sql-show: true

在这里插入图片描述

实体类与 Mapper 定义

package baodanbao.com.cn.meituan.sharding.entity;

import lombok.Data;

@Data
public class ParticipationRecord {
private Long id;
private Long userId;
private Long activityId;
private String status;
private java.time.LocalDateTime createTime;
}

使用 MyBatis:

package baodanbao.com.cn.meituan.sharding.mapper;

import baodanbao.com.cn.meituan.sharding.entity.ParticipationRecord;
import org.apache.ibatis.annotations.*;

@Mapper
public interface ParticipationRecordMapper {

@Insert("INSERT INTO t_participation (user_id, activity_id, status, create_time) " +
"VALUES (#{userId}, #{activityId}, #{status}, #{createTime})")
void insert(ParticipationRecord record);

@Select("SELECT * FROM t_participation WHERE user_id = #{userId}")
java.util.List<ParticipationRecord> findByUserId(@Param("userId") Long userId);

@Select("SELECT * FROM t_participation WHERE activity_id = #{activityId}")
java.util.List<ParticipationRecord> findByActivityId(@Param("activityId") Long activityId);
}

关键查询行为验证

用户查询(精准路由)

List<ParticipationRecord> records = mapper.findByUserId(1001L);

ShardingSphere 日志显示:

Actual SQL: ds1 ::: SELECT * FROM t_participation_1 WHERE user_id = 1001

→ 1001 % 4 = 1 → 库 ds1;若 activity_id=2001,则 2001 % 8 = 1 → 表 t_participation_1。

活动查询(广播?不!)

注意:仅指定 activity_id 时,因未提供 user_id,无法确定库,ShardingSphere 会默认在所有库中查询对应表(即 4 个库 × 1 张表 = 4 次查询),非全表扫描但仍有性能损耗。

优化建议:运营后台查询应限定时间范围 + 分页,或建立异步同步到 OLAP 系统(如 Doris)。

分布式主键生成

避免自增 ID 冲突,使用 Snowflake:

spring:
shardingsphere:
rules:
sharding:
key-generators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 1

实体类注解:

@TableId(type = IdType.ASSIGN_ID)
private Long id;

事务与批量插入

ShardingSphere 支持本地事务(非跨库):

@Transactional
public void batchInsert(List<ParticipationRecord> records) {
for (ParticipationRecord r : records) {
mapper.insert(r); // 自动路由到正确库表
}
}

若一批数据涉及多个库,需确保业务可接受最终一致性,或使用 Seata 等分布式事务方案。

运维注意事项

  • 所有 DDL 需通过 ShardingSphere 执行,或手动在各库表同步;
  • 监控各分片数据倾斜,必要时调整分片算法;
  • 备份策略需覆盖所有物理库。

通过 ShardingSphere 的声明式配置,霸王餐系统在不修改核心业务逻辑的前提下,实现了水平扩展,支撑亿级参与记录的高效读写。

本文著作权归 俱美开放平台 ,转载请注明出处!

赞(0)
未经允许不得转载:171主机测评 » 外卖霸王餐系统数据库分库分表策略:ShardingSphere实战案例
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址