Nepxion / Discovery

☀️ Nepxion Discovery is a solution for Spring Cloud with blue green, gray, route, limitation, circuit breaker, degrade, isolation, tracing, dye, failover, active 蓝绿灰度发布、路由、限流、熔断、降级、隔离、追踪、流量染色、故障转移、多活
http://www.nepxion.com
Apache License 2.0
5.64k stars 1.43k forks source link

service层获取requst上下文时,优先从restStrategyContext获取,在没使用异步情况下,会不会有内存泄漏问题 #200

Open testc1 opened 1 year ago

testc1 commented 1 year ago
每次getCurret时,都给当前线程绑定了一个初始的context,但是并没有看见调用clean方法

public ServletRequestAttributes getRestAttributes() { // 异步场景下 会复制请求信息到RestStrategyContext RequestAttributes requestAttributes = RestStrategyContext.getCurrentContext().getRequestAttributes(); if (requestAttributes == null) { requestAttributes = RequestContextHolder.getRequestAttributes(); } return (ServletRequestAttributes) requestAttributes; }

testc1 commented 1 year ago

还有一个问题,在使用了Agent插件时,已经设置在了request中,为什么还在再设置在restStrategyContext中,但道理两个都设置了,但是异步场景下,直接从RequestContextHolder.getRequestAttributes();中还是娶不到,只有从RestStrategyContext.getCurrentContext().getRequestAttributes();才能取到 @Override public Object create() { RequestAttributes request = RequestContextHolder.getRequestAttributes(); if (requestDecoratorEnabled) { if (null != request) { request = ServiceStrategyRequestDecoratorFactory.decorateRequestAttributes(request); } } return request; }

@SuppressWarnings("unchecked")
@Override
public void before(Object object) {
    if (object instanceof RequestAttributes) {
        RequestAttributes requestAttributes = (RequestAttributes) object;
        RequestContextHolder.setRequestAttributes(requestAttributes);
        RestStrategyContext.getCurrentContext().setRequestAttributes(requestAttributes);
    }
}
HaojunRen commented 1 year ago

第一个问题,如果用了同步,上下文会从RequestContextHolder去取,这是Spring Boot自带的,它会主动清理,如果用了异步,那必须用DiscoveryAgent,它里面有清理代码,所有,两种情况都不会造成泄露

第二个问题,Agent下,Spring Boot 自带的会发生取不到的情况,所以框架自己维护了一个threadlocal,保证能取到

testc1 commented 1 year ago

①RequestAttributes requestAttributes = RestStrategyContext.getCurrentContext().getRequestAttributes(); ②public static RestStrategyContext getCurrentContext() { return THREAD_LOCAL.get(); } ③ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }

在调入到第三部的时候,会调用 private static final ThreadLocal THREAD_LOCAL = new ThreadLocal() { @Override protected RestStrategyContext initialValue() { return new RestStrategyContext(); } };初始化方法,给每个线程绑定了一个RestStrategyContext,同步的时候没有地方清除这个绑定,这样会有问题吗?

testc1 commented 1 year ago

public ServletRequestAttributes getRestAttributes() { RequestAttributes requestAttributes = RestStrategyContext.getCurrentContext().getRequestAttributes(); if (requestAttributes == null) { requestAttributes = RequestContextHolder.getRequestAttributes(); }

    return (ServletRequestAttributes) requestAttributes;
}

这里获取的时候,可以换成先从 RequestContextHolder.getRequestAttributes() 这里为空,再从RestStrategyContext.getCurrentContext().getRequestAttributes()里边取吗?这样有问题吗?能不能避免先从RestStrategyContext中取,同步调用下,给当前线程绑定RestStrategyContext而没清理的情况

HaojunRen commented 1 year ago

同步情况下,RestStrategyContext.getCurrentContext().getRequestAttributes()返回的是null