写点什么

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

用户头像
garlic
关注
发布于: 2020 年 11 月 22 日
性能优化-数据库,JVM,  秒杀场景

数据库基本原理


数据库架构



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

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

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

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


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


B+树


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

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

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



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

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


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


数据库事务(ACID)


  • 原子性 (Atomicity)

  • 隔离性(IsoLation)

  • 持久性(Durability)

  • 一致性(Consistency)


数据库事务日志


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


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

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


JVM 架构原理及垃圾回收


JVM 组成架构


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



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

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

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

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

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

Java 字节码文件


  • 字节码执行流程

解释执行和编译执行。



  • 字节码翻译过程



类加载器的双亲委托模型


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


自定义类加载器:

  • 隔离加载类

  • 扩展加载源

  • 字节码加密


运行时数据区


  • 堆 &栈

  • 方法区 &程序计数器

  • 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



实现:

  • 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



用户头像

garlic

关注

还未添加个人签名 2017.11.15 加入

还未添加个人简介

评论

发布
暂无评论
性能优化-数据库,JVM,  秒杀场景