hystrix降级预热问题
作者:互联网
hystrix降级预热问题
1、问题描述
模拟hystrix
在高并发条件下流量降级处理。设计使用多级降级策略。但是在使用测试时发现第一次直接就不断的降级一直到最低级策略。当使用httpclient
客户端模拟请求时,一直在降级。
2、问题分析
这是由于java
程序在初次服务时效率总是很低。对用户发送的请求需要花很长时间处理。所以服务就自动降级了。
3、问题解决
如果是使用浏览器访问,则再访问一次就可以了。在java
分布式开发过程中,有很多时候明明代码写的都是正确的,但是实验的结果总是和预期不符。这里很大一部分是这个原因,尤其是在使用httpclient
客户端模拟请求时。这里我们还是需要使用浏览器测试。
首先模拟一个服务。返回产品信息。
package com.njust.eshop.product.ha.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.njust.eshop.product.ha.utils.HttpClientUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* 缓存服务的接口
*
* @author Administrator
*/
@RestController
public class ProductController {
@RequestMapping("/getProductInfo")
public String getProductInfo(Long productId) {
return "{\"id\": " + productId + ", \"name\": \"iphone7手机1\", \"price\": 5599, \"pictureList\":\"a.jpg,b.jpg\", \"specification\": \"iphone7的规格\", \"service\": \"iphone7的售后服务\", \"color\": \"红色,白色,黑色\", \"size\": \"5.5\", \"shopId\": 1, \"modifiedTime\": \"2017-01-01 12:00:00\", \"cityId\": 1, \"brandId\": 1}";
}
}
接着定义hystrix
降级策略。这里假设用户的productId
为-1的时候采用一级降级,当productId
为-2的时候采用二级降级。
package com.njust.eshop.cache.ha.hystrix.command;
import com.alibaba.fastjson.JSONObject;
import com.netflix.hystrix.*;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;
import com.njust.eshop.cache.ha.cache.local.BrandCache;
import com.njust.eshop.cache.ha.cache.local.LocationCache;
import com.njust.eshop.cache.ha.entity.ProductInfo;
import com.njust.eshop.cache.ha.utils.HttpClientUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 获取商品信息
*
* @author Administrator
*/
public class GetProductInfoCommand extends HystrixCommand<ProductInfo> {
public static final HystrixCommandKey KEY = HystrixCommandKey.Factory.asKey("GetProductInfoCommand");
private Long productId;
public GetProductInfoCommand(Long productId) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ProductInfoService"))
.andCommandKey(KEY)
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GetProductInfoPool"))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(10)
.withMaxQueueSize(12)
.withQueueSizeRejectionThreshold(15))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withCircuitBreakerRequestVolumeThreshold(30)
.withCircuitBreakerErrorThresholdPercentage(40)
.withCircuitBreakerSleepWindowInMilliseconds(3000)
.withExecutionTimeoutInMilliseconds(500)
.withFallbackIsolationSemaphoreMaxConcurrentRequests(30))
);
// super(HystrixCommandGroupKey.Factory.asKey("ProductInfoService"));
this.productId = productId;
}
@Override
protected ProductInfo run() throws Exception {
// System.out.println("调用接口,查询商品数据,productId=" + productId);
//
if (productId.equals(-1L)) {
throw new Exception();
}
if (productId.equals(-2L)) {
throw new Exception();
}
//
// if(productId.equals(-2L)) {
// Thread.sleep(3000);
// }
//
// if(productId.equals(-3L)) {
//// Thread.sleep(250);
// }
String url = "http://127.0.0.1:8084/getProductInfo?productId=" + productId;
String response = HttpClientUtils.sendGetRequest(url);
return JSONObject.parseObject(response, ProductInfo.class);
}
// @Override
// protected String getCacheKey() {
// return "product_info_" + productId;
// }
@Override
protected ProductInfo getFallback() {
System.out.println("--------getFallback-------------------");
return new FirstLevelFallbackCommand(productId).execute();
}
private static class FirstLevelFallbackCommand extends HystrixCommand<ProductInfo> {
private Long productId;
public FirstLevelFallbackCommand(Long productId) {
// 第一级的降级策略,因为这个command是运行在fallback中的
// 所以至关重要的一点是,在做多级降级的时候,要将降级command的线程池单独做一个出来
// 如果主流程的command都失败了,可能线程池都已经被占满了
// 降级command必须用自己的独立的线程池
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ProductInfoService"))
.andCommandKey(HystrixCommandKey.Factory.asKey("FirstLevelFallbackCommand"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("FirstLevelFallbackPool")));
this.productId = productId;
}
@Override
protected ProductInfo run() throws Exception {
// 这里,因为是第一级降级的策略,所以说呢,其实是要从备用机房的机器去调用接口
// 但是,我们这里没有所谓的备用机房,所以说还是调用同一个服务来模拟
System.out.println("-------------------response-------------------: ");
if (productId.equals(-2L)) {
throw new Exception();
}
System.out.println("-------------------response-------------------: ");
String url = "http://127.0.0.1:8084/getProductInfo?productId=" + productId;
String response = HttpClientUtils.sendGetRequest(url);
System.out.println("response: " + response);
return JSONObject.parseObject(response, ProductInfo.class);
}
@Override
protected ProductInfo getFallback() {
System.out.println("-------------------response---getFallback----------------: ");
// 第二级降级策略,第一级降级策略,都失败了
ProductInfo productInfo = new ProductInfo();
// 从请求参数中获取到的唯一条数据
productInfo.setId(productId);
// 从本地缓存中获取一些数据
productInfo.setBrandId(BrandCache.getBrandId(productId));
productInfo.setBrandName(BrandCache.getBrandName(productInfo.getBrandId()));
productInfo.setCityId(LocationCache.getCityId(productId));
productInfo.setCityName(LocationCache.getCityName(productInfo.getCityId()));
// 手动填充一些默认的数据
productInfo.setColor("默认颜色 第二级降级策略");
productInfo.setModifiedTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
productInfo.setName("默认商品");
productInfo.setPictureList("default.jpg");
productInfo.setPrice(0.0);
productInfo.setService("默认售后服务");
productInfo.setShopId(-1L);
productInfo.setSize("默认大小");
productInfo.setSpecification("默认规格");
return productInfo;
}
}
public static void flushCache(Long productId) {
HystrixRequestCache.getInstance(KEY,
HystrixConcurrencyStrategyDefault.getInstance()).clear("product_info_" + productId);
}
}
定义浏览器测试类,测试该降级策略。这里模拟使用一级降级策略。
package com.njust.eshop.cache.ha.controller;
import com.njust.eshop.cache.ha.hystrix.command.GetProductInfoCommand;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Chen
* @version 1.0
* @date 2020/4/12 16:52
* @description:
*/
@RestController
public class TestController {
@RequestMapping("testMutil")
public String testMutil() {
GetProductInfoCommand getProductInfoCommand1 = new GetProductInfoCommand(-1L);
// Thread.sleep(3000);
// System.out.println(getProductInfoCommand1.execute());
// GetProductInfoCommand getProductInfoCommand2 = new GetProductInfoCommand(-2L);
// System.out.println(getProductInfoCommand2.execute());
// Thread.sleep(5000);
return getProductInfoCommand1.execute().toString();
}
}
运行两个服务器,输出结果为:
第一次直接输出二级降级数据,明显不符合预期。再次刷新浏览器。我们发现可以获取到正常结果。
控制台输出结果如下;
--------getFallback-------------------
-------------------response-------------------:
-------------------response-------------------:
-------------------response---getFallback----------------:
response: {"id": -1, "name": "iphone7手机", "price": 5599, "pictureList":"a.jpg,b.jpg", "specification": "iphone7的规格", "service": "iphone7的售后服务", "color": "红色,白色,黑色", "size": "5.5", "shopId": 1, "modifiedTime": "2017-01-01 12:00:00", "cityId": 1, "brandId": 1}
--------getFallback-------------------
-------------------response-------------------:
-------------------response-------------------:
response: {"id": -1, "name": "iphone7手机", "price": 5599, "pictureList":"a.jpg,b.jpg", "specification": "iphone7的规格", "service": "iphone7的售后服务", "color": "红色,白色,黑色", "size": "5.5", "shopId": 1, "modifiedTime": "2017-01-01 12:00:00", "cityId": 1, "brandId": 1}
--------getFallback-------------------
-------------------response-------------------:
-------------------response-------------------:
response: {"id": -1, "name": "iphone7手机1", "price": 5599, "pictureList":"a.jpg,b.jpg", "specification": "iphone7的规格", "service": "iphone7的售后服务", "color": "红色,白色,黑色", "size": "5.5", "shopId": 1, "modifiedTime": "2017-01-01 12:00:00", "cityId": 1, "brandId": 1}
其实我们发现第一次请求的时候已经获取到http的请求结果,但是由于超时的原因直接降级了。
下面来直接编写测试类。测试类的好处就是不需要启动服务器,测试便捷。
package com.njust.eshop.cache.ha;
import com.njust.eshop.cache.ha.hystrix.command.GetProductInfoCommand;
/**
* @author Chen
* @version 1.0
* @date 2020/4/11 19:44
* @description:
*/
public class MultiLevelFallbackTest {
public static void main(String[] args) throws Exception {
GetProductInfoCommand getProductInfoCommand1 = new GetProductInfoCommand(-1L);
// Thread.sleep(3000);
System.out.println(getProductInfoCommand1.execute());
// GetProductInfoCommand getProductInfoCommand2 = new GetProductInfoCommand(-2L);
// System.out.println(getProductInfoCommand2.execute());
// Thread.sleep(5000);
}
}
这里的逻辑和上面的一样。直接运行测试类。输出结果如下:
-------------------response-------------------:
-------------------response-------------------:
-------------------response---getFallback----------------:
ProductInfo(id=-1, name=默认商品, price=0.0, pictureList=default.jpg, specification=默认规格, service=默认售后服务, color=默认颜色 第二级降级策略, size=默认大小, shopId=-1, modifiedTime=2020-04-12 17:14:15, cityId=1, cityName=北京, brandId=1, brandName=iphone)
这里我们发现无论我们运行多少次,都是直接使用的二级降级的策略。因为每次我们测试只是相当于第一次。控制台输出结果:
-------------------response-------------------:
-------------------response-------------------:
-------------------response---getFallback----------------:
ProductInfo(id=-1, name=默认商品, price=0.0, pictureList=default.jpg, specification=默认规格, service=默认售后服务, color=默认颜色 第二级降级策略, size=默认大小, shopId=-1, modifiedTime=2020-04-12 17:30:26, cityId=1, cityName=北京, brandId=1, brandName=iphone)
4、总结
由于java
有编译优化的功能,所以当测试类不行的时候,直接走正常测试吧。
点个赞再走呗!欢迎留言哦!
标签:降级,预热,hystrix,productInfo,import,com,response,productId 来源: https://blog.csdn.net/qq_32510597/article/details/105472788