如何用Netty写一个高性能的分布式服务框架?( 六 )


 

  • 缺点是索引计算时间复杂度高 , 请根据自己场景衡量 。
 
9)如果要读一个int , 用Bytebuf.readInt() , 不要Bytebuf.readBytes(buf , 0 , 4)
 
  • 这能避免一次memory copy (long , short等同理) 。
 
10)配置
UnpooledUnsafeNoCleanerDirectByteBuf来代替jdk的DirectByteBuf , 让netty框架基于引用计数来释放堆外内存
 
io.netty.maxDirectMemory:
 
  • < 0: 不使用cleaner , netty方面直接继承jdk设置的最大direct memory size , (jdk的direct memory size是独立的 , 这将导致总的direct memory size将是jdk配置的2倍) 。
 
  • == 0: 使用cleaner , netty方面不设置最大direct memory size 。
 
0:不使用cleaner , 并且这个参数将直接限制netty的最大direct memory size , (jdk的direct memory size是独立的 , 不受此参数限制) 。
 
11)最佳连接数
 
  • 一条连接有瓶颈 , 无法有效利用cpu , 连接太多也白扯 , 最佳实践是根据自己场景测试 。
 
12)使用PooledBytebuf时要善于利用
-Dio.netty.leakDetection.level 参数
 
  • 四种级别:DISABLED(禁用) , SIMPLE(简单) , ADVANCED(高级) , PARANOID(偏执) 。
 
  • SIMPLE , ADVANCED采样率相同 , 不到1%(按位与操作 mask ==128 - 1) 。
 
  • 默认是SIMPLE级别 , 开销不大 。
 
  • 出现泄漏时日志会出现“LEAK: ”字样 , 请时不时grep下日志 , 一旦出现“LEAK: ”立刻改为ADVANCED级别再跑 , 可以报告泄漏对象在哪被访问的 。
 
  • PARANOID:测试的时候建议使用这个级别 , 100%采样 。
 
13)Channel.attr() , 将自己的对象attach到channel上
 
  • 拉链法实现的线程安全的hash表 , 也是分段锁(只锁链表头) , 只有hash冲突的情况下才有锁竞争(类似ConcurrentHashMapV8版本) 。
 
  • 默认hash表只有4个桶 , 使用不要太任性 。
 
9 从 Netty 源码中学到的代码技巧
 
1)海量对象场景中
AtomicIntegerFieldUpdater --> AtomicInteger
 
  • Java中对象头12 bytes(开启压缩指针的情况下) , 又因为Java对象按照8字节对齐 , 所以对象最小16 bytes , AtomicInteger大小为16 bytes , AtomicLong大小为 24 bytes 。
 
  • AtomicIntegerFieldUpdater作为static field去操作volatile int 。
 
2)FastThreadLocal , 相比jdk的实现更快
 
  • 线性探测的Hash表 —> index原子自增的裸数组存储 。
 
3)IntObjectHashMap / LongObjectHashMap …
 
  • Integer—> int
  • Node[] —> 裸数组
 
4)RecyclableArrayList
 
  • 基于前面说的Recycler , 频繁new ArrayList的场景可考虑 。
 
5)JCTools
 
  • 一些jdk没有的 SPSC/MPSC/SPMC/MPMC 无锁并发队以及NonblockingHashMap(可以对比ConcurrentHashMapV6/V8)




推荐阅读