字节一面凉了!被问接口超时频繁,线程池该怎么优化?面试官:你管这叫高并发优化?
一、真实面经栽在线程池这个坑里上周朋友去字节面后端岗上来就是一道场景题线上接口超时频繁报错堆在一起你看了下日志发现大部分都卡在线程池队列满了拒绝请求你会怎么优化朋友想了两分钟回答说那把核心线程数调大一点队列容量也改大一点不就能装更多请求了。面试官听完就笑了你管这叫高并发优化然后就没有然后了。其实这真不能怪他很多人对线程池的理解还停留在创建的时候填四个参数知道核心线程、最大线程、存活时间、队列就完事了。真到线上出问题全靠瞎调参数蒙对了就万事大吉蒙错了反而更糟。这里要注意线程池调优不是越大越好。队列加太大请求堆积多了反而会让平均响应时间更长用户还是超时。线程开太多CPU 切换不过来上下文切换开销把性能都吃掉了。有意思的是很多公司的线程池配置从项目上线那天起就没动过。默认参数用到底出了问题才慌慌张张改一改改完又出新问题。其实线程池调优是有章法的不是靠感觉瞎蒙。二、别上来就调参数先搞清楚问题在哪碰到接口超时全是线程池拒绝第一步真不是改参数。你得先搞明白到底是请求真的太多了还是线程卡在那里动不了两种情况解法完全不一样。如果是某个慢查询把线程都block住了你就算开一百个线程很快还是会被占满问题根本没解决。这个时候应该去优化慢接口而不是扩容线程池。这里说个简单的判断方法看一下线程的平均等待时间和实际执行时间。如果等待时间很长执行时间很短说明确实是线程数不够请求排不上队。如果执行时间本身就很长那问题出在任务本身不是线程池。举个例子你的接口处理一次请求需要 100ms8 核机器开了 16 个线程理论上每秒能处理 160 个请求。如果每秒来了 300 个请求那自然排不过来这个时候可以考虑扩容。如果每个请求要等 2 秒数据库查询开 100 个线程一下子就占满了这时候优先优化 SQL 加索引比加线程有用多了。线程池解决的是排队问题不是慢问题。先治病还是先止痛得分清楚。很多人误以为核心线程数就设成CPU核数乘以2就行。其实这个公式只适用于CPU密集型任务。如果你的任务大部分都是在等IO——等数据库、等第三方接口那线程数可以设得大很多因为很多线程都是在等待CPU其实是空的。举个实际例子我之前做过一个推送服务大部分时间都在等第三方网关回调线程数开到 CPU 核数的 10 倍吞吐量反而更高因为闲着也是闲着多开线程能多处理请求。三、真正实用的优化步骤一步步来搞清楚问题之后再动手优化就不会错了。说几个实战中真正有用的优化手段按顺序来第一缩小任务本身的执行时间。这是性价比最高的优化。把慢SQL优化了把不必要的串行调用改成并行加上缓存能解决 80% 的问题。任务跑得快了自然不需要那么多线程排队。第二根据任务类型设置合理的线程数。公式给你放这了线程数 CPU核数 × (1 平均等待时间 / 平均计算时间)等待时间越长需要的线程越多。IO密集型任务等待时间远大于计算时间线程数可以大一点。CPU密集型计算时间占比高线程数接近CPU核数就够了开多了反而增加切换开销。第三拒绝策略真的很重要。很多人默认用AbortPolicy队列满了直接抛异常用户直接看到报错。其实更合理的是用CallerRunsPolicy让提交任务的线程自己去执行这个任务这样能把请求速率降下来不至于把所有用户都拒绝了。当然你也可以自己实现拒绝策略把请求放到Redis队列里慢慢处理或者直接返回系统繁忙请稍后重试给用户比直接抛异常强得多。第四队列选型别瞎选。你用无界LinkedBlockingQueue试试请求一来堆积几万条内存直接炸掉。所以生产环境一定要用有界队列。那用SynchronousQueue好不好这个队列不存任务来了直接提交给线程线程不够就拒绝适合请求量大但处理快的场景能减少排队延迟。如果你希望请求尽量都能处理接受一点延迟那就用有界LinkedBlockingQueue。这里踩过坑才知道队列不能太长。队列太长请求排队时间久了用户还是超时你堆积那么多请求干嘛还不如早点拒绝让用户重试或者降级。还有一点容易忽略不同类型的任务要分开线程池。你不能把推送任务、导入任务、接口请求都塞到同一个线程池里。一旦某个类型的任务把线程都占满了其他正常请求也别想处理了全被连累。拆分之后就算一个池子炸了不影响其他业务。四、别光说不练线上要这么监控调完参数不是完事了你得盯着看实际运行效果。线程池有几个关键指标必须监控当前活跃线程数是不是经常跑到最大线程数说明确实不够用队列中等待的任务数是不是经常排队排满任务完成速度和提交速度对比如果提交一直比完成快那迟早会崩平均执行时间、平均等待时间看你的调优有没有效果其实很多问题监控一看就明白。你调完参数观察一天看看拒绝次数还多不多接口超时率降了没有一目了然。面试官其实不care你能背出多少参数他就想知道你线上真碰到问题会怎么一步步分析解决。你把这套诊断流程说出来比你背十个线程池参数有用多了。回到最开始那个问题接口超时频繁线程池队列满了拒绝请求你该怎么回答别上来就说加大线程加大队列先问清楚任务是CPU密集还是IO密集现在每个任务平均执行时间多少是不是有慢接口拖后腿然后再一步步来先优化任务再调整参数再拆分隔离最后上监控。这么说面试官基本就满意了。很多时候候选人凉不是因为不知道线程池是什么是因为太着急给答案没搞清楚问题就瞎优化正好踩中面试官挖的坑。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2559213.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!