netty之ObjectSizeEstimator

今天测试netty,之前一直会出现阻塞,最后测试服务器所有线程挂起,最后无法正常工作,
  • ExecutionHandler,  使用了这玩意的,在网上翻来拂去的找,都一个莫子出来的,天朝咋都这样,希望转载别人的一定标注下地址啦,扯远了,使用了ExecutionHandler(有兴趣看看源码你会发现他对于读取数据流事件开的是true,写的话是false--默认),保证你提交的任务能够继续处理,worker线程返回,但是有个问题,他的pool参数,这里是用的MemoryAwareThreadPoolExecutor(长连接,业务复杂,就最好用这个咯,至于为什么,请看源码),他有两个重要参数 maxChannelMemorySize,  maxTotalMemorySize,,其他几个参数什么keepAliveTime, TimeUnit unit, keepAliveTime, TimeUnit unit, ObjectSizeEstimator objectSizeEstimator,这里就是问题的关键,当提交的任务超过maxTotalMemorySize,处理不过来,会根据你设置的线程工厂不断创建线程来处理,处理不过来,那么还是继续创建,直到你的cpu被搞死,worker线程也就阻塞了,应为无法添加任务,最后就完全挂起,在overfolw上面有个老外提问(韩国棒子,我还以为是天朝的,也有这个问题,但是貌似回答的都没有解决问题,没有找到答案,)为什么说这个呢,我想强调的是 ,大家找答案,实在不好搞,最好看源码,或则API,好继续正题,刚刚谈到线程挂起和挂起的原因,我是如下解决的,
  • Using an alternative task size estimation strategy
    Although the default implementation does its best to guess the size of an object of unknown type, it is always good idea to to use an alternative ObjectSizeEstimator implementation instead of the DefaultObjectSizeEstimator to avoid incorrect task size calculation, especially when: 
    you are using MemoryAwareThreadPoolExecutor independently from ExecutionHandler, 
    you are submitting a task whose type is not ChannelEventRunnable, or 
    the message type of the MessageEvent in the ChannelEventRunnable is not ChannelBuffer. 
    Here is an example that demonstrates how to implement an ObjectSizeEstimator which understands a user-defined object: 
     public class MyRunnable implements Runnable {
    
         private final byte[] data;
    
         public MyRunnable(byte[] data) {
             this.data = data;
         }
    
         public void run() {
             // Process 'data' ..
         }
     }
    
     public class MyObjectSizeEstimator extends DefaultObjectSizeEstimator {
    
         @Override
         public int estimateSize(Object o) {
             if (o instanceof MyRunnable) {
                 return ((MyRunnable) o).data.length + 8;
             }
             return super.estimateSize(o);
         }
     }
    
     ThreadPoolExecutor pool = new MemoryAwareThreadPoolExecutor(
             16, 65536, 1048576, 30, TimeUnit.SECONDS,
             new MyObjectSizeEstimator(),
             Executors.defaultThreadFactory());
    
     pool.execute(new MyRunnable(data));
    在源码上(api也有)找到答案,根据你的业务,重写估算内存数目的策略,替换默认的估算策略(如果你的业务处理数据有缓存的策略话,建议 maxChannelMemorySize ,maxTotalMemorySize两个参数设置为0,即是不启用缓存限制,本身在实际项目中无法估计出队列的缓存大小,只有测试后才知道哦。如果启用了的话,超过了maxTotalMemorySize,将会导致业务线程阻塞,进而引发IOworker线程以及boss线程阻塞,导致程序崩掉!!!对与接受到来自c的数据,按理来讲应该缓存的,对于业务响应的数据,你可以直接write出去,没有必要缓存,本身底层也是有缓存的)我替换之后,测试10000(一万个,估计还可以加,因为笔记本限制怕出问题)个连接轮询发送数据,没有问题,没有阻塞,worker线程完全返回专注自己的事情,pool,接手业务逻辑处理,另外在工作站上测试200多个连接并行的发送死循环,毫无压力
  • 后记,今天测试连接数15000,呵呵毫无压力,

转载于:https://my.oschina.net/chenleijava/blog/95748

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值