本文原文链接
文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 :
免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备
免费赠送 :《尼恩技术圣经+高并发系列PDF》 ,帮你 实现技术自由,完成职业升级, 薪酬猛涨!加尼恩免费领
免费赠送 经典图书:《Java高并发核心编程(卷1)加强版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 经典图书:《Java高并发核心编程(卷2)加强版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 经典图书:《Java高并发核心编程(卷3)加强版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 资源宝库: Java 必备 百度网盘资源大合集 价值>10000元 加尼恩领取
阿里面试:5000qps访问一个500ms的接口,如何设计线程池的核心线程数、最大线程数? 需要多少台机器?
尼恩特别说明: 尼恩的文章,都会在 《技术自由圈》 公号 发布, 并且维护最新版本。 如果发现图片 不可见, 请去 《技术自由圈》 公号 查找
尼恩说在前面
在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的面试题:
如何确定系统的最佳线程数?
5000qps,下游一个接口响应时间 500ms,接口超时时间 1S,一台机器4核8g,如何设计线程池的核心线程数、最大线程数、队列,需要多少台机器
5000qps访问 一个 500ms响应时间接口,如何设计线程池的核心线程数、最大线程数? 需要多少台机器?
最近有小伙伴在面试阿里,又遇到了相关的面试题。小伙伴懵了,因为没有遇到过,所以支支吾吾的说了几句,面试官不满意,面试挂了。
所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。
当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V171版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,回复:领电子书
本文目录
本文的配套视频, 尼恩的参考答应
https://mp.weixin.qq.com/s/JFWjDSQ4HRGbZhj9ei3t6Q
线程使用的两个核心规范
首先看编程规范中, 有两个很重要的,与线程有关的需要强制执行的规范:
规范一:【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。
说明:Java线程的创建非常昂贵,需要JVM和OS(操作系统)配合完成大量的工作:
1)消耗内存资源:必须为线程堆栈分配和初始化大量内存块,其中包含至少1MB的栈内存。
2)消耗CPU资源:需要进行系统调用,以便在OS(操作系统)中创建和注册内核线程,大量内核线程调度会导致CPU上下文过度切换。
所以,Java高并发应用频繁创建和销毁线程的操作将是非常低效的,而且是不被编程规范所允许的。
如何降低Java线程的创建成本?必须使用到线程池。使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。
以上的内容,在尼恩的 《Java 高并发核心编程 卷2》 进行了详细介绍。
规范二:【强制】 线程池不允许使用Executors去创建快捷线程池 ,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors返回的线程池对象的弊端如下:
- FixedThreadPool和SingleThreadPool: 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
- CachedThreadPool和ScheduledThreadPool: 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
通过以上规范,说明我们应用中,需要用自定义线程池。然而,由于构造一个线程池竟然有7个参数
7个重要参数中,最为重要的三个是:核心,最大线程数量, BlockingQueue。前两个参数和线程数量有关系, 后一个和内存资源消耗有关。
线程数设置太少或者阻塞队列太小, 会导致大量任务被拒绝,抛出RejectedExecutionException,触发线上的接口降级,用户体验很差。
二线程数设置太多或者阻塞队列太长,会导致资源消费高而有效负荷很小, 特别是阻塞队列设置过长,会导致频繁FullGC,甚至OOM。
如何确定系统的最佳线程数?来一个牛逼轰轰的答案
如何确定系统的最佳线程数,大体上分三步:
第一步,理论预估;
第二步,压测验证;
第三步,监控调整。
这也是尼恩给大家归纳的,最为理想的:可监控/可弹性的 线程池模式
第一步: 完成线程数的理论预估 (设计阶段)
在尼恩的 《Java 高并发核心编程 卷2》 进行了详细介绍。
首先,按照任务类型对线程池进行分类, 分为三类,具体如下图:
具体,请参见在尼恩的 《Java 高并发核心编程 卷2》 1.7.1 小节。
核心线程数的设置
- CPU 密集型任务:如果应用程序执行的是CPU密集型任务,通常情况下,核心线程数应该设置为等于CPU核心数。这可以充分利用CPU资源。
- IO 密集型任务:如果应用程序执行的是IO密集型任务(例如,文件读写、网络通信等),通常情况下,核心线程数可以设置为 CPU核心数 2倍,以充分利用等待IO操作时的线程空闲时间。
- 混合型任务:如果应用程序同时执行CPU密集型和IO密集型任务,核心线程数的 按照 线程等待时间 + 线程 工作时间的占比来计算。
第1类:IO 密集型线程池线程数预估
线程数就是 CPU的核数的2倍。
具体,请参见在尼恩的 《Java 高并发核心编程 卷2》 1.7.2 小节。
第2类:CPU密集线程池线程数预估
CPU密集型任务并行执行的数量应当等于CPU的核心数, 线程数就是 CPU的核数
具体,请参见在尼恩的 《Java 高并发核心编程 卷2》 1.7.3小节。
第3类:混合型线程池线程数预估
混合型线程池线程数预估, 参考下面的的公式:
最佳线程数 = ((线程等待时间 + 线程 CPU 时间) / 线程 CPU 时间 ) * CPU 核数
具体,请参见在尼恩的 《Java 高并发核心编程 卷2》 1.7.4小节。
第二步: 完成线程数的压测验证 (测试阶段)
过少的线程会造成任务拒绝,业务降级。
过多的线程会造成,额外的内存开销CPU开销,甚至会导致OOM。
所以,合理的线程池线程数,才是王道。
在设计阶段完成了step1的线程数的理论预估之后, 那么我们的理论值就出来了。
如何做验证呢?这里需要 压测。
根据公式:
服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量
前面线程等待时间,线程cpu时间都是 预估的 ,都是要验证的。
首先通过用户慢慢递增来进行性能压测,观察QPS。
持续大的增加用户数, 压测出最大的吞吐量。
然后再 收集 最大的吞吐量场景的 线程等待时间,线程cpu时间, 再计算出最佳线程数。
第三步: 完成线程数的线上调整 (生产阶段)
压测的场景,是有限的。而线上的业务, 是复杂的,多样的。
由于系统运行过程中存在的不确定性,很难一劳永逸地规划一个合理的线程数。
所以,需要进行生产阶段线程数的两个目标:
- 可监控预警
- 可在线调整
第1个维度:可在线监控预警
第2个维度:可在线调整
参数的在线动态调整:结合Nacos 实现动态化线程池
优秀的动态化线程池轮子,主要有:
- Hippo4J
- dynamic-tp
如果线上使用,可以使用这些轮子项目。
但是尼恩的是[技术自由圈]一个实战社群,必须自己从0到1,去撸一把代码,提升自己的水平。
大实操:5000qps 线程数的理论预估 大实操
1. 核心参数解释
- 请求量 (QPS): 5000 QPS意味着每秒有5000个请求需要被处理。
- 接口响应时间: 500ms,即每个请求的处理时间为500毫秒。
- 接口超时时间: 1秒,表示如果请求处理时间超过1秒,接口就会超时。
- 机器配置: 每台机器4个CPU核心,8GB内存。
2. 核心线程数 设计
为了设计合理的线程池, 需要考虑如何合理配置核心线程数、最大线程数和队列大小。
首先是 核心线程数。
核心线程数决定了线程池中最小的线程数,线程池会始终保持这个数量的线程。
根据 面试的业务场景:
- 每台机器有4个CPU核心,因此每个CPU核心可以并发处理多个请求。通常情况下,核心线程数会设置为与CPU核心数相同。
- 由于接口响应时间是500ms,每个线程可以在500ms内处理完一个请求,因此设置核心线程数为4,或者根据实际负载情况适当调整。
建议: 核心线程数设置为 4(与CPU核心数一致)。
3. 最大线程数 设计
一般业务接口都是混合型 任务, 相对应的 ,线程池 属于 混合型线程池。
混合型任务 的工作,分为两个时间:
- 等待时间,进行大量非 CPU 耗时操作 ,比如在 Web 应用处理 HTTP 请求处理时,一次请求处理会包括 DB 操作、 RPC 操作、缓存操作等多种耗时操作。
- 工作时间, 执行简单的计算,一般是 几十个ms 搞定。
所以,混合型任务 CPU 利用率不是太高,非 CPU 耗时往往是 CPU 耗时的数10倍。
一般来说,一次 Web 请求的 CPU 计算耗时往往较少,大致在 20ms-50ms 之间,而其他耗时操作会占用 500ms-1000ms 甚至更多的时间。
在为混合型任务创建线程池时,如何确定线程数呢?
业界有一个比较成熟的估算公式,具体如下:
最佳线程数 = ((线程等待时间+线程CPU 时间) / 线程CPU 时间 ) * CPU 核数
比如在 Web 服务器处理 HTTP 请求时,假设平均线程 CPU 运行时间为 50ms,而线程等待时间(比如包括 DB 操作、 RPC 操作、缓存操作等)为500ms,如果 CPU核数为 4,那么根据上面这个公式,估算如下:
((500+50) / 50) * 4 ≈ 50
建议:最大线程数50
4. 线程池 的队列大小 设计
队列的大小决定了等待处理的请求数量。
一般来说,线程池的队列大小设置与最大线程数成正比。
-
如果队列太小,可能会导致请求被拒绝;
-
如果队列太大,会导致内存压力增大。
在高并发场景下,为避免内存占用过高,队列的大小可以设置为最大线程数的2倍左右。
建议: 队列大小设置为 50*2 =100 。
5. 计算所需机器数量
为了计算所需机器数量,我们首先要计算每台机器能够处理的请求量,然后计算出总请求量所需的机器数。
a. 每台机器的处理能力
每台机器的4个CPU核心可以并行处理多个请求,假设每个线程的响应时间为500ms。
每个线程每秒能处理 2 个请求(500ms处理一个请求,1秒可以处理2个请求)。
每台机器的最大请求处理能力为:
- 最大请求处理能力 =
每台机器最大线程数 * 每个线程每秒处理的请求数
- 假设最大线程数为50,每台机器的最大处理能力为:
50 * 2 = 100
个请求/秒。
6. 所需机器数量
如果系统需要处理5000 QPS,每台机器可以处理100个请求/秒,计算所需机器数量:
- 所需机器数量 = 总请求量 / 每台机器处理能力
所需机器数量 = 5000 QPS / 100 请求/秒/机器 ≈ 50
台机器。
为了保证性能和冗余,建议多几台,因此需要 50台机器。
7. 完成线程数的理论预估 (设计阶段) 总结
- 核心线程数:4(与机器核心数一致)
- 最大线程数:50(根据负载情况)
- 队列大小:100(根据最大线程数设置)
- 所需机器数量:大约 50 台机器
这些设置可以根据系统的实际负载和性能需求进一步调整。
相关面试题:
阿里面试:系统的最佳线程数,怎么确定?
说在最后:有问题找老架构取经
只要按照上面的 尼恩团队梳理的 方案去作答, 你的答案不是 100分,而是 120分。 面试官一定是 心满意足, 五体投地。
按照尼恩的梳理,进行 深度回答,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。
在面试之前,建议大家系统化的刷一波 5000页《尼恩Java面试宝典PDF》,里边有大量的大厂真题、面试难题、架构难题。
很多小伙伴刷完后, 吊打面试官, 大厂横着走。
在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。
另外,如果没有面试机会, 可以找尼恩来改简历、做帮扶。前段时间,刚指导一个小伙 暴涨200%(涨2倍),29岁/7年/双非一本 , 从13K一次涨到 37K ,逆天改命。
狠狠卷,实现 “offer自由” 很容易的, 前段时间一个武汉的跟着尼恩卷了2年的小伙伴, 在极度严寒/痛苦被裁的环境下, offer拿到手软, 实现真正的 “offer自由” 。
技术自由的实现路径:
实现你的 架构自由:
《吃透8图1模板,人人可以做架构》
《10Wqps评论中台,如何架构?B站是这么做的!!!》
《阿里二面:千万级、亿级数据,如何性能优化? 教科书级 答案来了》
《峰值21WQps、亿级DAU,小游戏《羊了个羊》是怎么架构的?》
《100亿级订单怎么调度,来一个大厂的极品方案》
《2个大厂 100亿级 超大流量 红包 架构方案》
… 更多架构文章,正在添加中
实现你的 响应式 自由:
《响应式圣经:10W字,实现Spring响应式编程自由》
这是老版本 《Flux、Mono、Reactor 实战(史上最全)》
实现你的 spring cloud 自由:
《Spring cloud Alibaba 学习圣经》 PDF
《分库分表 Sharding-JDBC 底层原理、核心实战(史上最全)》
《一文搞定:SpringBoot、SLF4j、Log4j、Logback、Netty之间混乱关系(史上最全)》
实现你的 linux 自由:
《Linux命令大全:2W多字,一次实现Linux自由》
实现你的 网络 自由:
《TCP协议详解 (史上最全)》
《网络三张表:ARP表, MAC表, 路由表,实现你的网络自由!!》
实现你的 分布式锁 自由:
《Redis分布式锁(图解 - 秒懂 - 史上最全)》
《Zookeeper 分布式锁 - 图解 - 秒懂》
实现你的 王者组件 自由:
《队列之王: Disruptor 原理、架构、源码 一文穿透》
《缓存之王:Caffeine 源码、架构、原理(史上最全,10W字 超级长文)》
《缓存之王:Caffeine 的使用(史上最全)》
《Java Agent 探针、字节码增强 ByteBuddy(史上最全)》
实现你的 面试题 自由:
4800页《尼恩Java面试宝典 》 40个专题