写点什么

架构师训练营:第七周性能测试、系统、文件系统

用户头像
zcj
关注
发布于: 2020 年 07 月 23 日

性能测试

性能测试是性能优化的前提和基础,也是性能优化结果的检查和度量标准。不同视角下的网站性能有不同的标准,也有不同的优化手段。

性能的两种视角

主管视角:用户感受到的性能。

  • 用户感觉到系统是否及时的在响应请求操作,就是用感受到的性能。

  • 优化手段:前端碎片化响应,把大的请求碎片化为多个小的小的请求。每个请求响应后立即呈现响应结果。使用动画,动态提示的方法等前端的交互方法。让用户感觉系统及时响应了请求操作。

客观视角:性能指标衡量的性能

  • 通过性能测试得到的各项性能指标,根据指标的数值反映系统的性能情况。

  • 优化手段:需要根据具体的情况到系统的不同层级结构中调整优化。

性能测试的指标

不同视角写有不同的性能标准,不同的标准有不同的性能测试指标,网站性能测试的主要指标有响应时间,并发数,吞吐量、性能计数器

  • 响应时间:即完成一次任务花费的时间。指应用系统从发出请求开始到收到最后响应数据所需的时间。响应时间是系统最重要的性能指标,只管的反映了系统的“快慢”。

  • 并发数:即同时处理的任务数。系统能够同时处理请求的数目,这个数字也反映了系统的负载特性。对于网站而言,并发数即系统并发用户数,指同时提交请求的用户数目,于此相对应,还有在线用户数(当前登录的用户数)和系统用户数(可能访问系统的总用户数)。

  • 吞吐量:即单位时间内完成的任务数。指单位时间内系统处理的请求的数量,体现系统的处理能力,对于网站,可以用“请求数/秒”或是“页面数/秒”来衡量,也可以用“访问人数/天”或是“处理的业务数/小时”等来衡量。TPS (每秒事务数)也是吞吐量的一个指标,此外还有 HPS(每秒 HTTP 请求数),QPS(每秒查询数)等。 吞吐量=(1000/响应时间 ms) x 并发数。

  • 性能计数器:是描述服务器或操作系统性能的一些数据指标。包括 System Load、对象与线程数、内存使用、CPU 使用、磁盘与网络 I/O 等指标。这些指标也是系统监控的重要参数,对这些指标设置报警阀值,当监控系统发现性能计数器超过阀值的时候,就向运维和开发人员报警,及时的发现处理系统异常。

性能测试的方法

性能测试是一个总称,具体可细分为性能测试、负载测试、压力测试、稳定性测试

  • 性能测试:以系统设计初期规划的性能指标为预期目标,对系统不断施加压力,验证系统资源在可接受范围内,是否能达到性能预期。性能测试的目的是,获得系统的性能指标

  • 负载测试:对系统不断增加并发请求以增加系统压力,知道系统的某项或多项性能指标达到安全临界值,如某种资源已经呈现饱和状态,这时候继续对系统施加压力,系统的处理能力不但不能提高,反而会下降。负载测试的目的是为了发现系统的性能问题(系统的性能瓶颈、内存泄漏、不能实时同步等问题),从而为性能改进提供帮助。

  • 压力测试:超过安全负载的情况下,对系统继续施加压力,查看应用系统在峰值使用情况下操作行为,从而有效地发现系统的某项功能隐患、系统是否具有良好的容错能力和可恢复能力。直到系统崩溃或不能再处理任何请求,以此获得系统最大承受能力

  • 稳定性测试:系统在特定硬件、软件、网络环境下,给系统加载一定业务压力,使系统运行一段较长时间,以此检测系统是否稳定。在生产环境,请求压力是不均匀的,呈波浪特性,因此为了更好的模拟生产环境,稳定性测试也应不均匀的对系统施加压力。


性能测试中系统吞吐量(TPS)及系统响应时间与用户并发数量的关系曲线图:



性能优化

两个基本原则:

  • 你不能优化一个没有测试的软件:针对性能测试出现的问题去优化,而不是直接使用新的高大上的技术替代原有的技术方案。

  • 你不能优化一个你不了解的软件:需要了解系统的应用场景,针对使用场景对系统优化,否则可能走向错误的优化方向。

性能优化的一般方法

1、性能测试,获得性能指标

2、指标分析,发现性能与资源瓶颈点

3、架构与代码分析,寻找性能与资源瓶颈关键所在

4、架构与代码优化,优化关键技术点,平衡资源利用

5、性能测试,进入性能优化闭环

系统性能优化的分层思想

  • 机房与骨干网络性能优化 :异地多活的多级机房架构、专用网络与自主 CDN 建设等

  • 服务器与硬件性能优化:使用专业的服务器、增加分布式服务器主机数量等

  • 操作系统性能优化:关闭无关的操作系统活动等

  • 虚拟机性能优化:调整虚拟机内存、垃圾回收策略,jvm 参数

  • 基础组件性能优化:各个组件(中间件)针对不同场景专门配置

  • 软件架构性能优化:考虑多级缓存、异步架构、集群架构的使用

  • 软件代码性能优化:考虑多线程与锁,线程池对象池,异步编程,算法与数据结构等方面优化。


操作系统是如何运行程序的

程序的运行时架构

程序是静态的,程序运行起来以后,被称作进程。程序的代码存放在计算机的磁盘中,在程序运行时,代码从磁盘加载到内存交给 cpu 执行。

操作系统如何做到并发

并发定义:是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。

如何做到并发:对多个任务分时执行,每个任务分配一定的小的时间段,CPU 调度一个任务执行完时间段后,在调度其他任务执行。

人为何会感觉到任务在同时执行:一个 CPU 中某时刻只能执行一个任务。由于 CPU 的计算能力非常快,任务的分时执行时间段很小,人来感觉不到,整体上看起来任务还是流畅的执行。

进程与线程

不同进程轮流在 CPU 上执行,每次都要进行进程间 CPU 的切换,代价非常大。因此服务器应用通常是单进程多线程的。

进程从操作系统获得基本的内存空间,所有的线程共享着进程的内存地址空间。而每个线程也会拥有自己私有的内存地址范围(线程栈),其他线程不能访问。

Java Web 应用多线程运行时视图

线程安全问题

一个进程中的多个线程,同时访问修改共享的内存区域的数据时,就会出现线程不安全的现象。倒置修改的数据动作不能产生正确的结果。

解决线程安全为题的主要方法是使用锁。锁将共享的数据保护起来。需要操作被保护数据时需要先获得锁,期间其他线程操作数据时,因为锁只能同时被一个线程持有而不能获得,必须等待前一个线程释放锁才能继续执行,就避免了同时对数据进行修改了。

使用锁会引起线程的阻塞,阻塞倒置线程既不能继续执行,也不能释放资源。进而倒置资源耗尽。最终倒置系统崩溃。

避免阻塞引起系统崩溃的方法

  • 限流:控制计算机的请求数,进而减少创建的线程数。

  • 降级:关闭部分功能程序的执行,尽早释放资源。

  • 避免阻塞:使用异步 I/O ,异步编程模型(Actor 模型)。

程序中的锁

锁的实现需要操作系统底层的支持,使用到的技术就是 CAS 锁原语技术

CAS (compare and set):意为比较并替换,其中有两个动作,比较和替换,在系统底层必须保证这两个动作连续的执行,中间不允许中断。保证两个操作为一个原子操作。


Jvm 中的锁实现

java 通过 CAS 原语在对象头中修改 Mark Word 实现加锁

如下图所示:

对 Mark Work 的区域的数据更改是就使用了 CAS 原语,保证加锁和释放的过程是原子的操作。


如上图中所示,jvm 默认的锁关键字加锁机制,会从正常、偏向锁、轻量级锁、重量级锁逐渐膨胀。过程如下:

1、一个没有被锁住的时候对象头呈现正常状态

2、当对象被锁关键字锁住时,首先获得偏向锁,该锁假定使用锁的线程只有一个,并已经为那一个线程后续获得锁做了准备,可以使用很小的代价就可以获得锁。但是如果发现有其他线程需要获取到锁,偏向锁就会膨胀为轻量级锁。

3、使用轻量级锁时,不需要申请互斥量,仅仅将 Mark Word 中的部分字节 CAS 更新指向线程栈中的 Lock Record,如果更新成功,则轻量级锁获取成功,记录锁状态为轻量级锁;否则,说明已经有线程获得了轻量级锁,目前发生了锁竞争(不适合继续使用轻量级锁),接下来膨胀为重量级锁。轻量级锁目的是减少无实际竞争情况下,使用重量级锁产生的性能消耗,包括系统调用引起的内核态与用户态切换、线程阻塞造成的线程切换。

4、重量级锁是直接对应底层操作系统中的互斥量(mutex),这种同步方式的成本非常高,包括系统调用引起的内核态与用户态切换、线程阻塞造成的线程切换等。


多 CPU 执行任务时也会涉及到操作主存中的数据,在这种情况下。操作系统解决办法是 缓存一致性协议或者 总线锁机制


java 中的各种锁的意思

公平锁:多个线程按照申请锁的顺序来获取锁

非公平锁:不按照顺序获取锁,随机或由系统调度决定。

可重入锁:某个线程已经获得锁后,再次获取该锁不会出现死锁现象。

独享锁/互斥锁:锁只能被一个线程持有

共享锁:锁可以被多个线程持有

读写锁:多个读线程间不互斥,写线程与任何线程互斥。

乐观锁:默认认为数据不会被其他线程修改,发现修改时过时,放弃自己的修改。

悲观锁:默认数据肯定会被其他线程修改,在自己修改数据前一定要加锁保证其他线程不能修改数据。

分段锁:针对数组,将数据锁的粒度细化为多段,每一段一个锁。减小大粒度的锁。应用案例 java 中 ConcurrentHashMap 实现。

自选锁:在获取锁失败时不立阻塞,采用循环多次重试尝试获得锁,减少线程上下文切换的消耗,缺点是循环会消耗 CPU。


文件与硬件 I/O

普通操作 linux 系统+机械硬盘存储文件的弊端:

1、机械硬盘使用物理驱动磁头读取磁道上数据的方式,读写速度不高,随机读写数据更慢。

2、操作系统使用文件控制块记录每个文件占据的硬盘数据,而 linux 的 Inode 文件控制块的结构固定,单个文件最大不能超过 70G。

3、系统单点存储文件,没有备份,数据的可用性不高。


改进方案

1、针对磁盘存储随机写入的优化

使用 LSM 树(日志结构合并树)结构存储文件,将随机的读写改动现在内存中与原来的内容合并为一个连续的内容。在连续写入到磁盘。降低随机写入的操作。


2、使用 RAID 独立硬盘冗余阵列,一个文件分布到多个磁盘块上,并增加备份块或者数据校验块保证数据可用性,写入时同时对多个磁盘块读写,大幅提高读写速度。常用 RAID5(螺旋校验块),RAID6(螺旋双校验块)。校验块用于数据丢失是,通过校验和计算出丢失的数据。


3、使用分布式文件系统 HDFS

将数据更加广泛的分布到多个存储服务器,构成分布式文件系统。文件系统的每一存储服务器相当于一个大的磁盘块,分布式文件系统中由 NameNode 记录文件分布信息。读写数据时,客户端视分布式文件系统为一个整体,当做普通的存储磁盘的方式使用。分布式文件系统可以动态且方便的扩展存储服务器,理论上,单个文件大小不受限制(只需要增加分布式文件系统的存储服务器)。数据读写也由于多个服务器同时读写,也非常快。同时除了每个单个服务器上有数据备份,服务器节点之间也有备份。是真正达到了,数据的高存储量,高读写速度,数据高可用的特点。


用户头像

zcj

关注

还未添加个人签名 2019.10.12 加入

精神小伙

评论

发布
暂无评论
架构师训练营:第七周性能测试、系统、文件系统