Closed DockerFan closed 2 years ago
@DockerFan
PS:ForkJoinPool有不风格的用法;这些不同用法本身的区别,可以先查资料了解。
先介绍下背景:
CompletableFuture.supplyAsync
提交了一个Runnable
任务到ForkJoinPool
sandbox-repeater
绑定到被测服务以后需要把每个主请求下面的所有子请求根据traceId
进行关联
(所谓主请求就类似是浏览器发送的http
请求,子请求就是处理这个http
请求所涉及到的中间件的交互)sandbox-repeater
处理的是加载到jvm
后的处理目前解决方案:
一、将ttl-agent
绑定到被测服务,这样对于ForkJoinPool
所有线程池方法都进行了增强,理论上是不是就可以通过sandbox-repeater
从TransmittableThreadLocal
拿到正确的上下文拷贝结果呢?
二、通过反射机制,将ForkJoinPool
的execute(Runnable task)
如下方法的runnable
转成ttlRunnable
public void execute(Runnable task) {
if (task == null) throw new NullPointerException();
ForkJoinTask<?> job;
if (task instanceof ForkJoinTask<?>) // avoid re-wrap
job = (ForkJoinTask<?>) task;
else
job = new ForkJoinTask.RunnableExecuteAction(task);
externalPush(job);
}
目前看两种方式都没成功,不知道是哪块理解和使用不到位,期待您的回复。
先介绍下背景:
……
- 然后
sandbox-repeater
绑定到被测服务以后需要把每个主请求下面的所有子请求根据traceId
进行关联 (所谓主请求就类似是浏览器发送的http
请求,子请求就是处理这个http
请求所涉及到的中间件的交互)- 所以会涉及到线程池上下文拷贝的问题,但是
sandbox-repeater
处理的是加载到jvm
后的处理
TTL Agent
不支持 Attach方式,即『对已加载的类做增强』。更多说明与讨论 参见已有issue:
sandbox-repeater
使用,你可以了解或询问sandbox-repeater
项目。 @DockerFan一、将
ttl-agent
绑定到被测服务,这样对于ForkJoinPool
所有线程池方法都进行了增强, 理论上是不是就可以通过sandbox-repeater
从TransmittableThreadLocal
拿到正确的上下文拷贝结果呢?
ForkJoinPool
所有线程池方法都进行了增强』,具体如何增强?给一下完整可运行的代码,方便实际情况确认与讨论。
增强的逻辑与sandbox-repeater
无关,sandbox-repeater
只是实现增强逻辑的工具。sandbox-repeater
使用的部分,你可以了解sandbox-repeater
项目。
(sandbox-repeater
我没有具体使用过、不熟悉 :")二、通过反射机制,将
ForkJoinPool
的execute(Runnable task)
如下方法的runnable
转成ttlRunnable
上面『通过反射机制 转换』,你的说明和代码少 & 问题相对复杂,不能清楚理解。
比如runnable
是ForkJoinPool#execute
方法参数,在不修改/增强这个方法的情况下,用反射修改如何能生效?在你上面的评论说明中,不能看出如何修改/增强这个方法的逻辑。
下面假设在ForkJoinPool#execute
方法增强加入了
runnable = TtlRunnable.get(runnable);
作为方法第一行,以在方法入口将参数runnable
转成ttlRunnable
。
简单看来(具体要展开细挖),在入口转成ttlRunnable
,影响了ForkJoinPool#execute(Runnable task)
方法原有的执行逻辑。
比如,导致ForkJoinPool#execute
后续原有逻辑总是会调用new ForkJoinTask.RunnableExecuteAction(task)
wrap 成ForkJoinTask<?>
。
即,这样的转换修改可能会影响 ForkJoinPool
本身的逻辑正确性,看起来并不是一个安全可靠的修改方式。
@DockerFan
ForkJoinPool
的实现有些复杂,运行时增强修改的有些问题我也没有找到可靠可行的解决方法。推荐先了解一下已有的讨论:
TTL Agent
支持运行时加载(aka. Agent Attach使用方式)的实现讨论:https://github.com/alibaba/transmittable-thread-local/issues/226#issuecomment-771538927性能优化那些事(3) https://zhuanlan.zhihu.com/p/503149395
这篇文章提到:
TTL Agent
运行时生效增强 的问题@DockerFan 可以看看:具体解决到什么程度、是不是有可以参考借鉴的。
TTL
的首要场景与实现要求TTL
功能要首要支持的是 生产环境在线场景;即,像测试的便利性 在优先级上要低于 生产在线的可靠性。 当然,如果能找到 两者兼顾的解决方法,就不需要做这样的取舍了。
先 close 了;有进一步信息或问题可以继续讨论。
@DockerFan 之前我自己做了一个方案,分两步
ForkJoinTask
里面插入字段 private final Object captured = capture();
doExec()
中插入包装 Object backup; try { backup = replay(captured); <...原有代码...>} finally { restore(backup); }
这步由于涉及到添加字段,如果类已加载则会失效,必须保障在类初始化之前进行增强。
debug看业务代码ForkJoinPool的execute方法里的传参是个runnable类型,那可以把一个ForkJoinTask的任务强转成一个runnable,然后处理成ttlRunnable类型这样来开启ttl吗?