Week_07 总结
性能测试
性能测试的意义
性能优化的基础
性能优化结果的度量标准
性能标准
主观性能
用户感受到的性能
客观性能
性能指标衡量的性能
性能指标:
响应时间
并发数:系统在某一时刻,同时处理的请求数(注意与在线用户数,系统用户数区别)
吞吐量:单位时间内处理的请求数,如请求数/每秒,业务数/每小时,访问人数/每天。
TPS:每秒事务数
HPS:每秒 http 请求数
QPS:每秒查询数
性能计数器
系统负载
线程数
进程数
cpu
内存
磁盘
网络使用率
性能测试方法
性能测试
验证系统在资源可接受范围内,能否达到性能预期
负载测试
达到了最初的预期后,持续增加压力,直到系统达到临界值,此时再加压,性能不升反降
压力测试
系统超过安全负载后,直到系统崩溃或不在处理任何请求,此时系统能承受的最大压力
通过这样的图表,很容易反应系统指标。有助于后续分析决策
稳定性测试
在特定软硬件网络环境条件下,加载一定的业务压力,使系统运行较长时间,检测系统是否稳定
全链路性能压测
特定业务场景下,相关链路完整串联,并同时施加压力,尽可能模拟用户行为。当系统的流量进入后,必定会暴露系统性能瓶颈
全链路压测的难点
压测数据的构造
压测数据模型如何贴近真实情况
线上压测,如何保障对线上的无影响
测试的流量如何构造
数据构造
数据隔离
逻辑隔离
方法:测试数据和业务数据放一起,通过特殊标识区分
缺点:污染线上数据,存在数据安全隐患
虚拟隔离
方法:对写数据的位置进行 mock,不真正的入库
缺点:压测结果的准确性产生干扰
物理隔离
方法:所有写数据的地方进行压测流量识别,写到隔离的位置,包括存储,缓存,搜索引擎等等
缺点:额外的资源
流量构造
通过 cdn 进行流量构造
性能优化
优化原则
不能优化一个没有经过性能测试的软件
不能优化一个不了解的软件
性能优化的流程
性能测试
根据测试指标进行分析,发现性能和资源瓶颈点
架构与代码分析,定位瓶颈点
架构与代码以及其他方面进行优化,优化关键技术点,平衡资源利用
再次进行性能测试
系统优化的分层思想
从上到下,从全局到细节,全方位从不同维度,思考可优化的点。
机房与骨干网络的性能优化
异地多活,多机房架构
专用网络与自主 cdn 建设
服务器与硬件性能优化
直接换更好的硬件设施,性能提升是数量级的。网络吞吐量如果持续达到最大值,说明网卡是瓶颈
操作系统性能优化
例:通过一段时间内 cpu 使用率的分析(系统 cpu 使用率与用户态 cpu 使用率)
tips: linux 大页类型有两类:普通大页(Huge Pages)和透明大页(Transparent Huge Pages),这些大页是为了适应越来越大的系统内存管理而出现的。二者的区别是普通大页管理是预分配的方式,而透明大页管理则是动态分配的方式。
示例中由开启透明大页导致的 cpu 系统使用率高问题,说明跑的应用程序,是密集型内存运算的程序
虚拟机性能优化
例子中,讲了 java 虚拟机的垃圾回收对性能的影响。对应 golang 中的运行时系统和垃圾回收机制。
基础组件性能优化
基础组件的不同版本,性能也不一样
软件架构性能优化
优化手段有缓存,异步,集群
读操作通过缓存来优化;写操作通过异步的方式来优化;通过集群扩展系统整体处理能力
软件代码性能优化
易于阅读的代码是好代码
并发编程(多线程与锁)提高性能
池化技术(线程池,对象池)
异步编程(生产者消费者)
数据结构的优化
操作系统并发请求的处理
系统设计时,架构师脑子里应该有整个运行时的视图
锁引起阻塞
锁的使用会引起线程阻塞,如果阻塞时间过长,同时大量请求进入,会导致系统崩溃
避免阻塞引起崩溃
限流:控制进入系统的请求数。进入系统的请求越多,越会消耗系统的资源(cpu,内存,网络),这些资源消耗过大,会导致系统的不可用
降级:关闭程序部分功能,尽早释放线程
反应式编程
锁
轻量级锁(CAS 指令):通过 cpu 上的 CAS 指令实现。
重量级锁(互斥锁):通过阻塞线程+自旋锁+cpu 指令的方式(等待队列和引用计数器)
CAS 锁的问题
CAS 指令针对指定的 cpu 进行操作,多 cpu 情况下会有多个线程进入临近区,导致锁失败。这种情况下,需要操作系统和硬件本身去支持。
总线锁:某 cpu 在内存总线上发出 lock 信号后,独占内存,其他 cpu 阻塞。(代价过大,使性能急剧下降)
缓存锁:如果内存里数据已经被缓存到了 cpu 缓存行中,且在 lock 期间被锁定,那么当 cpu 计算完毕后,回写内存时,通过缓存一致性机制保证操作的原子性。
可重入锁(读写锁)
悲观锁:(业务级别说法)读取数据之前加锁,哪怕它在临界区中未修改数据
乐观锁:(业务级别说法)先读取数据,改写操作时,再判断此期间是否有其他线程进行了写入。(理解程度较浅)
分段锁:哈希结构中使用较多
自旋锁:通过循环不停的去获取锁,此间线程不会阻塞,不会切换上下文,但是会消耗 cpu
Actor 模型
与 erlang 中的 actor 一样,每一个 actor 有自己的 mailbox,用于接收消息队列。有一组线程池。轻量级 actor 如果有消息时,会以操作系统协程的方式将逻辑放入线程上下文中执行。调度的粒度更细,协程更轻量。
评论