服务发现
什么是服务发现?
在微服务架构中,服务实例动态变化(扩缩容、故障恢复),需要一种机制让服务相互发现。
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 服务 A │ │ 服务 B │ │ 服务 C │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└────────────────────┼────────────────────┘
│
┌────────▼────────┐
│ 服务注册中心 │
│ (Nacos/Eureka) │
└─────────────────┘Nacos 服务注册发现
依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>配置
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: dev
group: DEFAULT_GROUP服务注册
@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}服务发现
@Service
public class OrderService {
@Autowired
private DiscoveryClient discoveryClient;
public void callUserService() {
// 获取服务实例列表
List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
if (instances.isEmpty()) {
throw new RuntimeException("无可用服务");
}
// 负载均衡选择一个实例
ServiceInstance instance = instances.get(0);
String url = instance.getUri() + "/user/1";
// 调用服务
User user = restTemplate.getForObject(url, User.class);
}
}负载均衡
Ribbon(已废弃,使用 Spring Cloud LoadBalancer)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>使用 RestTemplate + @LoadBalanced
@Configuration
public class RestConfig {
@Bean
@LoadBalanced // 自动负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate;
public User getUser(Long id) {
// 直接使用服务名,自动负载均衡
return restTemplate.getForObject("http://user-service/user/" + id, User.class);
}
}使用 OpenFeign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>@FeignClient("user-service")
public interface UserClient {
@GetMapping("/user/{id}")
User getUser(@PathVariable("id") Long id);
}
// 使用
@Service
public class OrderService {
@Autowired
private UserClient userClient;
public User getUser(Long id) {
return userClient.getUser(id);
}
}负载均衡策略
| 策略 | 说明 |
|---|---|
| RoundRobinLoadBalancer | 轮询(默认) |
| RandomLoadBalancer | 随机 |
自定义负载均衡
@Configuration
public class LoadBalancerConfig {
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory factory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}服务注册中心对比
| 特性 | Nacos | Eureka | Consul | Zookeeper |
|---|---|---|---|---|
| CAP | AP/CP | AP | CP | CP |
| 健康检查 | TCP/HTTP/MySQL | 心跳 | TCP/HTTP | 心跳 |
| 负载均衡 | Ribbon | Ribbon | Fabio | 否 |
| 配置中心 | 支持 | 不支持 | 支持 | 不支持 |
| 社区活跃度 | 高 | 低(停更) | 高 | 高 |
面试高频问题
Q1: 服务发现的流程?
- 服务启动时向注册中心注册
- 注册中心维护服务实例列表
- 消费者从注册中心获取实例列表
- 消费者通过负载均衡调用服务
Q2: Nacos 和 Eureka 的区别?
| 对比 | Nacos | Eureka |
|---|---|---|
| 模式 | AP/CP 可切换 | AP |
| 配置中心 | 支持 | 不支持 |
| 健康检查 | 多种方式 | 心跳 |
| 状态 | 活跃 | 停止维护 |
Q3: 如何保证服务发现的高可用?
- 注册中心集群部署
- 本地缓存服务列表
- 健康检查及时剔除故障实例
总结
服务发现核心要点:
1. 服务注册:启动时向注册中心注册
2. 服务发现:从注册中心获取实例列表
3. 负载均衡:Ribbon 或 Spring Cloud LoadBalancer
4. 常用注册中心:Nacos(推荐)、Eureka、Consul