我在成都卷完考研,转身用Spring Cloud搭了个微服务demo
去年12月走出考场那一刻,我就知道:研,大概是没上岸了。
今年3月查完成绩,果然——差了国家线8分。但生活总得继续,好在成都这地方节奏舒服,早上八点起床还能赶上楼下豆花饭刚出锅的热气。投了几份简历后,意外拿到了一家本地SaaS创业公司的offer,岗位是Java后端开发。
入职第一周,CTO拍着我肩膀说:“小张啊,咱们产品马上要重构,你先熟悉下Spring Cloud,下周开始搞微服务拆分。”
我当时心里一咯噔:微服务?面试题里倒是背过一堆,但实操?连Eureka长啥样都没见过!
为什么非得上微服务?
我们现在的“产品”是个企业培训平台,单体架构跑了三年,代码库已经膨胀到40万行。上周五晚上,产品经理提了个看似简单的需求:“加个学习进度实时同步功能”。结果改完之后,整个用户中心模块崩了,线上报错 java.lang.OutOfMemoryError: Metaspace,运维半夜打电话骂街。
老板急了,说再这么下去,双11大促(对,我们这种ToB平台也有“大促”)肯定扛不住。于是微服务成了政治任务。
我翻了翻招聘网站,发现几乎所有中高级Java岗JD都写着“熟悉Spring Cloud微服务架构”,甚至有些还要求“有Go语言经验优先”——虽然我们不用Go,但这也让我意识到:微服务不是选修课,是生存技能。
从零开干:注册中心选型踩坑记
第一步当然是选注册中心。面试题里常说ZooKeeper、Consul、Nacos、Eureka四选一,但真到生产环境,每个都有坑。
| 组件 | 优点 | 缺点 | 我们的结论 |
|---|---|---|---|
| Eureka | Spring全家桶亲儿子 | 停止维护,CAP只保证AP | 学习用可以,别上产线 |
| ZooKeeper | 强一致性 | 运维复杂,临时节点机制易误判 | 放弃 |
| Consul | 多语言支持好 | HTTP API性能一般 | 备选 |
| Nacos | 阿里开源,配置+注册一体 | 文档混乱,早期版本有内存泄漏 | 最终选择 |
我们选了Nacos,主要是它能同时管配置和服务,省掉一套Config Server。而且阿里系的组件,在国内社区活跃,遇到问题Stack Overflow搜不到,至少能翻中文博客。
启动Nacos很简单:
# 下载nacos-server
wget https://github.com/alibaba/nacos/releases/download/2.2.3/nacos-server-2.2.3.tar.gz
tar -zxvf nacos-server-2.2.3.tar.gz
cd nacos/bin
sh startup.sh -m standalone # 单机模式跑起来先
访问 http://localhost:8848/nacos,默认账号密码都是 nacos,界面清爽,比Eureka那个复古风舒服多了。
拆!把单体切成微服务
我们决定先拆两个核心模块:user-service 和 course-service。
user-service(用户服务)
# bootstrap.yml
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:884ckage com.example.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient // 关键注解!让服务自动注册到Nacos
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
Controller就写个最简单的:
@RestController
public class UserController {
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
// 实际走MyBatis查DB,这里简化
return new User(id, "张三", "zhangsan@example.com");
}
}
启动后,刷新Nacos控制台,看到 user-service 出现在服务列表里,心跳正常——那一刻真的有点小激动,感觉自己像个架构师了(虽然只是幻觉)。
course-service(课程服务)
同样的套路,但这里有个坑:课程服务需要调用用户服务获取讲师信息。这时候就得上 OpenFeign 了。
先在 course-service 里加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
然后定义Feign客户端:
@FeignClient(name = "user-service") // 指向Nacos里的服务名
public interface UserClient {
@GetMapping("/user/{id}")
User getUserById(@PathVariable("id") Long id);
}
在CourseController里注入使用:
@RestController
public class CourseController {
@Autowired
private UserClient userClient;
@GetMapping("/course/{id}")
public CourseWithTeacher getCourse(@PathVariable Long id) {
Course course = courseMapper.selectById(id);
User teacher = userClient.getUserById(course.getTeacherId()); // 远程调用!
return new CourseWithTeacher(course, teacher);
}
}
但是! 第一次跑直接500错误:
Load balancer does not contain an instance for the service user-service
查了半天,发现 user-service 虽然注册了,但IP是Docker内网地址(因为我们用Docker Compose跑),course-service 在宿主机上根本连不上。最后加了个配置解决:
spring:
cloud:
inetutils:
preferred-networks: 192.168 # 强制注册局域网IP
这种细节,面试题可不会考,但生产环境天天见。
性能优化:别让微服务变成“龟速服务”
微服务最大的陷阱就是网络开销。每次调用都要走HTTP,加上序列化反序列化,延迟蹭蹭涨。
我们压测发现,一个课程详情接口(内部调用3次其他服务)平均响应时间从单体时的45ms飙到180ms。产品经理看了直摇头:“这用户体验,不如回石器时代。”
于是祭出几招:
Feign + Ribbon 超时调优
feign: client: config: default: connectTimeout: 2000 readTimeout: 5000启用Gzip压缩
server: compression: enabled: true mime-types: application/json缓存高频数据
用户基本信息变动少,直接上Redis缓存:@Cacheable(value = "users", key = "#id") public User getUser(Long id) { ... }
优化后,P99延迟降到85ms,勉强能交差了。
面试题 vs 现实:那些没人告诉你的事
准备面试时,我背过无数道Spring Cloud题:
- “说说服务雪崩怎么处理?” → 答:Hystrix熔断。
- “配置中心怎么实现动态刷新?” → 答:@RefreshScope。
但现实是:
- Hystrix官方已停更,我们改用 Sentinel(阿里开源),规则配置更直观;
- @RefreshScope 在生产环境慎用!有一次刷新配置导致连接池泄露,差点引发雪崩;
- 微服务拆分不是越细越好,我们一开始拆太狠,结果链路追踪日志爆炸,排查Bug像在玩“大家来找茬”。
上周还因为服务间循环依赖(A调B,B又调A),导致整个系统假死。最后靠Arthas在线诊断才定位出来——这种事故,简历上可不敢写。
最后一点碎碎念
现在回头看,Spring Cloud入门其实不难,难的是在真实业务场景里权衡取舍。微服务不是银弹,它带来弹性、独立部署的同时,也引入了分布式事务、链路追踪、配置管理等一系列新问题。
不过,作为一个考研失败转码的新人,能在成都这座安逸的城市里,每天早上八点坐在工位上,一边喝着盖碗茶,一边调试Feign超时参数,也挺踏实的。
毕竟,代码跑通那一刻的快乐,和考研上岸的快乐,其实差不多——都是“我做到了”的瞬间。
如果你也在从零学微服务,别怕踩坑。每一个500错误背后,都是通往高级工程师的垫脚石。
(当然,要是能顺便帮我内推个大厂就更好了,简历已更新,求捞!)

评论 0