Hystrix面试 - 基于 request cache 请求缓存技术优化批量商品数据查询接口

Hystrix command 执行时 8 大步骤第三步,就是检查 Request cache 是否有缓存。

首先,有一个概念,叫做 Request Context 请求上下文,一般来说,在一个 web 应用中,如果我们用到了 Hystrix,我们会在一个 filter 里面,对每一个请求都施加一个请求上下文。就是说,每一次请求,就是一次请求上下文。然后在这次请求上下文中,我们会去执行 N 多代码,调用 N 多依赖服务,有的依赖服务可能还会调用好几次。

在一次请求上下文中,如果有多个 command,参数都是一样的,调用的接口也是一样的,而结果可以认为也是一样的。那么这个时候,我们可以让第一个 command 执行返回的结果缓存在内存中,然后这个请求上下文后续的其它对这个依赖的调用全部从内存中取出缓存结果就可以了。

这样的话,好处在于不用在一次请求上下文中反复多次执行一样的 command,避免重复执行网络请求,提升整个请求的性能

举个栗子。比如说我们在一次请求上下文中,请求获取 productId 为 1 的数据,第一次缓存中没有,那么会从商品服务中获取数据,返回最新数据结果,同时将数据缓存在内存中。后续同一次请求上下文中,如果还有获取 productId 为 1 的数据的请求,直接从缓存中取就好了。

HystrixCommand 和 HystrixObservableCommand 都可以指定一个缓存 key,然后 Hystrix 会自动进行缓存,接着在同一个 request context 内,再次访问的话,就会直接取用缓存。

下面,我们结合一个具体的业务场景,来看一下如何使用 request cache 请求缓存技术。当然,以下代码只作为一个基本的 Demo 而已。

现在,假设我们要做一个批量查询商品数据的接口,在这个里面,我们是用 HystrixCommand 一次性批量查询多个商品 id 的数据。但是这里有个问题,如果说 Nginx 在本地缓存失效了,重新获取一批缓存,传递过来的 productIds 都没有进行去重,比如 productIds=1,1,1,2,2,那么可能说,商品 id 出现了重复,如果按照我们之前的业务逻辑,可能就会重复对 productId=1 的商品查询三次,productId=2 的商品查询两次。

我们对批量查询商品数据的接口,可以用 request cache 做一个优化,就是说一次请求,就是一次 request context,对相同的商品查询只执行一次,其余重复的都走 request cache。

实现 Hystrix 请求上下文过滤器并注册

定义 HystrixRequestContextFilter 类,实现 Filter 接口。

/*** Hystrix 请求上下文过滤器*/
public class HystrixRequestContextFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {HystrixRequestContext context = HystrixRequestContext.initializeContext();try {filterChain.doFilter(servletRequest, servletResponse);} catch (IOException | ServletException e) {e.printStackTrace();} finally {context.shutdown();}}@Overridepublic void destroy() {}
}

然后将该 filter 对象注册到 SpringBoot Application 中。

@SpringBootApplication
public class EshopApplication {public static void main(String[] args) {SpringApplication.run(EshopApplication.class, args);}@Beanpublic FilterRegistrationBean filterRegistrationBean() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new HystrixRequestContextFilter());filterRegistrationBean.addUrlPatterns("/*");return filterRegistrationBean;}
}

command 重写 getCacheKey() 方法

在 GetProductInfoCommand 中,重写 getCacheKey() 方法,这样的话,每一次请求的结果,都会放在 Hystrix 请求上下文中。下一次同一个 productId 的数据请求,直接取缓存,无须再调用 run() 方法。

public class GetProductInfoCommand extends HystrixCommand<ProductInfo> {private Long productId;private static final HystrixCommandKey KEY = HystrixCommandKey.Factory.asKey("GetProductInfoCommand");public GetProductInfoCommand(Long productId) {super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ProductInfoService")).andCommandKey(KEY));this.productId = productId;}@Overrideprotected ProductInfo run() {String url = "http://localhost:8081/getProductInfo?productId=" + productId;String response = HttpClientUtils.sendGetRequest(url);System.out.println("调用接口查询商品数据,productId=" + productId);return JSONObject.parseObject(response, ProductInfo.class);}/*** 每次请求的结果,都会放在Hystrix绑定的请求上下文上** @return cacheKey 缓存key*/@Overridepublic String getCacheKey() {return "product_info_" + productId;}/*** 将某个商品id的缓存清空** @param productId 商品id*/public static void flushCache(Long productId) {HystrixRequestCache.getInstance(KEY,HystrixConcurrencyStrategyDefault.getInstance()).clear("product_info_" + productId);}
}

这里写了一个 flushCache() 方法,用于我们开发手动删除缓存。

controller 调用 command 查询商品信息

在一次 web 请求上下文中,传入商品 id 列表,查询多条商品数据信息。对于每个 productId,都创建一个 command。

如果 id 列表没有去重,那么重复的 id,第二次查询的时候就会直接走缓存。

@Controller
public class CacheController {/*** 一次性批量查询多条商品数据的请求** @param productIds 以,分隔的商品id列表* @return 响应状态*/@RequestMapping("/getProductInfos")@ResponseBodypublic String getProductInfos(String productIds) {for (String productId : productIds.split(",")) {// 对每个productId,都创建一个commandGetProductInfoCommand getProductInfoCommand = new GetProductInfoCommand(Long.valueOf(productId));ProductInfo productInfo = getProductInfoCommand.execute();System.out.println("是否是从缓存中取的结果:" + getProductInfoCommand.isResponseFromCache());}return "success";}
}

发起请求

调用接口,查询多个商品的信息。

http://localhost:8080/getProductInfos?productIds=1,1,1,2,2,5

在控制台,我们可以看到以下结果。

调用接口查询商品数据,productId=1
是否是从缓存中取的结果:false
是否是从缓存中取的结果:true
是否是从缓存中取的结果:true
调用接口查询商品数据,productId=2
是否是从缓存中取的结果:false
是否是从缓存中取的结果:true
调用接口查询商品数据,productId=5
是否是从缓存中取的结果:false

第一次查询 productId=1 的数据,会调用接口进行查询,不是从缓存中取结果。而随后再出现查询 productId=1 的请求,就直接取缓存了,这样的话,效率明显高很多。

删除缓存

我们写一个 UpdateProductInfoCommand,在更新商品信息之后,手动调用之前写的 flushCache(),手动将缓存删除。

public class UpdateProductInfoCommand extends HystrixCommand<Boolean> {private Long productId;public UpdateProductInfoCommand(Long productId) {super(HystrixCommandGroupKey.Factory.asKey("UpdateProductInfoGroup"));this.productId = productId;}@Overrideprotected Boolean run() throws Exception {// 这里执行一次商品信息的更新// ...// 然后清空缓存GetProductInfoCommand.flushCache(productId);return true;}
}

这样,以后查询该商品的请求,第一次就会走接口调用去查询最新的商品信息。

转载来源:https://github.com/doocs/advanced-java/blob/master/docs/high-availability/hystrix-request-cache.md

Hystrix面试 - 基于 request cache 请求缓存技术优化批量商品数据查询接口相关推荐

  1. vue获取商品数据接口_基于 request cache 请求缓存技术优化批量商品数据查询接口...

    Hystrix command 执行时 8 大步骤第三步,就是检查 Request cache 是否有缓存. 首先,有一个概念,叫做 Request Context 请求上下文,一般来说,在一个 we ...

  2. hystrix基于request cache请求缓存技术优化批量数据查询接口

    1.创建command,2种command类型 2.执行command,4种执行方式 3.查找是否开启了request cache,是否有请求缓存,如果有缓存,直接取用缓存,返回结果 首先,有一个概念 ...

  3. Hystrix面试 - 基于 Hystrix 线程池技术实现资源隔离

    Hystrix面试 - 基于 Hystrix 线程池技术实现资源隔离 上一讲提到,如果从 Nginx 开始,缓存都失效了,Nginx 会直接通过缓存服务调用商品服务获取最新商品数据(我们基于电商项目做 ...

  4. Hystrix面试 - 基于本地缓存的 fallback 降级机制

    Hystrix面试 - 基于本地缓存的 fallback 降级机制 Hystrix 出现以下四种情况,都会去调用 fallback 降级机制: 断路器处于打开的状态. 资源池已满(线程池+队列 / 信 ...

  5. Hystrix面试 - 基于 Hystrix 信号量机制实现资源隔离

    Hystrix面试 - 基于 Hystrix 信号量机制实现资源隔离 Hystrix 里面核心的一项功能,其实就是所谓的资源隔离,要解决的最最核心的问题,就是将多个依赖服务的调用分别隔离到各自的资源池 ...

  6. Hystrix面试 - 基于 timeout 机制为服务接口调用超时提供安全保护

    Hystrix面试 - 基于 timeout 机制为服务接口调用超时提供安全保护 一般来说,在调用依赖服务的接口的时候,比较常见的一个问题就是超时.超时是在一个复杂的分布式系统中,导致系统不稳定,或者 ...

  7. node.js request get 请求怎么拿到返回的数据_NodeJS运维: 从 0 开始 Prometheus + Grafana 业务性能指标监控...

    为什么需要指标监控告警 一个复杂的应用,往往由很多个模块组成,而且往往会存在各种各样奇奇怪怪的使用场景,谁也不能保证自己维护的服务永远不会出问题,等用户投诉才发现问题再去处理问题就为时已晚,损失已无法 ...

  8. node.js request get 请求怎么拿到返回的数据_从零开始用nodejs写一个简单的静态服务器

    nodejs搭建服务器第一步 const http = require("http")const PORT = 8000 const server = http.createSer ...

  9. jsp 页面刷新_如何应用XML+XSLT+AJAX组合技术实现无刷新数据查询

    软件项目实训及课程设计指导--如何应用XML +XSLT +AJAX组合技术实现无刷新的数据查询的应用实例 1.在Web应用系统项目中添加一个实现查询的请求页面searchBook.jsp (1)创建 ...

最新文章

  1. operator conv_transpose1‘s input 1 is not linked
  2. Vijos p1165 火烧赤壁 离散化+单调栈
  3. -bash: jps: command not found
  4. 【转载】dirs、pushd、popd指令
  5. 浅谈ATP检查中的“确认可用部分数量”(一)
  6. java chinapay_通过PHP/Java Bridge来实现ecshop的chinapay支付接口
  7. PHP代码审计笔记--变量覆盖漏洞
  8. C语言课后习题(38)
  9. 中建股份400亿大型IPO获“特批”
  10. 推理框架runtime的动态输入、输出思路
  11. Linux中fasttext安装
  12. 如何把图纸转换为t3格式_CAD图纸快速转换天正T3格式_鹏业CAD云服务
  13. java计算机毕业设计基于安卓Android的团务智慧管理APP
  14. java.sql.SQLException:
  15. 当我们给别人提意见时,要注意些什么?
  16. 廖雪峰git教程阅读之一
  17. 【读论文】Self-supervised feature adaption for infrared and visible image fusion
  18. Python 基础代码
  19. EFR32 资源汇总
  20. python实现括号匹配算法_Python实现括号匹配方法详解

热门文章

  1. CSS3: 常用动画特效及4个最流行的动画库
  2. 零基础 Amazon Web Services (AWS) 入门教程图文版(一)
  3. Magento 1.9.2 Unknown cipher in list: TLSv1
  4. Magento 默认排序为最新 How to sort Magento products by date added as default
  5. 3K 万能JQuery弹出层类库
  6. Centos7上kvm虚拟化自定义NAT网络
  7. TensorFlow指定特定GPU以及占用显存的比例
  8. 文件从一台服务器拷贝到另一台服务器
  9. 办公自动化-幻灯片中插入图片与表格-pptx模块-0225
  10. python-办公自动化-索引-202002