JAVA技术栈
2024-11-09 12:16:03 24 举报
AI智能生成
java 技术栈
作者其他创作
大纲/内容
分布式消息中间件
ROCKETMQ
ROCKETMQ详细特性和场景
消息类型
顺序消息
广播消息
延迟消息
批量消息
过滤消息
事务消息
消息存储
刷盘机制
同步刷盘
异步刷盘
消息主从复制
同步复制
异步复制
RocketMQ消息的存储分为三个部分
CommitLog:存储消息的元数据。
ConsumerQueue:存储消息在CommitLog的索引。
IndexFile:为了消息查询提供了一种通过key或时间区间来查询消息的方法,
ROCKETMQ核心源码解析
参考:https://note.youdao.com/ynoteshare/index.html?id=c91c232cb5052cc9917c35ff2aa62e49&type=note&_time=1726298216245
ROCKETMQ源码解读和实践问题
参考:https://note.youdao.com/ynoteshare/index.html?id=34ee9fe19157c6f4f0ab416d69622c7a&type=note&_time=1726303554161
KAFKA
KAFKA快速实战和基本原理
KAFKA发送接收消息核心参数配置与设计原理详解
KAFKA生产问题总结和性能优化实战
RABBITMQ
RABBITMQ集群及高级特性
RABBITMQ如何作可靠消息的投递
分布式技术MongDBSharding-Sphere
MONGDB
MONGDB集群架构及高级特性
MONGDB企业应用实战
ShardingSphere
ShardingSphere核心概念
ShardingSphere内核原理及核心源码解析
ShardingProxy分库分表实战及同类产品选型
MYSQL主从架构分库分表
分布式通信netty框架
JAVA BIO&NIO&AIO精讲
netty核心功能与线程模型精讲
netty编解码&粘包拆包及零拷贝精讲
netty线程模型源码解析
分布式技术apache Dubbo
DUBBO基本应用和高级应用
负载均衡
随机负载均衡(Random Load Balance)
轮询负载均衡(Round Robin Load Balance)
最少活跃数负载均衡(Least Active Load Balance)
一致性哈希负载均衡(Consistent Hash Load Balance)
服务超时
集群容错
服务降级
本地存根
本地伪装
参数回调
异步调用
泛化调用
DUBBO的可扩展SPI源码解析
Spring与Dubbo整合原理
DUBBO服务导出源码解析
DUBBO服务导入源码解析
DUBBO服务调用源码解析
分布式ELK
ElasticSearch核心语法与集群环境搭建
ElasticSearch集群架构原理和搜索技术深入
ElasticSearch底层原理与分组聚合查询
ElasticSearch进阶与Java api整合ES
微服务技术
SpringBoot自动装配核心源码剖析
为什么Springboot可以运行jar包?
@SpringBootApplication
继承@Configuration,标注这是一个Spring Boot配置类:@SpringBootConfiguration
启用Spring Boot的自动配置机制,尝试根据类路径设置、其他bean以及各种属性设置自动配置:@EnableAutoConfiguration
启用组件扫描,允许Spring Boot查找其他组件、配置文件和服务。:@ComponentScan
微服务架构Alibaba nacos 注册中心实战
负载均衡组件RRibbon&LLoadBalancer实战
JVM性能调优
类加载机制
引导类加载器
扩展类加载器
应用程序类加载器
自定义加载器
扩展类加载器
应用程序类加载器
自定义加载器
类加载机制流程图
类加载的双亲委派机制
JVM
JVM整体结构
JVM整体结构图
JVM内存分配
对象内存分配图
对象内存分配流程图
对象进入老年代几种机制
大对象直接进入老年代
大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。JVM参数 -XX:PretenureSizeThreshold 可以设置大对象的大小,如果对象超过设置大小会直接进入老年代,不会进入年轻代,这个参数只在 Serial 和ParNew两个收集器下有效。
大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。JVM参数 -XX:PretenureSizeThreshold 可以设置大对象的大小,如果对象超过设置大小会直接进入老年代,不会进入年轻代,这个参数只在 Serial 和ParNew两个收集器下有效。
长期存活的对象将进入老年代
既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应放在新生代,哪些对象应放在老年代中。为了做到这一点,虚拟机给每个对象一个对象年龄(Age)计数器。
既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应放在新生代,哪些对象应放在老年代中。为了做到这一点,虚拟机给每个对象一个对象年龄(Age)计数器。
对象动态年龄判断
当前放对象的Survivor区域里(其中一块区域,放对象的那块s区),一批对象的总大小大于这块Survivor区域内存大小的50%(-XX:TargetSurvivorRatio可以指定),那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代了,例如Survivor区域里现在有一批对象,年龄1+年龄2+年龄n的多个年龄对象总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代。这个规则其实是希望那些可能是长期存活的对象,尽早进入老年代。对象动态年龄判断机制一般是在minor gc之后触发的。
当前放对象的Survivor区域里(其中一块区域,放对象的那块s区),一批对象的总大小大于这块Survivor区域内存大小的50%(-XX:TargetSurvivorRatio可以指定),那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代了,例如Survivor区域里现在有一批对象,年龄1+年龄2+年龄n的多个年龄对象总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代。这个规则其实是希望那些可能是长期存活的对象,尽早进入老年代。对象动态年龄判断机制一般是在minor gc之后触发的。
老年代空间分配担保机制
年轻代每次minor gc之前JVM都会计算下老年代剩余可用空间
如果这个可用空间小于年轻代里现有的所有对象大小之和(包括垃圾对象)
就会看一个“-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了
如果有这个参数,就会看看老年代的可用内存大小,是否大于之前每一次minor gc后进入老年代的对象的平均大小。
如果上一步结果是小于或者之前说的参数没有设置,那么就会触发一次Full gc,对老年代和年轻代一起回收一次垃圾,如果回收完还是没有足够空间存放新的对象就会发生"OOM"
当然,如果minor gc之后剩余存活的需要挪动到老年代的对象大小还是大于老年代可用空间,那么也会触发full gc,full gc完之后如果还是没有空间放minor gc之后的存活对象,则也会发生“OOM”
年轻代每次minor gc之前JVM都会计算下老年代剩余可用空间
如果这个可用空间小于年轻代里现有的所有对象大小之和(包括垃圾对象)
就会看一个“-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了
如果有这个参数,就会看看老年代的可用内存大小,是否大于之前每一次minor gc后进入老年代的对象的平均大小。
如果上一步结果是小于或者之前说的参数没有设置,那么就会触发一次Full gc,对老年代和年轻代一起回收一次垃圾,如果回收完还是没有足够空间存放新的对象就会发生"OOM"
当然,如果minor gc之后剩余存活的需要挪动到老年代的对象大小还是大于老年代可用空间,那么也会触发full gc,full gc完之后如果还是没有空间放minor gc之后的存活对象,则也会发生“OOM”
老年代空间分配担保机制流程图
JVM字节码文件结构
JVM调优工具
调优流程
对于还在正常运行的系统:
1.可以使用jmap来查看JVM中各个区域的使用情况
2.可以通过jstack来查看线程的运行情况,比如哪些线程阻塞、是否出现了死锁
3.可以通过jstat命令来查看垃圾回收的情况,特别是fullgc,如果发现fulgc比较频繁,那么就得进行调优了4.通过各个命令的结果,或者jvisualvm等工具来进行分析
5.首先,初步猜测频繁发生fullgc的原因,如果频繁发生fullgc但是又一直没有出现内存溢出,那么表示fullgc实际上是回收了很多对象了,所以这些对象最好能在younggc过程中就直接回收掉,避免这些对象进入到老年代,对于这种情况,就要考虑这些存活时间不长的对象是不是比较大,导致年轻代放不下,直接进入到了老年代,尝试加大年轻代的大小,如果改完之后,fullgc减少,则证明修改有效
6.同时,还可以找到占用CPU最多的线程,定位到具体的方法,优化这个方法的执行,看是否能避免某些对象的创建,从而节省内存
1.可以使用jmap来查看JVM中各个区域的使用情况
2.可以通过jstack来查看线程的运行情况,比如哪些线程阻塞、是否出现了死锁
3.可以通过jstat命令来查看垃圾回收的情况,特别是fullgc,如果发现fulgc比较频繁,那么就得进行调优了4.通过各个命令的结果,或者jvisualvm等工具来进行分析
5.首先,初步猜测频繁发生fullgc的原因,如果频繁发生fullgc但是又一直没有出现内存溢出,那么表示fullgc实际上是回收了很多对象了,所以这些对象最好能在younggc过程中就直接回收掉,避免这些对象进入到老年代,对于这种情况,就要考虑这些存活时间不长的对象是不是比较大,导致年轻代放不下,直接进入到了老年代,尝试加大年轻代的大小,如果改完之后,fullgc减少,则证明修改有效
6.同时,还可以找到占用CPU最多的线程,定位到具体的方法,优化这个方法的执行,看是否能避免某些对象的创建,从而节省内存
对于已经发生了OOM的系统:
1.一般生产系统中都会设置当系统发生了OOM时,生成当时的dump文件(-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/base)
2.我们可以利用jsisualvm等工具来分析dump文件
3.根据dump文件找到异常的实例对象,和异常的线程(占用CPU高),定位到具体的代码
4.然后再进行详细的分析和调试
1.一般生产系统中都会设置当系统发生了OOM时,生成当时的dump文件(-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/base)
2.我们可以利用jsisualvm等工具来分析dump文件
3.根据dump文件找到异常的实例对象,和异常的线程(占用CPU高),定位到具体的代码
4.然后再进行详细的分析和调试
调优工具
arthas工具
jsisualvm工具
JVM调优实战
垃圾收集器
Serial
Serial收集器
parallel
Parallel收集器
parNew
ParNew收集器
CMS
CMS收集器
CMS收集器步骤图
CMS相关参数
垃圾回收器底层算法-三色标记
GC ROOTS算法
G1
G1垃圾回收器
G1收集器参数设置
ZGC
垃圾回收器选择
MYSQL性能调优
MYSQL索引底层数据结构和算法
底层数据结构
索引是帮助MySQL高效获取数据的排好序的数据结构
二叉树
红黑树
Hash表
B-Tree
B+Tree
存储引擎索引
MyISAM存储引擎索引实现
InnoDB存储引擎索引实现
索引最左前缀原理
explain详解与索引的最佳实践
索引类型(type)
依次从最优到最差分别为:system>const>eq_ref>ref>range>index>ALL;
一般来说,得保证查询达到range级别,最好达到ref
一般来说,得保证查询达到range级别,最好达到ref
explain的sql字段说明
key_len计算规则如下:
字符串
char(n):n字节长度
varchar(n):如果是utf-8,则长度 3n+2 字节,加的2字节用来存储字符串长度0
数值类型
tinyint:1字节。
smallint:2字节
int:4字节
bigint:8字节
时间类型
date:3字节
timestamp:4字节。
dateime:8字节
如果字段允许为 NULL,需要1字节记录是否为 NULL索引最大长度是768字节,
当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引。
字符串
char(n):n字节长度
varchar(n):如果是utf-8,则长度 3n+2 字节,加的2字节用来存储字符串长度0
数值类型
tinyint:1字节。
smallint:2字节
int:4字节
bigint:8字节
时间类型
date:3字节
timestamp:4字节。
dateime:8字节
如果字段允许为 NULL,需要1字节记录是否为 NULL索引最大长度是768字节,
当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引。
一条SQL怎么执行
MYSQL索引优化实战
trace工具
开启trace
trace信息:预估成本
trace信息:最优选择
关闭trace
order by和group by优化
总结
单路排序和双路排序
索引设计原则
索引设计实战
分页查询
优化前:EXPLAIN select * from employees ORDER By name limit 90000,5;
优化后:EXPLAIN select * from employees inner join (select id from employees order by name limited 90000,5) ed on e.id = ed.id;
优化后:EXPLAIN select * from employees inner join (select id from employees order by name limited 90000,5) ed on e.id = ed.id;
join优化
in和exsits优化
count优化
字段类型优化
MYSQL事务隔离级别和锁机制
事务及其ACID属性
原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。
隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的"独立“环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
持久性(Durable): 事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
并发事务带来问题
脏读
不可重复读
幻读
事务隔离级别
未提交读
提交读
可重复读:写时加锁
可串行化:读写加锁
锁分类
乐观锁
悲观锁
读锁(共享锁,S锁(Shared)):针对同份数据,读操作可以同时进行而不会互相影响
写锁(排它锁,X锁(eXclusive)):当前写操作没有完成前,它会阻断其他写锁和读锁
行锁
每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。InnoDB与MYISAM的最大不同有两点:
InnoDB支持事务(TRNSACTION)
InnoDB支持行级锁
每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。InnoDB与MYISAM的最大不同有两点:
InnoDB支持事务(TRNSACTION)
InnoDB支持行级锁
表锁
每次操作锁住整张表。
开销小,加锁快;不会出现死锁:锁定粒度大,
发生锁冲突的概率最高,并发度最低:
一般用在整表数据迁移的场景
每次操作锁住整张表。
开销小,加锁快;不会出现死锁:锁定粒度大,
发生锁冲突的概率最高,并发度最低:
一般用在整表数据迁移的场景
间隙锁
临键锁
无索引行锁会升级为表锁
查看锁情况
锁优化建议
概述
MVCC与BufferPool缓存机制
MVCC
MVCC的判断规则
可重复读事务:在一个事务中,第一个查询会生成一个readview,后面的查询都使用这个readview;
已提交读事务:在一个事务中,第一个查询会生成一个readview,后面的查询都会实时生成一个readview;
已提交读事务:在一个事务中,第一个查询会生成一个readview,后面的查询都会实时生成一个readview;
BufferPool
TOMCAT性能调优
TOMCAT核心组件及应用架构详解
TOMCAT核心组件源码解析
TOMCAT源码之HTTP请求响应过程剖析
TOMCAT源码之热加载热部署及类加载器剖析
并发编程专题
操作系统底层工作的底层认识
JMM&volatile详解
多线程下可见性
可见性:当一个线程修改了一个被声明为 volatile 的共享变量时,其他线程能够立即看到这个变化,
而不是等待缓存失效或刷新。这意味着对 volatile 变量的写操作会强制刷入主内存,
并且读操作会从主内存中读取最新值。
而不是等待缓存失效或刷新。这意味着对 volatile 变量的写操作会强制刷入主内存,
并且读操作会从主内存中读取最新值。
多线程下有序性
禁止指令重排序:编译器和CPU不会对 volatile 变量进行指令重排序优化,
保证了程序执行的顺序与源代码中的顺序一致(即 happens-before 规则)。
这对于依赖于特定顺序执行的操作特别重要。
保证了程序执行的顺序与源代码中的顺序一致(即 happens-before 规则)。
这对于依赖于特定顺序执行的操作特别重要。
内存屏障:Java内存模型(JMM)通过插入内存屏障来实现 volatile 的语义。内存屏障是一种硬件层面的技术,
它可以确保一些内存操作按照指定顺序执行。对于 volatile 写操作,会在其后插入“写屏障”,
这样能确保所有之前的操作都完成并刷新到主内存;对于 volatile 读操作,则在其前插入“读屏障”,
确保在此之后的所有操作都能看到此变量的最新值。
它可以确保一些内存操作按照指定顺序执行。对于 volatile 写操作,会在其后插入“写屏障”,
这样能确保所有之前的操作都完成并刷新到主内存;对于 volatile 读操作,则在其前插入“读屏障”,
确保在此之后的所有操作都能看到此变量的最新值。
缓存一致性协议:现代多核处理器使用缓存一致性协议(如Intel的MESI协议等)来维持不同CPU核心之间的缓存数据同步。
当一个CPU核心修改了 volatile 变量时,该协议会确保其他核心上的缓存副本失效,从而需要从主内存重新加载最新的值。
当一个CPU核心修改了 volatile 变量时,该协议会确保其他核心上的缓存副本失效,从而需要从主内存重新加载最新的值。
总结:
总结来说,volatile关键字是Java中用于简化并发编程的一种机制,它确保了多线程环境下的简单同步问题,但不能替代原子操作或解决复杂的互斥问题。在实际应用中,volatile 常用于状态标志、计数器等简单的并发场景,而更复杂的并发控制通常需要借助于 synchronized 或 java.util.concurrent 包中的工具类。
总结来说,volatile关键字是Java中用于简化并发编程的一种机制,它确保了多线程环境下的简单同步问题,但不能替代原子操作或解决复杂的互斥问题。在实际应用中,volatile 常用于状态标志、计数器等简单的并发场景,而更复杂的并发控制通常需要借助于 synchronized 或 java.util.concurrent 包中的工具类。
JMM&MESI协议
synchronized详解
锁的状态总共有四种,无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁,但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。从JDK 1.6 中默认是开启偏向锁和轻量级锁的,可以通过-XX:-UseBiasedLocking来禁用偏向锁。
AQS应用lock详解
AQS核心:①自旋;②线程阻塞;③cas;④队列;
AQS应用阻塞队列(BlockingQueue)
countDownLatch&SemaPhore应用
底层是基于AQS实现的
countDownLatch
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。
每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,
它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,
它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
CountDownLatch.countDown()
CountDownLatch.await();
CountDownLatch.await();
SemaPhore
Semaphore 字面意思是信号量的意思,它的作用是控制访问特定资源的线程数目
构造方法
public Semaphore(int permits)
public Semaphore(int permits, boolean fair)
permits 表示许可线程的数量
fair 表示公平性,如果这个设为 true 的话,下次执行的线程会是等待最久的线程
public Semaphore(int permits)
public Semaphore(int permits, boolean fair)
permits 表示许可线程的数量
fair 表示公平性,如果这个设为 true 的话,下次执行的线程会是等待最久的线程
重要方法
public void acquire() throws InterruptedException
public void release()
tryAcquire(int args,long timeout, TimeUnit unit)
acquire() 表示阻塞并获取许可
release() 表示释放许可
public void acquire() throws InterruptedException
public void release()
tryAcquire(int args,long timeout, TimeUnit unit)
acquire() 表示阻塞并获取许可
release() 表示释放许可
atomic&Unsafe详解
Map&List&Set详解
ArrayList、LinkedList、Vector区别和实现原理
ArrayList和Vector是基于动态数组实现的,LinkedList是基于双向链表实现的(含有头结点)
ArrayList、LinkedList不具有有线程安全性,
如果在并发环境下使用它们,可以用Collections类中的静态方法synchronizedList()对ArrayList和LinkedList进行调用即可,即可达到线程安全问题。
Vector实现线程安全的,即他的方法大都包含关键字synchronized,但是Vector的效率没有ArraykList和LinkedList高。
如果在并发环境下使用它们,可以用Collections类中的静态方法synchronizedList()对ArrayList和LinkedList进行调用即可,即可达到线程安全问题。
Vector实现线程安全的,即他的方法大都包含关键字synchronized,但是Vector的效率没有ArraykList和LinkedList高。
hashMap hashtable ConcurrentHashMap区别
hashMap内部存储结构是数组加链表,线程非安全
hashtable内部存储结构是数组加链表,线程安全,在很多方法定义时都会加上 synchronized关键字
ConcurrentHashMap底层采用分段的数组+链表实现,底层先调用lock(),lock是ReentrantLock类的一个方法,因此是线程安全
锁分段技术:首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
锁分段技术:首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
Excutor线程池原理和源码解读
ThreadPoolExcutor七大参数说明
拒绝策略
线程数设置
定时任务线程池
Future&ForkJoin框架
无锁并发框架-Disruptor
源码框架专题
SpringIOC流程和源码
流程1:
流程2:
流程3:
SpringAOP流程和源码
切面术语:
切面流程:
解析切面:
创建动态代理:
调用:
aop的四种实现方式:
一、BeanNameAutoProxyCreator
二、DefaultAdvisorAutoProxyCreator
三 、aop:config 配置代理
四 、注解方式实现AOP
链接:https://blog.csdn.net/d1451545368/article/details/127304500
声明式事务管理和编程式事务管理
声明式事务管理和编程式事务管理
Spring事务流程和源码
声明性事务四大特性ACID
A 原子性:原子性指的是 在一组业务操作下 要么都成功 要么都失败
在一组增删改查的业务下 要么都提交 要么都回滚
在一组增删改查的业务下 要么都提交 要么都回滚
C 一致性:事务前后的数据要保证数据的一致性
在一组的查询业务下 必须要保证前后关联数据的一致性
在一组的查询业务下 必须要保证前后关联数据的一致性
I 隔离性:在并发情况下 事物之间要相互隔离。
D 持久性:数据一旦保存就是持久性的。
@Transactional注解应该写在哪:
@Transactional 可以标记在类上面(当前类所有的方法都运用上了事务)
@Transactional 标记在方法则只是当前方法运用事务
也可以类和方法上面同时都存在, 如果类和方法都存在@Transactional会以方法的为准。如果方法上面没有@Transactional会以类上面的为准
建议:@Transactional写在方法上面,控制粒度更细, 建议@Transactional写在业务逻辑层上,因为只有业务逻辑层才会有嵌套调用的情况。
建议:@Transactional写在方法上面,控制粒度更细, 建议@Transactional写在业务逻辑层上,因为只有业务逻辑层才会有嵌套调用的情况。
子类继承父类事务,子类依然具有事务功能
事务配置属性
isolation:设置事务的隔离级别
propagation:事务的传播行为
noRollbackFor:那些异常事务可以不回滚
noRollbackForClassName:填写的参数是全类名
rollbackFor:哪些异常事务需要回滚
rollbackForClassName:填写的参数是全类名
readOnly:设置事务是否为只读事务
timeout:事务超出指定执行时长后自动终止并回滚,单位是秒
propagation:事务的传播行为
noRollbackFor:那些异常事务可以不回滚
noRollbackForClassName:填写的参数是全类名
rollbackFor:哪些异常事务需要回滚
rollbackForClassName:填写的参数是全类名
readOnly:设置事务是否为只读事务
timeout:事务超出指定执行时长后自动终止并回滚,单位是秒
设置隔离级别(isolation)
并发事务产生问题
脏读
不可重复度
幻影读
事务隔离级别
并发安全:SERIALIZABLE>REPEATABLE_READ>READ_COMMITTED
运行效率:READ_COMMITTED>REPEATABLE_READ>SERIALIZABLE
运行效率:READ_COMMITTED>REPEATABLE_READ>SERIALIZABLE
事务的传播特性
超时属性(timeout)
指定事务等待的最长时间(秒)
当前事务访问数据时,有可能访问的数据被别的数据进行加锁的处理,那么此时事务就必须等待,如果等待时间过长给用户造成的体验感差。
当前事务访问数据时,有可能访问的数据被别的数据进行加锁的处理,那么此时事务就必须等待,如果等待时间过长给用户造成的体验感差。
设置事务只读(readOnly)
异常属性
在实战中事务的使用方式
面试题
面试题:
Spring事务的实现方式和实现原理
说一下Spring的事务传播行为
说一下 spring 的事务隔离?
Spring框架的事务管理有哪些优点?
操作!!
Spring事务的实现方式和实现原理
说一下Spring的事务传播行为
说一下 spring 的事务隔离?
Spring框架的事务管理有哪些优点?
操作!!
事务实现流程
SpringMVC流程和源码
SpringMVC流程
MyBatis流程和源码
Spring整合MyBatis的源码解析
分布式缓存技术Redis
Redis核心数据结构与高性能原理
五种数据结构
高性能原理
Redis持久化
RDB快照(snapshot)
AOF(append-only file)
Redis 4.0 混合持久化
Redis的主从、哨兵、集群架构
主从架构
主从、哨兵架构
集群架构
Redis分布式实战锁
Redis缓存设计与性能优化
缓存穿透
1、缓存空对象
2、布隆过滤器
缓存失效(击穿)
由于大批量缓存在同一时间失效可能导致大量请求同时穿透缓存直达数据库,可能会造成数据库瞬间压力过大甚至挂掉,
对于这种情况我们在批量增加缓存时最好将这一批数据的缓存过期时间设置为一个时间段内的不同时间。
对于这种情况我们在批量增加缓存时最好将这一批数据的缓存过期时间设置为一个时间段内的不同时间。
缓存雪崩
1) 保证缓存层服务高可用性,比如使用Redis Sentinel或Redis Cluster。
2) 依赖隔离组件为后端限流熔断并降级。比如使用Sentinel或Hystrix限流降级组件。
比如服务降级,我们可以针对不同的数据采取不同的处理方式。当业务应用访问的是非核心数据(例如电商商品属性,用户信息等)时,暂时停止从缓存中查询这些数据,而是直接返回预定义的默认降级信息、空值或是错误提示信息;当业务应用访问的是核心数据(例如电商商品库存)时,仍然允许查询缓存,如果缓存缺失,也可以继续通过数据库读取。
比如服务降级,我们可以针对不同的数据采取不同的处理方式。当业务应用访问的是非核心数据(例如电商商品属性,用户信息等)时,暂时停止从缓存中查询这些数据,而是直接返回预定义的默认降级信息、空值或是错误提示信息;当业务应用访问的是核心数据(例如电商商品库存)时,仍然允许查询缓存,如果缓存缺失,也可以继续通过数据库读取。
3) 提前演练。 在项目上线前, 演练缓存层宕掉后, 应用以及后端的负载情况以及可能出现的问题, 在此基础上做一些预案设定。
热点缓存key重建优化
开发人员使用“缓存+过期时间”的策略既可以加速数据读写, 又保证数据的定期更新, 这种模式基本能够满足绝大部分需求。 但是有两个问题如果同时出现, 可能就会对应用造成致命的危害:
当前key是一个热点key(例如一个热门的娱乐新闻),并发量非常大。
重建缓存不能在短时间完成, 可能是一个复杂计算, 例如复杂的SQL、 多次IO、 多个依赖等。
在缓存失效的瞬间, 有大量线程来重建缓存, 造成后端负载加大, 甚至可能会让应用崩溃。
要解决这个问题主要就是要避免大量线程同时重建缓存。
我们可以利用互斥锁来解决,此方法只允许一个线程重建缓存, 其他线程等待重建缓存的线程执行完, 重新从缓存获取数据即可。
当前key是一个热点key(例如一个热门的娱乐新闻),并发量非常大。
重建缓存不能在短时间完成, 可能是一个复杂计算, 例如复杂的SQL、 多次IO、 多个依赖等。
在缓存失效的瞬间, 有大量线程来重建缓存, 造成后端负载加大, 甚至可能会让应用崩溃。
要解决这个问题主要就是要避免大量线程同时重建缓存。
我们可以利用互斥锁来解决,此方法只允许一个线程重建缓存, 其他线程等待重建缓存的线程执行完, 重新从缓存获取数据即可。
redis的高并发
配置优化
配置文件优化:可以适当增加Redis的最大连接数(maxclients),设置合适的内存限制(maxmemory),根据实际情况设置合理的超时时间,确保Redis能够处理足够多的连接和请求
网络配置优化:调整操作系统的参数,如增加文件描述符限制、调整TCP连接参数等,以提高Redis的并发处理能力。
数据分片
分片横向扩展:将数据按照一定规则划分到多个Redis实例中,每个实例负责处理一部分数据。这样可以将负载均衡到多个实例上,提高整体并发能力。
分区键优化:合理选择分区键,避免某个键对应的数据集中在某个实例上,导致某个实例成为热点,影响整体性能。
数据预加载和缓存预热
数据预加载:启动Redis时,可以通过导入rdb文件或者aof文件来提前将数据加载到内存中,避免数据一开始大量访问导致的性能瓶颈。
缓存预热:根据业务情况,在Redis启动前预先将热点数据加载到缓存中,可以提前将数据加载到内存中,避免大量请求的时候造成冷启动的性能问题。
使用主从复制和哨兵模式
主从复制:通过搭建Redis主从复制架构,将读请求分发到从节点,减轻主节点的负载,提高并发能力。
哨兵模式:通过引入Redis哨兵来实现自动的故障转移和主从切换,保证Redis的高可用性。
使用集群模式
Redis Cluster:Redis Cluster支持在多个节点上分布数据,自动进行数据分片和容错,实现高可用和高并发
总结
综上所述,通过合理的配置优化、数据分片、数据预加载和缓存预热、主从复制和哨兵模式、使用集群模式等方法来解决Redis高并发问题。
分布式协调服务zookeeper
zookeeper特性和节点数据类型
PERSISTENT-持久化目录节点
客户端与zookeeper断开连接后,该节点依旧存在,只要不手动删除该节点,他将永远存在
PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点
客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
EPHEMERAL-临时目录节点
客户端与zookeeper断开连接后,该节点被删除
EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点
客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
Container 节点
Container 节点(3.5.3 版本新增,如果Container节点下面没有子节点,则Container节点在未来会被Zookeeper自动清除,定时任务默认60s 检查一次)
TTL 节点
( 默认禁用,只能通过系统配置 zookeeper.extendedTypesEnabled=true 开启,不稳定)
zookeeper客户端使用和集群特性
zookeeper典型使用场景实战
zookeeper典型核心源码解析
zookeeper的ZAB原理和源码
设计模式
单例模式:懒汉与饿汉,使用饿汉模式,数据库连接池,创建一个单例对象,用于提供对数据库连接方法,还有在一些配值类中,声明一个配置读取单例用于配值类的读取。
原型模式:创建复杂对象时,如果每次都是从头初始化,可能会带来性能开销或者逻辑过于复杂,通过实现Cloneable()接口与实现Searializiable接口实现浅克隆与深克隆。
模板方法模式:主要特点是封装了不变的部分,扩展了可变的部分。它将不变的算法骨架封装在父类中,而将可变的步骤留给子类实现。
使用场景:当某个方法的实现需要多个步骤,其中有些步骤是固定的,而有些步骤可以变化时。
使用场景:当某个方法的实现需要多个步骤,其中有些步骤是固定的,而有些步骤可以变化时。
工厂方法模式:定义工厂接口,然后根据具体工厂类进行产品的管理,客户端直接与具体的工厂进行交互。
建造者模式:创建带参数的构造器对象的时候可以使用建造者模式,可以动态改变参数传递顺序,代码可读性也会更好。
代理模式:面向切面编程,日志处理,事务管理这些都可以用代理模式,有接口用jdk动态代理,无接口用cglib动态代理。
策略模式:在Java开发中,策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。通过定义一系列可互换的算法(策略),并在上下文中使用这些策略来解决特定问题,就是定义抽象的策略接口,定义不同接口实现类实现不同的策略,比如:电商网站购卡的不同优惠策略。
观察者模式:用于实现对象之间的依赖关系,当一个对象的状态改变时,所有依赖于它的对象都会得到通知并自动更新。比如:消息队列就是典型的观察者模式。
备忘录模式:用于在不违反封装性原则的前提下,捕获并存储对象的内部状态,以便将来可以恢复到之前的状态,用于在一些回滚的场景,用于还原状态。
装饰者模式:java.io` 包中的输入/输出流类如 `BufferedReader`、`BufferedWriter`、`DataInputStream` 和 `DataOutputStream` 等,这些类作为装饰器添加额外功能到基础的 `InputStream` 和 `OutputStream` 流上。
好的编程习惯
类名使用 UpperCamelCase 风格,以下情形例外 :DO / PO(持久对象) / DTO(数据传输对象 )/ BO(业务对象) / VO / UID 等。
使用版本控制:如Git,管理代码变更,便于追踪和协作。
编写清晰的注释:为复杂的逻辑、方法和类提供注释。
异常处理:妥善处理异常,并给出明确的错误信息。
遵循SOLID原则:编写可维护、可扩展和可测试的代码。
使用日志:记录关键信息和错误,便于调试和排查问题。
编写测试:包括单元测试、集成测试和功能测试。
避免硬编码:将常量、配置信息等放入配置文件或环境变量中。
遵循代码风格指南:保持代码风格一致。
使用合适的集合:根据需求选择合适的集合类型。
避免长方法:将长方法拆分为多个小方法。
使用设计模式:在适当的情况下使用设计模式。
考虑接口兼容性:修改老接口时,确保新旧接口的兼容性。
遵循依赖注入原则:通过依赖注入来解耦代码,提高代码的可测试性和可维护性。
使用接口隔离原则:为每个类定义明确的接口,并只让它们依赖于它们真正需要的接口。
使用设计模式:不仅限于常见的设计模式,也要根据具体场景选择合适的设计模式,如观察者模式、策略模式等。
使用版本控制:如Git,管理代码变更,便于追踪和协作。
编写清晰的注释:为复杂的逻辑、方法和类提供注释。
异常处理:妥善处理异常,并给出明确的错误信息。
遵循SOLID原则:编写可维护、可扩展和可测试的代码。
使用日志:记录关键信息和错误,便于调试和排查问题。
编写测试:包括单元测试、集成测试和功能测试。
避免硬编码:将常量、配置信息等放入配置文件或环境变量中。
遵循代码风格指南:保持代码风格一致。
使用合适的集合:根据需求选择合适的集合类型。
避免长方法:将长方法拆分为多个小方法。
使用设计模式:在适当的情况下使用设计模式。
考虑接口兼容性:修改老接口时,确保新旧接口的兼容性。
遵循依赖注入原则:通过依赖注入来解耦代码,提高代码的可测试性和可维护性。
使用接口隔离原则:为每个类定义明确的接口,并只让它们依赖于它们真正需要的接口。
使用设计模式:不仅限于常见的设计模式,也要根据具体场景选择合适的设计模式,如观察者模式、策略模式等。
自由主题
0 条评论
下一页