获取资料
后台回复:C++ 干货
背景
最近的一个项目需要用到招标,临时加了给我们的系统增加了一个性能需求,多少呢?
一秒钟 300 次 NTP(不知道 ntp 的同学可以百度一下),平均 3ms 一次啊,没测试过,心里没有底.(⊙o⊙)...
情境介绍:
系统是一个时间服务器系统,客户端就是 window 系统,或者其他的一些服务器,来向时间服务器同步时间.
默认的 window 会向这个 time.winodows.com 进行时间同步, 当然你也可以换成其他时间同步服务器.
划重点了:服务端 NTP 接口采用的是 netty 框架写的一个接口, netty 想必大家都了解的吧,nio 通信,性能超好的.
测试代码是使用 Executors.newFixedThreadPool 写的客户端,10 个线程数发送 ntp 包
第一次测试
数据库连连接池最大设置为 40 个,测试结果俩一秒钟 28 次,是的你没有看错,连十分之一都没有,怎么这么差劲啊
达不到预期啊,不行啊,这不就达不到要求的了吗,得改啊,哪里改啊,怎么改啊?
回到代码中去,顺藤摸瓜找到具体业务类,就是继承 SimpleChannelInboundHandler 的类,从头到尾打量了一下业务代码,发现业务主要是构造返回消息,记录日志.
构造返回就是 Java 里的构造对象什么的,根本不耗时的.
那就想不是有记录日志吗,不往数据库里面写东西了,把它注释掉,跑一遍试试看.
第二遍测试
哎呦妈呀,起飞了老铁,直接飙到了每秒钟 2 万次.
看到这个令人惊讶的数据,这远远超过要求啊,哈哈哈,妥妥的.
突然一想,不对啊,这好像和产品设计不符合啊,设计里是要求记录日志的啊,这个是有点滥竽充数啊,不行不行,这个得改.
仔细分析一下,日志得写到数据库,读了《java 高并发程序设计》,心想是不是可以用异步的方式记录日志呢,弄一个线程池吧.
阿里巴巴 JAVA 开发手册里是不推荐使用 Executors 中的现成的线程池的(具体原因我就不说了,可以看一下),那就自己写一个吧.
第三次测试
考虑到任务提交速度快的原因,第一次构造线程池采用了直接提交的队列,这样任务处理的快一些
测试代码再跑一遍,哎呦妈呀,又起飞了老铁!
private static ExecutorService saveThreadPool = new ThreadPoolExecutor(2, 100, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy());
心想我这么牛逼的吗,这随便写个线程池就 OK 了.
在服务器执行了 top 一看,不得了:
这个 cpu 直接占满了,系统里还有其他服务的,不能把资源全都给它啊.
这次留了个心眼看了下数据库日志,不对啊,没有全部记录啊,尼玛发了一百多万结果只记录了几万条,这个差太多了啊.
为什么漏掉了呢,回过头来继续看线程池的构造.
终于发现了纰漏,拒绝策略是用了 new ThreadPoolExecutor.DiscardPolicy(),这个可出事了啊,不行不行,这直接丢弃了,记录日志的任务不能直接丢弃.
第四次测试
这次又把书拿出来看了看,看了一些大牛写的线程池构造,最终敲定了这样的构造方式.
采用 LinkedBlockingQueue,最多可有 50000 个任务在阻塞队列中,线程池最大值设置 40 个,核心池大小设置 2 个,多出来的 38 个线程最多活跃 60 秒就会被回收.
private static ExecutorService saveThreadPool = new ThreadPoolExecutor(2, 40, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(50000), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
拒绝采用 CallerRunsPolicy,不会丢弃任务,只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务.显然这样做不会真的丢弃任务,但是,任务提交线程的性能极有可能会急剧下降.
在代码测试中,执行了 top,发现 cpu 的利用率稳定在 24% 左右, 这个可以接受
测试结果:
每秒钟 1 千 2,这个也远远超过了性能指标,而且日志也全都记录到数据中,不过这个不是及时性的,它会在测试程序结束 1 分钟后,才会完成数据如插入,这个和队列任务有关.
总结:
这个线程池我是没有关闭的,因为每次任务提交后队列中还有很多任务,如果关闭的话,每次在开启一个线程池会降低速度,所以这个就不关闭了吧
如果有大神看出什么端倪的话,欢迎批评斧正,继续优化,个人感觉还有提升空间.
原文作者:风的轻语
来源: http://mp.weixin.qq.com/s/Kj6lgmTy2eRmAghaUfZINQ