Hystrix案例

wen java案例 2

本文目录导读:

Hystrix案例

  1. 项目基础配置
  2. 基础降级案例
  3. 进阶功能案例
  4. 自定义Hystrix配置
  5. 请求合并案例
  6. 实际业务应用场景
  7. 测试案例

我来提供一个完整的Hystrix使用案例,包括服务降级、熔断、线程隔离等核心功能。

项目基础配置

Maven依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.10.RELEASE</version>
</dependency>
<!-- 如果需要Feign配合使用 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

启动类配置

@SpringBootApplication
@EnableHystrix  // 或者使用 @EnableCircuitBreaker
@EnableFeignClients
public class HystrixApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixApplication.class, args);
    }
}

基础降级案例

服务提供者(UserService)

@RestController
@RequestMapping("/api/users")
public class UserController {
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        // 模拟数据库查询
        return User.builder()
            .id(id)
            .name("张三")
            .email("zhangsan@example.com")
            .build();
    }
}

服务消费者(使用Hystrix降级)

@RestController
@RequestMapping("/api/client")
@Slf4j
public class UserClientController {
    @Autowired
    private UserServiceClient userServiceClient;
    /**
     * 使用注解方式实现降级
     */
    @GetMapping("/user/{id}")
    @HystrixCommand(
        fallbackMethod = "getUserFallback",
        commandKey = "getUserCommand",
        groupKey = "userServiceGroup",
        threadPoolKey = "userServiceThreadPool"
    )
    public User getUser(@PathVariable Long id) {
        // 调用远程服务
        User user = userServiceClient.getUserById(id);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        return user;
    }
    /**
     * 降级方法
     */
    public User getUserFallback(Long id, Throwable throwable) {
        log.error("获取用户信息失败,id: {}, 原因: {}", id, throwable.getMessage());
        return User.builder()
            .id(id)
            .name("默认用户")
            .email("default@example.com")
            .remark("降级返回的默认用户")
            .build();
    }
    /**
     * 使用编程式方式实现降级
     */
    @GetMapping("/programmatic/user/{id}")
    public User getUserProgrammatic(@PathVariable Long id) {
        User user = executeWithHystrix(() -> userServiceClient.getUserById(id));
        return user != null ? user : getDefaultUser(id);
    }
    private User executeWithHystrix(Supplier<User> action) {
        return new HystrixCommand<User>(
            com.netflix.hystrix.HystrixCommand.Setter
                .withGroupKey(HystrixCommandGroupKey.Factory.asKey("ProgrammaticGroup"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("GetUserCommand"))
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("ProgrammaticThreadPool"))
        ) {
            @Override
            protected User run() {
                return action.get();
            }
            @Override
            protected User getFallback() {
                return getDefaultUser(0L);
            }
        }.execute();
    }
}

进阶功能案例

自定义注解与配置

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HystrixRateLimit {
    String fallback() default "";
    int timeoutInMs() default 1000;
    int threadPoolSize() default 10;
}

配置化降级

@RestController
@RequestMapping("/api/advanced")
@Slf4j
public class AdvancedHystrixController {
    @Autowired
    private PaymentService paymentService;
    /**
     * 配置化的降级处理
     */
    @GetMapping("/payment/create")
    @HystrixCommand(
        fallbackMethod = "createPaymentFallback",
        commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000"),
            @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
        },
        threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "10"),
            @HystrixProperty(name = "maxQueueSize", value = "100")
        },
        ignoreExceptions = {IllegalArgumentException.class}
    )
    public PaymentResult createPayment(@RequestBody PaymentRequest request) {
        // 调用支付服务
        return paymentService.pay(request);
    }
    public PaymentResult createPaymentFallback(PaymentRequest request, Throwable throwable) {
        log.error("支付服务降级,原因:{}", throwable.getMessage());
        return PaymentResult.builder()
            .code("PAY_FALLBACK")
            .message("支付服务暂时不可用,请稍后重试")
            .fallbackTime(LocalDateTime.now())
            .build();
    }
    /**
     * 批量模式降级
     */
    @PostMapping("/batch/payments")
    @HystrixCommand(
        fallbackMethod = "batchPaymentFallback",
        commandProperties = {
            @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"),
            @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "20"),
            @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "10")
        }
    )
    public List<PaymentResult> batchPayments(@RequestBody List<PaymentRequest> requests) {
        return requests.stream()
            .map(paymentService::pay)
            .collect(Collectors.toList());
    }
}

服务间调用降级

@Component
@FeignClient(
    name = "order-service",
    fallbackFactory = OrderServiceFallbackFactory.class
)
public interface OrderServiceClient {
    @GetMapping("/api/orders/{orderId}")
    OrderResponse getOrderById(@PathVariable String orderId);
    @GetMapping("/api/orders/user/{userId}")
    List<OrderResponse> getUserOrders(@PathVariable Long userId);
    @PostMapping("/api/orders")
    OrderResponse createOrder(@RequestBody CreateOrderRequest request);
}
@Component
@Slf4j
public class OrderServiceFallbackFactory implements FallbackFactory<OrderServiceClient> {
    @Override
    public OrderServiceClient create(Throwable cause) {
        return new OrderServiceClient() {
            @Override
            public OrderResponse getOrderById(String orderId) {
                log.error("获取订单失败,orderId: {}, 原因: {}", orderId, cause.getMessage());
                return OrderResponse.builder()
                    .orderId(orderId)
                    .status("FALLBACK")
                    .errorMsg("订单服务不可用")
                    .build();
            }
            @Override
            public List<OrderResponse> getUserOrders(Long userId) {
                return Collections.singletonList(
                    OrderResponse.builder()
                        .userId(userId)
                        .status("FALLBACK")
                        .errorMsg("订单服务不可用")
                        .build()
                );
            }
            @Override
            public OrderResponse createOrder(CreateOrderRequest request) {
                return OrderResponse.builder()
                    .orderId("FALLBACK")
                    .status("FAILED")
                    .errorMsg("订单服务不可用")
                    .build();
            }
        };
    }
}

自定义Hystrix配置

配置文件

# application.yml
hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: THREAD
          thread:
            timeoutInMilliseconds: 3000
            timeoutEnabled: true
          semaphore:
            maxConcurrentRequests: 10
      circuitBreaker:
        enabled: true
        requestVolumeThreshold: 20
        sleepWindowInMilliseconds: 5000
        errorThresholdPercentage: 50
        forceOpen: false
        forceClosed: false
      metrics:
        rollingStats:
          timeInMilliseconds: 10000
          numBuckets: 10
      fallback:
        enabled: true
        isolation:
          semaphore:
            maxConcurrentRequests: 10
    getUserCommand:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000
      circuitBreaker:
        requestVolumeThreshold: 10
        sleepWindowInMilliseconds: 10000
        errorThresholdPercentage: 40
  threadpool:
    default:
      coreSize: 10
      maxQueueSize: 100
      queueSizeRejectionThreshold: 10
      keepAliveTimeMinutes: 1
      allowMaximumSizeToDivergeFromCoreSize: true
      maximumSize: 20
    userServiceThreadPool:
      coreSize: 5
      maxQueueSize: 50

监控配置

@Configuration
public class HystrixMetricsConfig {
    @Bean
    public HystrixMetricsPoller hystrixMetricsPoller() {
        return new HystrixMetricsPoller();
    }
    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

请求合并案例

@Service
public class RequestCollapsingService {
    @HystrixCollapser(
        scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
        batchMethod = "batchGetUsers",
        collapserProperties = {
            @HystrixProperty(name = "timerDelayInMilliseconds", value = "100"),
            @HystrixProperty(name = "maxRequestsInBatch", value = "100")
        }
    )
    public User getUserInfo(Long userId) {
        return new User();  // 这个方法的返回值会被批量方法覆盖
    }
    @HystrixCommand(commandKey = "batchGetUsers")
    public List<User> batchGetUsers(List<Long> userIds) {
        // 批量调用用户服务
        return userService.batchGetUsers(userIds);
    }
}

实际业务应用场景

电商系统降级案例

@RestController
@RequestMapping("/api/mall")
@Slf4j
public class MallController {
    @Autowired
    private ProductServiceClient productService;
    @Autowired
    private InventoryServiceClient inventoryService;
    @Autowired
    private PriceServiceClient priceService;
    /**
     * 商品详情页(多服务降级)
     */
    @GetMapping("/product/{id}")
    @HystrixCommand(
        fallbackMethod = "getProductDetailFallback",
        commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20")
        }
    )
    public ProductDetailVO getProductDetail(@PathVariable Long id) {
        // 并行调用多个服务
        CompletableFuture<Product> productFuture = 
            CompletableFuture.supplyAsync(() -> getProductWithFallback(id));
        CompletableFuture<Inventory> inventoryFuture = 
            CompletableFuture.supplyAsync(() -> getInventoryWithFallback(id));
        CompletableFuture<Price> priceFuture = 
            CompletableFuture.supplyAsync(() -> getPriceWithFallback(id));
        // 等待所有服务响应
        CompletableFuture.allOf(productFuture, inventoryFuture, priceFuture).join();
        return ProductDetailVO.builder()
            .product(productFuture.join())
            .inventory(inventoryFuture.join())
            .price(priceFuture.join())
            .status("SUCCESS")
            .build();
    }
    private Product getProductWithFallback(Long id) {
        try {
            return productService.getProduct(id);
        } catch (Exception e) {
            return Product.builder()
                .id(id)
                .name("商品信息获取失败")
                .fallback(true)
                .build();
        }
    }
    /**
     * 秒杀系统降级
     */
    @PostMapping("/seckill/{skuId}")
    @HystrixCommand(
        fallbackMethod = "seckillFallback",
        threadPoolKey = "seckillThreadPool",
        threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "5"),
            @HystrixProperty(name = "maxQueueSize", value = "50")
        },
        commandProperties = {
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000")
        }
    )
    public SeckillResult seckill(@PathVariable Long skuId, @RequestParam Long userId) {
        // 秒杀逻辑
        if (userId == null) {
            throw new IllegalArgumentException("非法参数");
        }
        return seckillService.doSeckill(skuId, userId);
    }
    public SeckillResult seckillFallback(Long skuId, Long userId, Throwable throwable) {
        log.warn("秒杀服务降级,skuId: {}, userId: {}, 原因: {}", skuId, userId, throwable.getMessage());
        return SeckillResult.builder()
            .code(500)
            .message("活动太火爆,请稍后重试")
            .fallback(true)
            .build();
    }
}

测试案例

@SpringBootTest
@RunWith(SpringRunner.class)
public class HystrixTest {
    @Autowired
    private UserClientController userClientController;
    @Test
    public void testFallback() {
        // 测试降级
        User user = userClientController.getUser(999L);
        assertNotNull(user);
        assertEquals("默认用户", user.getName());
        assertTrue(user.isFallback());
    }
    @Test
    public void testCircuitBreaker() {
        // 测试熔断器
        for (int i = 0; i < 50; i++) {
            try {
                userClientController.getUser(1000L + i);
            } catch (Exception e) {
                // 忽略异常
            }
        }
        // 检查熔断器状态
        HystrixCircuitBreaker breaker = HystrixCircuitBreaker.Factory.getInstance(
            HystrixCommandKey.Factory.asKey("getUserCommand")
        );
        assertNotNull(breaker);
        assertTrue(breaker.isOpen() || breaker.allowRequest());
    }
}

这些案例覆盖了Hystrix的核心功能,包括:

  • 基本降级处理
  • 自定义配置
  • 线程池隔离
  • 请求合并
  • 熔断器配置
  • 监控集成
  • 实际业务场景应用

你可以根据具体需求选择合适的实现方式,记得合理配置超时时间和降级策略,避免影响系统性能。

抱歉,评论功能暂时关闭!