Java技术栈以及面试知识点
2021-12-14 01:18:24 2 举报
Java工程师技术点总结以及粗略知识脉络,本人经历逐步更新
作者其他创作
大纲/内容
Java 基础
面向对象和面向过程
面向过程
节省资源、常用语单片机、嵌入式开发
面向对象
方便维护、复用、扩展
抽象类和普通类
抽象类不能被实例化,可以有构造方法
方法访问权限修饰符
private 私有成员属性和方法,只能类自身可以调用,内部类除外
默认 本类和同一包下的类
protected 自身+同包+不同包的子类
public 自身+同包+不同包
内部类
种类
成员内部类
成员内部类可以无条件访问外部类所有的成员属性和方法,包括private
外部类如果访问内部类成员,必须先创建一个内部类对象才能进行访问
成员内部类不允许用static修饰
静态内部类
关键字static中提到Static可以修饰成员变量、方法、代码块,其他它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。
创建不依赖外部、静态内部类不能引用外部非静态成员活方法
匿名内部类
必须集成一个抽象类或者实现接口
没有类名、没有构造方法
深入理解
CompareTo
对象之间比较大小
例如obj1.compareTo(obj2),
如果该方法返回0,则表示两个对象相等,
如果该方法返回一个正整数,则表明obj1大于obj2;
如果该方法返回一个负整数,则表明obj1小于obj2。
例如obj1.compareTo(obj2),
如果该方法返回0,则表示两个对象相等,
如果该方法返回一个正整数,则表明obj1大于obj2;
如果该方法返回一个负整数,则表明obj1小于obj2。
默认对比方式、也可以重写
BigDecimal类、BigInteger以及所有的数值型对应的包装类:按他们对应的数值大小进行比较
Character:按照字符的UNICODE值进行比较
Boolean:true对应的包装类实例大于false对应的包装类实例
String:按照字符的UNICODE值进行比较
Date\Time:后面的时间、日期比前面的时间、日期大
BigDecimal类、BigInteger以及所有的数值型对应的包装类:按他们对应的数值大小进行比较
Character:按照字符的UNICODE值进行比较
Boolean:true对应的包装类实例大于false对应的包装类实例
String:按照字符的UNICODE值进行比较
Date\Time:后面的时间、日期比前面的时间、日期大
字符串
内存泄漏
异常
JDK1.8+新特性
日志
注解
反射
Redis
基础常识
磁盘、内存、IObuffer
数据库DataPage 4K
中文官网
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
memcached 对比
安装
线程模型
Reactor线程模型
1:BIO 线程之间是相互阻塞的运行模式 称为阻塞IO
2:同步非阻塞 NIO, 基于轮询的处理模式,在用户空间内对链接进行轮询处理,请求多了以后还是会有调度成本耗费高的问题
3:多路复用 NIO 基于select事件监听,只对有请求得到客户进行响应,但是多个线程之间的调用从用户态到内核态互相切换还是有消耗
4:mmap NIO epoll的文件描述符,有共享内存区域维护一个红黑树进行数据传输,极大的减轻了系统的调用
Redis基于NIO网络模型 epoll的系统调度 可以快速响应 、 kafka也是类似原理
默认16个DB
Redis-cli 连接 ./redis-cli -p 10001 -a
查看帮助 ./redis-cli -h
数据类型
String
字符
set
get
append
setrange
getrange
strlen
数值
incr
incrby
bitMap
setbit
bitcount
bitpos
bitop
场景
1:用户系统统计登录天数,且窗口随机
list
栈 同向命令
lpush
lpop
队列 反向命令
lpush
rpop
数组
lindex
阻塞队列 单播队列
blpop 阻塞取,没取到阻塞
循环取出
lrange key left right
hash map(k-v) 命令H开头
set
无序、随机存放、不重复
随机事件
sorted sets
发布订阅
订阅一个topic
SUBSCRIBE first topic1
客户端向领一个topic发布消息
事务
multi
开始
exec
执行
descard
放弃
watch
监听 标记所有指定的key 被监视起来,在事务中有条件的执行(乐观锁)
布隆过滤器
概率解决问题,将缓存中的数据向BitMap中标记 ,可能请求的被错标 , 可以很大程度的去 减少缓存穿透,而且成本极低
如果穿透了,数据不存在,client 增加Redis中key为null , 不用走布隆过滤了 , 增加元素需要完成对布隆过滤器的添加(双写一致)
Redis 作为 数据库/缓存的区别
KEY 有效期
主动设置过期时间
set key value ex
设置过期时间 EXPIRE
倒计时监听
过期判断原理
1:被动访问判定
2:周期轮询判定
冷热数据
最大内存配置
maxmemory
回收策略
noeviction
返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
LFU
碰了多少次
LRU
多久没碰他
存储层
快照 RDB
时点性
save
Linux中 子进程的修改不会破坏父进程,父进程的修改也不会破坏子进程
redis 在时间点 fork 出一个进程 进行RDB备份存储 , 主进程依旧对外服务
bgsave
fork创建子进程
配置文件中可以去配置保存时间,默认是5分钟
save 900 1
save 300 10
save 60 3600
save 300 10
save 60 3600
弊端
不支持Linux日期拉链,永远只有一个dump.rdb , 备份比较难
落盘时候宕机了会造成数据丢失
优点:AOF文件格式类似Java序列化,恢复速度快
Linux 管道
衔接、前一个命令的输出作为后一个命令的输入
管道会出发创建子进程
echo $$ | more
echo $BASHPID | more
父子进程
父进程设置的变量、子进程对外修改,父进程并不会感知
日志 AOF
redis的操作记录会写到文件中
RDB 和 AOF 会同时开启,恢复只会用AOF恢复,速度快,完整性好一点
弊端
体量无线变大、恢复慢
优化:RDB 落盘以后 AOF追加操作
AOF配置
AOF文件过大会进行重写、重新落盘
集群
单节点问题 AKF拆分可解决
单点故障
容量有线
存储压力 、 网络压力
多节点
一致性问题
同步阻塞、强一致性、破坏可用性
异步 弱一致性,暂时丢失数据、最终一致性
主从复制
1:BGSave 2:同步
replica-save-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-backlog-size 1mb
增量复制
min-replicas-to-write 3
min-replicas-max-log 10
HA
哨兵 sentinel
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:
监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
哨兵会修改自己的配置文件, 可以根据主节点变化修改自身配置文件
redis 发布订阅
管连接点进行通信
可以订阅topic , 查看所有通信内容
shard分片
业务逻辑拆分
hash
hash取摸是固定的,产生数据倾斜,难以新增机器
random
随机
消息队列
一致性hash算法
key和设备都需要参与hash计算
产生一个hash环
优缺点
优点:加节点的确可以分担其他节点的压力、不会造成全局洗牌、节点进行LRU\LFU 淘汰算法
缺点:新增节点会造成部门节点数据失效,无法命中; 击穿、请求到mysql 双写一致性 , 可以每次取离我最近的连个物理节点
缓存常见问题
击穿
一个key过期后,瞬时太多的请求打进来,瞬间访问数据库
这里就要用分布式锁, setnx 只允许一个线程去取这个数据,其余进程进行等待
穿透
业务数据查询不到、穿过redis
解决:布隆过滤器
client 包含数据
算法 bitmap -> redis
redis 集成布隆
雪崩
大量key同时失效、见解造成访问到达数据库
业务上 均匀分布过期时间
业务不允许
击穿方案
业务层面加时间判断,零点延迟
一致性(双写)
分布式锁
API
子主题
SQL调优
性能监控
schema与数据类型优化
ACID
A 原子性
C 一致性
I 隔离性
D 持久性
范式和反范式
范式
反范式
其他注意点
多加一些冗余,减少JOIN选择。以空间换时间的思想进行设计
主键选择
代理主键(推荐)
与业务无关、无意义的数字序列
自然主键
事务属性中的自然唯一标识
数据库字符集
存储引擎
InnoDB
聚簇索引、支持事务、表锁、行锁、全文索引
MyISAM
非聚簇索引、不支持事务、不支持表锁、不支持行锁、使用大量select
MEMORY
数据存储在内存中
InnoDB 与 MyISAM 对比
适当拆分
执行计划
explain select * from users
ID 越大 越先执行
id号分为三种情况:
1、如果id相同,那么执行顺序从上到下
2、如果id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
3、id相同和不同的,同时存在:相同的可以认为是一组,从上往下顺序执行,在所有组中,id值越大,优先级越高,越先执行
1、如果id相同,那么执行顺序从上到下
2、如果id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
3、id相同和不同的,同时存在:相同的可以认为是一组,从上往下顺序执行,在所有组中,id值越大,优先级越高,越先执行
select_type 查询类型
主要用来分辨查询的类型,是普通查询还是联合查询还是子查询
sample:简单的查询,不包含子查询和union
primary:查询中若包含任何复杂的子查询,最外层查询则被标记为Primary
union:若第二个select出现在union之后,则被标记为union
dependent union:跟union类似,此处的depentent表示union或union all联合而成的结果会受外部表影响
union result:从union表获取结果的select
subquery:在select或者where列表中包含子查询
dependent subquery:subquery的子查询要受到外部表查询的影响
DERIVED: from子句中出现的子查询,也叫做派生类,
UNCACHEABLE SUBQUERY:表示使用子查询的结果不能被缓存
uncacheable union:表示union的查询结果不能被缓存:sql语句未验证
sample:简单的查询,不包含子查询和union
primary:查询中若包含任何复杂的子查询,最外层查询则被标记为Primary
union:若第二个select出现在union之后,则被标记为union
dependent union:跟union类似,此处的depentent表示union或union all联合而成的结果会受外部表影响
union result:从union表获取结果的select
subquery:在select或者where列表中包含子查询
dependent subquery:subquery的子查询要受到外部表查询的影响
DERIVED: from子句中出现的子查询,也叫做派生类,
UNCACHEABLE SUBQUERY:表示使用子查询的结果不能被缓存
uncacheable union:表示union的查询结果不能被缓存:sql语句未验证
type 访问方式
type显示的是访问类型,访问类型表示我是以何种方式去访问我们的数据,最容易想的是全表扫描,直接暴力的遍历一张表去寻找需要的数据,效率非常低下,访问的类型有很多,效率从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
possible_key 显示可能用到那些索引
key 实际用到索引
rows 预估行数
extra 额外信息 例如排序类型 、覆盖索引
索引优化
索引基础知识
索引结构
哈希表
B+树
了解常用数据结构 哈希表、二叉树、红黑树、B树、B+树
优点
减少服务器数据检索时间 , 索引列已经排好顺序
随机IO变为顺序IO
用途
快速匹配where子句
MySQL会排除多余数据扫描,总会命中行数最少的索引
分类
主键
唯一
普通
全文
组合
技术名词
回表
覆盖索引
最左匹配
索引下推
索引匹配方式
全值匹配
匹配最左前缀
匹配列前缀
匹配范围
精确匹配某一列并范围匹配另一列
只访问索引查询
hash索引
memory 存储引擎
基于哈希表实现,只有精确匹配才能被查找
只存储hash值,数据紧凑,索引非常快
限制
只包含hash值,不进行字段存储,不是顺序存储,无法进行排序
不支持部分列存储
考虑哈希冲突情况,冲突比较多会造成数据列维护不方便,代价也很高
使用案例
当需要存储大量的URL,并且根据URL进行搜索查找,如果使用B+树,存储的内容就会很大
select id from url where url=""
也可以利用将url使用CRC32做哈希,可以使用以下查询方式:
select id fom url where url="" and url_crc=CRC32("")
此查询性能较高原因是使用体积很小的索引来完成查找
select id from url where url=""
也可以利用将url使用CRC32做哈希,可以使用以下查询方式:
select id fom url where url="" and url_crc=CRC32("")
此查询性能较高原因是使用体积很小的索引来完成查找
组合索引
包含多个列作为索引,需要注意的是正确的顺序依赖改索引的查询,同事满足最左匹配原则
案例,建立索引 a,b,c
a = 3
a
a=3 and b=5
a 、 b
a=3 and b=4 and c=5
a,b,c
b=3 or c=4
没使用索引
a = 3 and c=4
a
a = 3 and b>10 and c = 7
a,b
a = 3 and b like '%1%' and c = 7
a
聚簇索引与非聚簇索引
聚簇索引
优点
可以把相关数据保存在一起
数据访问更快,不需要另外查找
覆盖索引扫描可以直接到叶节点
缺点
聚簇数据极大的现在了数据IO的扩展性
插入速度验证依赖插入书序,按照主键插入顺序最快
更新聚簇索引列代价很高,会强制将每个更新的行移动到新的位置
新插入行如果超过索引页大小,会导致页分裂的问题
全表扫描变慢
非聚簇索引
覆盖索引
介绍
如果一个索引包含所有需要查询的字段的值,称之为覆盖索引
不是所有类型的索引都成为覆盖索引,覆盖索引必须要存储索引列的值
不同存储引擎实现索引的方式不同,不是所有引擎都支持覆盖索引,memory不支持
优势
索引条目通常小于数据行大小,如果只需要读取索引,会极大的减少数据访问
索引按照顺序存储的,对IO密集型范围查找会比随机查找快很多
IO密集型
InnoDB是聚簇索引,覆盖索引效率特别高
案例
优化细节
索引列进行扫描时,尽量不要用表达式,将计算放到业务层而不是数据层
尽量使用主键索引,避免发生回表
使用前缀索引
使用索引扫描进行排序
union all , in , or 都能够使用索引,推荐使用in
范围列可以用到索引 但是只能用一列索引
强制转换可能会导致全表扫描
更新十分频繁的操作不宜建立索引
索引列不能为空
表进行连接时候,最好不要超过三张表,因为join需要的字段数据类型必须一致
能使用limit时候尽量使用limit limit 限制输出
单表索引建议控制在5个以内
组合索引字段不应该超过5个
索引监控
索引优化简单案例
查询优化
查询慢的原因
网络
CPU
IO
上下文切换
系统调用
生成统计信息
锁等待时间
1:分析存储引擎
2:读锁、写锁
优化数据访问
大数据量
加载多余数据
执行过程的优化
查询缓存
MySQL 优化机制
重新定义关联查询顺序
外连接转内连接
等价变换规则、简化SQL
优化 count min max
带条件 , 索引分组
索引覆盖扫描
子查询进行优化、进行缓存
等值传播
两个列的值关联,MySQL可以进行参数传播
排序优化
算法优化
两次传输排序
第一次数据读取是将需要排序的字段读取出来,然后进行排序,第二次是将排好序的结果按照需要去读取数据行。
这种方式效率比较低,原因是第二次读取数据的时候因为已经排好序,需要去读取所有记录而此时更多的是随机IO,读取数据成本会比较高
两次传输的优势,在排序的时候存储尽可能少的数据,让排序缓冲区可以尽可能多的容纳行数来进行排序操作
这种方式效率比较低,原因是第二次读取数据的时候因为已经排好序,需要去读取所有记录而此时更多的是随机IO,读取数据成本会比较高
两次传输的优势,在排序的时候存储尽可能少的数据,让排序缓冲区可以尽可能多的容纳行数来进行排序操作
一次传输排序
先读取查询所需要的所有列,然后再根据给定列进行排序,最后直接返回排序结果,此方式只需要一次顺序IO读取所有的数据,而无须任何的随机IO,问题在于查询的列特别多的时候,会占用大量的存储空间,无法存储大量的数据
当需要排序的列的总大小超过max_length_for_sort_data定义的字节,mysql会选择双次排序,反之使用单次排序,当然,用户可以设置此参数的值来选择排序的方式
分区表
服务器参数设置
MySQL集群
面试
隔离级别
读未提交
读已提交
可重复读
串行化
多线程高并发
基本概念
进程
操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位。
线程
线程,有时被称为轻量级进程(Lightweight Process,LWP),是操作系统调度(CPU调度)执行的最小单位。
协程
协程,是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。
开启一个线程
Thread
Runnable 接口
Callable
线程池
Future 接口
Thread Status 线程状态(JVM管理)
NEW
新建
Runnable 运行
Ready
准备
Runnable
执行
wait
等待
wait
join
park
Block
阻塞
synchronized
Teminated
结束
基本方法
sleep
睡眠
Yield
线程谦让一下,暂时离开一会 , 进入等待队列中
join
调度其他线程的join方法相当于其他线程,当前线程等待
wait
等待、需要用nitify方法唤醒
synchronized
锁升级
无锁
偏向锁
记录线程ID 高效率
自旋锁
多线程调用后,一直在等待资源释放
重量级锁
插入阻塞队列,释放资源 成为等待状态
可重入
可重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的。synchronized 和 ReentrantLock 都是可重入锁。
锁粒度越小约好
Volatile
保证多线程可见
主线程和自身线程 副本进行同步、MESI CPU的缓存一致性协议
禁止指令重排序
单例模式双重检测Double Check Lock
new Object()
1:申请内存
2:设置初始值
3:进行赋值
CAS 无锁优化 资源 乐观锁
三个值
期望值 期望是0
更新值 更新为1
m=0; m++ ; cas(0,1)
Compare And Set
CPU原语支持
Atomic***
底层都是unsafe 相当于C 、c++ malloc free new delete
单例 静态unsafe 直接对内存地址进行操作 native 修饰的方法
unsafe类可以读写一个类的属性,即便是私有的也可以读写
Volatile 读写
有序性读写
CAS
线程调度
内存屏障
ABA 问题
1 2 1 操作后加版本号记录
案例:1000线程分别对 atomicInt synchronized LongAdder 相加 10000次
结果: longAdder > atomic > Syonchorized
longAdder 分段锁
Atomic CPU 原子操作
synchronized CPU申请锁
ReentrantLock
可重入锁
synchronized 功能类似 但是必须手动释放锁 在final 里面
tryLock
尝试申请锁
wait
等待
lock Interruptibly
打断加锁
true 为公平锁、 默认为非公平锁
new ReentrantLock(true);
CountDownLatch
计数器 线程阻塞
countDown
减一操作
await
等待、阻塞
等待所有线程结束才进行下一步
CyclicBarrier
满人发车、装载完成后开始执行
复杂操作、访问数据库、网络、文件 顺序执行 效率很低 并发执行但是可以
限流 -- 令牌桶 Guava RateLimiter
ReadWriteLock
共享锁、排他锁
static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
static Lock readLock = readWriteLock.readLock();
static Lock writeLock = readWriteLock.writeLock();
static Lock readLock = readWriteLock.readLock();
static Lock writeLock = readWriteLock.writeLock();
Semaphore
信号量、允许同时执行的线程数
s.acquire();
取的信号、没取到会进行阻塞
s.release();
释放信号
LockSupport
LockSupport.park();
LockSupport.unpark(t);
AQS 读源码
CAS+ volatile
面试问题
死锁
产生原因
互斥条件、同一时间只能一个线程去获取资源
不可剥夺条件、一个资源被占有,不可被其他线程剥夺
请求和保持条件、等待过程不会释放占有资源
循环条件等待、多个线程互相等待
解决方案
加锁
CAS
AQS
多线程几种创建方式
实现Runnable 实现run方法 无返回值 无法抛出异常
集成Thread类 执行start方法开始
实现Callable call() 方法带返回值
线程池创建线程
Future 接口
线程安全活跃状态
状态
死锁
同一个线程资源竞争
活锁
不会阻塞线程,线程会一直重复执行某个相同操作,但是一直失败
饥饿
读写锁(读的时候一直等待,产生饥饿)
竞态条件
加锁,保证你的操作都是原子性操作
wait 和 sleep
进程和线程的区别
线程生命周期
阻塞
IO
WAIT
分布式算法
前提概要
一致性
数据节点保持一致,多节点数据值是一致的
弱一致性、保证最终一致性
主从异步复制
主从半同步复制
多数派写
强一致性、数据时刻保持一致
主从同步复制
Paxos算法
解决方案
角色
Proposer
向集群发出议案,设置自己为leader 提议内容格式编号n内容value)
Acceptor
对议案进行投票,达到多数派提议认可时提议才会被接受
Learner
对提议记录,对一致性没有任何影响
阶段
prepare阶段
1:prepare(N)请求
2:promise(N-Value)返回
accept阶段
1:accept(N-value)请求
2:accepted 返回
图解
先进行选举,产生最新leader,后续选举互动返回Leader
多个节点进行选举,未产生leader时,选则最大的N,直到过半accepted返回成功,在进行Leader 同步
优化缺点
活锁
一次选举被拒绝会产生更大的N,如果两个Proposer发现自己的N小会进行更高N的选举,这样就会导致死循环,产生活锁
解决方案
二进制指数退避算法
设置最大请求次数,超过请求次数便不再请求,请求时间依次递减直至不请求
效率低
每次选举请求经过两轮请求返回
实现困难
视频详解
前提条件
集群所有消息均可靠,内部通信没有叛徒
CAP原则
CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。
计算 TP90、TP95 和 TP99 等水位线的方法
统计请求的延迟+请求次数,按照延迟时间进行升序排序,第99%位为最低满足延迟
银行家算法
分布式事务
基本概念
本地事务
2pc
3pc
SEATA
基础概念
TC 事务协调者
TM 事务管理者、发起者
RM 资源管理者、每个参与事务的微服务
AT 模式
一阶段
1:请求
2:RM1
执行业务数据
回滚日志记录
日志记录操作前、操作后数据记录
提交本地事务
释放资源
3:RM2
RM1 操作相同 共同提交给TC
二阶段
正常:TC 进行确认操作、提交 删除日志记录
异常: 回滚
依赖日常记录进行回滚、不会滚日志不删除
锁
本地锁+全局锁
1:获取本地锁
2:执行sql
3:获取全局锁
4:提交本地事务
5:释放本地锁
1:获取本地锁
2:执行sql
3:获取全局锁
4:提交本地事务
5:释放本地锁
TCC 模式
Try
confirm
cancel
TX
kafka
优点简介
Kafka是一个分布式的基于发布、订阅的消息系统,有着强大的消息处理能力,相比与其他消息系统,具有以下特性:
快速数据持久化,实现了O(1)时间复杂度的数据持久化能力。
高吞吐,能在普通的服务器上达到10W每秒的吞吐速率。
高可靠,消息持久化以及副本系统的机制保证了消息的可靠性,消息可以多次消费。
高扩展,与其他分布式系统一样,所有组件均支持分布式、自动实现负载均衡,可以快速便捷的扩容系统。
离线与实时处理能力并存,提供了在线与离线的消息处理能力
快速数据持久化,实现了O(1)时间复杂度的数据持久化能力。
高吞吐,能在普通的服务器上达到10W每秒的吞吐速率。
高可靠,消息持久化以及副本系统的机制保证了消息的可靠性,消息可以多次消费。
高扩展,与其他分布式系统一样,所有组件均支持分布式、自动实现负载均衡,可以快速便捷的扩容系统。
离线与实时处理能力并存,提供了在线与离线的消息处理能力
基础概念
组件
kafka 分布式消息系统,将消息直接存入磁盘,默认保存一周
broker kafka节点、没有主从挂你,依赖ZK进行协调。broker负责消息读写存储,一个broker可以管理多个partition
topic 一类消息总称,一个消息队列,topic是有partition组成的,指定创建partition数量
partition 组成topic的单元,每个partition有副本,由broker来进行管理
Producer 消息的生产者,自己决定向哪一个partatition中取生产消息,两种机制:hash、轮询
consumer 消息消费者,consumer 通过Zookeeper去维护消费者偏移量,consumer有自己的消费组,不同的组之间消费同一个topic的数据互不干扰,同一个组内的topic消费只产生一次
依赖 ZK 进行分布式协调 , 环境搭建完成后会通过zc 来进行broker管理
主体与日志
Topic
每个Topic分为多个partition,每个分区存储不同的消息,消息进入partation时候回从0开始维护一个offset,并保证分区上唯一,消息在分区上的顺序由offset保证,消息在一个分区内是有序的
log
分区在逻辑上对应一个日志(Log),物理上对应的是一个文件夹。到kafka log文件夹去看,效果如下
消息写入分区时会进行分片,默认没片大小为1G ,实际存储为三个文件 .index .timeindex .log
日志索引
副本文件
ISR集合 -- 连通性&活跃性 的节点
副本所在节点需要与ZooKeeper维持心跳。
从副本的最后一条消息的offset需要与主副本的最后一条消息offset差值不超过设定阈值(replica.lag.max.messages)或者副本的LEO落后于主副本的LEO时长不大于设定阈值(replica.lag.time.max.ms),官方推荐使用后者判断,并在新版本kafka0.10.0移除了replica.lag.max.messages参数
从副本的最后一条消息的offset需要与主副本的最后一条消息offset差值不超过设定阈值(replica.lag.max.messages)或者副本的LEO落后于主副本的LEO时长不大于设定阈值(replica.lag.time.max.ms),官方推荐使用后者判断,并在新版本kafka0.10.0移除了replica.lag.max.messages参数
高水位 High Watermark
LEO(Log End Offset)
生产者
ACK
1:默认为1,表示在ISR中的leader副本成功接收到数据并确认后再发送下一条消息,如果主节点宕机则可能出现数据丢失场景,详细分析可参考前面提到的副本章节。
0:表示生产端不需要等待节点的确认就可以继续发送下一批数据,这种情况下数据传输效率最高,但是数据的可靠性最低。
-1:表示生产端需要等待ISR中的所有副本节点都收到数据之后才算消息写入成功,可靠性最高,但是性能最低,如果服务端的min.insync.replicas值设置为1,那么在这种情况下允许ISR集合只有一个副本,因此也会存在数据丢失的情况。
幂等
唯一标识:判断某个请求是否重复,需要有一个唯一性标识,然后服务端就能根据这个唯一标识来判断是否为重复请求。
记录已经处理过的请求:服务端需要记录已经处理过的请求,然后根据唯一标识来判断是否是重复请求,如果已经处理过,则直接拒绝或者不做任何操作返回成功。
消费者
消费组
消费组订阅主题下的每个分区只会分配给消费组中的一个消费者。
group.id标识消费组,相同则属于同一消费组。
不同消费组之间相互隔离互不影响。
group.id标识消费组,相同则属于同一消费组。
不同消费组之间相互隔离互不影响。
偏移量 offset
自动提交
手动提交
基于一条记录
基于partition (推荐,因为kafka的offset是基于partition维护的)
基于一次拉取数据
Zookeeper
基础概念
数据保存在内存中
集群 主从复制、分片处理
增、删、改 只能在主节点、查询能在其他节点
增、删、改 只能在主节点、查询能在其他节点
Leader 挂掉、可快速选举、快速修复
数据模型、目录树
节点存数据很少 1M
并且是数据二进制安全的
客户端链接维护了一个session
通过session可以判断持续时间
通过session可以判断持续时间
顺序一致性、客户端链接是顺序的
原子性操作
最终一致性
基本命令
create /xxoo “”
后面数据只能1M 大小 并且是二进制安全的 不会乱码
-S
-E 临时节点
ls /
ls -s
cZxid 创建事务ID
ctime 创建时间
mzxid 修改事务ID
mtime 修改时间
pzxid 子节点最后修改的事务id
cversion 子节点版本号
dataVersion 数据版本号
aclVersion 权限版本号
ephemeralOwner 创建临时节点的回话sessionID
dataLength 节点数据长度
Children
子节点数量
角色
Leader
主节点,不参与计算,发号命令
Follow
选举
Observer
增加查询能力
zoo.cfg
多节点配置
特征
扩展性
可靠性
快速恢复:攘外必先安内
对外: 一致性、可靠性
内部 Paxos 协议选举
Paxos算法
解决方案
角色
Proposer
向集群发出议案,设置自己为leader 提议内容格式编号n内容value)
Acceptor
对议案进行投票,达到多数派提议认可时提议才会被接受
Learner
对提议记录,对一致性没有任何影响
阶段
prepare阶段
1:prepare(N)请求
2:promise(N-Value)返回
accept阶段
1:accept(N-value)请求
2:accepted 返回
图解
先进行选举,产生最新leader,后续选举互动返回Leader
多个节点进行选举,未产生leader时,选则最大的N,直到过半accepted返回成功,在进行Leader 同步
优化缺点
活锁
一次选举被拒绝会产生更大的N,如果两个Proposer发现自己的N小会进行更高N的选举,这样就会导致死循环,产生活锁
解决方案
二进制指数退避算法
设置最大请求次数,超过请求次数便不再请求,请求时间依次递减直至不请求
效率低
每次选举请求经过两轮请求返回
实现困难
视频详解
前提条件
集群所有消息均可靠,内部通信没有叛徒
zab
Paxos 协议精简版-- 原子广播协议
1:客户端创建节点
2:Follow 转 Leader
3:Leader 创建zxid -- 内存中维护数据,并且维护发送队列
4:Leader 写入Follow 日志中,磁盘写日志
5:Follow 回复写成功
6:过半Follow 回复OK 触发自身写操作 -- Follow 也写内存
2:Follow 转 Leader
3:Leader 创建zxid -- 内存中维护数据,并且维护发送队列
4:Leader 写入Follow 日志中,磁盘写日志
5:Follow 回复写成功
6:过半Follow 回复OK 触发自身写操作 -- Follow 也写内存
watch
事件监听\观察
事件:
Create\delete\change\children
Create\delete\change\children
监听后执行callback
两类:
new zk 时候创建的时间,和session、path 没关系
API
callback
JVM
内存模型
内存模型 简述概况
类装载子系统
加载
BootStrap类加载器
加载JAVA_HOME/jre//lib/rt.jar 里面的子类
Extension类加载器
加载JAVA_HOME/jre/*.jar
Application类加载器
加载classpath中指定jar包以及目录中class
Custom自定义类加载器
用户开发者自定义、如Tomcat、JBoss 会根据J2EE规范自行实现classloader
链接
验证
字节码校验器会检查生成的字节码是否正确
准备
对静态变量分配内存以及默认值分配
识别
解析或识别是从运行时常量池的符号,引用中动态具体值的过程
初始化
类或接口的初始化,由执行类或接口初始化方法构成。这里所有的静态变量与原来的值将被指派,静态块被执行
运行时内存
方法区 Method Area 持久代
存储已被虚拟机加载的类、常量、静态变量、编译后的代码等数据
JVM8已经用MetaSpace完全代替方法区
Heap 堆
存放内存实例的区域、几乎所有的对象实例都分配在内存。存储的数据不是线程安全的,堆和常量池空间不足会引发outofMemory
线程区
VM虚拟机栈
每一个线程创建一个单独的运行时堆栈,对于每一个方法调用创建一个称为栈内存栈帧,所有局部变量被创建在栈内存中
本地方法区 Native Method Stack
与虚拟机类似,但是相关联的是计算机本地方法,Native方法
程序计数器
程序具体执行的计算机指令,当前指令执行完毕后,会更新下一个指令
Java执行引擎
解释器
即时编译器 JIT
中间代码生成器
代码优化器
目标代码生成器
探测分析器
GC
收集和删除未引用的对象。可以通过System.gc 触发垃圾回收,但不能保证执行。JVN垃圾回收对象是已创建的对象
本地方法接口 JNI
与本机方法库进行交互,并提供引擎所需要的机器类库
本地方法接库
计算机提供的方法库
类加载过程和初始化过程
加载
加载
.class 通过二进制字节流读入JVM中
1:通过classloader 在classpath中读取 class文件,然后存入内存
2:将字节流锁代表的静态存储结构转到方法区的运行时数据结构
3:内存生成该类的 java.lang.class 对象,作为方法区这个类的各种数据的访问入口
2:将字节流锁代表的静态存储结构转到方法区的运行时数据结构
3:内存生成该类的 java.lang.class 对象,作为方法区这个类的各种数据的访问入口
链接
验证
确保文件格式、元数据格式、字节码格式、符号引用格式正确
准备
静态文件在方法区分配内存,设置默认值
解析
虚拟机将常量池内的符号引用替换为直接引用
初始化
类加载过程最后一步,主要根据程序中的赋值语句主动为类变量赋值,如果有集成关系,先初始化父类,再子类
堆内存划分
运行时数据区
虚拟机栈(线程私有)
栈帧
一个栈帧包括局部变量表、操作数栈、动态链接、返回地址
局部变量表
一组变量值存储空间、用于存放方法参数和方法内部定义的局部变量
8中数据类型、对象引用类型、引用地址
变量槽 -- 基本数据类型
对象实例引用
动态链接
操作数栈
当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈/入栈操作。例如,在做算术运算的时候是通过操作数栈来进行的,又或者在调用其他方法的时候是通过操作数栈来进行参数传递的。举个例子,整数加法的字节码指令iadd在运行的时候操作数栈中最接近栈顶的两个元素已经存入了两个int型的数值,当执行这个指令时,会将这两个int值出栈并相加,然后将相加的结果入栈。
返回地址
本地方法栈(线程私有)
与虚拟机栈发挥作用相似,不过是为虚拟机创建资源的,内部调用C++方法活用native修饰的方法
程序计数器(线程私有)
一个较小的区域进行程序指令登记,程序执行字节码的行号指示器
永久代(公共区域)
存储虚拟机加载的类信息、常量、静态变量、编译后的代码。1.8以后已经用Metaspace完全替代了永久区,并且不在JVM中存储而存储到本地内存
Heap堆 (公共区域)
虚拟机启动时创建,用来存放对象实例,所有对象实例都在此分配内存,存储数据不是线程安全的,堆和常量池空间不足容易引起oom
执行引擎
解释器
即时编译器
GC
GC 垃圾回收(Java堆)
YGC 新生代堆
FGC 全堆
垃圾回收算法
面对生产频繁GC处理方式
定位工具
jmap
1, 查看堆内存各区域的使用率以及GC情况
jstat -gcutil -h20 pid 1000
2,查看堆内存中的存活对象,并按空间排序
jmap -histo pid | head -n20
3, dump堆内存文件
jmap -dump:format=b,file=heap pid
jstat -gcutil -h20 pid 1000
2,查看堆内存中的存活对象,并按空间排序
jmap -histo pid | head -n20
3, dump堆内存文件
jmap -dump:format=b,file=heap pid
jstat
分布式锁
可以参考ZK\Redis
计算机网络
网络请求基础
OSI 七层网络模型
物理层
数据链路层
网络层
传输层
会话层
表示层
应用层
用户空间
应用层
表示层
会话层
内核空间
传输控制层
网络层
链路层
物理层
IO 模型
socket : 请求队列 queue
IO 就是程序对socket-queue的包装
IO 就是程序对socket-queue的包装
状态
监听队列 -- Listion
accept 队列 -- 等待程序队列的链接
配置backLog 大小限制,不会被程序取走 (代码可以设置)
配置backLog 大小限制,不会被程序取走 (代码可以设置)
backLog 设置可以快速拒绝
服务快速响应
服务快速响应
得到客户端建立的链接
连通队列 -- eatablishd
消息传输在计算机内核中
程序员无感知
程序员无感知
accept 得到的
client 得到的
client 得到的
IO 模型
BIO
Server.accept() 进行阻塞 等待返回
NIO
Server.accept() 立刻返回 0 , 1
多路复用
select
循环IO驱动方式
poll
循环
epoll
时间驱动
和内核调用后才可以知道是否有时间,然后再进行队列
机制: 多路复用 、 阻塞、 非阻塞
都是计算机内核提供的机制
都是计算机内核提供的机制
内核增强了
select poll
epoll
select poll
epoll
端口监听
nc
面试突击
HTTP HTTPS
HTTP + SSL = https
CA 证书 非对称加密
CA 证书就是 公钥和私钥、机构颁发一个证书,公钥(用户的信息)和私钥
用户请求 证书的公钥, 私钥在服务器,进行非对称加密
用户请求 证书的公钥, 私钥在服务器,进行非对称加密
对称加密 是双方秘钥生成的
https 握手方式
客户请求---> 返回证书公钥
客户端浏览器 校验证书是否有效
客户端将加密后的秘钥发送给服务端
用私钥加密的信息发给客户端 进行双向认证
加密方式
对称加密
公钥 == 私钥 双方用一个秘钥进行加解密
非对称加密
加密和解密用不同秘钥
公钥加密的信息,只有私钥才能解开
私钥加密的信息,只要公钥才能解开
公钥加密的信息,只有私钥才能解开
私钥加密的信息,只要公钥才能解开
Connection Refused
1:服务没启动
2:Socket 队列满了
三次握手
1:client 发送 sync
状态: syn Send
2:Server 发送 synv -ack
状态: syn - receiver
3: client ACK
状态为连接状态
三次握手是内核层次的过程
握手成功进入 连通队列
如果队列满了 就会Connection Refuse
握手成功进入 连通队列
如果队列满了 就会Connection Refuse
四次分手
1:客户端 断开
client 状态就是 fin-wait1
2:服务端 断开 - ack
服务器状态是 close - wait
3:服务器 断开
服务器状态
4:客户端 断开 ack
DDOS 攻击
半链接过多
netstatus
Proto
协议
REcv
接受
send
发送
LocalAddress
本地端口
Foreign Address
链接端口
status
LISTEN :首先服务端需要打开一个socket进行监听,状态为LISTEN.
SYN_SENT:客户端通过应用程序调用connect进行activeopen.于是客户端tcp发送一个SYN以请求建立一个连接.之后状态SYN_SENT。
SYN_RECV:服务端应发出ACK确认客户端的 SYN,同时自己向客户端发送一个SYN.之后状态置为SYN_RECV
ESTABLISHED:代表一个打开的连接,双方可以进行或已经在数据交互了。
FIN_WAIT1:主动关闭(activeclose)端应用程序调用close,于是其TCP发出FIN请求主动关闭连接,之后进入FIN_WAIT1状态.
CLOSE_WAIT:被动关闭(passiveclose)端TCP接到FIN后,就发出ACK以回应FIN请求(它的接收也作为文件结束符传递给上层应用程序),并进入CLOSE_WAIT
FIN_WAIT2:主动关闭端接到ACK后,就进入了FIN-WAIT-2.
LAST_ACK:被动关闭端一段时间后,接收到文件结束符的应用程 序将调用CLOSE关闭连接。这导致它的TCP也发送一个 FIN,等待对方的ACK.就进入了LAST-ACK.
TIME_WAIT:在主动关闭端接收到FIN后,TCP 就发送ACK包,并进入TIME-WAIT状态。
CLOSING:比较少见
CLOSED:被动关闭端在接受到ACK包后,就进入了closed的状态。连接结束
UNKNOWN:未知的Socket状态。
SYN_SENT:客户端通过应用程序调用connect进行activeopen.于是客户端tcp发送一个SYN以请求建立一个连接.之后状态SYN_SENT。
SYN_RECV:服务端应发出ACK确认客户端的 SYN,同时自己向客户端发送一个SYN.之后状态置为SYN_RECV
ESTABLISHED:代表一个打开的连接,双方可以进行或已经在数据交互了。
FIN_WAIT1:主动关闭(activeclose)端应用程序调用close,于是其TCP发出FIN请求主动关闭连接,之后进入FIN_WAIT1状态.
CLOSE_WAIT:被动关闭(passiveclose)端TCP接到FIN后,就发出ACK以回应FIN请求(它的接收也作为文件结束符传递给上层应用程序),并进入CLOSE_WAIT
FIN_WAIT2:主动关闭端接到ACK后,就进入了FIN-WAIT-2.
LAST_ACK:被动关闭端一段时间后,接收到文件结束符的应用程 序将调用CLOSE关闭连接。这导致它的TCP也发送一个 FIN,等待对方的ACK.就进入了LAST-ACK.
TIME_WAIT:在主动关闭端接收到FIN后,TCP 就发送ACK包,并进入TIME-WAIT状态。
CLOSING:比较少见
CLOSED:被动关闭端在接受到ACK包后,就进入了closed的状态。连接结束
UNKNOWN:未知的Socket状态。
TCP 是长链接吗?
tcp 只是帮你建立链接 具体的是应用层协议
http 1.0 1.1 没有开启keepalive
一个连接只负责一次请求相应
一个连接只负责一次请求相应
开启了是同步复用链接 多次请求响应
同步阻塞、同步非阻塞
BIO \ NIO 都是同步的
粘包、拆包
程序+内核 协调工作
内核:三次握手
TCP 传输时候 分包的
内核:三次握手
TCP 传输时候 分包的
处理
在包头部添加数据包的长度
固定长度 发送,会自动拆分
数据包设置边界
0 条评论
下一页