猿码天地-Java超神之路
2021-02-24 17:25:07 9 举报
AI智能生成
猿码天地-Java超神之路
作者其他创作
大纲/内容
Java基础
基础语法
数据类型
整型
byte
short
int
long
字符型
char
浮点型
float
double
布尔型
boolean
面向对象
三大特征
封装
继承
多态
IOC(控制反转)
AOP(切面编程)
DI(依赖注入)
四种引用
强、软、弱、虚
集合
Collection接口
List
实现类
ArrayList、LinkedList 和 Vector
特点
1.可以允许重复的对象。
2.可以插入多个null元素。
3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
2.可以插入多个null元素。
3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
Set
实现类
HashSet、LinkedHashSet、TreeSet
HashSet
1.Set中是不能出现重复数据的。
2.Set中可以出现空数据。
3.Set中的数据是无序的。
2.Set中可以出现空数据。
3.Set中的数据是无序的。
LinkedHashSet
1.Set中是不能出现重复数据的。
2.Set中可以出现空数据。
3.Set中的数据是有序的。
2.Set中可以出现空数据。
3.Set中的数据是有序的。
TreeSet
1.不能写入空数据。
2.写入的数据是有序的。
3.不写入重复数据。
2.写入的数据是有序的。
3.不写入重复数据。
特点
1.不允许重复对象。
2.无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序。
3.只允许一个 null 元素。
4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。
2.无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序。
3.只允许一个 null 元素。
4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。
Map
实现类
HashMap、LinkedHashMap、Hashtable 和 TreeMap(HashMap、TreeMap最常用)
HashMap
线程不安全,效率高。允许null键和null值,是基于哈希表的Map接口实现,哈希表的作用是用来保证键的唯一性。
数据结构
数组+链表(当链表长度到8时,转化为红黑树)
底层原理
数组+链表
数组+链表+红黑树
TreeMap
是基于红黑树的Map接口的实现。
HashTable
ConcurrentHashMap
Java5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
特点
Map里你可以拥有随意个 null 值但最多只能有一个 null 键。
使用场景
反射
泛型
枚举
I/O
并发&多线程
线程
线程安全
互斥同步(阻塞同步)
临界区
syncronized、ReentrantLock
信号量
semaphore
互斥量
mutex
非阻塞同步
CAS(Compare And Swap)
无同步方案
ThreadLocal/Volaitile
线程本地的变量,每个线程获取一份共享变量的拷贝,单独进行处理。
ThreadLocal是用来维护本线程的变量的,并不能解决共享变量的并发问题。ThreadLocal是各线程将值存入该线程的map中,以ThreadLocal自身作为key,需要用时 获得的是该线程之前存入的值。如果存入的是共享变量,那取出的也是共享变量,并发问题 还是存在的。
线程本地存储
如果一个共享资源一定要被多线程共享,可以尽量让一个线程完成所有的处理操作,比如生产者消费者模式中,一般会让一个消费者完成对队列上资源的消费。典型的应用是基于请求-应答模式的web服务器的设计。
多线程
创建方式
继承Thread类
实现Runnable接口
实现Callable接口
线程池
使用ThreadPoolExecutor类
使用Executors类
缓存线程池newCachedThreadPool
同步队列SynchronousQueue
固定大小线程池newFixedThreadPool
无界队列LinkedBlockingQueue
单线程线程池newSingleThreadExecutor
无界队列LinkedBlockingQueue
定时及周期性执行任务的线程池newScheduledThreadPool
为什么不推荐使用
从队列长度和创建线程数入手分析
核心参数
corePoolSize
核心线程数大小
maximumPoolSize
最大线程数大小
keepAliveTime
线程空闲后的存活时间
unit
时间单位
workQueue
缓存异步任务的队列
threadFactory
用来构造线程池里的worker线程
handler
线程池任务满载后采取的任务拒绝策略(使用 RejectedExecutionHandler )
线程池大小分配
执行流程
1. 如果线程池中线程数量 < core,新建一个线程执行任务;
2. 如果线程池中线程数量 >= core ,则将任务放入任务队列;
3. 如果线程池中线程数量 >= core 且 < maxPoolSize,则创建新的线程;
4. 如果线程池中线程数量 > core ,当线程空闲时间超过了keepalive时,则会销毁线。
2. 如果线程池中线程数量 >= core ,则将任务放入任务队列;
3. 如果线程池中线程数量 >= core 且 < maxPoolSize,则创建新的线程;
4. 如果线程池中线程数量 > core ,当线程空闲时间超过了keepalive时,则会销毁线。
JUC并发包
Java并发包
ConcurrentHashMap
线程池 Executor/ThreadPoolExecute
阻塞队列 blockingqueue
ArrayBlockingQueue 有界的阻塞队列 其内部实现是将对象放到一个数组里
DelayQueue 延迟无界阻塞队列
LinkedBlockingQueue 有界/无界链表阻塞队列(线程池默认使用)
PriorityBlockingQueue 无界的并发队列
locks 同步锁
synchronized
Synchronized和Lock的区别
性能
锁机制
简洁性
用法
volatile关键字
保证内存的可见性,线程每次都从主存中读取数据。
CAS乐观锁(非阻塞算法)
包含三个操作数,内存值V,预估值A,更新值B,当且仅当V==A,V=B;否则,不做任何操作。
CAS乐观锁的缺点
ABA问题:如果另一个线程修改V值假设原来是A,先修改成B,再修改回成A。当前线程的CAS操作无法分辨当前V值是否发生过变化
如何解决ABA问题:用另一个标识判断某值是否有改变过。
ABA问题:如果另一个线程修改V值假设原来是A,先修改成B,再修改回成A。当前线程的CAS操作无法分辨当前V值是否发生过变化
如何解决ABA问题:用另一个标识判断某值是否有改变过。
Java并发工具类
CountDownLatch倒计时器
使用场景
现需要解析一个excel里的多个sheet数据,使用多线程,每个线程解析其中一个sheet的数据,等到所有sheet解析完,程序提示解析完成构造函数传入int型参数做改为计数器,countDown被调用,计数器减1,await会一直阻塞程序,直至计数为0.如果某个sheet解析较慢,可以使用带时间参数的await方法,到时间后,不再阻塞当前线程。
CountDownLatch 的作⽤就是 允许 count 个线程阻塞在⼀个地⽅,直⾄所有线程的任务都执⾏完 毕。
我们的API接口响应时间被要求在200ms以内,但是如果一个接口内部依赖多个三方/外部服务,那串行调用接口的响应时间必然很久,所以可使用内部服务并行调用进行优化。假设接口内部依赖了10个外部服务,创建CountDownLatch实例,计数数量为10,有10个线程来完成任务,等待在CountDownLatch上的线程执行完才能继续执行那个响应时间较快的接口。latch.countDown();方法作用是通知CountDownLatch有一个线程已经准备完毕,倒计数器可以减一了。latch.await()方法要求主线程等待所有10个检查任务全部准备好才一起并行执行。
Semaphore信号灯
CyclicBarrier循环栅栏
AQS
概念
AQS 是⼀个⽤来构建锁和同步器的框架
核心思想
AQS 核⼼思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的⼯作线 程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占⽤,那么就需要⼀套线程阻塞 等待以及被唤醒时锁分配的机制,这个机制 AQS 是⽤ CLH 队列锁实现的,即将暂时获取不到锁 的线程加⼊到队列中。
AQS 底层使⽤了模板⽅法模式
数据库
SQL语句
ORM框架
MyBatis
MyBatis-Plus
Hibernate
连接池
Druid
HikariCP
C3P0
分库分表
MyCAT
Sharding-JDBC
Sharding-Sphere
性能优化
硬件层面
增加机器性能
软件层面
SQL调优
表结构优化
读写分离
数据库集群
分库分表
隔离级别
Spring家族
Spring
IOC(控制反转)
DI(依赖注入)
AOP(切面编程)
概念图
涉及设计模式
应用相关
常用注解
类型类
@Controller、@Service、@Repository、@Component、@Configuration、@Bean
设置类
@Required、@Autowired、@Qualifier、@Scope
Web类
@RequestMapping、@GetMapping、@PostMapping、@PathVariable、@RequestParam、@RequestBoy、@ResponseBody
功能类
@lmportResource、@ComponentScan、@EnableCaching、@Cacheable、@Transactional、@Aspect、@Pointcut、@Scheduled
Spring中bean的生命周期
Spring扩展接口
Spring事务
实现方式
Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,
spring 是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过
binlog 或者 redo log 实现的。
spring 是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过
binlog 或者 redo log 实现的。
传播行为
Spring 事务的传播行为说的是,当多个事务同时存在的时候, Spring 如何
处理这些事务的行为。
处理这些事务的行为。
隔离级别
读未提交
读已提交
可重复读
序列化
事务种类
编程式事务
编程式事务管理使用 TransactionTemplate
声明式事务
声明式事务管理建立在 AOP 之上的
Spring解决循环依赖的方法
概念
解决思路
三级缓存
一级缓存,解决循环依赖
二级缓存,解决对象完整性
三级缓存,解决AOP
二级缓存,解决对象完整性
三级缓存,解决AOP
SpringMVC
结构图
运行原理
Spring Security
用户认证
用户授权
SpringBoot
Spring Boot设计目的
Spring Boot好处
基于Spring
快速编码
模块化
配置简单
便捷部署
有效监控
Spring Boot核心功能
独立运行Spring项目
内嵌servlet容器
提供starter简化Maven配置
自动装配Spring
准生产的应用监控
无代码生产和xml配置
SpringBoot 常用的注解
@RestController和@Controller
指定一个类,作为控制器的注解。
@RequestMapping
为方法级别的映射注解,这一个用过Spring MVC的小伙伴相信都很熟悉。
@EnableAutoConfiguration和@SpringBootApplication
类级别的注解,根据maven依赖的jar来自动完成正确的spring的对应配置,只要引入了spring-boot-starter-web的依赖,默认会自动配置Spring MVC和tomcat容器。
@Configuration
类级别的注解,一般这个注解,我们用来标识main方法所在的类,完成元数据bean的初始化。
@ComponentScan
类级别的注解,自动扫描加载所有的Spring组件包括Bean注入,一般用在main方法所在的类上。
@ImportResource
类级别注解,当我们必须使用一个xml的配置时,使用@ImportResource和@Configuration来标识这个文件资源的类。
@Autowired
一般结合@ComponentScan注解,来自动注入一个Service或Dao级别的Bean。
@Component
类级别注解,标识一个组件,比如自定义一个filter,则需要此注解标识之后,Spring Boot才会正确识别。
集成用法
Spring Boot项目属性配置
Spring Boot 中MVC支持
Spring Boot 集成 MyBatis
Spring Boot MyBatis Druid 多数据源配置
Spring Boot 返回JSON数据格式封装
Spring Boot 使用slf4j日志记录
Spring Boot 集成Swagger接口文档
Spring Boot 集成Thymeleaf模板引擎
Spring Boot 全局异常处理
Spring Boot 切面AOP处理
Spring Boot 事务管理
Spring Boot 监听器
Spring Boot 拦截器
Spring Boot 集成Redis
Spring Boot 集成 Quartz
Spring Boot 集成Shiro
Spring Boot 发送邮件
Spring Boot MongoDB 实战
Spring Boot 综合实战用户管理系统
SpringCloud
Eureka(服务注册与发现组件)
负载均衡
客户端负载均衡
Ribbon
服务实例的清单在客户端,客户端进行负载均衡算法分配。
客户端可以从Eureka Server中得到一份服务清单,在发送请求时通过负载均衡算法,在多个服务器之间选择一个进行访问。
服务端负载均衡
Nginx
服务实例的清单在服务端,服务器进行负载均衡算法分配。
服务消费者
Rest+Ribbon方式
Feign方式
Hystrix(服务熔断降级组件)
Zuul(路由网关组件)
SpringCloud Config(分布式配置中心)
SpringCloud Bus(消息总线)
SpringCloud Sleuth(服务链路追踪)
Hystrix Dashboard(断路器监控)
Hystrix Turbine(断路器聚合监控)
SpringCloud微服务架构图
微服务&分布式
架构演进
单体应用
Model1模式:jsp+java
Model2模式(MVC模式):Model View Controller (web service dao)
Model1模式:jsp+java
Model2模式(MVC模式):Model View Controller (web service dao)
垂直应用
RPC分布式应用
SOA流动计算架构
资源调度负载均衡动态服务创建...服务治理
资源调度负载均衡动态服务创建...服务治理
微服务
微,单一职业
微,单一职业
SOA VS 微服务
对比
Dubbo VS SpringCloud
对比
总结
微服务设计原则
AKF扩展拆分
背景:性能问题、容量问题、功能和模块数量多带来的系统复杂性问题
场景
AKF扩展立方
前后端分离
Rest通讯风格
无状态服务
微服务优缺点
优点
简单、灵活、独立部署
专注、专业、高效、可靠、小团队
松耦合、高内聚、易扩展
语言、工具无关
缺点
运维成本高,部署项目多
接口兼容版本问题
分布式系统的复杂性
分布式事务
常用组件
服务注册与发现
Zookeeper
Eureka
为什么需要注册中心?
解决什么问题?
服务管理
服务的依赖管理
三种角色
Eureka Server、Service Provider、Service Consumer
调用说明
CAP原则
Consistency 一致性
Availability 可用性
Partition tolerance 分区容错性
决策
实际应用
CA:单节点居多
AP:互联网居多,保证高可用,忽略一致性,例如小米秒杀
CA/CP:银行居多,保证一致性
架构原理
高可用
三大特点
自我保护
一般情况下,服务在Eureka上注册后,会每30秒发送心跳包,Eureka通过心跳来判断服务是否健康,同时会定期删除超过90 秒没有发送心跳的服务。
优雅停服
安全认证
Nacos
Consul
角色
服务发现及注册
当服务Producer启动时,会将自己的ip/host等信息通过发送请求告知Consul,Consul 接收到 Producer的注册信息后, 每隔
10s(默认)会向Producer发送一个健康检查的请求,检验Producer是否健康。
10s(默认)会向Producer发送一个健康检查的请求,检验Producer是否健康。
服务调用
当Consumer请求Product时,会先从Consul中拿到存储Product服务的IP和 Port的临时表(temp table),从temp table 表中任选一个Producer的IP和Port,然后根据这个IP和Port,发送访问请求;temptable 表只包含通过了健康检查的 Producer 信息,并且每隔 10s(默认)更新。
常见注册中心对比
服务调用(负载均衡)
Rest+Ribbon
Ribbon
什么是Ribbon?
解决什么问题?
负载均衡策略
轮询策略
权重轮询策略
随机策略
最少并发数策略
重试策略
可用性敏感策略
区域敏感性策略
点对点直联
点对点直连是指绕过注册中心, 直接连接服务提供者获取服务,一般在测试阶段使用比较多。
Feign
什么是Feign?
Feign解决什么问题?
和OpenFeign对比
性能优化
Gzip压缩
一种流行的文件压缩算法,对于纯文本文件,可以减少70%以上的文件大小
HTTP连接池
采用Http连接池,可以节约大量三次握手四次挥手,这样能大大提高吞吐量
状态查看
请求超时
Feign的负载均衡底层用的就是Ribbon,所以这里的请求超时配置其实就是配置Ribbon。
分布式项目中,服务压力比较大的情况下,可能处理服务的过程需要花费一定的时间,而默认情况下请求超时的配罟是1s,所以我们需要调整该配置延长请求超时时间。
分布式项目中,服务压力比较大的情况下,可能处理服务的过程需要花费一定的时间,而默认情况下请求超时的配罟是1s,所以我们需要调整该配置延长请求超时时间。
OpenFeign
熔断/降级
Hystrix
什么是Hystrix?
雪崩效应
架构图
解决方案
请求缓存
请求合并
服务隔离
服务熔断
服务降级
Sentinel
服务降级(调用本地方法)
服务限流
服务熔断(知道这个远端服务出问题,直接断开调用本地方法)
路由网关
Zuul
SpringCloud Gateway
作用
路由转发
权限校验
安全认证
配置中心
Apollo
特点
版本发布管理
配置修改实时生效(热发布)
统一管理不同环境、不同集群的配置
application (应用)
environment (环境)
cluster (集群)
namespace (命名空间)
environment (环境)
cluster (集群)
namespace (命名空间)
灰度发布
权限管理、发布审核、操作审计
提供Java和.Net原生客户端
提供开放平台API
部署简单
原理
执行流程
配置更新推送实现
SpringCloud Config
Nacos
客户端向注册中心发送心跳机制
服务自动感知
服务发现
Nacos就是一个SpringBoot工程,提供一系列接口
认证鉴权
OAuth2
Shiro
SSO单点登录
Spring Security
分布式事务
Seata 阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
任务调度
Quartz
XXL-JOB
运行原理
技术栈
spring + spring security + jetty+ quartz + mysql + 自研RPC
消息总线
SpringCloud Bus
消息驱动服务
SpringCloud Stream
链路追踪与监控
Zipkin
Sleuth
Skywalking
Pinpoint
日志分析
ELK
两代微服务比较
替代方案及发展现状
总结
三高
高性能
高可用
高扩展
亿级流量电商微服务架构
锁、分布式锁
什么是锁?什么是分布式锁?
单体项目
如果是一个传统方式开发和部署的单体应用,为确保多线程并发情况下共享资源只能被一个线程持有时,可以使用ReentrantLcok或synchronized进行互斥控制。
分布式项目
但随着业务的不断发展,原单体单机部署的系统逐渐被演化成分布式系统后,并发执行的线程分布在不同JVM上,原单机模式的并发控制锁策略将失效,分布式锁可以解决跨JVM的共享资源的并发访问。
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。
在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。
在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。
什么样的锁才是分布式锁?
只能被一个线程获取;
高可用、高性能的获取与释放锁;
可重入;
防止死锁,具备锁失效机制;
具备阻塞锁特性,即没有获取到锁将继续等待获取锁;
具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。
高可用、高性能的获取与释放锁;
可重入;
防止死锁,具备锁失效机制;
具备阻塞锁特性,即没有获取到锁将继续等待获取锁;
具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。
AQS
队列同步器
队列-》volatile共享变量-》CAS获取锁-》没有获取到则在队列中等待
zookeeper实现分布式锁
原理
ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录树结构,规定同一个目录下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步骤如下:
- 创建一个目录mylock;
- 线程A想获取锁就在mylock目录下创建临时顺序节点;
- 获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;
- 线程B获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;
- 线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。
利用 Zookeeper 的顺序临时节点,来实现分布式锁和等待队列。Zookeeper 设计的初衷,就是为了实现分布式锁服务的。
优缺点
优点
具备高可用、可重入、阻塞锁特性,可解决失效死锁问题。
缺点
因为需要频繁的创建和删除节点,性能上不如Redis方案。
redis如何实现分布式锁?
原理
使用Redis2.6.12及之后版本,通过SET key value NX PX lock-time命令获取锁,仅当key不存在时才能成功获取锁,且锁的有效期是lock-time秒。value是一个随机值,它必须在所有的服务器中唯一,释放锁时,仅当key存在且value值和预期值相等,执行del命令释放锁,为了保证原子性,等值判断和del操作放在Lua脚本中执行,同时为了高可用、高可靠,需要使用RedLock算法。
利用 Redis 的 setnx 命令。此命令同样是原子性操作,只有在 key 不存在的情况下,才能 set 成功。
过程
加锁
解锁
锁超时(死锁)
优缺点
优点
高性能、高可用、高可靠
缺点
RedLock算法的实现不简单
数据库如何实现分布式锁?
原理
锁持有者信息字段用于存储持有锁的机器和线程信息,当同样的线程再次请求获取锁时,可和当前值做对比,相同则直接获取锁,实现锁的可重入。
锁失效时间用于记录当前锁的有效期,正常处理下,锁被释放时当前行记录会被删除,但防不住一些意外情况,例如应用程序宕机了或重启了,此时持有锁的线程已经不存在了,所以锁不会释放,当前行记录不会被主动删除,所以需要设计定时任务定时删除已过期的锁。
对于阻塞的特性,需要设计获取锁等待的具体逻辑,不靠谱的方案是不断循环尝试获取,好一些设计是设置监听,等待被触发。
锁失效时间用于记录当前锁的有效期,正常处理下,锁被释放时当前行记录会被删除,但防不住一些意外情况,例如应用程序宕机了或重启了,此时持有锁的线程已经不存在了,所以锁不会释放,当前行记录不会被主动删除,所以需要设计定时任务定时删除已过期的锁。
对于阻塞的特性,需要设计获取锁等待的具体逻辑,不靠谱的方案是不断循环尝试获取,好一些设计是设置监听,等待被触发。
优缺点
优点
仅使用数据库表实现。
缺点
数据库的可用性和性能直接影响锁的可用性及性能;
为了实现高可用、高性能,数据库需要双机部署、数据同步、主备切换,各种成本很高;
需定时清除未及时释放的失效锁,时效无法准确保证;
为了实现其他特性,例如阻塞,不断加码,最后会很复杂。
为了实现高可用、高性能,数据库需要双机部署、数据同步、主备切换,各种成本很高;
需定时清除未及时释放的失效锁,时效无法准确保证;
为了实现其他特性,例如阻塞,不断加码,最后会很复杂。
强烈推荐,不重复造轮子
如果用Redis推荐成熟的分布式锁解决方案Redisson,如果用zk推荐Apache开源库Curator,轮子不是那么好造的!
事务、分布式事务
理解
分布式系统中的数据一致性就需要一种方案,可以保证数据在子系统中始终保持一致,避免业务出现问题,这种实现方案就叫做分布式事务,要么一起成功,要么一起失败,必须是一个整体性的事务。
例子
在电商网站中,用户对商品进行下单,需要在订单表中创建一条订单数据,同时需要在库存表中修改当前商品的剩余库存数量,两步操作一个添加,一个修改,我们一定要保证这两步操作一定同时操作成功或失败,否则业务就会出现问题。
CAP理论
CP架构:满足一致性和分区容错,一般用于银行;AP架构:一般用于互联网秒杀,先抢到单,满足可用性和分区容错。
2PC 二阶段提交 协议(阻塞)
参与者(指分布式系统各节点)将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。
两阶段(参与者+协调者)
投票阶段
提交阶段
优缺点
优点
尽量保证了数据的强一致,但不是100%一致。
缺点
3PC 三阶段提交 协议(非阻塞)
三阶段提交(Three-phase commit),三阶段提交是为解决两阶段提交协议|的缺点而设计的。 与两阶段提交不同的是,三阶段提交是“非阻塞”协议。三阶段提交在两阶段提交的第一阶段与第二阶段之间插入了一个准备阶段,使得原先在两阶段提交中,参与者在投票之后,由于协调者发生崩溃或错误,而导致参与者处于无法知晓是否提交或者中止的“不确定状态”所产生的可能相当长的延时的问题得以解决。
三阶段
询问阶段 CanCommit
准备阶段 PreCommit
提交阶段 DoCommit
解决两阶段问题
解决方案
强一致性分布式事务
单体架构多数据源
在业务开发中,肯定是先执行对订单库的操作,但是不提交事务,再执行对库存库的操作,也不提交事务,如果两个操作都成功,在一起提交事务,如果有一个操作失败,则两个都进行回滚。
基于XA协议的两阶段提交
最终一致性分布式事务方案(柔性事务)
JTA方案适用于单体架构多数据源时实现分布式事务,但对于微服务间的分布式事务就无能为力了。
1、本地消息表方案
核心思想
将分布式事务拆分成本地事务进行处理。
执行流程
2、MQ消息事务方案
核心思想
将两个事务通过消息中间件进行异步解耦。
执行流程
3、最大努力通知方案
核心思想
最大努力通知相比前两种方案实现简单,适用于一些最终一致性要求较低的业务,比如支付通知,短信通知这种业务。
执行流程
4、补偿事务TCC方案
核心思想
TCC Try-Confirm-Cancel的简称,针对每个操作,都需要有一个其对应的确认和取消操作,当操作成功时调用确认操作,当操作失败时调用取消操作,类似于二阶段提交,只不过是这里的提交和回滚是针对业务上的,所以基于TCC实现的分布式事务也可以看做是对业务的一种补偿机制。
执行流程
开源框架
基于TCC实现的分布式事务框架:ByteTCC,tcc-transaction
分布式session一致性问题
什么是Session?
分布式Session为什么会不一致?
解决方案
客户端存储
session复制(Tomcat自带该功能)
session绑定(基于nginx ip-hash策略)
nginx
作用
反向代理、负载均衡、http服务器(动静代理)、正向代理
如何使用nginx进行session绑定
我们利用nginx的反向代理和负载均衡,之前是客户端会被分配到其中一台服务器进行处理,具体分配到哪台服务器进行处理还得看服务器的负载均衡算法(轮询、随机、ip-hash、权重等),但是我们可以基于nginx的ip-hash策略,可以对客户端和服务器进行绑定,同一个客户端就只能访问该服务器,无论客户端发送多少次请求都被同一个服务器处理。
在nginx安装目录下的conf目录中的nginx.conf文件。
优缺点
基于nginx的ip-hash策略,可以对客户端和服务器进行绑定,实现session绑定。
后端统一集中存储(cache、db)
思路
将session存储在web-server后端的存储层,数据库或者缓存。
优缺点
基于redis存储session方案(推荐)
原理图
优缺点
基于令牌(Token)
最靠谱的分布式Session解决方案
基于令牌(Token)方式实现Session解决方案,因为Session本身就是分布式共享连接。
将生成的Token 存入到Redis中。
基于令牌(Token)方式实现Session解决方案,因为Session本身就是分布式共享连接。
将生成的Token 存入到Redis中。
常用框架
Spring
SpringMVC
MyBatis
Netty
设计模式
介绍
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。
设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。
这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
为了提高代码的可读性,可扩展性以及代码的复用性,为了解决在写代码过程中遇到的代码设计问题。
设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。
这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
为了提高代码的可读性,可扩展性以及代码的复用性,为了解决在写代码过程中遇到的代码设计问题。
分类
创建型模式(5种)
单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式
行为型模式(11种)
策略模式、责任链模式、模板方法模式、观察者模式、迭代器模式、命令模式、备忘录模式、状态模式、访问者模式、中介模式、解释器模式
结构型模式(7种)
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
中间件
缓存
Redis
特点
Redis 作为一个内存数据库:
1.性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS。
2.单进程单线程,是线程安全的,采用 IO 多路复用机制。
3.丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。
4.支持数据持久化。
5.可以将内存中数据保存在磁盘中,重启时加载。
6.主从复制,哨兵,高可用。
7.可以用作分布式锁。
8.可以作为消息中间件使用,支持发布订阅。
1.性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS。
2.单进程单线程,是线程安全的,采用 IO 多路复用机制。
3.丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。
4.支持数据持久化。
5.可以将内存中数据保存在磁盘中,重启时加载。
6.主从复制,哨兵,高可用。
7.可以用作分布式锁。
8.可以作为消息中间件使用,支持发布订阅。
作用
数据库、缓存、消息中间件、分布式锁
5种类型及使用场景
String
使用场景
常规key-value缓存应用; 常规计数:微博数,粉丝数等。
Hash
使用场景
存储用户信息,商品信息等。
List
使用场景
异步消息:一般使用list结构作为队列,rpush异步消息:生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
Set
使用场景
比如在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis可以非常 方 便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程。
ZSet
使用场景
缓存和数据库数据一致性问题
缓存失败重试机制
UDF(Userdefined function)用户自定义函数
binlog
缓存雪崩
概念
所谓缓存雪崩就是在某一时刻,缓存大量失效,导致大量请求直接打到数据库,给数据库带来巨大的负担。
解决方案
防止缓存雪崩主要的就是要主动控制Redis中key的过期时间,不要让key在同一时间过期,在批量往 Redis 存数据的时候,把每个 Key 的失效时间都加个随机值就好了,这样可以保证数据不会在同一时间大面积失效。setRedis(key, value, time+Math.random()*10000);
缓存穿透
概念
缓存穿透是指缓存和数据库中都没有的数据,而用户(黑客)不断发起请求。
解决方案
1、查询返回的数据为空,仍把这个空结果进行缓存,但过期时间会比较短。
2、布隆过滤器(Bloom Filter):将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据 会被这个 bitmap 拦截掉,从而避免了对 DB 的查询。
缓存击穿
概念
缓存击穿,跟缓存雪崩有点像,但是又有一点不一样,缓存雪崩是因为大面积的缓存失效,打崩了 DB。
而缓存击穿不同的是缓存击穿是指一个 Key 非常热点(LFU机制发现热点数据),在不停地扛着大量的请求,大并发集中对这一个点进行访问,当这个 Key 在失效的瞬间,持续的大并发直接落到了数据库上,就在这个 Key 的点上击穿了缓存。
而缓存击穿不同的是缓存击穿是指一个 Key 非常热点(LFU机制发现热点数据),在不停地扛着大量的请求,大并发集中对这一个点进行访问,当这个 Key 在失效的瞬间,持续的大并发直接落到了数据库上,就在这个 Key 的点上击穿了缓存。
解决方案
1、设置热点数据永不过期,物理不过期,但逻辑过期(后台异步线程去刷新)。
2、加上互斥锁:当缓存失效时,不立即去load db,先使用如Redis的setnx去设置一个互斥锁,当操作成功返回时再进行load db的操作并回设缓存,否则重试get缓存的方法。
数据同步问题(双删策略)三种更新策略
先更新数据库,再更新缓存
先删除缓存,再更新数据库
延时双删策略
MySQL的读写分离架构
先更新数据库,再删除缓存
Memcache
消息
MQ基础概念模型
同步/异步
流量削峰
扩展性/解耦
缓冲/可恢复性
生产者与消费者
MQ常见解决方案
MQ如何避免消息堆积
提高消费者速率(集群)
消费者批量获取消息
MQ如何避免消费者重复消费(幂等问题)
全局ID+业务场景保证唯一性
MQ如何保证消息不丢失
消息确认机制
持久化
消息ack
MQ如何保证消息顺序一致性
绑定同一个消费者和队列
MQ推与拉架构模型
生产者如何获取消费结果
异步返回一个全局ID,前端使用ajax定时主动获取
主流MQ
RabbitMq
架构思想
RabbitMq管理平台中心
Virtual Hosts(分团队开发路径存放消息队列)
Exchange(路由分发消息)
路由key
四种交换机类型
Direct exchange(直联交换机)
针对路由模式
Fanout exchange(扇形交换机)
针对发布与订阅模式
Topic exchange(主题交换机)
针对主题模式
Headers exchange(头交换机)
常见面试题
RabbitMq如何保证消息不丢失
生产者
确保生产者消息投递到MQ服务器端成功
ACK消息确认机制(confirm)
同步或异步形式
事务消息
消费者
消费手动签收模式
自动签收(不推荐)
手动签收(推荐)
MQ服务端消息持久化
RabbitMq死信队列
消息投递到MQ中存放 消息已经过期
队列容器已经满了
消费者消费多次消息失败,就会存放到死信队列中
RabbitMq自动重试机制
重试多次还是失败,如何处理?
转移到死信队列中
记录到日志表中定时补偿或人工补偿
如何避免消费者幂等问题?
全局ID+业务场景保证唯一性
工作模式、队列模型
简单模式(simple)
流程图
工作队列(work queues)
流程图
使用场景
发布与订阅模式(publish/subscribe)
流程图
使用场景
路由模式(routing)
流程图
队列与交换机的绑定,不能是任意绑定了,而是要指定一个 RoutingKey(路由key)
消息的发送方在向 Exchange 发送消息时,也必须指定消息的 RoutingKey
Exchange 不再把消息交给每一个绑定的队列,而是根据消息的 Routing Key 进行判断,只有队列的Routingkey 与消息的 Routing key 完全一致,才会接收到消息
消息的发送方在向 Exchange 发送消息时,也必须指定消息的 RoutingKey
Exchange 不再把消息交给每一个绑定的队列,而是根据消息的 Routing Key 进行判断,只有队列的Routingkey 与消息的 Routing key 完全一致,才会接收到消息
主题模式(topic)
流程图
Topic 类型与 Direct 相比,都是可以根据 RoutingKey 把消息路由到不同的队列。只不过 Topic 类型Exchange 可以让队列在绑定 Routing key 的时候使用通配符!
Routingkey 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: item.insert
通配符规则:# 匹配一个或多个词,* 匹配不多不少恰好1个词,例如:item.# 能够匹配 item.insert.abc 或者 item.insert,item.* 只能匹配 item.insert
Routingkey 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: item.insert
通配符规则:# 匹配一个或多个词,* 匹配不多不少恰好1个词,例如:item.# 能够匹配 item.insert.abc 或者 item.insert,item.* 只能匹配 item.insert
远程条用模式(RPC)较少用
流程图
作用
应用解耦
提升容错性和可维护性
异步提速
用户点击完下单按钮后,只需等待25ms就能得到下单响应 (20 + 5 = 25ms)。
提升用户体验和系统吞吐量(单位时间内处理请求的数目)
提升用户体验和系统吞吐量(单位时间内处理请求的数目)
削峰填谷
提高系统稳定性
消息确认机制
高级特性
消费端限流
TTL
死信队列
延迟队列
消息可靠性传递
小结
消息可靠性总结
持久化:包括exchange持久化、queue持久化、message持久化
生产方确认Confirm
消费方确认Ack
Broker高可用
Consumer ACK
小结
消息幂等性保障
消息幂等性保障--乐观锁机制
消息积压
Kafka(大数据)
核心架构设计模型
Broker(MQ服务器端)
Topic (主题根据业务分类)
Partiiton(分区存储消息)
Producer(生产者)
Consumer(消费者)
Consumer Group(消费者组)
Replica (副本机制)
Offset(消费记录)
为什么kafka能够支持高并发
存储结构层面
消息会实现压缩,减少带宽传输
kafka分区partition存储结构模型
.log存储消息文件
.index存储消息的索引
.timeIndex,时间索引文件
分段存储日志(segment file)
- 使用稀疏索引查找消息物理位置(不会为每个消息创建索引,好处可以节约空间
消息存储之后,消费成功不会立即删除根据offset获取消息(需要考虑配置日志清理策略)
Java应用层面
生产者
产者批量投递消息(缓冲池设计)
消费者
消费者批量获取消息(多个offset)
每个分区对应一个消费者(可扩展性)
Linx内核层面
采用顺序读写方式
使用零拷贝机制
sendfile+mmap 用户态与内核态映射
不需要cpu拷贝数据
减少用户态与内核态切换次数
利用Page Cache缓存提高读写 需要考虑刷盘问题
kafka如何保证可靠消息
副本机制(Replication)
ISR副本可靠机制
分区中副本选举
HW高水位线 消费者能够消费最大offset
LEO队列中最大的offset值
生产者投递消息ack
0表示生产者不等待(可能会丢失消息)
1表示生产者等待,Leader刷盘(建议默认配置)
-1表示生产者需要等待所有节点同步完成
kafka选举原理控制器原理
依托于Zookeeper临时节点实现选举
消费者手动提交offset
Kafka如何查找指定offset的Message的
1.根据offset查找Segment分段文件(二分查找)
2.访问到index文件(稀疏索引),查找到对应物理存放位置。
3.根据物理访问位置,访问log日志查找物理对应消息
查找到该消息索引值 直接返回物理消息(时间复杂度o(1))
没有查找到该消息索引值 依次顺序查找(时间复杂度o(N))
kafka的性能优化
生产者
生产者内存缓冲的大小
重试策略“retries”和“retries.backoff.ms 该参数设置定重试的次数、间隔时间
确认机制:acks 建议设置为1比较平衡
消费者
消费者分区的个数
消费者根据多个offset批量获取消息
消费者开启手动提交offset
Broker(MQ服务器端)
日志保留策略配置
log数据文件刷盘策略
replica复制配置
网络和IO线程配置优化
RocketMQ
RPC
Dubbo
介绍
架构图
工作流程
Motan
介绍
架构图
工作流程
Tars
介绍
架构图
工作流程
SpringCloud
介绍
架构图
工作流程
gRPC
介绍
架构图
工作流程
Netty
Thrift
介绍
架构图
工作流程
容器化技术
Docker
K8s
JVM
类加载机制
字节码执行机制
JVM内存模型
GC垃圾回收
JVM性能监控与故障定位
JVM调优
Linux
运维
Web服务器
Nginx(重要)
应用服务器
Tomcat
Jetty
Undertow(性能好)
持续集成/部署
Jenkins
日志分析
ELK
性能优化
数据结构与算法
数据结构
数组Array
优点:查找快
缺点:插入、删除慢、大小固定、只能存储单一元素
链表LinkedList
优点:插入快、删除快
缺点:查找慢
栈Stack
优点:提供后进先出的存取方式
缺点:存取其它项很慢
堆Heap
优点:插入快、删除快、对最大数据项存取快
缺点:对其它数据项存取慢
队列Queue
优点:提供先进先出的存取方式
缺点:存取其它项很慢
树Tree
二叉树
优点:如果树是平衡的,则查找、插入、删除都快
缺点:删除算法复杂
红黑树
优点:查找、插入、删除都快,树总是平衡的算法复杂。
缺点:算法复杂
2-3-4树
优点:查找、插入、删除都快,树总是平衡的,类似的树对磁盘存储有效。
缺点:算法复杂
哈希表Hash
优点:如果关键字已知则存取极快
缺点:删除慢,如果关键字未知则存取慢,对存储空间使用不充分
图Graph
优点:对现实世界建模
缺点:有些算法慢且复杂
算法
排序
查找
贪心
分治
动态规划
回溯
工具
Linux
常用命令
Shell脚本
构建
Maven
Gradle
代码管理
SVN
git
集成开发
Intellij IDEA
VSCode
Eclipse
开源项目
gitee
github
大数据
ODPS离线分析
Hive
Spark
Hadoop
Hbase
HDFS
大数据体系
粉丝福利
月薪3万简历模板
1000+Java精华电子书
0 条评论
下一页