从县城敲代码到微服务上云:一个小镇做题家的Spring Cloud入门血泪史
去年冬天,我坐在老家县城的小出租屋里,窗外是南方湿冷的雨,屋内是发烫的MacBook和凌晨三点的IDEA。当时刚跳槽进深圳一家腾讯系中厂,团队里清一色“大厂履历”,而我这个靠刷LeetCode+啃GitHub源码混进来的小镇做题家,接到第一个任务就是:“把单体后端拆成微服务,下个迭代上线。”
产品经理笑眯眯地说:“技术方案你们定,但双十二前必须跑通。”
我:???
说实话,之前在学校和小公司都是写CRUD单体应用,Spring Boot用得还算溜,但“微服务”三个字对我而言,还停留在B站视频里的概念图。好在咱小镇做题家的优势就是——能肝、敢啃源码、不怕报错。于是花了两周时间,从零开始搞定了Spring Cloud全家桶的最小可行部署。今天这篇教程,就是给和我一样“被迫成长”的Java后端新人准备的实战指南。
为啥非要用微服务?别被PPT忽悠了
先说句大实话:很多项目根本不需要微服务!尤其是初创团队或者业务逻辑简单的小系统,硬拆反而增加运维成本。我们团队之所以要拆,是因为原来的单体架构已经快撑不住了:
- 用户量暴涨,订单服务和用户服务互相拖慢
- 每次改个小功能都要全量发布,测试同学天天找我“对需求”
- 线上出问题,日志像大海捞针,运维大哥看我都摇头
领导原话是:“隔壁组用了Spring Cloud Alibaba,QPS翻倍,你们也搞搞。”
行吧,搞就搞。
第一步:搭架子,别一上来就炫技
很多人一学微服务就冲着Nacos、Sentinel、Seata这些高级组件去,结果连服务注册都配不对。我的建议是:先跑通最简链路——服务注册 → 服务调用 → 配置中心。
1. 服务注册与发现:Nacos真香
以前用Eureka,现在主流基本都切Nacos了(阿里开源,文档友好,支持配置中心)。我本地启动Nacos Server特别简单:
# 下载nacos-server-2.2.3.tar.gz,解压后
cd nacos/bin
sh startup.sh -m standalone # 单机模式,开发够用
然后在两个Spring Boot项目里加依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2022.0.0.0</version>
</dependency>
application.yml里指定Nacos地址:
spring:
application:
name: user-service # 服务名,别重名!
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
启动后打开 http://localhost:8848/nacos,能看到服务列表,那一刻我真的感动了——终于不是localhost:8080孤零零一个了!
2. 服务间怎么“打电话”?Feign比RestTemplate优雅太多
最初我想用RestTemplate手动拼URL调用,结果写了半天还得处理序列化、超时、重试……同事瞥了一眼说:“你这代码像2015年的。”
换成OpenFeign后,直接定义接口:
@FeignClient(name = "order-service")
public interface OrderClient {
@GetMapping("/orders/user/{userId}")
List<OrderDTO> getOrdersByUserId(@PathVariable("userId") Long userId);
}
在user-service里注入这个OrderClient,就像调本地方法一样:
@Service
public class UserService {
@Autowired
private OrderClient orderClient;
public UserDetail getUserWithOrders(Long userId) {
User user = userMapper.selectById(userId);
List<OrderDTO> orders = orderClient.getOrdersByUserId(userId); // 看!像本地调用
return new UserDetail(user, orders);
}
}
注意:记得在启动类加@EnableFeignClients,否则会报No qualifying bean,我当时卡了半小时,差点砸键盘。
3. 配置集中管理:告别“改配置重启十次”
以前改个数据库连接池参数,得重新打包、上传、重启,测试环境和生产环境配置混在一起,提心吊胆。现在把配置扔到Nacos配置中心:
# dataId: user-service-dev.yaml
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://dev-db:3306/user_db
username: root
password: dev123
项目里加依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
再加个bootstrap.yml(注意!不是application.yml):
spring:
application:
name: user-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: dev # 隔离环境
现在改配置不用重启!Nacos会自动推送更新(前提是加了@RefreshScope注解)。上周五晚上改了个超时时间,刷新页面立马生效,我直接原地起飞。
踩坑实录:那些让我想删库跑路的瞬间
| 坑点 | 现象 | 解决方案 |
|---|---|---|
| 服务注册了但调不通 | Feign报Load balancer does not contain an instance for the service |
检查服务名是否一致(区分大小写!),确认Nacos里服务状态是UP |
| 配置不生效 | 改了Nacos配置,程序还是旧值 | 必须加@RefreshScope,且不能用于@ConfigurationProperties类(有坑) |
| 本地能跑,上K8s挂了 | 连不上Nacos | K8s里要用Service名代替localhost,记得配headless service |
最惨的是有一次,我把order-service的端口写成了8080,和user-service冲突,两个服务互相覆盖注册,线上用户看到别人的订单……运维紧急回滚,我请全组喝了三天奶茶才平息民愤。
性能与架构:别只顾跑通,忘了设计
微服务不是堆组件,核心是解耦 + 可观测 + 弹性。
- 数据库隔离:每个服务独立数据库,严禁跨库join。我们把原来的单库拆成
user_db、order_db,用Saga模式保证最终一致性。 - 接口幂等:订单创建接口加了
requestId去重,避免用户狂点支付导致重复下单。 - 链路追踪:接入SkyWalking,现在查慢接口只要点几下,再也不用grep日志了。
顺便吐槽一句:有些同学喜欢在Feign里传大对象,结果网络序列化慢得像蜗牛。记住,微服务间通信尽量传ID,让对方自己查!
写在最后:小镇做题家也能玩转高大上架构
现在回头看,Spring Cloud并没有想象中那么可怕。它本质就是一堆约定好的规范+工具链,帮你解决分布式系统的经典问题。关键不是背概念,而是动手跑起来,遇到问题再深挖。
我在县城远程办公,没有大厂导师带,全靠GitHub issue、Stack Overflow和深夜的咖啡续命。但每次解决一个Bug,看到服务稳稳跑在K8s集群上,那种成就感,比在深圳湾一号看夜景还爽。
如果你也是刚入行的Java后端,别怕微服务。从一个@FeignClient开始,慢慢来,我们都能从CRUD Boy进化成架构Boy(Girl)。
对了,下周我要开始学Spring Cloud Gateway做统一网关了……产品经理又提新需求了,说是“参考微信小程序架构”。我:好的,马上肝。
(完)
P.S. 所有代码已脱敏上传GitHub,搜“town-coder/spring-cloud-demo”就能找到。欢迎star,但别fork后改成你自己的名字说是你写的啊!

评论 0