sofastack / sofa-rpc

SOFARPC is a high-performance, high-extensibility, production-level Java RPC framework.
https://www.sofastack.tech/sofa-rpc/docs/Home
Apache License 2.0
3.83k stars 1.18k forks source link

RpcInternalContext 中的 JDK原生 ThreadLocal 能否替换成 Netty 的 FastThreadLocal? #67

Closed stateIs0 closed 6 years ago

stateIs0 commented 6 years ago

com.alipay.sofa.rpc.context.RpcInternalContext 中的 ThreadLocal 被大量使用,能否使用 Netty 中性能更高的 FastThreadLocal ?

leizhiyuan commented 6 years ago

1.是否有数据支撑这个结论?目前我们这边的压测,这个地方没有发现明显的性能瓶颈 2.rpc 框架目前现阶段依赖 netty, 但是如果有一天有一个更性能搞的网络通信框架,我们可能也会考虑更换,所以框架层面并不会强依赖 netty 的工具类.

stateIs0 commented 6 years ago

经过我本机测试和内部原理(ftl 使用数组比 Map 查询性能更高),比原生 ThreadLocal 性能更高是没有疑问的。 但考虑到后期的依赖和框架当前状态(性能瓶颈不在这里),的确可以不用替换。。。。。

leizhiyuan commented 6 years ago

@stateIs0 还有一种方案.就是参考FastThreadLocal 在我们内部实现一个类似的.直接作为内部所有 ThreadLocal 的替换.

NeGnail commented 6 years ago

在你的机器上测试下来,FastThreadLocal 比 ThreadLocal 性能更高。不知道是不是在 SOFARPC 的场景下测试的呢。是否你只是单独测试的 FastThreadLocal 和 ThreadLocal 吗。

leizhiyuan commented 6 years ago

如果你这边方便的话,可以提供下测试数据哈,这个之后在迭代中,也测试一下 rpc 内部的一些使用的类型/原生类型的测试.看看性能上的提升数据. @stateIs0 @NeGnail N

leizhiyuan commented 6 years ago

@stateIs0 https://github.com/alipay/sofa-rpc/wiki/DeveloperGuide#%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95 这是我们的性能测试.后续的压测我们也争取提供个cpu/内存消耗的火焰图.帮助参考哈

stateIs0 commented 6 years ago

@NeGnail 我的确没有在 SOFARPC 场景下测试,性能更高的结论来自于我单独对 ThreadLocal 和 FastThreadLocal 的测试。结合 FastThreadLoca 内部原理,性能更高可能性很大。不知在 SOFARPC 下会有什么样的性能表现。

@leizhiyuan 自己参考 netty 实现一个的确可行,如果可以的话,可以扩展一下线程池里面的 Thread 类,参考 Netty 的 FastThreadLocalRunnable ,防止内存泄漏。

leizhiyuan commented 6 years ago

@stateIs0 好的,感谢提供思路.如果有兴趣的话,可以提个 pr. 我们这边后续也提供相应的压测火焰图这些信息.帮忙大家了解当前的某些性能瓶颈

https://github.com/alipay/sofa-rpc/issues/68 这里我记录一下,之后提供了完善相关文档.感谢~

NeGnail commented 6 years ago

@stateIs0 单独压测下,我也比较相信 FastThreadLocal 的性能表现。我们也更关注它能给 SOFARPC 带来的提升,如果提升可观,可以考虑做一个内部实现。

khotyn commented 6 years ago

@NeGnail @leizhiyuan @stateIs0 我觉得有可靠的数据证明加上可靠的测试,即使不是可观的性能提升,也是可以做下改进的,性能优化也可以小步前进嘛~

leizhiyuan commented 6 years ago

@khotyn 恩,之后我们在这里更新 issue. 做一个本地的性能测试数据.然后看下 FastThreadLocal 是否相关依赖比较多.可以参考实现个我们的版本.

stateIs0 commented 6 years ago

@khotyn @leizhiyuan @NeGnail 我可以尝试 PR 这一块的代码吗?

NeGnail commented 6 years ago

@stateIs0 当然可以啊。欢迎。

stateIs0 commented 6 years ago

@NeGnail 能沟通一下吗?cxstateis0@gmail.com

leizhiyuan commented 6 years ago

大致看了一下

FastThreadLocal 是 netty 相当深度定制的,本身依赖的第三方类比较多,比如这些.

import org.jctools.queues.MpscArrayQueue;
import org.jctools.queues.MpscChunkedArrayQueue;
import org.jctools.queues.SpscLinkedQueue;
import org.jctools.queues.atomic.MpscAtomicArrayQueue;
import org.jctools.queues.atomic.MpscLinkedAtomicQueue;
import org.jctools.queues.atomic.SpscLinkedAtomicQueue;
import org.jctools.util.Pow2;
import org.jctools.util.UnsafeAccess;

并且看代码要使用达到最好性能的话,还需要尽量使用FastThreadLocalThread 这个 Thread 类.参考实现的时候,正确性和之后的长远维护性也需要作为考虑.

stateIs0 commented 6 years ago

@leizhiyuan 您好,我已经将 Ftl 相关的都抽取出来了,除了日志系统,可以不依赖其他第三方库。后面,我会进行完整的性能测试(已经进行了简单的测试)。关于 FastThreadLocalThread 类,我觉得有必要使用该类的设计—— 即使不使用 Ftl, 也可以在 run 方法运行之后删除 ThreadLocal , 确保即使使用错误也不会造成内存泄漏。

leizhiyuan commented 6 years ago

除了日志系统 也不要依赖第三方库.日志系统也不能依赖具体的实现,需要使用

com.alipay.sofa.rpc.log.LoggerFactory 
stateIs0 commented 6 years ago

@leizhiyuan 可以的,这个没问题。还有,本来我想在做完性能测试后,再把具体问题提出来,但后来想先提出来也没什么坏处,So,下面几个问题还请参考一下:

  1. 使用 Netty 的源码,开源协议怎么处理?(目前是在源码上方,加入了 Copyright).
  2. 我准备将 FTL 相关的类放到 com.alipay.sofa.rpc.common.utils 下,新建一个 concurrent 包,包含 FTL,新的线程工厂,新的线程类(扩展 Thread 和 Runnable 以配合 FTL)。不知这么做合适否?
  3. 由于 2 的关系,我需要在 FTL 中使用日志,而 common 模块现阶段是没有日志的,这个地方如何处理比较合适呢?(该问题使用 com.alipay.sofa.rpc.log.LoggerFactory 能否解决?)
  4. 目前,我针对 Netty 的源码增加了一些中文的注释。是否有必要?
  5. 如果使用新的 FTL,那么,SOFA 中的线程池构造器中的 ThreadFactory 也需要进行替换或者修改,修改原有的 newThread 方法,是否可行?
leizhiyuan commented 6 years ago
  1. 使用了 netty, 那上面jctools这么些类也准备对应的移动过来?

2.可以放到 com.alipay.sofa.rpc.common.struct 这个 package 下面,放置一些数据结构相关的.

3.可以使用LoggerFactory 是一个非常底层的包

4.不建议,尽量英文注释

5.这种整体需要看下是不是可以通过设置一个参数.来决定是否开启,只有开启了,才使用FastThreadLocal和FastThread这种.需要看下如何抽象,不作为默认开启,之后如果发现有问题,可以允许用户关掉.方便更多同学直观理解和使用代码.

khotyn commented 6 years ago

关于开源协议的处理,Netty 用的是 Apache 2.0 的协议,请注意 Apache 2.0 协议中的限制部分:

image

请遵照协议中的内容进行处理。

stateIs0 commented 6 years ago

@leizhiyuan 不需要使用 jctools 的或者其他第三方的库。

stateIs0 commented 6 years ago

@leizhiyuan 我使用 com.alipay.sofa.rpc.bolt.start.BoltClientMultipleMain 测试类:经过统计, 50 并发下,客户端每秒会调用 ThreadLocal 的 get 方法 35 万次左右,调用 set 方法 2.5 万次左右,读写比 14:1。

而 Netty 几乎没有写(set)的现象(通过 initialValue() 初始化,后期 get 后操作内部数据 )。

使用这种比率(14:1)进行测试,FastThreadLocal 对于 SOFA 的提升非常小。

模拟 1 小时调用所消耗时间(毫秒),测试结果:

netty ---- >546
jdk   ---- >3452
只读
===============
netty ---- >9880
jdk   ---- >10207
读写(14:1)
===============
netty ---- >8585
jdk   ---- >8738
写

结果:几乎无提升。

测试用例如下:

   final ThreadLocal<String> jdk = new ThreadLocal<String>();
   final FastThreadLocal<String> netty = new FastThreadLocal<String>();

    new Thread(new Runnable() {
      @Override
      public void run() {
        long s = System.currentTimeMillis();
        // 35 万代表每秒 50并发调用 get 次数,共 1 小时
        for (long i = 0; i < 350000L * 60 * 60; i++) {
          if ((i % 14) == 0) {
            jdk.set("" + i);
          }
          jdk.get();
        }
        System.out.println("jdk   ---- >" + (System.currentTimeMillis() - s));

      }
    }).start();

    new FastThreadLocalThread(new Runnable() {
      @Override
      public void run() {
        long s = System.currentTimeMillis();
        for (long i = 0; i < 350000L * 60 * 60; i++) {
          if ((i % 14) == 0) {
            netty.set("" + i);
          }

          netty.get();
        }

        System.out.println("netty ---- >" + (System.currentTimeMillis() - s));

      }
    }).start();
  }

结论:FastThreadLocal 适合 Netty 这种几乎不写但大量读的应用。普通应用使用 FTL带来的复杂和性能提升不成正比。因此不建议引入 SOFA。

leizhiyuan commented 6 years ago

@stateIs0 好的.感谢感谢.学习了!

stateIs0 commented 6 years ago

但是有没有可能针对 SOFA 的上下文场景重写 ThreadLocal 呢?我觉得可以尝试一下。

leizhiyuan commented 6 years ago

@stateIs0 恩,我理解重写ThreadLocal主要是为了性能,目前我个人觉得,可以暂时不重写ThreadLocal,之后的压测中如果出现适合的情况,可以再做重写.

stateIs0 commented 6 years ago

@leizhiyuan 好的,可以。我昨天用数组重写了一个,测试了一下,在 SOFA 场景下性能和 FastThreadLocal 类似,目前也没想到好的办法能做到很明显的性能提升。

leizhiyuan commented 6 years ago

@stateIs0 好的,那这个 issue 先关掉.有兴趣可以 再看看其他的 feature~

stateIs0 commented 6 years ago

@leizhiyuan 好的。