这段时间接了个需求,需要在我目前负责的数据系统上加个接口,主要是实现用户行为的记录。前端对接的项目主要有公司的PC,WAP,WEIXIN,APP等,每个端大概有两台左右的负载。因为目前我的这个项目主要是面向内部,负责数据运营相关的内容,是个单体项目。如果线上各个接入点不做限制,瞬间大量的并发进入必然会导致目前项目的崩溃,其他的功能也无法正常使用。

1、需求分析

通过前期的需求分析,目前线上系统无法进行限流处理,所以最终解决问题还是要从接口入手。

目前我对接口的处理有两种实现方案:

  1. 可以利用MQ实现消息的错峰,将消息发送到MQ服务器。
  2. 实现对接口的隔离限流,避免当前接口对其他功能的影响。

其实我认为最好的实现方案就是第一种了,可以保证消息的准确送达,避免并发资源的占用。不过,因为公司条件的限制暂时不能新增中间件,所以只能在现有系统上进行改造,最后只能采用第二种方法了。

2、Hystrix的简单介绍

官方的定义就不说了,这里简单说下我的理解。Hystrix作为断路器主要是实现对服务的容错保护,简单来说就是服务隔离、服务降级、服务熔断,服务限流这几项。

举个常见的例子,当你某宝【抢购】一个产品时,经常会弹出[网络错误,请重试。]的提示,这种时候是真的网络问题吗?显示不是。这种情况下其实是对调用的接口进行了降级处理,当降级的次数或比例达到一定的条件后,断路器就会直接打开,之后的访问就会直接降级,而不会判断是否降级了。达到对服务的容错保护以及给用户友好提示的目的。详细的流程可以看下图。

一般Hystrix的容错保护在微服务中是用在客户端,也就是调用方。而我这次实际上是用在了提供方,主要是前台的项目我无法控制,只能在接口上想方法了。目前我使用Hystrix的主要目的就是实现对服务的隔离和限流,而对降级和熔断反而不是特别的关心,当然实际的使用要结合场景。

因为一般Tomcat默认是一个线程池150个线程,如果单个热点接口的请求过多,就会造成其他功能没有线程可用甚至直接程序崩溃的问题。Hystrix的服务隔离主要有两种,常用的就是线程池隔离的方式,对热点接口建立单独的线程池避免对主程序的影响。另一种是信号量的方式,用的场景不是太多。两者的区别其实就是一个增大系统的开销,一个则直接限制了线程总的并发数,开销更小一些。

Hystrix服务调用逻辑图

3、项目中的应用实现

本文是在传统Spring项目中的应用,Springboot中的相关配置和依赖有稍许的不同。

maven依赖:

  1. <!-- hystrix -->
  2. <dependency>
  3. <groupId>com.netflix.hystrix</groupId>
  4. <artifactId>hystrix-core</artifactId>
  5. <version>1.5.9</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.netflix.hystrix</groupId>
  9. <artifactId>hystrix-metrics-event-stream</artifactId>
  10. <version>1.5.9</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>com.netflix.hystrix</groupId>
  14. <artifactId>hystrix-javanica</artifactId>
  15. <version>1.5.9</version>
  16. </dependency>

在Spring的配置文件中配置Hystrix的切面信息

  1. <bean id="hystrixAspect" class="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"></bean>
  2. <aop:aspectj-autoproxy />

主要是开启注解的AOP扫描,这里我们可以在这个类的源码中看到实现

可以看到我们主要是通过这个类切面扫描Hystrix的相关注解,以达到接口处理前,提前执行Hystrix相关逻辑的代码。

  1. /**
  2. * 提供客户行为接口
  3. *
  4. */
  5. @Controller
  6. @RequestMapping(value = "/test")
  7. public class BehaviorController {
  8. Logger logger = Logger.getLogger(BehaviorController.class);
  9. @Autowired
  10. private BehaviorService behaviorService;
  11.  
  12. @RequestMapping(value="/addBehavior",method = RequestMethod.POST,produces = "application/json;charset=UTF-8")
  13. @ResponseBody
  14. @HystrixCommand(fallbackMethod = "fallback", threadPoolProperties = {
  15. @HystrixProperty(name = "coreSize", value = "20"), @HystrixProperty(name = "maxQueueSize", value = "100"),
  16. @HystrixProperty(name = "queueSizeRejectionThreshold", value = "20")},
  17. commandProperties = {
  18. @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "30000"),
  19. @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20")
  20.  
  21. })
  22. public String addBehavior(@RequestBody String parms) {
  23.  
  24. //业务逻辑实现
  25. return result;
  26. }
  27.  
  28. public String fallback(@RequestBody String parms){
  29. logger.info("fallback");
  30. //失败的实现
  31. return result;
  32. }
  33. }

注意:
请求的接口必须为public,fallback为降级的接口逻辑,可以为private,也可以为public。

但是要特别注意fallback方法的返回值和参数必须和请求方法相同

另外需要说的是,当请求失败、被拒绝、超时或者断路器打开时,都会进入回退方法,但是进入回退方法并不意味着断路器已经被打开。

4、常用参数的介绍

参数

描述

默认值

execution.isolation.strategy

隔离策略,有THREAD和SEMAPHORE

THREAD - 它在单独的线程上执行,并发请求受线程池中的线程数量的限制
SEMAPHORE - 它在调用线程上执行,并发请求受到信号量计数的限制

默认使用THREAD模式,以下几种场景可以使用SEMAPHORE模式:

只想控制并发度

外部的方法已经做了线程隔离

调用的是本地方法或者可靠度非常高、耗时特别小的方法(如medis)

execution.isolation.thread.timeoutInMilliseconds

超时时间

默认值:1000

在THREAD模式下,达到超时时间,可以中断

在SEMAPHORE模式下,会等待执行完成后,再去判断是否超时

设置标准:

有retry,99meantime+avg meantime

没有retry,99.5meantime

execution.timeout.enabled

HystrixCommand.run()执行是否应该有超时。

默认值:true

fallback.isolation.semaphore.maxConcurrentRequests

设置在使用时允许执行fallback方法的最大并发请求数

默认值:10

circuitBreaker.requestVolumeThreshold

设置滚动时间窗中,断路器熔断的最小请求数

默认值:20

滚动窗口默认10s,即10s内失败请求达到20个,熔断器即打开

coreSize

设置执行命令线程池的核心线程数。

默认值:10

maxQueueSize

设置执行命令线程池的核心线程数。

默认值:-1

当设置为-1时,线程池使用SynchronousQueue实现的队列,否则将使用LinkedBlockingQueue实现的队列

queueSizeRejectionThreshold

为队列设置拒绝阈值

默认值:5

当设置该参数后,即使队列没有达到最大值也能拒绝请求。

注意:当maxQueueSize属性为-1的时候,该属性不会生效

另外需要特别注意的是:fallback的属性maxConcurrentRequests,当请求达到了最大并发数时,后续的请求将会被拒绝并抛出异常(因为它已经没有后续的fallback可以被调用了),异常信息一般为com.netflix.hystrix.exception.HystrixRuntimeException: xxxxxxx fallback execution rejected.

更多参数见官方文档:https://github.com/Netflix/Hystrix/wiki/Configuration

另外附一个网友翻译的文档:https://blog.csdn.net/tongtong_use/article/details/78611225

5、接口测试

并发接口测试的方法很多,可以写代码,也可以用apache batch以及jmeter等工具。以常用的jmeter为例,测试本接口。

  1. 设置环境变量:
  2. JMETER_HOME D:\apache-jmeter-3.0
  3. CLASSPATH %JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;%JMETER_HOME%\lib\jorphan.jar;%JMETER_HOME%\lib/logkit-2.0.jar;

新建线程组:

设置并发参数:

第一个参数为线程数,第二个参数为启动时间,第三个参数为请求次数。以上述配置为例即为1秒内启动50个线程,每个线程请求一次。

添加HTTP请求

这里设置请求的路径,参数等等。

设置请求头信息,因人而异

我的设置:Content-Type:application/json

表格查看结果

查看结果:

这个可以根据机器的性能进行测试,以我的接口为例,当设置并发数为100以内时,基本上不会有降级处理,当并发数大于100时,就会有部分请求进入降级接口了。

6、接口监控

实际项目中,经常需要对我们的接口和项目情况进行监控,Hystrix已经为我们考虑到了。Hystrix提供了近乎实时的监控,Hystrix会实时的,累加的记录所有关于HystrixCommand的执行信息,包括执行了每秒执行了多少请求,多少成功,多少失败等等,更多指标请查看:https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring

在web.xml中添加下述配置:

  1. <!-- for Hystrix -->
  2. <servlet>
  3. <display-name>HystrixMetricsStreamServlet</display-name>
  4. <servlet-name>HystrixMetricsStreamServlet</servlet-name>
  5. <servlet-class>com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet</servlet-class>
  6. </servlet>
  7.  
  8. <servlet-mapping>
  9. <servlet-name>HystrixMetricsStreamServlet</servlet-name>
  10. <url-pattern>/hystrix.stream</url-pattern>
  11. </servlet-mapping>

启动应用。访问http://hostname:port/项目名/hystrix.stream,可以看到下面信息

这种是最原生的监控使用方式,大家可以另外集成Hystrix 提供的一个 Dashboard 应用。Dashboard 是一个单独的应用,我们可以独立部署。如果需要监控整个 Hystrix 集群,就需要使用 Turbine 应用。Turbine 也是 Netflix 开源的一个服务。但是使用 Hystrix Stream 和 Turbine 存在一个明显的不足,那就是无法查看历史的监控数据。解决这个问题就需要我们自己来实现了。

监控的相关不是本文的重点,就不多介绍了,大家可以百度下hystrix在微服务项目中监控的实现,这里网上文章很多,基本上和传统项目没有任何区别了,大家可以参考实现。

传统项目利用Hystrix实现热点接口的服务隔离的更多相关文章

  1. springboot项目利用Swagger2生成在线接口文档

    Swagger简介. Swagger2是一款restful接口文档在线生成和在线调试工具.很多项目团队利用Swagger自动生成接口文档,保证接口文档和代码同步更新.在线调试.简单地说,你可以利用这个 ...

  2. Spring Cloud实战之初级入门(四)— 利用Hystrix实现服务熔断与服务监控

    目录 1.环境介绍 2.服务监控 2.1 加入依赖 2.2 修改配置文件 2.3 修改启动文件 2.4 监控服务 2.5 小结 3. 利用hystrix实现消费服务熔断 3.1 加入服务熔断 3.2 ...

  3. Dubbo 项目与传统项目

    1.什么是传统工程 单工程 MVC 架构 控制层通过调用服务层完成业务逻辑处理 业务层调用持久层进程数据操作 2.什么是分布式工程 将传统项目的单工程结构,拆分成多工程 一般会有这几个工程: 父工程: ...

  4. SpringBoot项目集成Hystrix

    Hystrix Hystrix是由Netflix开源的一个服务隔离组件,通过服务隔离来避免由于依赖延迟.异常,引起资源耗尽导致系统不可用的解决方案. 1.什么是服务熔断   服务熔断就是对该服务的调用 ...

  5. 利用python3 调用zabbix接口完成批量加聚合图形(screens)

    在上一篇博客中,我们完成的利用python3 调用zabbix接口批量增加主机,增加主机的item,增加主机的图形! 接下来我们完成批量增加主机的screen 首先我们要增加screen需要哪些参数呢 ...

  6. Winform项目调用asp.net数据接口

    最近一个WPF项目需要改写成android项目,思路是在asp.net项目中编写一个通用接口,便于其它平台下调用数据.刚接触到这些东西的时候完全是一头雾水,最根本的原因是不明白网站中的一个网页,为什么 ...

  7. 若依项目利用nginx实现负载均衡及保持会话

    记录一下若依项目利用nginx实现负载均衡及保持会话的步骤. 此次作为试验性的测试,为了方便在本地window的环境上实现. 具体步骤: 1.安装两个tomcat8,可以下载一个后,另一个复制即可,下 ...

  8. 关于传统项目打成war包的的分析

    技术在不断的革新,以前的项目没有jar管理工具时,都是手动将依赖的jar拷贝到项目之下,然后Build Path,之后Maven出现了,出现了jar包中央仓库,所有的jar包资源集中在这里,免去频繁去 ...

  9. laravel项目利用twemproxy部署redis集群的完整步骤

    Twemproxy是一个代理服务器,可以通过它减少Memcached或Redis服务器所打开的连接数.下面这篇文章主要给大家介绍了关于laravel项目利用twemproxy部署redis集群的相关资 ...

随机推荐

  1. 在 R 中使用 Python 字符串函数

    sprintf( )函数很强大,但并非适用于所有应用场景.例如,如果一些部分在模板中多次出现,那么就需要多次写一样的参数.这通常会使得代码冗长而且难以修改:sprintf("%s, %d y ...

  2. MQ是什么 RabbitMQ

    一.rabbitMQ是什么: RabbitMQ,遵循AMQP协议,由内在高并发的erlanng语言开发,用在实时的对可靠性要求比较高的消息传递上. 学过websocket的来理解rabbitMQ应该是 ...

  3. UTF-8里包括GB2312

    用最易懂的说法就是UTF-8里包括GB2312.UTF-8是国际通用的标准(包括世界所有的语言),而GB2312(只是简体中文)只适合做中文的网站. 假设你想做个中文网页,但是还可以翻成英文的话,就得 ...

  4. Rails 5 Test Prescriptions 第7章 double stub mock

    https://relishapp.com/rspec/rspec-mocks/v/3-7/docs/basics/test-doubles 你有一个问题,如果想为程序添加一个信用卡程序用于自己挣钱. ...

  5. a标记无效问题

    当在<a href=''></a>这个标记中嵌入<td></td>  就会导致部分浏览器无法单击,所以在开发HTML页面的时候,一定不要在 a标记中嵌入 ...

  6. Lucene Scoring 评分机制

    原文出处:http://blog.chenlb.com/2009/08/lucene-scoring-architecture.html Lucene 评分体系/机制(lucene scoring)是 ...

  7. 单链表是否有环的问题解决与讨论(java实现)

    单链表是否有环的问题经常在面试中遇到,一般面试中会要求空间为O(1);再者求若有环,则求环产生时的起始位置. 下面采用java实现. //单链表class ListNode{ int val; Lis ...

  8. flex布局在垂直居中里,元素超过容器大小后,不能通过滚动条滚动到顶端,这是个flex的bug

    The Problem Flexbox makes centering very easy. By simply applying align-items: center and justify-co ...

  9. java日常知识点积累

    java类型中的普通非static方法 示例代码: package com.lvzhi; /** * Created by lvzhi on 2017/9/3 */ public class MyTh ...

  10. 首次运行tensorflow-gpu 1.0 报错 failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED

    发现博客: https://blog.csdn.net/u010752600/article/details/79534910 于是找到解决方法. sudo rm -rf ~/.nv/