微服务拆分后的服务注册发现问题
单体应用拆分为微服务后,服务实例的IP和端口动态变化,硬编码地址行不通。服务注册发现是微服务架构的基础设施——每个实例启动时注册自己的地址,消费端通过注册中心获取可用实例列表。
这篇文章以Spring Boot 3.x + Nacos为技术栈,覆盖服务注册、负载均衡、熔断降级和流量控制四个核心配置。
Nacos服务注册与发现配置
添加依赖:
<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:
discovery:
server-addr: 192.168.1.50:8848
namespace: production
group: DEFAULT_GROUP
cluster-name: BJ-CLUSTER
config:
server-addr: 192.168.1.50:8848
namespace: production
file-extension: yaml
启动类加@EnableDiscoveryClient(Spring Boot 3.x中该注解已非必须,但保留可增加可读性):
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
健康检查配置:
Nacos默认用心跳检测实例存活。临时实例(ephemeral=true)由客户端发送心跳,永久实例(ephemeral=false)由服务端主动探测。生产环境推荐临时实例+健康检查:
spring:
cloud:
nacos:
discovery:
ephemeral: true
heart-beat-interval: 5000 # 心跳间隔5秒
heart-beat-timeout: 15000 # 心跳超时15秒
ip-delete-timeout: 30000 # IP删除超时30秒
OpenFeign声明式调用与负载均衡
微服务间的HTTP调用推荐用OpenFeign,声明式接口比RestTemplate简洁得多:
@FeignClient(
name = "product-service",
fallbackFactory = ProductFeignFallbackFactory.class
)
public interface ProductFeignClient {
@GetMapping("/api/products/{id}")
ProductDTO getProduct(@PathVariable("id") Long id);
@PostMapping("/api/products/batch")
List<ProductDTO> batchGetProducts(@RequestBody List<Long> ids);
}
负载均衡默认用RoundRobin轮询。需要加权或按地域优先时配置Spring Cloud LoadBalancer:
spring:
cloud:
loadbalancer:
cache:
enabled: true
ttl: 30s
retry:
enabled: true
max-retries-on-next-service-instance: 2
Feign超时配置:
feign:
client:
config:
default:
connectTimeout: 3000
readTimeout: 10000
product-service:
connectTimeout: 2000
readTimeout: 5000 # 特定服务可覆盖默认值
Sentinel熔断降级与流量控制
服务调用链中任何一个节点故障都可能引发雪崩。Sentinel提供熔断降级和流量控制两层防护。
添加依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2023.0.1.0</version>
</dependency>
熔断规则配置:
三种熔断策略——慢调用比例、异常比例、异常数:
@Configuration
public class SentinelRuleConfig {
@PostConstruct
public void initRules() {
// 慢调用比例熔断:RT超过500ms视为慢调用
// 慢调用比例超过50%且请求量 >= 10 时触发熔断
DegradeRule slowCallRule = new DegradeRule("order-service")
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
.setCount(500) // 慢调用阈值500ms
.setSlowRatioThreshold(0.5) // 慢调用比例50%
.setTimeWindow(30) // 熔断持续30秒
.setMinRequestAmount(10) // 最小请求数
.setStatIntervalMs(60000); // 统计时长60秒
// 异常比例熔断
DegradeRule errorRule = new DegradeRule("order-service")
.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
.setCount(0.3) // 异常比例30%
.setTimeWindow(30)
.setMinRequestAmount(10)
.setStatIntervalMs(60000);
DegradeRuleManager.loadRules(Arrays.asList(slowCallRule, errorRule));
}
}
流量控制规则:
FlowRule flowRule = new FlowRule("order-service")
.setCount(200) // QPS阈值200
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setLimitApp("default")
.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP) // 预热模式
.setWarmUpPeriodSec(10); // 预热时长10秒
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
WARM_UP预热模式适合冷启动场景——服务刚上线时逐步放量,避免瞬间流量压垮实例。
网关层流量路由与统一鉴权
Spring Cloud Gateway作为微服务入口,承担路由转发、限流、鉴权和日志记录职责:
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: orderCircuitBreaker
fallbackUri: forward:/fallback/order
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**
filters:
- StripPrefix=1
网关鉴权Filter:
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders()
.getFirst("Authorization");
if (StringUtils.isBlank(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
try {
Claims claims = JwtUtil.parseToken(token.replace("Bearer ", ""));
// 将用户信息传递到下游服务
exchange.getRequest().mutate()
.header("X-User-Id", claims.getSubject())
.header("X-User-Role", claims.get("role", String.class))
.build();
} catch (Exception e) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -100; // 最高优先级
}
}
分布式追踪与可观测性
微服务调用链路需要全链路追踪。Spring Boot 3.x用Micrometer Tracing + Zipkin/Jaeger:
management:
tracing:
sampling:
probability: 1.0 # 采样率,生产环境建议0.1
zipkin:
tracing:
endpoint: http://192.168.1.60:9411/api/v2/spans
配合日志的traceId关联:
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%X{traceId},%X{spanId}] [%thread] %-5level %logger - %msg%n</pattern>
Spring Boot微服务架构的服务治理是层层递进的——注册发现解决”找到谁”,负载均衡解决”选哪个”,熔断降级解决”挂了怎么办”,网关解决”统一入口”。每一层都需要配合业务规模做精细化配置,不存在一套通用模板能覆盖所有场景。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springboot-wei-fu-wu-jia-gou-shi-zhan-fu-wu-zhu-ce-fa-xian/