【关于性能优化】15道「私藏」面试题答案解析公布原创
前言
之前我们在社区进行了1场面试题打卡活动,其中针对前端、后端、测试的面试题向大家征集题解;目前该活动已结束,其中涉及的面试题及答案解析列在本文,供大家参考!💥有不同想法的伙伴,欢迎在评论区留言、探讨哦~
本文的主要内容是👇:
- 后端岗位面试题及答案解析
- 前端岗位面试题及答案解析
- 测试岗位面试题及答案解析
后端岗位面试题及答案解析
一、如何面向内存实现一个map数据结构?如何设计存储协议、写入/检索策略?
本题主要考察的点在于存储协议的设计,以及基于写入/检索的需求来优化存储协议;首先需要阐述清楚如何设计存储协议能够实现map结构的正常put/get操作,例如:
1、最简单的回答,使用一个二维对象数组,index 0 作为key,index 1 作为 value,然后一维值每一个元素即是一对KV,记录一个当前的size,put就直接在尾部追加,get则遍历比对key值。
2、进阶一些的,使用一个一维字节数组,然后每一对KV使用一个不定长的存储单元,该存储单元的协议设计为[4字节单元长度][4字节key长度][key内容][value内容],然后记录一个全局的index标记,put就在尾部追加存储单元,get则遍历比对key值
3、更进阶一些的,下列都属额外加分项:
①如果优化检索效率?例如:针对i,可以利用key散列使用多个二维数组;针对ii,可以利用key散列使用多个字节数组。
②如何支持多线程安全操作?回答copyonwrite;同步锁计算存储长度,并发进行内容写入等答案皆可,并发实现有非常多解决方案。
二、如何面向磁盘实现一个map数据结构?如何设计存储协议、写入/检索策略?
和上一题类似,但是因为基于磁盘,所以你没法直接采用多维对象数组的方式,而是
1、将文件映射成为一个多维数组依然可行,例如最简单的使用一个properties文件,一行一组KV,天然就支持了这个结构。
2、进阶一些的,采用类似上一题中一维字节数组的协议设计,把一个文件映射到内存,或者直接操作文件流皆可,具体方式就按上一题的设计,只是载体发生了变化
3、更进阶一些的,下列都属额外加分项:
①优化检索效率,上一题中提到的方案依然适用,但是载体发生了变化,变为使用多个文件;
②如果支持多线程安全操作?同样可以采取上题中说到的方案,但是因为文件系统的特殊性,copyonwrite策略需要做一些调整,例如做A/B完整备份的方案,在写时临时使用其中一个作为写副本,另一个读,写结束后同步;同步锁计算存储长度,并发内容写入的方案依然适用
③基于磁盘如果额外答道考虑顺序读写相关的优化加分
三、如何高效的实现一个可水平扩展的全局ID生成服务?如何保证全局id的唯一性?
首先需要阐述清楚id的组成策略,最简单的方案:
1、64bit长度的id,16bit机器码 + 16bit计数器 + 32bit时间戳秒值(使用一个业务预设值的差值,而并非UNIX时间戳,以节约空间)
2、需要阐述相关设计针对的业务特性,例如上述设计,16bit机器码支持65536台机器同时构建id而不重复;16bit计数器支持在1秒内最高生成65536个id;也就是这个方案支持最高同时1秒内构建65536*65536个id,即该方案支持的最高秒级并发构建上限;32bit时间戳秒值,则声明该方案可以支持在业务预设时间值向后的推移的2000年内都不会产生重复id
3、上述仅是一个例子,只要能够在该框架内阐述清楚设计和设计对应的目的和特性皆可
四、如何实现一个无锁队列?简述无锁实现的原理与逻辑。并说明优缺点与适用场景?
1、基本能够阐述清楚lock-free ringbuffer的设计原理即可,阐述无锁链表实现亦可,但无锁链表实现相对复杂度更高,目前也没有太多工业实践,所以需要更多的细节阐述如果保证线程安全性。具体内容使用我前述的关键字都能检索到相关论文,可自行查询。
2、优缺点部分,能够提到ringbuffer容量问题,以及CAS竞争问题即可;使用场景也是应这两个特性而具体选择的,能够相互合理解释即可。
五、如何实现一个高效的网络请求服务端?简述通信协议的设计,网络线程模型的设计?
本题主要考察对网络通信部分实现细节的了解
1、基础回答,能够使用同步io,阐述清楚网络协议的设计,如何处理数据正确性等问题即可;例如:
①协议部分设计: 协议头[4字节整体长度][4字节协议头长度][协议头内容][协议体内容]
②利用协议中的包长度识别数据正确性问题
③同步io基本不涉及线程模型设计
④如果能够提到使用协议头中添加数据校验位来保证数据正确性加
2、进阶回答,使用异步io,
①协议部分设计与同步io时类似,但是需要增加请求标识位概念,以用于对应返回数据包
②数据正确性设计与同步io时类似,如果能够提到使用协议头中添加数据校验位来保证数据正确性加分
③重点在线程模型设计,主要的点在于io与业务处理线程分离;io线程与业务线程如何交互;两类线程分别按何种指标进行设计,大概的计算方式是怎样(比如一般io线程都以cpu逻辑核心位标准来定数量是因为什么)
3、更多的额外加分项:
①如果通过协议设计来进一步压缩请求包大小以提升网络效率
②如何处理异常情况来保障服务的可用性?长短链接的选择,优缺点和适用场景
前端岗位面试题及答案解析
一、前端大数据量UI渲染性能优化都有些哪些方法?
⼤数据量的DOM节点渲染主要会带来两个主要的性能问题:
1、DOM节点创建带来的高CPU占⽤,极端条件下会甚⾄导致CPU被瞬间拉满,页面出现卡顿现象;
2、海量DOM带来的内存占用量飙升;
通常来说有⼀些原生的API可以被利用,比如通过创建DocumentFragment延迟将节点添加到DOM树,减少不必要的Reflow来提升性能,但在数据量比较大的情况下依然无法有效解决性能瓶颈。在web页面中我们实际可见的内容区域是有限的,那么解决方案可以自然转换成如何只渲染可见范围内的DOM节点。通常有两种方案:懒加载、虚拟列表;懒加载通常适⽤与数据量不是特别大的场景,因为懒加载本身不做DOM节点的销毁,只是延迟加载不可见的DOM节点;而虚拟列表在组件库、业务中都有广泛应用,虚拟列表本质上也是实时计算可见区域位置的内容按需渲染DOM节点,不渲染可见区域外的DOM节点,这样把需要渲染的DOM节点数量控制在⼀个比较小的范围,显著提升页面性能。当然内存方面大数据量依然可能导致高内存占用量,可根据实际情况使用本地存储(LocalStorage、IndexedDB等)来代替内存储
二、前端性能优化指标有哪些,如何提升?
和前端性能相关的指标非常多,但这些指标里我们可以分为两类:⼀类是技术指标,⼀类是体验指标
1、技术指标可以用过浏览器API、业务埋点等方式获取,比如Performance上的大量API可以获取到大量技术型指标;
2、体验指标更注重用户实际使用体验感受的量化,这类指标目前比较主流的是Google Web Vitals,其中LCP、FID、CLS三个指标基本能涵盖用户的实际体验感受。但现实情况可能要更复杂的多,这三个指标数据提升后,可能也并不能完全带来实际体验的提升,因为现代web应⽤是交互式的,而这三个指标的采集计算⽬前主要针对页面首次加载渲染;因此我们还可以自定义⼀些指标,比如白屏时间、操作链路耗时这些实际的体验指标。
同样,关于指标数据的提升,可通过Google Web Vitals中的案例、Lighthouse中的建议进⾏优化,这些优化方案主要集中在网络的优化,比如CDN的使用、资源压缩、无效资源的优化等等;同时业界也沉淀了大量的最佳实践,比如SSR、SSG、PWA、预加载等
深入了解可参考文章:
性能优化基础实践https://heapdump.cn/article/3487842
以用户为中心的性能指标https://heapdump.cn/article/3479917
Largest Contentful Painthttps://heapdump.cn/article/3475558
优化 Largest Contentful Painthttps://heapdump.cn/article/3475737
核心web指标对业务的影响https://heapdump.cn/article/3475373
三、前端性能数据采集上报方案
⼀个完整的监控系统必备的几个主要能力:采集、上报、存储、分析、告警;
对前端来说这其中采集、 上报需要在端侧通过JS来实现,要尽可能准确、及时地采集、反馈性能数据,同时也需要兼顾整个系统的稳定性。因此三个目标:准确、及时、稳定。准确性保障上建议尽可能使⽤浏览器原⽣Performance API以及业界成熟方案。Google web vitalsLighthouse都包含了丰富的API可应用在先上线控集巡检的场景中。业务自定义指标可通过自定义采集上报的SDK来实现,业务型的自定义监控数据⼀般对业务会有⼀定侵入性,需要业务配合在埋点上报。但可通过对HTML节点配置钩子的而不是编码的形式将侵⼊性降低。不论业界成熟的⽅案还是自研实现的探针,除了降低侵入性这样的问题外,还会面临探针脚本加载方案以及上报方案问题。加载脚本要尽可能早但又不至于阻塞页面性能,上报方案要有采样率、合并上报等特性支持来满足稳定性上的诉求。
深入了解可参考文章:
Lighthouse 定制篇https://heapdump.cn/article/3469800
Lighthouse 篇https://heapdump.cn/article/3469499
四、主流框架React/Vue中性能优化方案
React组件生命周期图
React组件的性能优化主要方向集中在两个方面:1. 减少不必要的virtual dom diff,2. 减少不必要的组件更新;相对应的⼀些方法技巧如下:
1、使⽤PureComponent通过浅比较的方式来对props、state进行diff,减少不必要的组件更新
2、使⽤memo对函数组件的props做浅层对比减少不必要的组件更新
3、使⽤shouldComponentUpdate更细粒度的控制组件的diff和更新逻辑
4、合理使用Context,Context数据的变化会直接穿透memo和shouldCompoentUpdate的⽐较
5、通过发布订阅者模式更新数据,而不是通过props层层传递
6、使用lazy、React.Suspense懒加载组件,优化代码体积
7、合理使用截流、防抖机制减少频繁的数据更新带来的组件无用渲染
8、避免使用内联函数,减少组件更新时候函数的销毁和创建⼯作
9、为数据列表项制定唯⼀key
五、工程化工具中有哪些能力能带来性能的提升?
在webpack依然占据前端构建工具近90%份额的前提下,我们看看webpack可以在构建阶段给我们带来⼀些什么样的性能提升。
1、资源文件体积压缩,不论是JS、CSS还是图片在webpack的庞大生态体系中都有丰富的插件支持文件的压缩
2、按需加载,ESModule(动态import),CommonJS都有相应方法支持(ensure)
3、splitChunks开启代码拆分打包
通过externals配置避免将全局公用模块打入每个工程的构建产物中
深入了解可参考文章:
webpack5优化实战https://heapdump.cn/article/3466991
测试岗位面试题及答案解析
一、性能测试过程中什么情况下会用到思考时间?具体作用是什么?
1、如果性能测试对象是一个单一的业务,如单个API或单个业务场景,则不需要用到思考时间
2、设置考虑时间,是为了保证测试复合业务的时候,各个业务之间的比例关系符合我们的真实生产环境(即模拟真实生产用户操作)
二、QPS、TPS、RT和并发数间的关系
1、RT-响应时间:执行一个请求从开始到最后收到响应数据所花费的总体时间,即从客户端发起请求到收到服务器响应结果的时间;是一个系统最重要的指标之一,它的数值大小直接反应了系统的快慢。
2、QPS-QPS:Queries Per Second意思是“每秒查询率”,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准;主要用于查询场景
3、TPS:是TransactionsPerSecond的缩写,也就是事务数/秒。它是软件测试结果的测量单位。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程
4、并发数:并发数是指系统同时能处理的请求数量,这个也是反应了系统的负载能力
5、关系:QPS(TPS)= 并发数/平均响应时间 并发数=QPS*平均响应时间
6、通常,平均响应时间越短,系统吞吐量越大;平均响应时间越长,系统吞吐量越小;但是系统吞吐量越大, 未必平均响应时间越短;因为在某些情况(例如,不增加任何硬件配置)吞吐量的增大,有时会把平均响应时间作为牺牲,来换取一段时间处理更多的请求
三、如何识别性能瓶颈?
1、一般来说服务器上的性能瓶颈:如CPU、内存、磁盘读写等的瓶颈,为服务器硬件瓶颈
2、被测应用底层上的性能瓶颈:如服务器操作系统瓶颈(参数配置)、数据库瓶颈(参数配置)、web服务器瓶颈(参数配置)、中间件瓶颈(参数配置)等
3、被测应用程序上的性能瓶颈:应用程序上的性能瓶颈,如SQL语句、数据库设计、业务逻辑、算法等等
4、操作系统上的性能瓶颈:一般指的是Windows、linux等操作系统,如出现物理内存不足时,或虚拟内存设置不合理(虚拟内存设置不合理,会导致虚拟内存的交换率大大降低,从而导致行为的响应时间大大增加,可以认为在操作系统上出现了性能瓶颈)
5、网络设备上的性能瓶颈:一般是防火墙、动态负载均衡器、交换机等设备导致
6、工具或跑脚本机器上的性能瓶颈:如工具的参数配置、最大连接数、施压端机器资源瓶颈等
四、简述性能测试步骤
1、需求分析:根据测试目的,细化需求;熟悉架构
2、测试准备:客户端准备、测试数据准备
3、测试设计:性能测试场景、性能测试用例设计、脚本编写及调试
4、执行测试:监控测试客户端和服务器性能,监控服务器端应用情况,监控数据库情况,运行性能测试脚本
5、分析调优:找出性能瓶颈,提高系统整体性能,满足用户需求
6、测试报告:测试结束后,归档整理测试报告
五、每天300w PV 的在单台机器上,这台机器需要多少QPS?如果一台机器的QPS是58,需要几台机器来支持?
1、按二八定律来看,如果每天 80% 的访问集中在 20% 的时间里,这 20% 时间就叫做峰值时间
2、公式:( 总PV数 * 80% ) / ( 每天秒数 * 20% ) = 峰值时间每秒请求数(QPS)
3、机器:峰值时间每秒QPS / 单台机器的QPS = 需要的机器
①( 3000000 * 0.8 ) / (86400 * 0.2 ) = 139 (QPS)
②139 / 58 = 3
看完本文的大大们,记得给整理试题的大佬们、艰辛编辑的堆堆一点鼓励🤗呀,动动你的小鼠标,点个赞吧!