5-2 服务注册与发现
概念解析
服务发现核心概念
| 概念 | 说明 |
|---|---|
| 服务注册 | 实例启动时向注册中心注册 |
| 服务注销 | 实例关闭时从注册中心移除 |
| 心跳机制 | 定期向注册中心发送心跳 |
| 服务剔除 | 注册中心剔除不可用实例 |
注册中心对比
| 注册中心 | CAP | 一致性算法 | 特点 |
|---|---|---|---|
| Eureka | AP | - | 简单,停止维护 |
| Nacos | CP + AP | Raft | 功能全面 |
| Consul | CP | Raft | 多数据中心 |
| Zookeeper | CP | Zab | 重量级 |
代码示例
1. Nacos 服务注册
pom.xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2023.0.1.0</version>
</dependency>
application.yml
spring:
application:
name: order-service
cloud:
nacos:
server-addr: localhost:8848
username: nacos
password: nacos
discovery:
namespace: dev
group: DEFAULT_GROUP
cluster-name: BJ-GROUP-1 # 集群
metadata:
version: v1
instance: order-1
自动注册:添加依赖后自动注册到 Nacos
2. OpenFeign 服务调用
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类
@SpringBootApplication
@EnableFeignClients // 启用 Feign
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
定义 Feign Client
@FeignClient(name = "user-service", path = "/api/users")
public interface UserClient {
@GetMapping("/{id}")
Result<User> getUser(@PathVariable("id") Long id);
@GetMapping
Result<List<User>> list();
}
使用
@Service
public class OrderService {
@Autowired
private UserClient userClient;
public OrderVO createOrder(Long userId) {
// 调用用户服务
User user = userClient.getUser(userId).getData();
// 创建订单
return buildOrder(user);
}
}
3. 负载均衡配置
// 全局配置
@Configuration
public class FeignConfig {
@Bean
public Retryer.Retryer retryer() {
// 重试配置:最多重试 3 次,每次间隔 100-500ms
return new Retryer.Default(100, 500, 3);
}
}
// 针对特定服务配置
@FeignClient(
name = "user-service",
configuration = UserFeignConfig.class
)
public interface UserClient { }
// 指定负载均衡策略
@Configuration
public class UserFeignConfig {
@Bean
public IRule roundRobinRule() {
return new RoundRobinRule(); // 轮询
// return new RandomRule(); // 随机
// return new WeightedResponseTimeRule(); // 权重
// return new NacosRule(); // Nacos 权重
}
}
4. 服务降级
// 定义降级类
@Component
public class UserClientFallback implements UserClient {
private static final Logger log = LoggerFactory.getLogger(
UserClientFallback.class);
@Override
public Result<User> getUser(Long id) {
log.warn("UserService 调用失败,返回降级结果");
return Result.error("服务暂时不可用,请稍后重试");
}
@Override
public Result<List<User>> list() {
return Result.success(Collections.emptyList());
}
}
// 使用降级
@FeignClient(
name = "user-service",
fallback = UserClientFallback.class // 指定降级类
)
public interface UserClient { }
5. Nacos 集群配置
# application.yml
spring:
cloud:
nacos:
server-addr: nacos-1:8848,nacos-2:8848,nacos-3:8848
username: ${NACOS_USERNAME:nacos}
password: ${NACOS_PASSWORD:nacos}
# nginx 代理
# upstream nacos-cluster {
# server nacos-1:8848;
# server nacos-2:8848;
# server nacos-3:8848;
# }
# server {
# listen 8848;
# location / {
# proxy_pass http://nacos-cluster;
# }
# }
常见坑点
⚠️ 坑 1:服务注册不上
# ❌ 缺少 discovery 依赖
spring:
cloud:
nacos:
discovery:
enabled: true # 确保开启
# ✅ 检查启动日志
# Located property source: [BootstrapPropertySource {name='bootstrap properties'}]
# Discovery Client started ...
⚠️ 坑 2:Feign 超时
# 配置超时
feign:
client:
config:
default:
connect-timeout: 5000
read-timeout: 10000
user-service: # 特定服务配置
connect-timeout: 3000
read-timeout: 5000
hystrix:
enabled: true
⚠️ 坑 3:Ribbon vs LoadBalancer
// Spring Cloud 2020+ 使用 Spring Cloud LoadBalancer
@Configuration
public class LoadBalancerConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
Environment environment,
LoadBalancerClientFactory factory) {
String name = environment.getProperty(
SpringCloudLoadBalancerClientFactory.LOADBALANCER_CONFIG_PROPERTY_NAME);
return new RandomLoadBalancer(
factory.getLazyProvider(name, ServiceInstanceListSupplier.class),
name);
}
}
面试题
Q1:Nacos 的 AP 和 CP 模式?
参考答案:
Nacos 同时支持 CP 和 AP 模式:
| 模式 | 特点 | 使用场景 |
|---|---|---|
| AP | 可用性优先,分区容忍 | 服务注册与发现 |
| CP | 一致性优先 | 配置管理 |
# 切换模式
curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/mode?mode=CP'
# 或通过控制台切换
选择建议:
- 服务发现:使用 AP(保证可用性)
- 配置管理:使用 CP(保证一致性)
Q2:Eureka 和 Nacos 的区别?
参考答案:
| 维度 | Eureka | Nacos |
|---|---|---|
| CAP | AP | AP + CP 可切换 |
| 数据同步 | Peer-to-Peer | Raft 协议 |
| 健康检查 | 客户端心跳 | 服务端主动探测 |
| 配置管理 | 无 | 内置配置中心 |
| 运维成本 | 低 | 中 |
| 活跃度 | 停止维护 | 活跃 |
Q3:Feign 的工作原理?
参考答案:
- 启动时:扫描
@FeignClient注解 - 生成代理:为每个 FeignClient 生成代理对象
- 方法调用:
- 构建请求模板
- 调用 LoadBalancer 选择实例
- 发送 HTTP 请求
- 解析响应
// 关键源码
public FeignClientFactoryBean implements FactoryBean<Object> {
@Override
public Object getObject() {
return Feign.builder()
.encoder(new SpringFormEncoder())
.decoder(new ResponseEntityDecoder(
new SpringDecoder(messageConverters)))
.contract(new SpringMvcContract())
.target(Target.class, url, fallbackFactory);
}
}