服务拆分:别把单体拆成“碎纸片”
很多新手刚接触微服务,总想着“拆得越细越好”,结果拆完发现调用链比面条还乱——查一个订单问题要翻5个服务的日志,接口响应时间从200ms变成了2秒。其实拆分的核心是“按业务边界切”,不是为了拆而拆。

我总结了3个不会踩坑的拆分原则:
– 单一职责:一个服务只做一件事(比如“用户服务”只处理用户注册、登录,别掺订单逻辑);
– 避免循环依赖:比如“订单服务”依赖“商品服务”查库存,就别让“商品服务”再依赖“订单服务”查销量;
– 最小粒度:如果一个功能拆出来后,调用量只有主服务的1%,那不如留在主服务里(比如“用户备注”功能,没必要单独拆成“用户备注服务”)。
举个电商系统的例子,合理拆分后的结构应该是这样:
服务名称 | 核心职责 | 依赖服务 |
---|---|---|
用户服务 | 注册、登录、信息修改 | 无 |
商品服务 | 商品详情、库存查询 | 无 |
订单服务 | 下单、查订单、取消订单 | 用户服务、商品服务 |
支付服务 | 支付回调、退款 | 订单服务 |
记住:拆分的目的是提升效率,不是“为了微服务而微服务”。如果拆完反而更麻烦,不如先保持单体。
服务通信:用OpenFeign告别手写HTTP
微服务之间要通信,总不能每次都写RestTemplate
调接口吧?既要处理超时,还要重试,代码写得像“重复代码生成器”。试试OpenFeign——只需要写个接口,就能像调本地方法一样调其他服务。
第一步:加依赖
Spring Boot 3.x下,引入OpenFeign和Nacos Discovery(服务注册发现)的依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
第二步:写Feign客户端
比如订单服务要调用用户服务的“查用户信息”接口,只需要定义一个接口:
// 指向用户服务的服务名(Nacos里注册的名字)
@FeignClient(name = "user-service", path = "/api/user")
public interface UserFeignClient {
// 对应用户服务的GET /api/user/{id}接口
@GetMapping("/{id}")
UserDTO getUserById(@PathVariable("id") Long userId);
}
第三步:直接调用
在订单服务的业务类里,注入UserFeignClient
就能用:
@Service
public class OrderService {
@Autowired
private UserFeignClient userFeignClient;
public OrderDTO createOrder(OrderRequest request) {
// 调用用户服务查信息,像调本地方法一样
UserDTO user = userFeignClient.getUserById(request.getUserId());
// 后续业务逻辑...
}
}
注意:别忘在启动类加@EnableFeignClients
注解,否则Feign客户端不会被扫描到!
服务治理:Nacos一站式解决注册与配置
服务多了,两个问题立刻冒出来:怎么找到其他服务?(注册中心)怎么统一管理配置?(配置中心)——Nacos一句话解决:“我全都要”。
1. 服务注册与发现
先启动Nacos(官网下载压缩包,双击startup.cmd
就行),然后在Spring Boot项目里配置Nacos地址:
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos地址
application:
name: order-service # 服务名(Nacos里显示的名字)
启动项目后,打开Nacos控制台(http://localhost:8848/nacos),就能在“服务列表”里看到order-service
了。
2. 配置中心:改配置不用重启
以前改数据库密码要改application.yml
,还要重启服务——现在把配置放到Nacos里,改完直接生效。
比如我们把用户服务的数据库配置放到Nacos:
– 登录Nacos,点击“配置管理”→“配置列表”→“新建配置”;
– 配置集ID填user-service-dev.yaml
(格式:服务名-环境.后缀
);
– 配置内容写数据库信息:
spring:
datasource:
url: jdbc:mysql://localhost:3306/user_db
username: root
password: new_password_2025 # 新密码
然后在用户服务的application.yml
里配置Nacos配置中心:
spring:
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yaml # 配置文件后缀
profiles:
active: dev # 激活dev环境
最后在代码里用@Value
获取配置:
@Service
public class UserService {
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.password}")
private String dbPassword;
}
以后要改数据库密码,直接在Nacos里改user-service-dev.yaml
,不用重启服务——是不是爽翻了?
流量防护:用Sentinel挡住“突发流量”
秒杀活动一来,订单服务直接被冲垮?用户疯狂刷新页面,导致接口返回500?——用Sentinel做限流、降级、熔断,把突发流量挡在外面。
1. 快速接入Sentinel
先启动Sentinel Dashboard(下载地址:https://github.com/alibaba/Sentinel/releases),然后在项目里加依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
配置Sentinel地址:
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 # Sentinel Dashboard地址
2. 给接口加“流量防护盾”
比如对订单服务的/api/order/create
接口限流,每秒最多处理100个请求:
@RestController
@RequestMapping("/api/order")
public class OrderController {
// value是资源名,fallback是降级方法
@PostMapping("/create")
@SentinelResource(value = "createOrder", fallback = "fallbackCreateOrder")
public ResponseEntity<String> createOrder(@RequestBody OrderRequest request) {
// 正常业务逻辑
return ResponseEntity.ok("订单创建成功");
}
// 降级方法:当限流或出错时调用
public ResponseEntity<String> fallbackCreateOrder(OrderRequest request, Throwable e) {
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS)
.body("当前请求过多,请稍后重试~");
}
}
3. 在Sentinel里配置规则
启动项目后,访问几次/api/order/create
接口(让Sentinel捕获到资源),然后打开Sentinel Dashboard:
– 点击“簇点链路”→找到createOrder
资源;
– 点击“流控”→设置“阈值类型”为QPS,“阈值”为100→保存。
这样当每秒请求超过100次时,Sentinel会直接返回降级信息,不会把订单服务压垮。
链路追踪:用SkyWalking看清“调用链”
用户说“下单慢”,怎么查?是用户服务卡了?还是商品服务查库存慢?——用SkyWalking把调用链“画出来”,一眼就能找到问题。
1. 启动SkyWalking
下载SkyWalking OAP和UI(官网:https://skywalking.apache.org/),解压后:
– 启动OAP:双击bin/startup.bat
;
– 启动UI:双击bin/webappService.bat
(默认端口8080)。
2. 给服务加“追踪探针”
启动Spring Boot服务时,加上SkyWalking的Agent参数:
java -javaagent:D:skywalking-agentskywalking-agent.jar ^
-Dskywalking.agent.service_name=order-service ^ # 服务名
-Dskywalking.collector.backend_service=localhost:11800 ^ # OAP地址
-jar order-service.jar
3. 查看调用链
访问几次下单接口后,打开SkyWalking UI(http://localhost:8080):
– 点击“追踪”→选择“order-service”→就能看到每一次请求的调用链;
– 比如某条请求的耗时分布:order-service
用了500ms,其中user-service
的getUserById
用了300ms——问题出在用户服务!
再点进去看getUserById
的详细信息,发现是SQL查询慢(比如没加索引),直接优化SQL就行。
监控告警:用Prometheus+Grafana看住服务状态
微服务跑起来后,得知道“服务有没有挂?”“QPS多少?”“内存用了多少?”——用Prometheus采集数据,Grafana可视化,完美组合。
1. 让Spring Boot暴露监控端点
在项目里加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
配置暴露Prometheus端点:
management:
endpoints:
web:
exposure:
include: prometheus # 暴露/prometheus端点
metrics:
tags:
application: ${spring.application.name} # 给 metrics 加服务名标签
启动项目后,访问http://localhost:8080/actuator/prometheus
,就能看到监控数据(比如jvm_memory_used_bytes
是JVM已用内存)。
2. 用Prometheus采集数据
下载Prometheus(官网:https://prometheus.io/),修改prometheus.yml
配置:
scrape_configs:
- job_name: 'spring-boot-apps' # 任务名
metrics_path: '/actuator/prometheus' # 监控端点路径
static_configs:
- targets: ['localhost:8080', 'localhost:8081'] # 多个服务地址(订单服务、用户服务)
启动Prometheus后,访问http://localhost:9090
,就能看到采集到的 metrics。
3. 用Grafana做可视化
下载Grafana(官网:https://grafana.com/),启动后访问http://localhost:3000
(默认账号admin/admin):
– 点击“Add your first data source”→选择Prometheus→配置Prometheus地址(http://localhost:9090)→保存;
– 点击“Dashboards”→“Import”→输入Spring Boot的Dashboard ID(比如12856,这是官方维护的Spring Boot监控面板)→选择Prometheus数据源→导入。
导入后,你会看到一个漂亮的监控面板:包含各服务的QPS、错误率、JVM内存、GC次数——所有状态一目了然。
最后提醒一句:微服务不是银弹,它解决了单体的“扩容难”“协作慢”问题,但也带来了“调用链复杂”“治理成本高”的新问题。先想清楚需求,再选择架构——如果你的项目只有10个接口,用户量不到1万,保持单体反而更高效。
原创文章,作者:,如若转载,请注明出处:https://zube.cn/archives/393