13

性能优化-数据库,JVM, 秒杀场景

 3 years ago
source link: https://xie.infoq.cn/article/53c21c8f5e635e100e6b293ba
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

数据库基本原理

数据库架构

Zra2iuu.png!mobile

  • 连接器:为每个链接分配专属空间,一般通过连接池来减少资源开销。

  • 语法分析 :抽象语法树,分析SQL语法是否正确。

  • 语义分析优化:SQL进行优化, 利用索引进行优化。

  • 执行引擎:根据优化后语法树生成执行计划(索引类型,处理行数,潜在利用的索引)并执行。

PrepareStatement预编译 :可以先行完成SQL预处理, 有助于性能提升, 另外就是防止SQL注入。

B+树

排序树,一个块存储多个数据,非叶子节点还存放指针,使用指针完成索引, 叶子节点存放数据, 通过4级结构能访问几千万记录。

问题在于 数据块离散存储, 每次根据索引进行查找还是要进行多次读写。 性能较差。

下图,将键1–7链接到数据值d1-d7。 链接列表(红色)允许快速有序遍历

uu2MBzz.png!mobile

聚簇索引: 数据库记录和索引存储在一起。 MySQL 主键主键就是聚簇索引。

非聚簇索引: 叶子节点记录的就不是数据行记录,而是聚簇索引,也就是主键, 通过非聚簇索引找到主键索引,再通过主键索引找到行记录的过程也被称作回表。

合理添加使用索引: 增加索引后会生成对应的B+树,再insert,update, delete记录时, 都需要更新B+树,性能会有一定影响。 删除不必要的索引。

数据库事务(ACID)

  • 原子性 (Atomicity)

  • 隔离性(IsoLation)

  • 持久性(Durability)

  • 一致性(Consistency)

数据库事务日志

事务日志文件会记录更新前的数据记录,然后再更新数据库中的记录

  • UNDO: 取消本次操作的方法,按照此方法回滚。

  • REDO: 重复本次操作的方法

JVM架构原理及垃圾回收

JVM组成架构

执行引擎对应CPU, 运行期数据区对应内存, 就类似一个虚拟机器一样。

Yf2QRvE.png!mobile

  1. Java程序启动:启动jvm进程, 加载Class类, 通过类加载器,放到运行期数据区方法区

  2. JVM创建用户主线程, 并为 主线程分配Java堆栈, 为每个 线程分配程序计数寄存器

  3. 线程启动后检查 程序计数器存储的指令 到方法区取出指令;

  4. 指令通过 执行引擎 执行, 执行引擎 转化为本地执行指令

  5. 如果执行时需要 创建对象 , 在 堆中存放 , 针对 这个对象的引用放到Java栈中

Java字节码文件

  • 字节码执行流程

解释执行和编译执行。

qyi63uI.png!mobile

  • 字节码翻译过程

QNZFvmb.png!mobile

类加载起的双亲委托模型

低层次的当前类加载器,不 能覆盖更高层次类加载器已 经加载的类。

AfeuYbQ.png!mobile

自定义类加载器:

  • 隔离加载类

  • 扩展加载源

  • 字节码加密

运行时数据区

  • 堆&栈

  • 方法区&程序计数器

  • Java(线程)栈

  • 线程工作内存& volatile

对象引用存放Java栈,对象实例创建在堆中, 方法区存放类静态变量及代码。

Java运行环境

Java源码通过java编译器,编译成Java字节码, 通过类加载器加载到方法区,字节码交给解释器和即时编译器执行,编译成本地代码,交予本地操作系统执行。

Java垃圾回收

JVM 垃圾回收就是将 JVM 堆中的已经不再被使用的对象清理掉,释放宝贵的内存资源

内存回收的三种方法:

  • 清理

  • 压缩

  • 复制

内存回收分代回收:

  • 新生代

  • 老年代

内存回收算法:

  • 串行回收

  • 并行回收

  • 并发回收CMS

  • G1回收

Java启动参数

  • 标准参数,所有的 JVM 实现都必须实现这些参数的功能,而且向后兼容

  • 运行模式 -server,-client

  • 类加载路径 -cp,-classpath

  • 运行调试 –verbose

  • 系统变量 –D

  • 非标准参数, 默认jvm实现这些参数,但不保证所有 JVM 实现都实现,且不保证向后兼容

  • -Xms 初始堆大小

  • -Xmx 最大堆大小

  • -Xmn 新生代大小

  • -Xss 线程堆栈大小

  • 非Stable参数, 此类参数各个jvm实现会有所不同,将来可能会随时取消

  • -XX:-UseConcMarkSweepGC 启用 CMS 垃圾回收

Java性能诊断工具

  • 基本工具 :JPS ,JSTAT,JMAP,JSTACK

  • 集成工具 : JConsole,JVisualV

Java代码优化

合理并谨慎使用多线程

  • 使用场景(I/O 阻塞,多 CPU 并发)

  • 资源争用与同步问题

  • java.util.concurrent

启动线程数 = [任务执行时间 / (任务执行时间 - IO 等待时间)] * CPU 内核数

可以看到如果属于CPU密集型应用,不宜启动过多线程。 多了反而容易竞争,影响执行效率, 如果任务需要等待磁盘操作,网络响应,可以通过增加线程提高效率

竞态条件与临界区

在临界区中使用适当的同步就可以避免竞态条件。

Java线程安全

  • 方法局部变量

局部变量存储在线程自己的栈中。

  • 方法局部的对象引用

如果在某个方法中创建的对象不会逃逸出该方法,那么它就是线程安全的。

  • 对象成员变量

对象成员存储在堆上。如果两个线程同时更新同一个对象的同一个成员,那这个代码就不是 线程安全的。

Web Servlet单实例多线程共享, 需要增加锁保证线程安全。

ThreadLocal

niAbmii.png!mobile

实现:

  • Thread里有自己的ThreadLocalMap, ThreadLocalMap中存放这Thread的信息。

Java内存泄露

容易产生内存泄露部分:

  • 长生命周期对象

  • 静态容器

  • 缓存

合理使用线程池:

  • 复用线程或对象池

  • 池管理算法

  • 对象内容清除

合理容器类:

  • LinkList 和 ArrayList 的区别及适用场景 :根据随机访问和插入删除场景判断选择

  • HashMap 的算法实现及应用场景

  • 使用 concurrent 包,ConcurrentHashMap 比较 HashMap 是线程安全特性

缩短对象生命周期

  • 减少对象驻留内存的时间

  • 在使用时创建对象,用完释放

  • 创建对象的步骤(静态代码段-静态成员变量-父类构造函数-子类构造函数)

使用 I/O buffer 及 NIO

  • 延迟写与提前读策略

  • 异步无阻塞 IO 通信

优先使用组合代替继承

  • 减少对象耦合

  • 避免太深的继承层次带来的对象创建性能损失

合理使用单例模式

  • 无状态对象

  • 线程安全

计算机的任何问题都可以通过虚拟层(或者中间层)解决

  • 面向接口编程

  • 7层网络协议

  • JVM

  • 编程框架

  • 一致性 hash 算法的虚拟化实现

秒杀系统案例

需求分析:

系统涉及要满足业务需求

架构方案:

单独部署,比在原有系统基础上改造更简单,隔离性更好; 通过边缘计算缓解中心服务压力

设计原则

  • 静态化

  • 并发控制,防秒杀器

  • 简化流程

  • 前端优化

交易系统性能优化

  • 二跳页面优化

  • 交易系统优化

应急预案

通过降级,限流,拒绝服务防止系统异常

参考及引用

架构师训练营作业-李智慧老师相关讲义

Photo by  stein egil liland  from  Pexels


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK