本文倒序。
作者:金山软件西山居技术经理 刘超
09-结束语丨栉风沐雨,砥砺前行!
结束nothing
08-模块七 实战演练场(4讲)
43丨记一次双十一抢购性能瓶颈调优20200803
1.限流实现优化
nginx 包含了两个限流模块:ngx_http_limit_conn_module和ngx_http_limit_req_module 前者限制单个ip单位时间内的请求数量,后者是用来限制单位时间内所有皮的请求数量。
配置:
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
location / {
limit_conn addr 1
}
}
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server{
location / {
limit_req zone=one burst=5 nodelay;
}
}
在网关层,可以tongueolua编写OpenResty来实现一套限流功能,也可以通过现成的Kong安装插件来实现。
还可以基于服务才能实现接口的限流,通过Zuul RateLimit 活Guava RateLimiter实现。
42丨如何使用缓存优化系统性能?20200803 无重点
1.前端缓存
本地缓存
If-Modified-Since 字段与返回头部中的 Last- Modified 字段实现,也可以基于请求头部中的 If-None-Match 字段与返回头部中的 ETag 字段来实现。前者基于时间,后者基于唯一标示。
网关缓存
CDN
2.服务器缓存技术
Guava cache
Redis
41丨电商系统的分布式事务调优20200803 重要
1.分布式事务实现方式有多种,例如
XA协议实现的二阶段提交 2pc
DTP 模型,该模型规范了分布式事务的模型设计。DTP 规范中主要包含了 AP、RM、TM 三个部分,其中 AP 是应用程序,是事务发起和结 束的地方;RM 是资源管理器,主要负责管理每个数据库的连接数据源;TM 是事务管理器,负责事务的全局管理,包括事务的生命周期管理和资源的分配协调等。
三阶段提交3pc
3pc把2pc的准备阶段分为了准备阶段和预处理阶段。
第一阶段只是询问各个资源节点是否可以执行事务。
第二阶段 所有的几点反馈可以执行事务,才开始执行事务。
第三阶段 执行提交或回滚操作。RM、TM都引入了超时机制。
缺点:无法解决在最后提交全局事务时,由于网络故障无法通知到一些节点的问题,特别是回滚通知,会导致事务等待超时从而默认提交。
XA规范实现的事务提交,由于阻塞等性能问题,低性能、低吞吐。
TCC补偿性事务:最常用的分布式事务解决方案
分别在不同服务上连接数据源,提交数据库操作。
采用最终一致性的方式实现了一种柔性分布式事务,基于服务层实现的一种二阶事务提交。
三个阶段:
Try
Confirm
Cancel
缺点:对业务侵入性非常大,实现和维护成本高。
需要在设计的时候考虑预留资源;
需要编写大量业务性代码
考虑每个方法的幂等性
2.业务无侵入方案-Seata(Fescar)
40丨如何设计更优的分布式锁?20200728
1.数据库分布式锁
2.zookeeper分布式锁
3.Redis实现分布式锁
4.Redlock算法 redisson
07-模块六 数据库性能调优(6讲)
39丨答疑课堂:MySQL中InnoDB的知识点串讲 略,可以单独加强InnoDB 内容20200702
1.缓存池:不仅缓存了索引页和数据页,还包括了undo页、插入缓存、自适应哈希索引以及InnoDB的锁信息。
2.后台线程
Master Thread 主要负责将缓冲池中的数据异步刷新到磁盘中,初次之外还包括插入缓存,undo页的回收等。
IO Thread 是负责读写 IO 的线程,而 Purge Thread 主要用于回 收事务已经提交了的 undo log
3.存储文件
4.InnoDB 逻辑存储结构
InnoDB 逻辑存储结构分为表空间(Tablespace)、段 (Segment)、区 (Extent)、页 Page) 以及行 (row)。
表空间:
5.InnoDB 事务之 redo log 工作原理
6.LRU淘汰策略
InnoDB 则是将数据放在一个 midpoint 位置,通常这个 midpoint 为列 表长度的 5/8。避免一些不常查询的操作突然将热点数据淘汰出去。
38丨数据库参数设置优化,失之毫厘差之千里 略 20200702
1.SWAP 页交换:SWAP 分区在系统的物理内存不够用的时候,就会把物理内 存中的一部分空间释放出来,以供当前运行的程序使用。被释放的空间可能 来自一些很长时间没有什么操作的程序,这些被释放的空间的数据被临时保 存到 SWAP 分区中,等到那些程序要运行时,再从 SWAP 分区中恢复保存 的数据到内存中。
2.redo log 主要是为了解决 crash-safe 问题而引入的。
3.InnoDB Buffer Pool(IBP)是InnoDB存储引擎的一个缓冲池。
innodb_buffer_pool_size :默认128M,推荐配置IBP的大小为服务器内存的80%。
innodb_buffer_pool_instances:IBP被划分了多个实例,只有上面1G时才有用。
innodb_log_file_size:1g
innodb_log_buffer_size:InnoDB重做日志缓冲池的大小,默认8M
innodb_flush_log_at_trx_commit:控制重做日志从缓存写入文件刷新到磁盘中的策略,默认1
37丨电商系统表设计优化案例分析20200702
1.平时不用看,面试可略一眼
36丨什么时候需要分表分库20200702 看笔记即可
1.分布式事务,两阶段提交(2PC)以及补偿事务提交TCC.
2.中间件:Spring 实现的JTA,Fescar(seata)
3.跨节点JOIN查询问题
冗余基础表或者个别字段
4.跨节点分页查询问题
两套存储: 一套数据库,一套Elasticsearch
5.全局主键ID
uuid:性能差
redis分布式锁实现一个递增的主键ID,有一定性能损耗
Twiitter开源的分布式ID生产算法:snowflake。
6.扩容问题
2的倍数设置表数量
7.表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。
分表:指的是通过一定规则,将一张表分解成多张不同的表。比如将用户订单记录根据时间成多个表。
分表与分区的区别在于:分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表。
ALTER TABLE erp_bill_index PARTITION by RANGE(to_days(billdate))
35丨记一次线上SQL死锁事故:如何避免死锁?20200702
1.我们可以在 information_schema 数据库 中查询到具体的死锁情况
2.此节值得关注。
3.查看运行中事务:select * from information_schema.innodb_trx
当前出现的锁: select * from information_schema.innodb_locks
锁等待的对应关系 select * from information_schema.innodb_lock_waits
4.非唯一索引,RR事务隔离级别,for update 加锁类型为 gap lock。
34丨MySQL调优之索引:索引的失效与优化20200702
1.回表
基于主键查询可以直接获取到行信息,而基于辅助索引作为查询条 件,则需要进行回表,然后再通过主键索引获取到数据。
2.建立和使用索引 的调优方法
A覆盖索引优化查询
B自增字段作主键优化查询
C前缀索引优化
减小索引字段大小,可以增加一个页中存储的索引想,有效提高索引的查询速度,但又一定局限性,order by 无法使用前缀索引,无法吧前缀索引作为覆盖索引。
D防止索引失效
对索引进行函数操作或者表达式计算也会导致索引的失效
33丨MySQL调优之事务:高并发场景下的数据库事务调优20200701
1.行锁通过索引实现,如果不同过索引条件检索数据,行锁会升级到表锁。
2.优化高并发事务
结合业务场景,使用低级别事务隔离
避免行锁升级为表锁
控制事务的大小,减少锁定的资源量和锁定的时间长度。
3.binlog + redo log 两阶段提交保证持久性
事务的回滚机制 保证原子性 要么全部提交成功 要么回滚
undo log + MVCC 保证一致性 事务开始和结束的过程不会其它事务看到 为了并发可以适当破坏一致性。
32丨MySQL调优之SQL语句:如何写出高性能SQL语句?
1.explain
type:结果值从好到差依次是:system > const > eq_ref > ref > range > index > ALL
2.通过 Show Profile 分析 SQL 执行性能 -new
3.常用的SQL优化
优化分页查询,利用子查询优化分页查询。
select count(*) 可以增加汇总统计。
4.是否开启了记录慢sql的功能,以及最大的执行时间
Show variables like 'slow_query%’;
Show variables like 'long_query_time';
06-模块五 设计模式调优(6讲)
31 丨 答疑课堂:模块五思考题集锦 20200703
1.单例和享元模式区别联系
单例模式更多的是强调减少实例化提升性能
享元模式更多的是强调共享相同对象或对象属性,以此节约内存使用空间
共性:
这两种设计模式也有共性,单例模式可以避免重复创建对象,节约内存空间,享
元模式也可以避免一个类的重复实例化。
2.work-thread模式中,如果要获取子线程的结果
jdk1.5后Future 类 ,性能比较糟糕。
jdk1.8中提供了CompletableFuture 类,它是基于异步函数式编程。相对阻塞式等待返回结果, CompletableFuture 可以通过回调的方式来处理计算结果,所以实现了异步非阻塞,从性 能上来说它更加优越了。
3.漏桶算法可以通过限制容量池大小来控制流量,而令牌算法则可以通过限制
发放令牌的速率来控制流量
4.策略模式和装饰者模式区别:
策略模式与装饰器模式则更为相似,策略模式主要由一个策略基类、具体策略类以及一个工厂环境类组成,与装饰器模式不同的是,策略模式是指某个对象在不同的场景中,选择的实现策略不一样。例如,同样是价格策略,在一些场景中,我们就可以使用策略模式实现。基于红包的促销活动商品,只能使用红包策略,而基于折扣券的促销活动商品,也只能使用折扣券。
30 丨 装饰器模式:如何优化电商系统中复杂的商品价格策略? 20200703
1.可借鉴 复杂情景 业务开发。
29 丨 生产者消费者模式:电商库存设计优化 20200703
1.问题:生产方则会因为瞬时高并发,而发生大量线程阻塞。面对这样的情况,你知道有
什么方式可以优化线程阻塞所带来的性能问题吗?
精选答案:
A.网关与服务之间增加令牌桶 或者mq 以保护秒杀服务不会被大的流量压垮.
B.在网关层中把请求放入到mq中,后端服务从消费队列中消费消息并处理;或者用有固定容 量的消费队列的令牌桶,令牌发生器预估预计的处理能力,匀速生产放入令牌队列中,满 了直接丢弃,网关收到请求之后消费一个令牌,获得令牌的请求才能进行后端秒杀请求, 反之直接返回秒杀失败
C限流
2.其他略
28丨如何使用设计模式优化并发编程?20200703
整体来讲没咋理解。
线程上下文设计模式 没太明白
Thread-Per-Message 设计模式
Thread-Per-Message 设计模式翻译过来的意思就是每个消息一个线程的意思。
Worker-Thread 设计模式
当主线程处理每次请求都非常耗时时,就可能出现阻塞问题,这时候我们可以考虑将主线程 业务分工到新的业务线程中,从而提高系统的并行处理能力。而 Thread-Per-Message 设 计模式以及 Worker-Thread 设计模式则都是通过多线程分工来提高系统并行处理能力的设 计模式。
27丨原型模式与享元模式:提升系统性能的利器-新知识 20200702
1.通过 clone 方法复制的对象才是真正的对象复制,clone 方法赋值的对象完全是一个独立 的对象。
2.浅拷贝
拷贝成员变量值,但对于对象的引用以及List等类型的成员属性,只能复制这些对象的引用了。super.clone()属于浅拷贝。
3.深拷贝
深拷贝就是基于浅拷贝来递归实现具体的每个对象。
4.原型模式使用场景:
循环体内创建对象时
Student stu = new Student();
for(int i=0; i
Student stu1 = (Student)stu.clone();
}
5.为什么使用原型模式:
Object 类的 clone 方法是一个本地方法,它可以直接操作内存中的二进制流,所以性能相 对 new 实例化来说,更佳。
享元模式
1.运用共享技术有效地最大限度地复用细粒度对象的一种模式。
2.使用场景
字符串常量,线程池就是享元模式的一种实现。
26丨单例模式:如何创建单一对象优化系统性能?
1.happens—before: 前一个操作的结果可以被后续的操作获取。这条规则规范了编译器对程序的重排序优化。
2.单例内部类 写法-new。
05-模块四·JVM性能监测及调优(3讲)
25丨答疑课堂:模块四热点问题解答
1.cms
2.G1 和 CMS 主要的区别在于:
CMS 主要集中在老年代的回收,而G1集中在分代回收,包括了年轻代的Young GC以及老年代的 Mix GC;
G1 使用了Region方式对堆内存进行了划分,且基于标记整理算法实现,整体减少了垃圾碎片的产生;
在初始化标记阶段,搜索可达对象使用到的 Card Table,其实现方式不一样。
CMS 和 G1 在解决并发标记时漏标的方式也不一样,CMS 使用的是 Incremental Update 算法,而 G1 使用的是 SATB 算法.
24丨内存持续上升,我该如何排查问题?20200720
本节有一个内存溢出的案例-threadlocal。
1.vmstat 是一款指定采样周期和次数的功能性监测工具,它不仅可以统计内存的使用情况,还可以观测到 CPU 的使用率、swap 的使用情况。但 vmstat 一般很少用来查看内存的使用情况,而是经常被用来观察进程的上下文切换。
2.pidstat 命令则是深入到线程级别
3.jstat 可以监测 Java 应用程序的实时运行情况,包括堆内存信息以及垃圾回收信息。
4. jstack是一种线程堆栈分析工具,最常用的功能就是使 用 jstack pid 命令查看线程的堆栈信息,通常会结合 top -Hp pid 或 pidstat -p pid -t 一 起查看具体线程的状态,也经常用来排查一些死锁的异常。
5.jmap 查看堆内存初始化配置信息以及堆内存的使用情况。还可以使用 jmap 输出堆内存中的对象信息,包括产生了哪些对象, 对象数量多少等。
jmap -dump:format=b,file=/tmp/heap.hprof 28677
将文件下载下来使用MAT工具分析。
6.实例:https://mp.weixin.qq.com/s/IPi3xiordGh-zcSSRie6nA
https://mp.weixin.qq.com/s/ji_8NhN4NnEHrfAlA9X_ag
23丨如何优化JVM内存分配?
1.基本不打用看
22丨如何优化垃圾回收机制?
1.Gc调优策略
降低Minor GC频率
降低Full Gc的频率
减少创建大对象。
增加堆内存空间
选择合适的Gc回收期
2.对吞吐量有要求时,可以选择Parallel Scavenge回收器来提高系统的吞吐量。
3.在Java语言里,可作为GC Root对象的包括如下几种: 1. Java虚拟机栈中的引用的对 象 ; 2. 方法区中的类静态属性引用的对象 ; 3. 方法区中的常量引用的对象 ; 4. 本地方法栈中 JNI的引用的对象。
我们知道,垃圾回收一般是回收堆和方法区的对象,而堆中的对象在正常情况下,一般是通过常 量、全局变量、静态变量等间接引用堆中的对象,所以这些可以作为GC Root。
4.
21丨深入JVM即时编译器JIT,优化Java编译 20200720
本节主要:学习运行时编译如何实现对java代码的优化
1.编译后的字节码文件主要包括常量池和方法表集合这两部分。
2.在字节码转换为机器码的过程中,虚拟机中还存在着一道编译,那就是即时编译。
3.在hotpot虚拟机中,内置了两个JIT,分别是C1编译器和C2编译器。分层编译将jvm执行状态分为了5个层次。
4.热点探测是JIT优化的条件。虚拟机为每个方法指标了两类计数器:方法计数器和回边计数器。
建立汇编计数器的主要目的是为了出发OSR编译,(On StackReplacement) ,即 栈上编译。
5.编译优化技术
方法内联
逃逸分析
是判断一个对象是否被外部方法引用或外部线程访问的分析技术,编译器会根据逃逸分析的结果对代码进行优化。
锁消除
6.Class.forName加载类的时候会对类进行初始化,如静态代码块,ClassLoader 不会做初 始化。spring做类加载的时候应该用的是ClassLoader把。
7.
20丨磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
1.方法区主要是用来存放已被虚拟机加载的类相关信息,包括类信息、运行时常量池、字符串常量池。类信息又包括了类的版本、字段、方法、接口和父类等信息。
2.方法区与堆空间类似,也是一个共享内存区,所以方法区是线程共享的。
JVM 的运行原理
1.过程
A.JVM 向操作系统申请内存,根据参数内部分配
B.JVM获得内存空间后,会根据配置参数分配堆,栈以及方法区的内存大小
C.class文件加载验证准备以及解析。
D.初始化,JVM执行构造器
E.执行main
04-模块三 . 多线程性能调优(8讲)
加餐丨什么是数据的强、弱一致性?20200717
1.Java 提出了 Happens-before 规则来规范线程的执行顺序
2.
答疑课堂:模块三热点问题解答20200717
1.vmstat是一款指定采样周期和次数的动能性检测工具,可以使用他监控进程上下文切换的情况。
2.pidstat命令:
检测到具体的线程的上下文切换。
3.jstack
查看具体线程的上下文切换异常,可以使用jstack命令查看堆栈的运行情况。
jstack 最常用的功能就是使用 jstack pid 命令查看线程堆栈 信息,通常是结合 pidstat -p pid -t 一起查看具体线程的状 态,也经常用来排查一些死锁的异常。
19丨如何用协程来优化多线程业务?
1.内核线程(Kernel-Level Thread, KLT)是由 操作系统内核支持的线程,内核通过调度器对线程进行调 度,并负责完成线程的切换。
2.轻量级进程(Light Weight Process,即 LWP):使用 clone() 系统调用创建线程。LWP 是跟内核线程一对一映射的,每个 LWP 都是由一个内核线程支持。
3.实现线程主要有三种方式:
轻量级进程和内核线程一对一相 互映射实现的 1:1 线程模型
复制一份,占用大量内存空间,又消耗大量 CPU 时间用 来初始化内存空间以及复制数据。
用户线程和内核线程实现的 N:1 线程模型以及用户线程
N:1 线程模型的缺点在于操作系统不能感知用户态的线程, 因此容易造成某一个线程进行系统调用内核线程时被阻塞, 从而导致整个进程被阻塞。
轻量级进程混合实现的 N:M 线程模型。
N:M 线程模型是基于上述两种线程模型实现的一种混合线 程管理模型,即支持用户态线程通过 LWP 与内核线程连 接,用户态的线程数量和内核态的 LWP 数量是 N:M 的映 射关系。
4.我们可以将协程看作是一个类函数或者一块函数中的代码,我们可以在一个主线程里面轻松创建多个协程。
5.协程少了由于同步资源竞争带来的 CPU 上下文 切换,I/O 密集型的应用比较适合使用,特别是在网络请求 中,有较多的时间在等待后端响应,协程可以保证线程不会 阻塞在等待网络响应中,充分利用了多核多线程的能力。
6.线程是通过 共享内存来实现数据共享,而协程是使用了通信的方式来实 现了数据共享,主要就是为了避免内存共享数据而带来的线 程安全问题。
7.I/O 阻塞型场景也就是协程在 Java 中的主要应用。
8.Kilim
18丨如何设置线程池大小?20200716
1.调用 prestartAllCoreThreads() 或者 prestartCoreThread() 方法的话,可以提前创建等于核心线程数的线程数量,这种方式被称为预热,在抢购系统中 就经常被用到。
2.CPU 密集型任务:这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N(CPU 核心 数)+1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因 导致的任务暂停而带来的影响。
3.I/O 密集型任务:2N。
4.参考以下公式来计算线程数:
线程数 =N(CPU 核数)*(1+WT(线程等待时间)/ST(线程时间运行时间))
17丨并发容器的使用:识别不同场景下最优容器20200715
1.在非线程安全的 Map容器中,用TreeMap容器来存取大数据;在线程安全的Map容器中,用SkipListMap 容器来存取大数据。
2.跳跃表
跳跃表是基于链表扩展实现的一种特殊链表,类似于树的实现,跳跃表不仅实现了横向链表,还实现了垂直方向的分层索引。
3.如果对数据有强一致要求,则需使用 Hashtable;在大部分场景通常都是弱一致性的情况 下,使用ConcurrentHashMap 即可;如果数据量在千万级别,且存在大量增删改操作, 则可以考虑使用 ConcurrentSkipListMap。
4.
16丨多线程调优(下):如何优化多线程上下文切换?20200715
1.竞争锁优化:
在多线程编程中,锁其实不是性能开销的根源,竞争锁才是。
优化方式:
减少锁的持有时间
降低锁粒度:锁分离;锁分段
非阻塞乐观锁替代竞争锁
15丨多线程调优(上):哪些操作导致了上下文切换?20200710
1.自发性上下文切换指线程由 Java 程序调用导致切出,在多 线程编程中,执行调用以下方法或关键字,常常就会引发自 发性上下文切换。
非自发性上下文切换指线程由于调度器的原因被迫切出。常见的有:线程被分配的时间片用完,虚拟机垃圾回收导致或者执行优先级的问题导致。
2.进程上下文切换,是指用户态和内核态的来回切 换。当Synchronized锁资源竞争激烈,线程将会被阻塞, 阻塞的线程将会从用户态调用内核态,尝试获取mutex,这 个过程是Synchronized锁产生的进程上下文切换。
14丨多线程之锁优化(下):使用乐观锁优化并行操作
1.不会带来死锁、饥饿等活性故障问题,线程间的相互影响也远远比悲观锁要小。更为重要的是,乐观锁没有因竞争造成的系统开销,所以在性能上也是更胜一筹。
2.CAS 是实现乐观锁的核心算法,它包含了 3 个参数:V(需 要更新的变量)、E(预期值)和 N(最新值)。
3.目前最新的处理器都支持缓存锁定机制。
4.LongAdder
将热点数据value被分离成多个单 元的cell,每个cell独自维护内部的值,当前对象的实际值 由cell[]数组中所有的cell累计合成。这样,热点就进行了 有效的分离,提高了并行度,所以LongAdder虽然降低 了并发竞争,但是却对实时更新的数据不友好。
在高并发场景下会比 AtomicInteger 和 AtomicLong 的性能更好,代价就是会消耗更多的内存空 间。
5.CAS 乐观锁在平常使用时比较受限,它只能保证单个变量操 作的原子性,当涉及到多个变量时,CAS 就无能为力了,但 前两讲讲到的悲观锁可以通过对整个代码块加锁来做到这 点。
6.
13丨多线程之锁优化(中):深入了解Lock同步锁的优化方法
ReentrantReadWriteLock 和 StampedLock还需要再看看。
1.
2.ReentrantLock 独占锁。
3.读写锁 ReentrantReadWriteLock
state
获取写锁:
获取写锁:
4.读写锁再优化之StampedLock
在读很多、写入很少的情况下,RRW会使写线程遭遇饥饿问题,也就是说写入线程会因迟迟无法竞争到锁而一直处于等待状态。
StampedLock控制锁有是三种模式:
写
悲观读
乐观读
StampedLoack不支持重入,不支持条件变量,线程中断时可能导致CPU暴涨。
12丨多线程之锁优化(上):深入了解Synchronized同步锁的优化方法 20200630
1.synchronizede 修饰方法时,jvm使用了ACC_SYNCHRONIZED访问标志来区分一个方法是否是同步方法。synchronizede修改代码块时,使用monitorenter和moniterexit指令,依靠底层操作系统的Mutex Lock来实现互斥的。存在用户态和内核态之间的切换,增加了性能开销。
synchronized 加在非静态方法是对象锁,静态方法是类锁。
2.jdk1.6引入了偏向锁、轻量级锁、重量级锁概念,来减少锁竞争带来的上下文切换,
而正是新增的Java对象头实现锁升级功能。
3.java对象头由mark word、指向类的指针以及数组长度三部分组成。
4.偏向锁:主要用来优化统一线程多次申请同一个锁的竞争。
5.轻量级锁:使用与线程交替执行同步快的场景。
6.在锁竞争不激烈且锁占用时间非常短的场景下,自旋锁可以提高系统性能。
-XX:-UseSpinning // 参数关闭自旋锁优化 (默认打开)
7.锁消除,同步快只被一个线程访问,不会生产synchonized所表示的锁的申请和释放的机器码。java7后自动
8.锁粗化
9.减小锁粒度
经典:jdk1.8之前实现的concurrentHashMap版本。
03-模块二 · Java编程性能调优 (10讲)
加餐丨推荐几款常用的性能测试工具
本节可略
1.ab -c 并发次数,例如:10个请求,10个并发,实际就是1人请求1次。
2.付费测试工具LoadRunner,支持iP欺骗
11丨答疑课堂:深入了解NIO的优化实现原理
本节 关于I/O模型东西多,不是很理解。可在看一遍
- 阻塞IO:调用read()线程阻塞了
- 非阻塞IO:调用read()马上拿到一个数据未就绪,或者就绪。
- I/O多路复用:selector线程阻塞,channel非阻塞,用阻塞一个selector线程换了多个channel了非阻塞。select()函数基于数组,fd个数限制1024,poll()函数也是基于数组但是fd数目无限制。都会负责所有的fd(未就绪的开销浪了),
- epll()基于红黑数实现,fd无大小限制,平衡二叉数插入删除效率高。
- 信号驱动模式IO:对IO多路复用进一步优化,selector也非阻塞了。但是sign信号无法区分多信号源。所以socket未使用这种,只有在单一信号模型上才能应用。
- 异步IO模型:真正的非阻塞IO,其实前面的四种IO都不是真正的非阻塞IO,他们的非阻塞只是,从网络或者内存磁盘到内核空间的非阻塞,调用read()后还需要从内核拷贝到用户空间。异步IO基于回调,这一步也非阻塞了,从内核拷贝到用户空间后才通知用户进程。
tomcat 调优
10丨网络通信优化之通信协议:如何优化RPC网络通信?
1.作者认为 微服务的核心是远程通信和服务治理。
2.无论是微服务、SOA还是RPC架构,他们都是分布式服务架构,都需要实现服务之间的互相通信,我们通常吧这种通信统称为RPC通信.
3.RPC remote Process Call 即远程服务调用,是通过网络请求远程计算机程序服务的通信技术。
4.RMI Remote Method Invocation 是jdk中最先实现了RPC通信的框架之一。
5.一个高并发场景下的RPC通信优化路径:
RPC 通信包括建立通信、实现报文、传输协议以及传输数据编码解码等操作。
A.选择合适的通信协议
B.使用单一长链接
C.使用Socket通信
D.量身定做报文格式
E.编码、解码
F.调整Linux的TCP参数设置选项:需要看 pdf
6.三次握手:
URG:紧急指针(urgent pointer)有效。
ACK:确认序号有效。
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。
SYN:发起一个新连接。
FIN:释放一个连接。
7.四次挥手:
所谓的四次挥手即TCP连接的释放(解除)。连接的释放必须是一方主动释放,另一方被动释放
2MSL:为的是确认服务器端是否收到客户端发出的ACK确认报文
大文件传输,使用 hessian协议较好。
09丨网络通信优化之序列化:避免使用Java序列化20200701
1.java序列化机制:能够将一个对象序列化为二进制形式(字节数组),用于写入磁盘活输出到网络,同时也能从网络或磁盘中读取字节数组,反序列化成对象,在程序中使用。
2.java序列化的缺陷
无法跨语言
易被攻击
序列化后的流太大
序列化性能太差
3.使用protobuf序列化替换Java序列化
4.没太懂:单例模式 implements serializable ,序列化会通过反射调用午餐构造器返回一个新对象,破坏单例模式。
解决方法是添加readResolve()方法,自定义返回对象策略。
08丨网络通信优化之I-O模型:如何解决高并发下I-O瓶颈?20200701
本节略简单,看下笔记即可
1.传统IO和NIO的做大区别就是传统IO是面向流,NIO是面向Buffer。
Buffer可以将文件一次性读入内存在做后续处理,而传统的方式是边读文件边处理数据。
NIO是基于块(block)的,以块为基本单位处理数据。
2.NIO提供了一个直接访问物理内存的类DirectBuffer。非jvm,创建和小会代价很高。
3.NIO NON-block I/O 非阻塞I/O.
通过 通道和多路复用器两个基本组件实现了NIO的非阻塞。
通道:channel
多路复用器:用于检查一个或多个NIO channel的状态是否处于可读、可写。
epoll 相比传统的select机制,epoll没有最大连接句柄的限制。所以selector理论上可以轮询成千上万个的客户端。
4.AIO 实现了真正意义 上的异步 I/O,它是直接将 I/O 操作交给操作系统进行异步处理。这也是对 I/O 操作的一 种优化,那为什么现在很多容器的通信框架都还是使用 NIO 呢?
答:异步I/O没有在Linux内核中实现
07丨深入浅出HashMap的设计与优化-基础知识补强 20200701
1.
2.Object类中的equals方法和“==”是一样的,没有区别,即俩个对象的比较是比较他们的栈内存中存储的内存地址。而String类,Integer类等等一些类,是重写了equals方法,才使得equals和“==不同”,他们比较的是值是不是相等。所以,当自己创建类时,自动继承了Object的equals方法,要想实现不同的等于比较,必须重写equals方法。
3.但一个面临问题:若两个对象equals相等,但不在一个区间,因为hashCode的值在重写之前是对内存地址计算得出,所以根本没有机会进行比较,会被认为是不同的对象。所以Java对于eqauls方法和hashCode方法是这样规定的:
1 如果两个对象相同,那么它们的hashCode值一定要相同。也告诉我们重写equals方法,一定要重写hashCode方法,也就是说hashCode值要和类中的成员变量挂上钩,对象相同–>成员变量相同—->hashCode值一定相同。
4. putVal 方法中的 (n - 1) & hash 决定 该 Node 的存储位置?为什么?
2的幂次方减1后每一位都是1,让数组每一个位置都能添加到元素。
例如十进制8,对应二进制1000,减1是0111,这样在&hash值使数组每个位置都是可以添加到元素的,如果有一个位置为0,那么无论hash值是多少那一位总是0,例如0101,&hash后第二位总是0,也就是说数组中下标为2的位置总是空的。
如果初始化大小设置的不是2的幂次方,hashmap也会调整到比初始化值大且最近的一个2的幂作为capacity。
总之,减少哈希冲突,均匀分布元素。
5.
06丨Stream如何提高遍历集合效率?20200630
本节新知识
1.Stream操作类型
中间操作
- 无状态Stateless
- 有状态Stateful
终结操作
- 非短路操作
- 短路操作
2.使用场景:
在循环迭代次数较少的情况下,常规的迭代方式性能反 而更好;在单核 CPU 服务器配置环境中,也是常规迭代方式更有优势;而在大数据循环迭 代中,如果服务器是多核 CPU 的情况下,Stream 的并行迭代优势明显。所以我们在平时 处理大数据的集合时,应该尽量考虑将应用部署在多核 CPU 环境下,并且使用 Stream 的 并行迭代方式进行处理。
05丨ArrayList还是LinkedList?使用不当性能差千倍
1.可略
04丨慎重使用正则表达式
可参考:
1.
2.三种匹配模式:
贪婪模式、懒惰模式、独占模式
独占模式:正则表达式尽可能长地去匹配字符串,一旦匹配不成功就会结束匹配而不会回溯
3.正则引擎主要可以分为基本不同的两大类:一种是DFA(确定型有穷自动机),另一种是NFA(不确定型有穷自动机)
4.正则表达式的优化:
A少用贪婪模式,多用独占模式
B减少分支选择 (X|Y|Z)
C减少捕获嵌套
捕获组是指把正则表达式中,子表达式匹配的内容保存到以数字编号或显式命名的数组中, 方便后面引用。一般一个 () 就是一个捕获组,捕获组可以进行嵌套。
如果你并不需要获取某一个分组内的文本,那么就使用非捕获分组。例如,使 用“(?:X)”代替“(X)”,我们再看下面的例子: 具体看例子。
03丨字符串性能优化不容小觑,百M内存轻松存储几十G数据
1.在java中,有两种创建字符串对象的方式,一种是通过字符串常量创建,如String s=“abc”;
另一张是字符串变量通过new形式创建String s =new Stirng(“abc”)
2.String对象的优化
A如何构建超大字符串,StringBuidler 线程不安全
B如何使用String.intern节省内存
在字符串常量中,默认会将对象放入常量池。
3.如何使用字符串的分割方法
A.
02-模块一 · 概述 (2讲) 20200629
02丨如何制定性能调优策略?
1.两种常用的测试方法
微基准性能测试
宏基准性能测试:是一个综合测试,需要考虑到测试环境、测试场景和测试目标
2.几种调优策略
A.优化代码,LinkedList集合 for慢,要使用Iterator(迭代器),因为LinkedList是链表实现的,如果使用for循环获取元素,在每次循环获取元素时,都会去遍历一次List,这样会降低读的效率。
B.优化设计
C.优化算法
D.时间换空间
E.空间换时间:使用存储空间来提升访问速度
F.参数调优
01 如何制定性能调优标准
性能调优的标准:响应时间、吞吐量、计算机资源分配使用率、负载承受能力
1.磁盘吞吐量
IOPS:Input/output Per Second ,每秒的输入输出量(或读写次数)
数据吞吐量:单位时间内可以成功传输的数据量。
精选问题:请问老师最近段时间遇到端口被CLOSE_WAIT占用,重启后过了半天又重现,以前没有出现过,一般如何排查:
作者回复: 可以通过tcpdump抓包看看连接状态,分析是否是服务端的FIN packet没有发出去。
正常的关闭流程是:服务端在接收到客户端发送的关闭请求FIN后,会进入CLOSE_WAIT状态,同 时发送ACK回去。在完成与客户端直接的通信操作之后,再向客户端发送FIN,进入LAST_ACK状态。
如果连接是CLOSE_WAIT状态,而不是LAST_ACK状态,说明还没有发FIN给Client,那么可能是 在关闭连接之前还有许多数据要发送或者其他事要做,导致没有发这个FIN packet。
建议确定关闭请求的四次握手,哪个环节出了问题,再去排查业务代码,可能是由于超时或者异
常导致没有正常关闭连接。
01-开篇词