架构师训练营 -week07- 总结
本周知识点比较多,重点学习了以下几个方面的内容:
性能相关定义,包括:并发数、吞吐量、响应时间这些基础概念的含义和关系等。
性能测试相关知识,包括测试维度:性能测试、负载测试、压力测试、稳定性测试等。
大厂里性能测试的做法,全链路压力的一些指导方法,例如:数据隔离、流量复制和构造等。
性能优化的思路:性能测试、指标分析、架构与代码的分析和优化实施、再次通过性能测试进行验证。
性能优化的分层思想:机房与骨干网、服务器与硬件性能、操作系统、虚拟机、基础组件(中间件、JVM 等)、架构层面、代码层面。
架构优化的常见方案:缓存、异步、集群。
代码层面优化的常见方案:并发编程、资源复用、异步处理、善用数据结构。
操作系统层面的基础知识,进程和线程的概念和联系、线程安全的保障、CAS 和各种锁的概念:偏向锁、轻量级锁、重量级锁、总线锁、缓存锁、公平锁、非公平锁、可重入锁、独享锁、共享锁、读写锁、乐观锁、悲观锁、分段锁、自旋锁等。
学习非阻塞的编程框架 akka,是一款基于消息传递机制的非阻塞编程框架,它提供了一种称为 Actor 的并发模型,其粒度比线程更小,所以能够在系统中启用大量的 Actor,用以在有限的硬件环境下依然能够支持很大的并发量。
上面的基础知识点,老师在 PPT 里都有很详细的解释了,再结合了网上一些其他的资源,下面列出对我个人需要加深印象的几个方面:
1. 性能测试基础概念
下面两张图比较清晰的表达了并发数、吞吐量、响应时间的关系:
2. 性能测试的步骤
有张总结图不错,借用在下面
3. 性能优化的几个层面
性能优化不仅仅是从架构或者代码层面进行优化,而是有一套分层思想,分别是:
机房与骨干网络性能优化
服务器与硬件性能优化
操作系统性能优化
虚拟机性能优化
基础组件性能优化
软件架构性能优化
软件代码性能优化
下面这张图形象的解释分层思想的优化逻辑:
物理服务器是软件运行的基础,服务器硬件性能决定 IO 数量、计算速度和存储
而操作系统负责进程和硬件资源的管理,相当于进程和物理资源的过渡,决定进程对资源的有效利用;
一个进程单独占用内存和其他资源,与其他进程是隔离的,JVM 进程的内存分配、垃圾收集器选择影响软件运行性能;Java 应用的基础就是 JVM,JVM 帮助 Java 语言屏蔽了不同操作系统的区别,JVM 负载管理类和对象的生命周期,每个线程栈管理
如果开发的是一个普通 Java 应用,直接运行 main 方法就可以启动并执行,但是 WEB 应用(servlet)并不能直接运行在 JVM 上,需要一个【WEB 容器】提供运行环境、端口访问和程序生命周期管理;一台服务器启动一个 JVM 进程,多个 WEN 容器(如 Tomcat)共享这个 JVM 的内存
一个应用程序的启动和关闭都依赖 WEB 容器管理,而一个 WEB 容器上可以同时运行多个 WEB 应用
4. 相关的一些锁
公平锁:多个线程按照申请锁的顺序来获取锁的
非公平锁:多个线程后去锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁,可能会造成饥饿现象
可重入锁:某个线程已经获得某个锁,可以再次获取锁而不会出现死锁
独享锁/互斥锁:该锁一次只能被一个线程所持有
共享锁:该锁可以被多个线程所持有
读写锁:多个读线程之间并不互斥,而写线程则要求与任何线程互斥
悲观锁:认为对于同一个数据的并发操作,一定是会发生修改的,哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁的并发操作一定会出问题
乐观锁:则认为对于同一个数据的并发操作,是不会发生修改的。在更新数据的时候,检查是否已经被修改过,如果修改过,就放弃。
分段锁:细化锁的粒度,当操作不需要更新整个数组的时候,就仅仅针对数组的一段进行加锁操作。
自旋锁:尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗 CPU
关于 CAS、偏向锁、轻量级锁、重量级锁的转换关系,也找到了一张状态图,如下所示:
5. Akka 与 Netty
以上是本周的学习内容,在最后的异步并发编程框架讲解中,也找到了一些关于 akaka 和 netty 的相关资料和比较。上 github 看了一下,目前 akka 的 starts 大概 1w 多,netty 的是 2w 多,都是非常著名的分布式框架。平时在工作中用到过 netty,但相对来讲用的层次都比较简单。后续计划选择一个入手,首先更深入的了解 API,然后再学习其实现思想和核心逻辑。
Akka 是一个建立在 Actors 概念和可组合 Futures 之上的并发框架,,Akka 设计灵感来源于 Erlang,Erlang 是基于 Actor 模型构建的。它通常被用来取代阻塞锁如同步、读写锁及类似的更高级别的异步抽象。
Netty 是一个异步网络库,使 JAVA NIO 的功能更好用。
注意:它们两个都提供了异步方法,你可以使用其中一个,或两个都用
Akka 针对 IO 操作有一个抽象,这和 netty 是一样的。使用 Akka 可以用来创建计算集群,Actor 在不同的机器之间传递消息。从这个角度来看,Akka 相对于 Netty 来说,是一个更高层次的抽象
从 Akka 出现背景来说,它是基于 Actor 的 RPC 通信系统,它的核心概念也是 Message,它是基于协程的,性能不容置疑;基于 scala 的偏函数,易用性也没有话说,但是它毕竟只是 RPC 通信,无法适用大的 package/stream 的数据传输,这也是 Spark 早期引入 Netty 的原因。
那么 Netty 为什么可以取代 Akka?首先不容置疑的是 Akka 可以做到的,Netty 也可以做到,但是 Netty 可以做到,Akka 却无法做到,原因是啥?在软件栈中,Akka 相比 Netty 要 Higher 一点,它专门针对 RPC 做了很多事情,而 Netty 相比更加基础一点,可以为不同的应用层通信协议(RPC,FTP,HTTP 等)提供支持,在早期的 Akka 版本,底层的 NIO 通信就是用的 Netty;其次一个优雅的工程师是不会允许一个系统中容纳两套通信框架。最后,虽然 Netty 没有 Akka 协程级的性能优势,但是 Netty 内部高效的 Reactor 线程模型,无锁化的串行设计,高效的序列化,零拷贝,内存池等特性也保证了 Netty 不会存在性能问题。
评论