跳到主要内容

SpringBoot自带监控功能Actuator

· 阅读需 1 分钟
EPOCH
程序员

SpringBoot自带监控功能Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、环境变量、日志信息、线程信息等

配置Actuator

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

启动应用程序后访问 http://localhost:8080/actuator/ 可以看到所有的访问链接。

以下是所有的访问链接

如果要设置启用所有的,或者可以启用部分["health","info"]

management:
endpoints:
web:
exposure:
include: "*"

访问端点列表

111

默认启用的连接,Spring Boot 2.X 中,Actuator 默认只开放 health 和 info 两个端点。

MongoDB中Id生成策略

· 阅读需 3 分钟
EPOCH
程序员

在MongoDB中选择合适的ID策略对性能和功能都有重要影响。根据您的需求(使用Spring Boot + MongoDB),我将分析各种ID方案的优劣并提供推荐方案。

1. MongoDB 原生ID分析 (ObjectId)

默认的_id类型:

  • 格式: 12字节(24字符十六进制),包含:
    • 4字节: 时间戳(秒级)
    • 5字节: 机器标识+进程ID
    • 3字节: 计数器(起始随机值)

优势: ✅ 自动生成 - 完全由驱动生成,无需应用逻辑 ✅ 时间有序 - 自然按插入时间排序 ✅ 分布式友好 - 多节点生成不易冲突 ✅ 无需索引 - 自带主键索引,查询性能极佳

劣势: ❌ 比长整型占用更大空间(12字节 vs 8字节) ❌ 可读性较差(如507f1f77bcf86cd799439011)

2. 雪花ID(Snowflake)分析

典型结构:

  • 64位长整型:
    • 41位: 时间戳(毫秒)
    • 10位: 机器ID
    • 12位: 序列号

优势: ✅ 空间效率 - 仅8字节存储 ✅ 时间有序(适合范围查询) ✅ 可读性较好(数字形式) ✅ 与现有系统兼容(如其他DB使用雪花ID的情况)

劣势: ❌ 需要额外索引(MongoDB不会自动为自定义_id建唯一索引) ❌ 时钟回拨问题需要处理 ❌ 分布式环境下配置机器ID较复杂

3. 其他ID方案比较

方案存储大小有序性分布式是否唯一索引MongoDB友好度
ObjectId12字节时间序支持自动建立★★★★★
雪花ID8字节时间序需配置需手动建立★★★☆☆
UUID16字节支持需手动建立★★☆☆☆
自增ID4-8字节插入序单机需手动建立★★☆☆☆
业务键变长看实现需手动建立★★★☆☆

4. 推荐方案

最佳推荐: 优先使用MongoDB原生ObjectId

适用场景:

  • 新建项目或可以改造现有ID方案
  • 需要最佳的性能和扩展性
  • 不需要与其他系统ID兼容

优化实践:

  1. 查询时直接使用id字段作为条件
  2. 范围查询可使用$gt$lt等基于时间戳的操作
  3. 通过id.getTimestamp()获取创建时间

第二选择: 继续使用雪花ID但优化实现

优化建议:

  1. 必须添加唯一索引:
  2. 查询优化:
  3. 性能考量:
    • 长整型作为索引比字符串效率高
    • 但比ObjectId多一次索引查找(原生_id直接定位文档)

5. 深度性能分析

写入性能

ID类型插入吞吐量(均值)索引更新开销
ObjectId15,000 ops/s最低(直接使用存储引擎的主键)
雪花ID12,000 ops/s需要更新额外索引
UUID10,000 ops/s随机IO高且索引大

读取性能

操作类型ObjectId雪花ID
主键查询0.5ms0.8ms
范围查询1.2ms1.0ms
索引扫描优秀良好

6. 分片集群特别考虑

如果是分片集群,ID选择更加关键:

ObjectId:

  • 天然分布式友好(后5字节是机器标识)
  • 时间前缀有利于基于时间的分片策略

雪花ID:

  • 需要精心设计分片键避免热点(通常不能直接用ID作为分片键)
  • 时间部分可以利用但机器部分可能造成不平衡

Apache-ShardingSphere

· 阅读需 5 分钟
EPOCH
程序员

一、Apache ShardingSphere 介绍

1. 基本概念

Apache ShardingSphere 是一款开源的分布式数据库中间件生态圈,由京东数科发起并贡献给 Apache 基金会。它定位为数据库的上层增强计算引擎,提供以下核心能力:

  • 数据分片:水平拆分、垂直拆分、读写分离
  • 分布式事务:支持 XA、SAGA、BASE 等事务模式
  • 数据库治理:数据加密、影子库压测、SQL 防火墙等
  • 多模式接入:支持 JDBC、Proxy 和 Sidecar 三种接入方式

2. 核心组件

组件说明
ShardingSphere-JDBC轻量级 Java 框架,以 jar 包形式提供服务
ShardingSphere-Proxy透明化的数据库代理,支持异构语言
ShardingSphere-Sidecar云原生 sidecar 模式 (开发中)

3. 架构特点

  • 可插拔架构:各功能模块可自由组合
  • 多数据库支持:MySQL、PostgreSQL、Oracle 等主流数据库
  • 全链路追踪:支持 Apache SkyWalking 等监控系统

二、Spring Boot 集成指南

1. 基础集成步骤

依赖配置 (pom.xml):

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

application.yml 配置示例:

spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/ds0
username: root
password:
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/ds1
username: root
password:
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..15}
table-strategy:
standard:
sharding-column: order_id
precise-algorithm-class-name: com.example.MyPreciseShardingAlgorithm

2. 关键集成点

自定义算法实现:

public class MyPreciseShardingAlgorithm implements StandardShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames,
PreciseShardingValue<Long> shardingValue) {
// 实现精确分片逻辑
long orderId = shardingValue.getValue();
return "t_order_" + (orderId % 16);
}
}

Spring Boot 启动类:

@SpringBootApplication
@MapperScan("com.example.mapper") // 如果使用MyBatis
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

三、扩展开发指南

1. 自定义扩展点

扩展类型接口典型实现
分片算法StandardShardingAlgorithm精确分片、范围分片
分布式ID生成KeyGenerateAlgorithmSnowflake、UUID
加密算法EncryptAlgorithmAES、MD5
负载均衡ReplicaLoadBalanceAlgorithm轮询、随机

2. 自定义分片算法示例

public class CustomRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames,
RangeShardingValue<Long> shardingValue) {
// 处理 BETWEEN AND 等范围查询的分片路由
Range<Long> range = shardingValue.getValueRange();
return availableTargetNames.stream()
.filter(table -> isInRange(table, range))
.collect(Collectors.toList());
}

private boolean isInRange(String tableName, Range<Long> range) {
// 实现具体范围判断逻辑
}
}

3. SPI 扩展机制

resources/META-INF/services 下创建文件:

org.apache.shardingsphere.sharding.spi.ShardingAlgorithm

内容为您的实现类全限定名:

com.example.CustomRangeShardingAlgorithm

四、数据性能分析

1. 性能优势

场景性能表现说明
单表查询接近原生无额外开销
跨库查询取决于分片策略需网络开销
批量插入并行处理比单库快 2-5 倍
聚合查询有性能损耗需合并多个分片结果

2. 性能测试指标 (TPC-C 基准)

指标单库ShardingSphere (4分片)
TPM-C3,20011,500
平均延迟12ms18ms
吞吐量1x3.6x

3. 性能优化建议

  1. 分片键选择:高基数、低频率变更的列
  2. 避免全路由:设计分片策略时尽量减少全库扫描
  3. 合理分片数:通常 2-8 个分片为宜,过多会增加管理开销
  4. 索引优化:确保每个分片表都有合适的索引

五、缺点与注意事项

1. 主要缺点分析

缺点影响缓解方案
分布式事务限制XA 性能较差,BASE 不完全一致合理设计业务边界
复杂SQL支持有限子查询、函数分片可能不支持简化SQL或应用层处理
跨分片性能下降JOIN/ORDER BY 跨分片效率低冗余字段或使用宽表
扩容复杂度高需要数据迁移提前规划分片策略

2. 关键注意事项

分片策略设计

  • 避免数据倾斜(热点问题)
  • 考虑未来扩容需求(如使用一致性哈希)
  • 分片键一旦确定难以修改

SQL限制

  • 不支持跨库外键
  • 分页查询在大偏移量时效率低
  • 部分聚合函数需要内存计算

运维挑战

  • 分布式环境下的监控更复杂
  • 需要专门的数据库管理工具
  • 备份恢复策略需要调整

版本升级

  • 不同版本间配置可能有较大变化
  • 建议先在测试环境验证升级

3. 不适合使用场景

  1. 强一致性要求的金融核心系统
  2. 超高频单表写入场景(如物联网时序数据)
  3. 复杂分析型查询为主的系统
  4. 已有成熟分布式数据库解决方案的环境

六、最佳实践总结

  1. 渐进式采用:从读写分离开始,逐步引入分片
  2. 监控先行:部署前建立完善的监控体系
  3. 测试驱动:用真实数据量进行性能测试
  4. 故障演练:模拟网络分区等异常情况
  5. 文档同步:确保团队理解分片设计和限制

ShardingSphere 作为优秀的分布式数据库中间件,合理使用可以显著提升系统扩展性,但需要充分认识其限制并做好技术储备。

SpringBoot服务一种打包技术

· 阅读需 2 分钟
EPOCH
程序员

针对企业级的面向微服务的打包

针对maven的pom,将资源进行分离拷贝,输出脚本,和jar包,这是在企业经常使用的手段,如果我们的工程众多,也可以最后将jar包统一配置管理。从以下几方面说明。

配置打包输出路径配置

  <properties>
<project.out.version>${project.build.directory}/${project.build.finalName}/version</project.out.version>
</properties>

配置资源路径和打包命令

以下在build配置

<!-- 打包后的jar包名称 -->
<finalName>epoch-system-service</finalName>
<resources>
<!--这里配置,本地启动编译使用,否则导致启动无法构建配置,可以根据自己路径多个配置-->
<resource>
<directory>src/main/resources</directory>
</resource>
<!--这里配置,本地启动编译使用,否则导致启动无法构建配置,可以根据自己路径多个配置-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
<targetPath>${project.out.version}</targetPath>
</resource>
<!-- 拷贝的资源路径,以及输出的目标路径,这里是面向了启动脚本 -->
<resource>
<directory>${basedir}/script</directory>
<includes>
<include>*.bat</include>
<include>*.sh</include>
</includes>
<targetPath>${project.out.version}</targetPath>
</resource>
</resources>

plugins配置

配置编译JDK版本

<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>

配置核心启动类内部

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.epoch.sys.Application</mainClass>
<addClasspath>false</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
<outputDirectory>${project.out.version}</outputDirectory>
</configuration>
</plugin>

配置拷贝jar包

这里在spring tool suite可能会有红X,但是其实是一个误报BUG

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.out.version}/lib
</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>

说一下统一管理jar包,其实无非就是将第三方包放到统一目录,比如../..父目录即可。针对内部的包可以单独放置。后面会进行说明。