架构师训练营第 1 期 - 第 9 周 - 学习总结
9.1 数据库的基本原理
数据库架构:
数据库连接器 --- 为每个连接请求分配一块专用的内存空间用于会话上下文管理。
语义分析与优化器---将各种复杂嵌套的 SQL 进行语义等价转化,得到有限几种关系代数计算结构,并利用索引等信息进一步进行优化。
执行计划 -- mysql> explain select * from users where id = 1;
为什么 PrepareStatement 更好?
1.PrepareStatement 会预先提交带占位符的 SQL 到数据库进行预处理,提前生成执行计划, 当给定占位符参数,真正执行 SQL 的时候,执行引擎可以直接执行,效率更好一点。
2.PrepareStatement 可以防止 SQL 注入攻击。
聚簇(cu 4 声调)索引:聚簇索引的数据库记录和索引存储在一起。
MySQL 数据库的主键就是聚簇索引,主键 ID 和所在的记录行存储在一个 B+树中。
非聚簇索引在叶子节点记录的就不是数据行记录,而是聚簇索引,也就是主键。
通过非聚簇索引找到主键索引,再通过主键索引找到行记录的过程也被称作回表。
合理使用索引
不要盲目添加索引,尤其在生产环境中
添加索引的 alter 操作会消耗较长的时间(分钟级)
Alter 操作期间,所有数据库的增删改操作全部阻塞,对应用而言,因为连接不能释放,事实上,查询也被阻塞。
删除不用的索引,避免不必要的增删开销。
使用更小的数据类型创建索引:int 4 字节,bigint 8 字节,Timestamp 4 字节,Datetime 8 字节
数据事务特性 ACID
原子性(Atomicity): 事务要么全部完成,要么全部取消。如果事务崩溃,状态回到事务之前(事务回滚)。
隔离性(Isolation): 如果 2 个事务 T1 和 T2 同时运行,事务 T1 和 T2 最终的结果是相的,不管 T1 和 T2 谁先结束,隔离性主要依靠锁实现。
持久性(Durability): 一旦事务提交,不管发生什么(崩溃或者出错),数据要保存在数据库中。
一致性(Consistency): 只有合法的数据(依照关系约束和函数约束)才能写入数据库。
数据库事务日志
进行事务操作时,事务日志文件会记录更新前的数据记录,然后再更新数据库中的记录,如果全部记录都更新成功,那么事务正常结束,如果过程中某条记录更新失败,那么整个事务全部回滚,已经更新的记录根据事务日志中记录的数据进行恢复,这样全部数据都恢复到事务提交前的状态,仍然保持数据一致性。
LSN:一个按时间顺序分配的唯一事务记录日志序列号。
Ø TransID:产生操作的事务 ID。
Ø PageID:被修改的数据在磁盘上的位置。
Ø PrevLSN:同一个事务产生的上一条日志记录的指针。
Ø UNDO:取消本次操作的方法,按照此方法回滚。
Ø REDO:重复本次操作的方法。
9.2 JVM 虚拟机架构原理
构成:1.类加载器 2.运行时数据区 3. 执行引擎
java 字节码文件
java 所有的指令有 200 个左右,一个字节(8Bit)可以存储 256 种不同的指令信息,一个这样的字节称为字节码(Bytecode)。
在代码的执行过程中,JVM 将字节码解释执行,屏蔽对底层操作系统的依赖,
JVM 也可以将字节码编译执行
如果是热点代码,会通过 JIT 动态地编议为机器码,提高执行效率。
字节码执行流程
Java 字节码文件编议过程
Java 源文件 -> 词法解析 ---(token 流)-->语法解析 ->语义分析 -> 生成字节码 -> 字节码
类加载器的双亲委托模型
自定义类加载器的意义何在:
隔离加载类: 同一个 JVM 中不同组件加载同一个类的不同版本。
扩展加载类: 从网络、数据库等处加载字节码。
字节码加密: 加载自定义的加密字节码,在 ClassLoader 中解密。
堆:每个 JVM 实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都入在这个堆中,并由应用所有的线程共享。
堆栈:JVM 为每个新创建的线程都分配一个堆栈。对于一个 Java 程序来说,它的运行就是通过对堆栈的操作来完成的。
建立一个对象时从两个地方分配内存,在堆中分配的内存实际存放这个对象,在堆栈中分配内存存放指向这个堆对象的引用。
方法区--主要存放从磁盘加载进来的类字节码,而程序运行过程中创建的类实例存放在堆中。
每个线程都用自己的 Java 栈,Java 栈里存放着方法运行期的局部变量。
当前线程执行到哪 一行字节码指令,这个信息就被存放在程序计数器寄存器中。
线程工作内存 & volatile (立即可见)
Java 内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行。
一个共享变量(类的成员变量、类的静态成员变量)被 volatile 修饰之后,保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这个新值对其他线程是立即可见的。
9.3 JVM 垃圾回收性能分析
启动参数:
标准参数:
运行模式: -server, -client
类加载路径: -cp , -classpath
运行调试: -verbose
系统变量:-D
非标准参数:
-Xms 初始堆大小
-Xmx 最大堆大小
-Xmn 新生代大小
-Xss 线程堆栈大小
非Stable参数,此类参数各个JVM实现会有所不同,将来可能会随时取消
-XX:-UseConcMarkSweepGC 启动CMS垃圾回收。
JVM性能诊断工具:
基本工具:JPS,Jstat,Jmap,Jstack
集成工具:JConsole,JVisualVM
JPS用来查看host上运行的所有Java进程的pid(jvmid).
jstat 是JDK自带的一个轻量级小工具。对Java应用程序的资源和性能进行实时的命令行的监控。包括了对Heap size和垃圾回收状况的监控。
例:jstat -gcutil 当前运行的java进程号 interval count
jmap是一个可以输出 所有内存中对象的工具,可以将VM中的heap以二进制输出成文本。
使用方法:jmap -histo pid>a.log
jmap -dump:format=b,file=1 PID
jstack可以查看JVM内的线程堆栈信息。
9.4 Java 代码优化技巧及原理
java.util.concurrent
最佳线程数 = [任务执行时间/(任务执行时间-IO等待时间)]*CPU内核数
当两个线程竞争同一资源时,如果对资源的访问顺序敏感,-->就是存在竞态条件。
导致竞态条件发生的代码区--> 称作 临界区。
在临界区中使用适当的同步可以避免竞态条件。
java线程安全:
基础类型的局部变量是线程安全的。
方法局部的对象引用(如果在方法中创建的对象不会逃逸出该方法,那么它就是线程安全的)
对象的成员变量(对象成员存储在堆上。如果两个线程同时更新同一个对象的同一个成员变量,那这个代码就不是线程安全的。)
ThreadLocal
Java内存泄漏:
长生命周期对象
静态容器(例如 static的Map,Set,List 等)
缓存
合理使用线程池和对象池
创建对象的步骤:
1.静态代码段
2.静态成员变量
3.父类构造函数
4.子类构造函数
计算机的任何问题都可以通过虚拟层(或者中间层)解决
面向接口编程
7 层网络协议
JVM
编程框架
一致性hash算法虚拟代实现
系统性能优化案例:秒杀系统
版权声明: 本文为 InfoQ 作者【wgl】的原创文章。
原文链接:【http://xie.infoq.cn/article/bc563acf60e2859aca68084b8】。未经作者许可,禁止转载。
评论