前言
微服务架构把单体应用拆分成多个服务,带来了灵活性和可扩展性,但也带来了新的挑战:服务如何发现彼此?如何保证服务间的调用稳定?如何防止单个服务故障影响整个系统?
服务治理是微服务架构的核心,包括服务发现、负载均衡、熔断降级、限流等。这篇文章从实战出发,系统性地讲解如何构建一个可靠的服务治理体系。
一、服务发现:微服务的基础
1.1 为什么需要服务发现
传统方式的问题:
# 硬编码服务地址api:user-service:"http://192.168.1.100:8080"order-service:"http://192.168.1.101:8080"问题:
- 服务地址变更需要修改配置
- 无法动态扩容
- 单点故障影响大
服务发现的优势:
- 服务自动注册和发现
- 动态负载均衡
- 故障自动剔除
1.2 服务发现模式
模式1:客户端发现(Client-side Discovery)
客户端 -> 查询服务注册中心 -> 获取服务列表 -> 客户端负载均衡 -> 服务实例实现:
- Eureka(Netflix)
- Consul
- Nacos
模式2:服务端发现(Server-side Discovery)
客户端 -> 负载均衡器 -> 查询服务注册中心 -> 转发到服务实例实现:
- Kubernetes Service
- Nginx + Consul Template
- Spring Cloud Gateway
1.3 Consul服务发现实战
Consul安装:
# 下载Consulwgethttps://releases.hashicorp.com/consul/1.16.0/consul_1.16.0_linux_amd64.zipunzipconsul_1.16.0_linux_amd64.zipmvconsul /usr/local/bin/# 启动Consul Serverconsul agent -server -bootstrap-expect=1-data-dir=/tmp/consul -ui -client=0.0.0.0服务注册:
# 方式1:HTTP API注册curl-X PUT http://localhost:8500/v1/agent/service/register -d'{ "ID": "user-service-1", "Name": "user-service", "Tags": ["v1", "web"], "Address": "192.168.1.100", "Port": 8080, "Check": { "HTTP": "http://192.168.1.100:8080/health", "Interval": "10s" } }'# 方式2:配置文件注册# /etc/consul.d/user-service.json{"service":{"name":"user-service","tags":["v1"],"address":"192.168.1.100","port":8080,"check":{"http":"http://192.168.1.100:8080/health","interval":"10s"}}}服务发现:
# 查询服务curlhttp://localhost:8500/v1/health/service/user-service# 输出示例[{"Service":{"ID":"user-service-1","Service":"user-service","Address":"192.168.1.100","Port":8080},"Checks":[{"Status":"passing"}]}]1.4 Nacos服务发现实战
Nacos安装:
# 下载Nacoswgethttps://github.com/alibaba/nacos/releases/download/2.3.0/nacos-server-2.3.0.tar.gztar-xzf nacos-server-2.3.0.tar.gzcdnacos/bin ./startup.sh -m standalone服务注册(Java):
@SpringBootApplication@EnableDiscoveryClientpublicclassUserServiceApplication{publicstaticvoidmain(String[]args){SpringApplication.run(UserServiceApplication.class,args);}}# application.ymlspring:cloud:nacos:discovery:server-addr:localhost:8848namespace:devgroup:DEFAULT_GROUP服务发现(Java):
@RestControllerpublicclassOrderController{@AutowiredprivateDiscoveryClientdiscoveryClient;@GetMapping("/orders")publicList<Order>getOrders(){// 获取服务实例列表List<ServiceInstance>instances=discoveryClient.getInstances("user-service");// 负载均衡选择实例ServiceInstanceinstance=loadBalance(instances);// 调用服务returnrestTemplate.getForObject(instance.getUri()+"/users",List.class);}}二、负载均衡:分散请求压力
2.1 负载均衡算法
| 算法 | 说明 | 适用场景 |
|---|---|---|
| 轮询(Round Robin) | 依次分配 | 服务器性能相近 |
| 加权轮询(Weighted Round Robin) | 按权重分配 | 服务器性能不同 |
| 随机(Random) | 随机选择 | 简单场景 |
| 最少连接(Least Connections) | 选择连接数最少的 | 长连接场景 |
| 一致性哈希(Consistent Hash) | 相同key路由到同一服务器 | 需要会话保持 |
2.2 Nginx负载均衡
配置示例:
upstream user-service { # 轮询(默认) server 192.168.1.100:8080; server 192.168.1.101:8080; server 192.168.1.102:8080; # 或加权轮询 # server 192.168.1.100:8080 weight=3; # server 192.168.1.101:8080 weight=2; # server 192.168.1.102:8080 weight=1; # 或最少连接 # least_conn; # 健康检查 # 需要nginx-upstream-check-module模块 } server { listen 80; location / { proxy_pass http://user-service; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }动态更新:
# 使用Consul Template动态更新# consul-template.hcltemplate{source="/etc/nginx/upstream.conf.ctmpl"destination="/etc/nginx/upstream.conf"command="nginx -s reload"}# upstream.conf.ctmplupstream user-service{{{rangeservice"user-service"}}server{{.Address}}:{{.Port}};{{end}}}2.3 Spring Cloud LoadBalancer
配置:
@ConfigurationpublicclassLoadBalancerConfig{@BeanpublicReactorLoadBalancer<ServiceInstance>randomLoadBalancer(Environmentenvironment,LoadBalancerClientFactoryloadBalancerClientFactory){Stringname=environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);returnnewRandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,ServiceInstanceListSupplier.class),name);}}使用:
@RestControllerpublicclassOrderController{@AutowiredprivateLoadBalancerClientloadBalancerClient;@GetMapping("/orders")publicList<Order>getOrders(){ServiceInstanceinstance=loadBalancerClient.choose("user-service");returnrestTemplate.getForObject(instance.getUri()+"/users",List.class);}}三、熔断降级:防止雪崩效应
3.1 为什么需要熔断
雪崩效应:
服务A -> 服务B -> 服务C(故障) ↓ 服务B等待超时 ↓ 服务A等待超时 ↓ 整个系统崩溃熔断器的作用:
- 快速失败,避免资源浪费
- 保护下游服务
- 自动恢复
3.2 Hystrix熔断器
依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>使用:
@ServicepublicclassUserService{@AutowiredprivateRestTemplaterestTemplate;@HystrixCommand(fallbackMethod="getUserFallback",commandProperties={@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value="10"),@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value="50"),@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value="5000")})publicUsergetUser(Longid){returnrestTemplate.getForObject("http://user-service/users/"+id,User.class);}publicUsergetUserFallback(Longid){returnnewUser(id,"默认用户");}}参数说明:
requestVolumeThreshold:熔断触发的最小请求数errorThresholdPercentage:错误率阈值(50%)sleepWindowInMilliseconds:熔断后等待时间(5秒)
3.3 Sentinel熔断器
依赖:
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>使用:
@ServicepublicclassUserService{@SentinelResource(value="getUser",fallback="getUserFallback",blockHandler="getUserBlockHandler")publicUsergetUser(Longid){returnrestTemplate.getForObject("http://user-service/users/"+id,User.class);}publicUsergetUserFallback(Longid){returnnewUser(id,"默认用户");}publicUsergetUserBlockHandler(Longid,BlockExceptionex){returnnewUser(id,"被限流");}}规则配置:
@PostConstructpublicvoidinitRules(){List<DegradeRule>rules=newArrayList<>();DegradeRulerule=newDegradeRule();rule.setResource("getUser");rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);rule.setCount(0.5);// 错误率50%rule.setTimeWindow(10);// 熔断10秒rules.add(rule);DegradeRuleManager.loadRules(rules);}3.4 熔断器状态
三种状态:
- 关闭(Closed):正常状态,请求正常通过
- 打开(Open):熔断状态,请求直接失败
- 半开(Half-Open):尝试恢复,允许少量请求通过
状态转换:
关闭 -> 打开:错误率超过阈值 打开 -> 半开:等待时间后 半开 -> 关闭:请求成功 半开 -> 打开:请求失败四、限流:控制请求速率
4.1 限流算法
令牌桶算法:
固定速率生成令牌 -> 桶满则丢弃 -> 请求消耗令牌 -> 无令牌则拒绝漏桶算法:
请求进入漏桶 -> 固定速率流出 -> 桶满则拒绝滑动窗口算法:
时间窗口内计数 -> 超过阈值则拒绝 -> 窗口滑动4.2 Guava RateLimiter
使用:
importcom.google.common.util.concurrent.RateLimiter;@ServicepublicclassOrderService{// 每秒允许10个请求privateRateLimiterrateLimiter=RateLimiter.create(10.0);publicOrdercreateOrder(OrderRequestrequest){// 获取令牌,如果没有则阻塞rateLimiter.acquire();// 或非阻塞方式if(!rateLimiter.tryAcquire()){thrownewRuntimeException("限流");}returnprocessOrder(request);}}4.3 Sentinel限流
注解方式:
@SentinelResource(value="createOrder",blockHandler="createOrderBlockHandler")publicOrdercreateOrder(OrderRequestrequest){returnprocessOrder(request);}publicOrdercreateOrderBlockHandler(OrderRequestrequest,BlockExceptionex){thrownewRuntimeException("限流");}规则配置:
@PostConstructpublicvoidinitRules(){List<FlowRule>rules=newArrayList<>();FlowRulerule=newFlowRule();rule.setResource("createOrder");rule.setGrade(RuleConstant.FLOW_GRADE_QPS);rule.setCount(10);// QPS限制10rules.add(rule);FlowRuleManager.loadRules(rules);}4.4 Nginx限流
配置:
# 限制每个IP每秒10个请求 limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; server { location /api/ { limit_req zone=api_limit burst=20 nodelay; proxy_pass http://backend; } }参数说明:
zone:限流区域rate:限制速率(10r/s)burst:突发允许数量(20)nodelay:不延迟,直接拒绝
五、服务降级:优雅降级策略
5.1 降级策略
| 策略 | 说明 | 示例 |
|---|---|---|
| 返回默认值 | 返回预设的默认数据 | 用户信息 -> 默认用户 |
| 返回缓存数据 | 返回缓存的历史数据 | 商品信息 -> 缓存数据 |
| 返回简化数据 | 返回简化版本 | 完整订单 -> 订单ID |
| 返回空数据 | 返回空结果 | 列表 -> 空列表 |
5.2 降级实现
Hystrix降级:
@HystrixCommand(fallbackMethod="getUserFallback")publicUsergetUser(Longid){returnuserService.getUser(id);}publicUsergetUserFallback(Longid){// 返回默认用户returnnewUser(id,"默认用户","default@example.com");// 或返回缓存// return cache.get("user:" + id);// 或返回空// return null;}Sentinel降级:
@SentinelResource(value="getUser",fallback="getUserFallback")publicUsergetUser(Longid){returnuserService.getUser(id);}publicUsergetUserFallback(Longid){returnnewUser(id,"默认用户");}5.3 多级降级
@ServicepublicclassOrderService{@HystrixCommand(fallbackMethod="getOrderFallback1")publicOrdergetOrder(Longid){returnorderService.getOrder(id);}@HystrixCommand(fallbackMethod="getOrderFallback2")publicOrdergetOrderFallback1(Longid){// 一级降级:查询缓存returncache.get("order:"+id);}publicOrdergetOrderFallback2(Longid){// 二级降级:返回默认订单returnnewOrder(id,"默认订单");}}六、服务监控与追踪
6.1 服务监控指标
关键指标:
- QPS(每秒请求数)
- 响应时间(P50、P95、P99)
- 错误率
- 可用性
Prometheus指标:
@ServicepublicclassOrderService{privatefinalCounterrequestCounter=Counter.build().name("order_requests_total").help("Total order requests").register();privatefinalHistogramresponseTime=Histogram.build().name("order_response_time_seconds").help("Order response time").register();publicOrdercreateOrder(OrderRequestrequest){Timertimer=responseTime.startTimer();try{requestCounter.inc();returnprocessOrder(request);}finally{timer.observeDuration();}}}6.2 分布式追踪
Sleuth + Zipkin:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-sleuth</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-sleuth-zipkin</artifactId></dependency>配置:
spring:sleuth:sampler:probability:1.0# 采样率zipkin:base-url:http://localhost:9411七、跨网络服务治理
7.1 场景:多机房服务调用
如果服务分布在不同的网络环境(不同机房、不同云),服务发现和调用可能受限。
解决方案:
- VPN/专线:稳定但部署周期长
- 组网工具:WireGuard、ZeroTier、星空组网等,快速组建虚拟内网
使用组网工具后,不同网络的服务可以通过虚拟IP直接通信:
# 服务注册(通过虚拟IP)spring:cloud:nacos:discovery:server-addr:10.0.0.100:8848# 虚拟内网IP优势:
- 统一网络后,服务发现配置简单
- 可以用Ansible批量配置服务注册
- 支持服务发现,动态添加节点
7.2 统一服务治理
# 使用Ansible批量配置服务注册ansible all -m copy -a"src=application.yml dest=/app/application.yml"ansible all -m systemd -a"name=app state=restarted"八、实战案例
8.1 案例:电商系统服务治理
架构:
用户服务 -> 订单服务 -> 支付服务 -> 商品服务配置:
# 订单服务配置spring:cloud:nacos:discovery:server-addr:localhost:8848loadbalancer:ribbon:enabled:falsesentinel:transport:dashboard:localhost:8080熔断配置:
@HystrixCommand(fallbackMethod="createOrderFallback",commandProperties={@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value="50"),@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value="10000")})publicOrdercreateOrder(OrderRequestrequest){// 调用支付服务paymentService.pay(request);returnorderRepository.save(order);}publicOrdercreateOrderFallback(OrderRequestrequest){// 降级:保存订单到队列,异步处理messageQueue.send("order.create",request);returnnewOrder(request.getId(),"订单已提交,处理中");}九、总结
| 治理方向 | 关键组件/方法 | 预期效果 | 注意事项 |
|---|---|---|---|
| 服务发现 | Consul/Nacos/Eureka | 动态服务注册和发现 | 需要高可用部署 |
| 负载均衡 | Nginx/Spring Cloud LB | 分散请求压力 | 选择合适的算法 |
| 熔断降级 | Hystrix/Sentinel | 防止雪崩效应 | 合理设置阈值 |
| 限流 | Guava/Sentinel/Nginx | 控制请求速率 | 避免误杀正常请求 |
| 监控追踪 | Prometheus/Sleuth | 可观测性 | 采样率影响性能 |
| 跨网络 | 组网工具统一网络 | 简化服务治理 | 需要安全审计 |
核心思路:
- 服务发现:使用Consul/Nacos等注册中心
- 负载均衡:选择合适的算法和工具
- 熔断降级:防止单个服务故障影响整体
- 限流:控制请求速率,保护后端服务
- 监控追踪:实时了解服务状态
- 跨网络:用组网工具统一网络后治理更简单
注意事项:
- 服务治理需要根据业务特性调整
- 熔断和限流阈值需要压测确定
- 跨网络场景可以用组网工具简化配置
- 监控是关键,及时发现和解决问题