精华内容
下载资源
问答
  • <div><p>Nepxion版本: 6.5.1 Discovery Agent版本: 1.0.1 IDE: Intellj idea ...并使用javaagent进行多线程调用,【RequestContextHolder.getRequestAttributes()】报空指针的错 报错类型: ...
  • 场景:在Mq的监听中,去调用其他的微服务,在对Feign进行拦截的时候报错 在链路拦截日志的RequestInterceptor中,我们可以看到通过下面方法,没有取得request的信息 RequestContextHolder.currentRequestAttributes...

    报错信息:

    No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

     

    场景:在Mq的监听中,去调用其他的微服务,在对Feign进行拦截的时候报错

    在链路拦截日志的RequestInterceptor中,我们可以看到通过下面方法,没有取得request的信息

    RequestContextHolder.currentRequestAttributes()

     通过源码可以查看到是从当前ThreadLocal 中获取上下文的RequestAtrributes

     

     当拿不到request时,创建NonWebRequestAttributes来实现RequestAttributes,然后加一个非空判断绕过强转的地方,这样就能正常的调用其他服务了

    
    @Component
    public class LogFeignInterceptor implements RequestInterceptor {
        public LogFeignInterceptor() {
        }
    
        public void apply(RequestTemplate requestTemplate) {
            HttpServletRequest httpRequest = this.getHttpServletRequestSafely();
            if (null != httpRequest && null != httpRequest.getAttribute("X-Request-No")) {
                requestTemplate.header("X-Request-No", new String[]{httpRequest.getAttribute("X-Request-No").toString()});
            }
    
        }
    
        public HttpServletRequest getHttpServletRequestSafely() {
            try {
                RequestAttributes requestAttributesSafely = this.getRequestAttributesSafely();
                return requestAttributesSafely instanceof NonWebRequestAttributes ? null : ((ServletRequestAttributes)requestAttributesSafely).getRequest();
            } catch (Exception var2) {
                return null;
            }
        }
    
        public RequestAttributes getRequestAttributesSafely() {
            Object requestAttributes = null;
    
            try {
                requestAttributes = RequestContextHolder.currentRequestAttributes();
            } catch (IllegalStateException var3) {
                requestAttributes = new NonWebRequestAttributes();
            }
    
            return (RequestAttributes)requestAttributes;
        }
    }

    展开全文
  • FeignClient注解中配置的fallback,不需要非阻塞操作、也不需要重试,hystrix 调用feign时候做了线程池隔离处理,这样增加了项目复杂度(线程池参数配置、线程少了请求服务直接拒绝,线程得管理。。。) 目前...

    需求描述

    spring cloud 项目中feign 整合 hystrix经常使用,但是最近发现hystrix功能强大,但是对我们来说有些大材小用。
    首先我只需要他的一个熔断作用,就是说请求超时、异常了返回 FeignClient注解中配置的fallback,不需要非阻塞操作、也不需要重试,hystrix 调用feign时候做了线程池隔离处理,这样增加了项目复杂度(线程池参数配置、线程少了请求服务直接拒绝,多了线程得管理。。。)
    目前feign 超时之后是直接抛异常的,这样的话虽然是及时熔断了,但是正常的程序逻辑不走了配置的fallback也没有作用,这个配置项得配合 hystrix 才行。
    我需要的是这样的效果

      try{
         feign.api();
      }catch(){
     	return fallback();
     }
    

    但是每个feign调用都手动加上try..catch 实在是太low了,最好能写个类似切面一样的玩意。

    这时候就想到了 hystrix,既然人家框架已经做了,我直接看下代码,copy不完了么

    源码学习

    前两天发布了一篇文章也是关于feign、hystrix 调用集成的
    基于之前的分析关键代码 HystrixInvocationHandler (feign.hystrix)

    @Override
      public Object invoke(final Object proxy, final Method method, final Object[] args)
          throws Throwable {
        .............
    	 // setterMethodMap 封装 hystrixCommand 配置信息(超时时间、是否重试.....)
        HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) {
          @Override
          protected Object run() throws Exception {
            ....
            HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
          	....
          }
    
          @Override
          protected Object getFallback() {
            .........
          }
        };
    
       ......
        return hystrixCommand.execute();
      }
    

    按照之前分析源码方式,直接看哪里被调用了就可以看到, hystrix 实际上自己封装了一个 feign.Builer 类名是 feign.hystrix.HystrixFeign.Builder 用的是建造者模式,生成的类是在调用服务时用到
    看到 关键的 build() 方法

    Feign build(final FallbackFactory<?> nullableFallbackFactory) {
          super.invocationHandlerFactory(new InvocationHandlerFactory() {
            // 重新定义一个 InvocationHandler 实现 类似 aop效果
            @Override public InvocationHandler create(Target target,
                Map<Method, MethodHandler> dispatch) {
              return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory);
            }
          });
          super.contract(new HystrixDelegatingContract(contract));
          return super.build();
        }
    

    spring 动态代理我这里不多说了,核心就是 InvocationHandler (如果是jdk动态代理的话),那么 feign 这里也是,我们看看feign 调用声明是个接口,实际上是spring 动态代理生成了代理类,调用方法时实际调用的是 java.lang.reflect.InvocationHandler#invoke

    方案构想

    那么我们只需要借鉴下 hystrix 的方式,自己实现一个feign.build ,将 InvocationHandler 换成自己的,
    然后在我们自己的 InvocationHandler 中调用feign 官方的 InvocationHandler 就行,也就是 feign.hystrix.HystrixInvocationHandler#invoke这个方法中的this.dispatch.get(method).invoke(args);这个代码

    方案具体代码实现

    方案一

    自己实现

    import feign.Feign;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.stereotype.Component;
    
    /**
     * 自定义feign 构建
     * @author hgf
     */
    public class CusFeignBuilder extends Feign.Builder{
    
        public CusFeignBuilder() {
    
            this.invocationHandlerFactory((target, dispatch) -> {
                Class<?> type = target.type();
                FeignClient annotation = type.getAnnotation(FeignClient.class);
    
                // 构造 fallback 实例
                Object fallBackObj = null;
                if (annotation != null && !annotation.fallback().equals(void.class)) {
    
                    try {
                        fallBackObj = annotation.fallback().newInstance();
                    } catch (InstantiationException | IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
    
                return new CusFeignInvocationHandler(target, dispatch, fallBackObj);
            });
        }
    
    
    }
    
    
    import feign.Feign;
    import feign.InvocationHandlerFactory;
    import feign.Target;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.openfeign.FeignClient;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    import static com.eco.common.utils.Md5Util.logger;
    import static feign.Util.checkNotNull;
    
    /**
     * 自定义的feign调用
     */
    @Slf4j
    public class CusFeignInvocationHandler implements InvocationHandler {
        private final Target target;
        private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
        private final Object fallbackObj;
        private final Map<String, Method> fallbackMethodMap = new ConcurrentHashMap<>();
    
        CusFeignInvocationHandler(Target target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch, Object  fallbackObj) {
            this.target = checkNotNull(target, "target");
            this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
            this.fallbackObj = fallbackObj;
        }
    
    
    
        public Object feignInvoke(Object proxy, Method method, Object[] args) throws Throwable {
            if ("equals".equals(method.getName())) {
                try {
                    Object
                            otherHandler =
                            args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                    return equals(otherHandler);
                } catch (IllegalArgumentException e) {
                    return false;
                }
            } else if ("hashCode".equals(method.getName())) {
                return hashCode();
            } else if ("toString".equals(method.getName())) {
                return toString();
            }
            return dispatch.get(method).invoke(args);
        }
    
    
        @Override
        public boolean equals(Object obj) {
            if (obj instanceof CusFeignInvocationHandler) {
                CusFeignInvocationHandler other = (CusFeignInvocationHandler) obj;
                return target.equals(other.target);
            }
            return false;
        }
    
        @Override
        public int hashCode() {
            return target.hashCode();
        }
    
        @Override
        public String toString() {
            return target.toString();
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            try {
                return feignInvoke(proxy, method, args);
            } catch (Throwable throwable) {
    
    
                String configKey = Feign.configKey(target.type(), method);
    
                logger.error("{} 请求 出现异常 ==> {}", configKey, throwable.getMessage());
    
    
                try {
                    return getFallbackReturn(method, args, throwable);
                } catch (Throwable e) {
                    throw throwable;
                }
            }
        }
    
        /**
         * 反射调用 {@link FeignClient#fallback()}生成失败返回值
         * @param method            当前feign方法
         * @param args              参数
         * @param throwable         异常
         */
        public Object getFallbackReturn(Method method, Object[] args, Throwable throwable) throws Throwable {
            if (fallbackObj == null) {
                throw new RuntimeException("fallbackObj is null");
    
            }
    
            String configKey = Feign.configKey(target.type(), method);
    
    
            Method fallbackMethod = fallbackMethodMap.get(configKey);
            if (fallbackMethod == null) {
    
                Class<?> declaringClass = method.getDeclaringClass();
    
                FeignClient annotation = declaringClass.getAnnotation(FeignClient.class);
                if (annotation == null) {
                    throw new RuntimeException("FeignClient annotation not found");
                }
    
                // 失败返回
                Class<?> fallback = annotation.fallback();
    
                fallbackMethod = fallback.getMethod(method.getName(), method.getParameterTypes());
    
                fallbackMethodMap.put(configKey, fallbackMethod);
            }
    
    
            if (fallbackMethod == null) {
                throw new RuntimeException("fallbackMethodMap not found");
    
            }
            return fallbackMethod.invoke(fallbackObj, args);
        }
    }
    

    然后在 spring 容器中注册这个bean就行

    @Bean
        CusFeignBuilder cusFeignBuilder(){
            return new CusFeignBuilder();
        }
    

    方案二

    集成 sentinel ,今天写博客再回头看源码时候才发现的
    加入依赖

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    

    配置开启

    feign.sentinel.enabled=true
    

    手动实现feign 接口,将实体类注册到 spring 中

    @Component
    public class DeviceApiFallBack implements DeviceApi{
    	 @Override
            public ServerResponse<String> login(String appId) {
                return ServerResponse.createByErrorMessage("请求失败");
            }
    }
    

    其实看代码知道原理一样,无非实现方式不一样

    两个方案其实都行,方案一自己实现代码量多,方案二sentinel 官方实现,但是需要引入依赖,增加复杂度,而且 接口实现需要注册到spring 中

    目前我选的还是方案一,简单

    展开全文
  • 记一次多线程调用Feign接口失败问题及其优化 自从学会用CompletableFuture来快速构建一个异步方法,就开始到处装逼,到处优化,但是在一次线上环境中反馈短信和消息没有发出去,我赶紧排查问题,前面说下我的发短信...

    记一次多线程异步调取Feign接口失败问题及其解决

    在一次线上环境中反馈短信和消息没有发出去,我赶紧排查问题,前面说下我的业务场景:发短信和发消息都是使用多线程异步执行,通过调取Feign来调取push服务的推送接口来进行推送,因为要快速反馈给用户消息,正好前一段时间学会用CompletableFuture,正想小试牛刀的我,依然决然采用之来实现异步推送,本来用起来还蛮好的,简单易懂方便,而且支持线程窃取等一系列功能,简直是如获至宝,但是今天线上突然出现了以下错误,泼了我一脸冷水:

    Task java.util.concurrent.FutureTask@68bb4099 rejected from java.util.concurrent.ThreadPoolExecutor@f8b8538[Running, pool size = 10, active threads = 10, queued tasks = 20, completed tasks = 693]
    

    开始一度以为是CompletableFuture的锅,但是经过我百度了会,发现其实我错怪了CompleteFuture了,一开始还去看CompleteFuture的源码,了解到CompletableFuture用的是ForkJoinPool的线程池,默认线程数是系统机的cpu核心数,但这个错误为啥报的是active threads=10,这个我就郁闷了,而且CompletableFuture默认会给每个工作线程分配独立的队列,应该不会出现并发调直接拒绝我的任务的问题啊!思前想后我还是想不通,后来索性把堆栈打出来了,我这才知道是Hystrix的问题:

    java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@6900a95d rejected from java.util.concurrent.ThreadPoolExecutor@5d2de59a[Running, pool size = 10, active threads = 10, queued tasks = 20, completed tasks = 54]
    	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
    	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
    	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
    	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
    	at com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler$ThreadPoolWorker.schedule(HystrixContextScheduler.java:172)
    	at com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler$HystrixContextSchedulerWorker.schedule(HystrixContextScheduler.java:106)
    	at rx.internal.operators.OperatorSubscribeOn.call(OperatorSubscribeOn.java:50)
    	at rx.internal.operators.OperatorSubscribeOn.call(OperatorSubscribeOn.java:30)
    	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
    	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
    	at rx.Observable.unsafeSubscribe(Observable.java:10327)
    	....
    

    原来是com.netflix.hystrix下面爆出来的错,o(╥﹏╥)o,找了好久,终于找到了,好了,知道了问题所在,我们开始分析为啥会报这错。之后发现一旦并发量大的时候,就会报,我一想这不就是hystrix熔断机制吗?自己然后查了下资料,发现hystrix调用其他服务的时候核心最大Threadsize=10,如果核心线程达到最大线程则直接拒绝,而且默认没有队列,可能hystrix是为了快速调用才这么设计,但根据我的业务此涉及不太靠谱,所以我就想着直接扩大线程数,但是最大线程数也不能乱调,大了会增加线程上下文切换,小了效率又不高,导致又会拒绝我的任务执行,后来查了下官网,有了如下解决方法,不多说直接贴出一下配置:

    hystrix:
      threadpool:
        default:
          coreSize: 16//并发执行的最大线程数,默认10,我这里用cpu核心数
          maxQueueSize: 1000//BlockingQueue的最大队列数,默认值-1
          queueSizeRejectionThreshold: 800 //即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝,默认值5
    

    配置直接放在application.yml中,这样遇到某些场景远程调用并发多的时候可以采用以上配置,但这个配置也不能乱用,因为加了队列,这就意味着你的熔断门槛就比较高了,所以各位同学一定要根据自己的业务场景来设置。

    展开全文
  • 微服务中尝试使用多线程访问其他服务,通过服务接口调用失败, 通过Debug模式,跟随子线程调用链,发现处理服务发送时的请求头设置中, ServletRequestAttributes attributes = (ServletRequestAttributes) ...

    微服务中尝试使用多线程访问其他服务,通过服务接口调用失败,

    通过Debug模式,跟随子线程调用链,发现处理服务发送时的请求头设置中,

    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
            .getRequestAttributes();
    
    HttpServletRequest request = attributes.getRequest();

    获取的request为null,

    通过度娘几番查找,找到一篇文章解决request为null的问题,

    https://blog.csdn.net/schcilin/article/details/92403362

    通过文章发现,在Spring cloud微服务中,feign开启了熔断器(hystrix):feign.hystrix.enabled=ture,并且使用默认的信号隔离级别,、HttpServletRequest对象在父线程与子线程是相互独立的,不共享的。所以子线程中使用父线程的HttpServletRequest数据为null。

    在我的测试代码中使用feign API接口前调用

    RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);

    来设置将父线程的HttpServletRequest对象设置共享,

     

    展开全文
  • 该逻辑中涉及个子系统之间的调用,原本的调用方式为使用RestTemplate,走服务名调用,并没有问题。后来接口改造为了调用方便,引入feign,于是导致获取不到irequest上下文及无法传递header及cookie等问题。 问题...
  • 背景微服务应用大多对外提供RESTful API,需要有相应的token才能访问,我们在聚合服务中使用Feign Client调用这些API,顺序执行往往会浪费大量的IO等待时间,为了提高查询速度,我们会使用异步调用,Java 8引入了...
  • 随着公司业务的增长,系统的调用量也越来越。对于第三方公司的我们,如何提高系统的稳定性是摆在我们面前的一个问题。为了解决系统稳定性问题,决定把整个服务的日志通过日志跟踪号(traceNo) 以及一次调用链中每一...
  • 微服务中,服务间调用关系错综复杂,一个服务的业务,有可能需要调用多个其它微服务,才能完成。 如图,如果说,我们需要访问的某个服务,Dependency-I发生了故障,此时,我们应用中,调用Dependency-I的服务,也会...
  • 如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象...
  • 在我们使用@Feign的时候,其实是用本质上采用的是http调用摸个服务下的其接口实现,那么http调用的话,就会产生一个线程,如图测试, 2018-04-22 00:37:26.517 INFO 24548 --- [nio-9999-exec-4] c.d.c.eureka....
  • 在异步方法中,需要用feign调用B服务获取相关数据,因为有鉴权的存在,所以异步方法调用B服务接口的时候也要携带token 那么就涉及到线程上下文的问题,配置了线程池,然后设置了线程上下文的数据切换(见下图) !...
  • 线程隔离 1.负载均衡 1.介绍 负载均衡(Load Balance)其意思就是分摊到个操作单元上进行执行 本质:负载均衡是一个算法,可以通过该算法实现从地址列表中获取一个地址进行服务调用。 Ribbon提供了**轮询、随机两...
  • Hystrix的资源隔离

    2021-02-27 15:27:52
    feign调用过程中,若开启了Hystrix熔断,则feign调用接口将是经过代理的Hystrix类。 对于每个feign client都会在服务启动时,创建名称为该应用名的线程池,默认10个核心线程数。 2、信号量 信号量这个并不是...
  • 在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的...
  • 在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的...
  • 在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的...
  • 基于注解使用,对业务代码可以说是零入侵,目前内置适配spring-cloud(Feign调用),dubbo。同时具有一定的扩展性与兼容性,因为存在自定义的服务框架,或者以后会涌现出更的流行分布式服务框架,所以会提供一些...
  • 一、Hystrix简介Hystrix是Netflix开源的一款容错框架,包含常用的容错方法:线程隔离、信号量隔离、降级策略、熔断技术。在高并发访问下,系统所依赖...本篇文章基于前一篇文章的工程二:使用Feign调用服务中使用Hy...
  • 结果很是奇怪 利用feign负载均衡算法之后请求错误率竟然比直接访问clientA的错误率还高 按理来说已经是两台服务器的client负载均衡 就算异常率减少的不 也不应该比原来更高啊 希望有个大佬帮我分析一下原因 ...
  • Spring Cloud中如何优雅的使用Feign调用接口:http://cxytiandi.com/blog/detail/12189 Spring Cloud Feign fallback错误解决:http://cxytiandi.com/blog/detail/12368 Spring Cloud Feign 启动Unsatisfied...
  • Hystrix的简单应用(五)

    2020-02-17 14:46:58
    在微服务架构中,根据业务来拆分成一个个的服务,而服务与服务之间存在着依赖关系,在SpringCloud中个微服务之间可以用RestTemplate + Ribbon 和Feign调用。在服务之间调用的链路上由于网络原因,资源繁忙或者...
  • Sleuth

    2019-02-02 17:27:17
    文章目录原理介绍Brave和Zipkin使用依赖Sleuth对feign的支持Sleuth对RestTemplate的支持Sleuth对多线程的支持 原理介绍 Sleuth通过Trace定义一次业务调用链,根据它的信息,我们就知道多少个系统参与了该业务处理。 ...
  • 商品调库存,库存调订单等等),在Spring Cloud中个微服务之间可以用 RestTemplate+Ribbon 和 Feign调用。 2、分布式微服务架构面临的问题 a:在服务之间调用的链路上由于网络原因、资源繁忙或者自身的原因,...
  • hystrix的服务降级

    2020-08-24 23:20:21
    线程/进程对应着系统资源,如果得不到释放的线程/进程就会越积越,资源就会被耗尽,最终导致服务不可用!hystrix就是解决这类问题的工具类库。 服务降级 用自己的话来说,就是当某个服务不可用的时候,有一个...
  • 微服务架构中服务之间互相调用,单个服务通常会集群部署,由于网络等原因,服务不能保证 100% 可用,如果单个服务出现问题会出现请求的堆积,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。 2. 短路器 一个请求...
  • 脱更了半个月,今天项目的初版已经完成,所以打算继续我们的微服务学习,由于Hystrix这一块东西好多,只好拆分几篇文章写,对于一般对性能要求不是很高的项目中,可以使用其基础上开发的Feign进行容错保护。...
  • springCloud

    2018-08-09 16:54:33
    这样就不会使得线程调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。 断路器示意图 SpringCloud Netflix实现了断路器库的名字叫Hystrix. 在微服务架构下,通常会有个层次的服务调用. 下面是...
  • 大型互联网级企业架构师视频教程 JAVA高级架构师必备课程 82G超强的JAVA架构师课程 ===============课程目录=============== ...├─(170) 调用链系统服务端实现 2018-06-26 20-09-48-357-.mp4 (32)\\07.解决方案专题...

空空如也

空空如也

1 2
收藏数 34
精华内容 13
关键字:

多线程feign调用