alibaba / transmittable-thread-local

📌 a missing Java std lib(simple & 0-dependency) for framework/middleware, provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.
https://github.com/alibaba/transmittable-thread-local
Apache License 2.0
7.59k stars 1.69k forks source link

对netty的EventExecutor进行修饰 #372

Closed heixiaoma closed 2 years ago

heixiaoma commented 2 years ago

image 目前这段代码可以完美的使用,但是性能不是很高,有没有办法直接获取ctx.executor()的就是TTL修饰过的,我尝试多次,貌似没有办法处理这个问题,前来和各位大哥交流学习下

heixiaoma commented 2 years ago

这代码每次的请求都会修饰,还有一种就是缓存修饰的对象,但是我认为这是对low的做法,应该可以直接在源头上处理

oldratlee commented 2 years ago

但是性能不是很高

我认为这是对low的做法,应该可以直接在源头上处理

赞成 +1 ! @heixiaoma


因为涉及执行器的库/框架会有很多,所以在TTL库中不能都集成实现好。

另外,尤其是对比较大的库/框架的TTL集成,需要


@heixiaoma 你可以实现整理一个: 😁

  1. 先解决自己的问题,也能有实际实践使用;
  2. 再整理成一个集成Netty使用的库,放出来方便大家使用。

提到Netty集成的 Issue 有好几个,相信大家挺希望能有更好的解决方案:

TTL集成相关说明的 Issue


  • 从库下层实现来看,这些上层的库使用方式(如TtlRunnableTtlExecutorService):
    • 只是些便利方法。
    • 没有对业务使用增加额外约束。
  • 下层核心是 CRR 操作。 @heixiaoma
    • CRR操作 不耦合/依赖 (最常见的、JDK自带的)RunnableExecutorService
    • 可以被用于其它的执行框架(如kotlin协程)来集成。
  • 当然,这些上层库使用方式是非常重要的,不是可有可无的存在:
    • 上层面向用户使用的友好程度甚至说库的生命力,非常依赖这些上层库使用方式的设计。
    • 绝大多数情况下,用户要的是开箱即用简单快速地解决问题,而不是理解相对复杂的下层操作。
heixiaoma commented 2 years ago

感谢老哥的建议,我多尝试尝试这个问题,或许通过javassist来修改netty的代码来实现或许是一种方法

heixiaoma commented 2 years ago
    /**
     * 修改Netty,让线程池被TTL包装
     * AbstractEventExecutor eventloop都继承了这个抽象类,我们只加入一点自己的逻辑,并在RouterHandler里使用
     */
    public static void modifyNetty() {
        ClassPool cp = ClassPool.getDefault();
        try {
            String strPath="io.netty.util.concurrent.AbstractEventExecutor";
            ClassPath classPath= new LoaderClassPath(Thread.currentThread().getContextClassLoader());
            cp.insertClassPath(classPath);
            Loader loader = new Loader(cp);
            Class<?> abstractEventExecutor = loader.loadClass(strPath);
            CtClass ctClass = cp.getCtClass(abstractEventExecutor.getName());
            ctClass.freeze();
            ctClass.defrost();
            CtClass executorType = cp.get(Executor.class.getCanonicalName());
            // final Executor executor=TtlExecutors.getTtlExecutor(this); 模拟这样一段代码
            CtField ctField = new CtField(executorType, "executor", ctClass);
            ctField.setModifiers(Modifier.FINAL);
            ctClass.addField(ctField, "com.alibaba.ttl.threadpool.TtlExecutors.getTtlExecutor(this);");
            //在添加一个get方法用于RouterHandler调用
            // public Executor getExecutor() {
            //        return this.executor;
            //    }
            CtMethod m = new CtMethod( cp.get(Executor.class.getCanonicalName()), "getTtlExecutor", new CtClass[]{}, ctClass);
            m.setModifiers(Modifier.PUBLIC);
            // 添加返回
            m.setBody("return this.executor;");
            ctClass.addMethod(m);
            ctClass.toClass();
            ctClass.detach();
        } catch (Throwable e) {
            log.error(ExceptionUtil.getMessage(e));
        }
    }
        if (getTtlExecutor == null) {
            getTtlExecutor = ctx.executor().getClass().getMethod("getTtlExecutor");
        }

        Executor executor = (Executor)getTtlExecutor.invoke(ctx.executor());

写了一个demo,看上去也很丑

oldratlee commented 2 years ago

先 close 了;有进一步信息或问题可以继续讨论。