架构师训练营第 7 周学习总结
7.1 性能测试:系统性能的主要技术指标
性能测试
性能测试是性能优化的前提和基础,也是性能优化结果的检查和度量标准。不同视角下的网站性能有不同的标准,也有不同的优化手段。
主观视角
客观视角
性能测试指标
响应时间:指应用系统从发出请求开始到收到最后响应数据所需要的时间。响应时间是系统最重要的性能指标,直观的反映了系统的“快慢”。
客户端视角
服务端视角
并发数:系统能够同时处理请求的数目,这个数字也反映了系统的负载特性。对于网站而言,并发数即系统并发用户数,指同时提交请求的用户数目,于此相对应,还有在线用户数(当前登录系统的用户数)和系统用户数(可能访问系统的总用户数)。
吞吐量:指单位时间内系统处理的请求的数量,体现件系统的处理能力。对于网站,可以用“请求数/秒”或是“页面数/秒”来衡量,也可以用“访问人数/天”或是“处理的业务数/小时”等来衡量。
TPS(每秒事务数)也是吞吐量的一个指标,此外还有HPS(每秒HTTP请求数),QPS(每秒查询数)等。
并发数是正在处理的。吞吐量是单位时间的。如果说响应时间是1秒钟,并发数就是吞吐量。
吞吐量= ( 1000 / 响应时间ms ) × 并发数
性能计数器:是描述服务器或操作系统性能的一些数据指标。包括System Load、对象与线程数、内存使用、CPU 使用、磁盘与网络I/O 等指标。这些指标也是系统监控的重要参数,对这些指标设置报警阀值,当监控系统发现性能计数器超过阀值的时候,就向运维和开发人员报警,及时发现处理系统异常。
性能测试方法
性能测试是一个总称,具体可细分为性能测试、负载测试、压力测试、稳定性测试。
性能测试(狭义):以系统设计初期规划的性能指标为预期目标,对系统不断施加压力,验证系统在资源可接受范围内,是否能达到性能预期。
负载测试:压测系统最大的处理能力。TPS不但不会增加,反而会下降。
压力测试:超过安全负载的情况下,对系统继续施加压力,直到系统崩溃或不能再处理任何请求,以此获得系统最大压力承受能力。
稳定性测试:被测试系统在特定硬件、软件、网络环境条件下,给系统加载一定业务压力,使系统运行一段较长时间,以此检测系统是否稳定。在生产环境,请求压力是不均匀的,呈波浪特性,因此为了更好地模拟生产环境,稳定性测试也应不均匀地对系统施加压力。
7.2 全链路压测的挑战
全链路压测其实指的就是在特定的业务场景下,将相关的链路完整的串联起来同时施压,尽可能模拟出真实的用户行为,当系统整站流量都被打上来的时候,必定会暴露出性能瓶颈,才能够探测出系统整体的真实处理能力,以及有指导的在大促前进行容量规划和性能优化,这便是线上实施全链路压测的真正目的。
数据构造
Dump真实线上数据
清洗,过滤,脱敏,隔离,订正
基础数据池
BI构造数据
限流调用
流量平台
数据隔离
读操作没有问题,写操作怎么办
逻辑隔离,和正常数据一起,加标识符区分。有可能破坏线上数据。
虚拟隔离,Mock
物理隔离,压测数据写到特定服务器
流量构造
流量平台,CDN模拟用户请求,CDN部署压测引擎。
Master-Slave机构,流量控制台是Master, CDN压测引擎是Slave。
7.3 性能优化:系统性能优化的分层思想
软件性能优化的两个基本原则
你不能优化一个没有测试的软件
你不能优化一个你不了解的软件
拿到一个锤子,看到什么都是钉子
性能优化的一般方法
性能测试,获得性能指标
指标分析,发现性能与资源瓶颈点
架构与代码分析,寻找性能与资源瓶颈关键所在
架构与代码优化,优化关键技术点,平衡资源利用
性能测试,进入性能优化闭环
系统性能优化的分层思想
机房与骨干网络性能优化
异地多活
服务器与硬件性能优化
硬盘
网卡
操作系统性能优化
CPU操作类型Sys
虚拟机性能优化
基础组件性能优化
组件的升级
软件架构性能优化
缓存
异步
集群
软件代码性能优化
清晰的,易于阅读和维护的代码
7.4 操作系统:计算机如何处理成百上千的并发请求?
程序运行时架构
程序是静态的。程序运行起来以后,被称作进程。
可执行代码的第一行入口交给CPU执行
堆主要放程序在运行过程中自己申请的一些内存,创建的一些对象,数据结构
栈是进程自己在执行的过程中,进程自己的上下文一些信息。
操作系统多任务运行环境
进程的分时执行 - 进程分时的在CPU核心上运行,可以使CPU的核心数目在远低于进程数目的情况下使所有的进程都可以同时运行。
进程的运行期状态
运行 - 一个进程正在CPU上运行
就绪 - 获得除CPU之外的所有资源
阻塞 - 进程等待某一事件发生而暂停运行,即使把CPU分配给进程也无法运行。
进程 VS 线程
单进程多线程 - 不同进程轮流在CPU 上执行,每次都要进行进程间CPU 切换,代价非常大。因此服务器应用通常是单进程多线程。
线程栈 - 每个线程都有自己的栈空间,每个线程在自己的栈空间记录局部变量。
线程安全 - 当某些代码修改内存堆(进程共享内存)里的数据的时候,如果有多个线程在同时执行,就可能会出现同时修改数据的情况。
临界区 - 多个线程访问共享资源的这段代码被称为临界区,解决线程安全问题的主要方法是使用锁,将临界区的代码加锁,只有获得锁的线程才能执行临界区代码。
阻塞导致高并发系统崩溃 - 锁(I/O)会引起线程阻塞。阻塞导致线程既不能继续执行,也不能释放资源。进而导致资源耗尽。最终导致系统崩溃。
避免阻塞引起的崩溃
限流
降级
反应式:异步,无临界区(Actor模型)
7.5 锁:锁原语CAS与各类锁
锁原语CAS
CAS(V,E,N)
V 表示要更新的变量
E 表示预期值
N 表示新值
如果V 值等于E 值,则将V 的值设为N,若V 值和E值不同,什么都不做。
CAS 是一种系统原语,原语的执行必须是连续的,在执行过程中不允许被中断。
Java 通过CAS 原语在对象头中修改Mark Word 实现加锁
Mark Word
正常
biased_lock: 0
lock: 01
偏向锁: 指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价
biased_lock: 1
lock: 01
轻量级锁:指当锁是偏向锁时,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能
ptr_to_lock_record,指向一个地址,CAS
重量级锁:指当锁是轻量级锁时,另一个线程虽然自旋,但自旋不会一直持续下去,当自旋到一定次数时,还没获取到锁,就会进入阻塞,该锁膨胀为重量级锁,重量级锁会让其他申请的线程进入阻塞,性能降低
ptr_to_heavyweight_monitor,指向一个队列
多CPU 情况下的锁
总线锁与缓存锁
公平锁 非公平锁
可重入锁 - 例如递归
独享锁/互斥锁共享锁读写锁
乐观锁 悲观锁
乐观锁则认为对于同一个数据的并发操作,是不会发生修改的。在更新数据的时候,检查是否已经被修改过,如果修改过,就放弃。
分段锁
JDK ConcurrentHashMap 是通过分段锁的形式来实现高效并发操作的。
自旋锁
7.6 案例:异步并发分布式编程框架akka
Akka’s vision
Simpler concurrency (scale up) 垂直伸缩
Simpler distribution (scale out) 水平伸缩
Simpler fault-tolerance (self healing)
All of that with a single unified programming model
Actors are small
The Akka toolkit
Akka runs on the JVM
Akka can be used from Java and Scala
Akka can be integrated with common infrastructure, e.g. Spring,etc.
Core concept: Actor
Behavior - react on messages it receives
State - shielded from the rest of the world, no need for synchronization
Communication - interact with other actors exclusively via messages
The Akka Actor
Actor之间的调用通过消息传输的
Mailbox - 一次只处理一个消息
Actor之间不共享状态
线程池
Receive message - One at a time
Send message - Asynchronous and nonblocking
ActorRef path
Local
Remote
The Akka ActorSystem
actor system
top-level actor
child actor
Benefits of using Akka actors
You don’t have to deal with concurrency details
You can manage failures easily
Distribution is just a deployment decision (not covered here)
评论