今天你Java了吗
2021-02-27 14:39:48 0 举报
AI智能生成
今天你Java了吗
作者其他创作
大纲/内容
痛点进化发展线路
IO发展
阻塞IO
多线程模型
一个线程一个链接
被阻塞
非阻塞IO
for循环多个链接
主动遍历,不知道哪个连接有数据了
一个线程可以处理多个链接
用户态到内核态切换的花费
多路复用
select模型
一个线程处理多个链接
select系统调用能一次读取多个链接
fd集合要用户态到内核态切换的花费
1024个连接
poll模型
一个线程处理多个链接
fd集合要用户态到内核态切换的花费
没有连接数的限制
epoll模型
基于mmap内核和用户态共享
基于事件回调,不用主动遍历
技术架构发展
传统应用
CS
BS
桌面应用
前后端分离
分布式
微服务
服务网格-serviceMesh
serviceless
数据存储发展
单文件
数据库
全量IO
查找慢
sql
nosql
doc
kv
内存数据库
热点缓存
子主题
时代发展
原始时代
蒸气时代
电力时代
计算机时代
科研计算机时代
PC时代
互联网时代
移动互联网
大数据时代
云计算时代
物联网时代
人工智能AI
调用方法发展
webservice
soap
xml
rpc
tcp
dubbo
restful
http
json
微服务
http
操作系统
环境安装
nasm
NASM是一个为可移植性与模块化而设计的一个80x86的汇编器。它支持相当多的目标文件格式,包括Linux和NetBSD/FreeBSD、a.out、ELF、COFF,微软16位的OBJ和Win32。它还可以输出纯二进制文件。它的语法设计得相当的简洁易懂,和Intel语法相似但更简单。它支持Pentium、P6、MMX、3DNow!、SSE和SSE2指令集。
bochs
数据结构
数组
稀疏数组
五子棋棋盘存档读档
队列
数组实现
环形队列
数组实现
丢手绢问题
链表
单向链表
双向链表
环形链表
常用设计模式
单例模式
静态工厂单例模式
饱汉式
饿汉式
DCL
双重锁校验,在多线程下需要
观察者模式
装饰者模式
适配器模式
工厂模式
代理模式
动态代理的2种实现方式及区别
JDK动态代理
只能代理实现了InvocationHandler接口的类
cglib动态代理
通过asm修改类的字节码来完成代理
区别:JDK代理针对的是接口,cglib是类,但是无法代理final修饰的类
多线程高并发
cas
AtomicInteger a = new AtomicInteger();
int b = a.incrementAndGet();
int b = a.incrementAndGet();
unsafe.getAndAddInt
native compareAndSwapInt
Hotspot里的cpp源码Atomic::cmpxchg
汇编指令Lock cmpxchg指令
unsafe 类似c++里的指针,能开辟内存
compare and swap
aba问题
记录数据外,加版本
AtomicStampedReference
自旋锁,一直循环,消耗cpu
对象布局
jol工具包
java object layout
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.13</version>
<scope>provided</scope>
</dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.13</version>
<scope>provided</scope>
</dependency>
对象头 object header
markword
32位jvm是4个字节
64位jvm是8个字节
classpointer
class对象的加载后的内存地址
4个字节
补齐 padding
补齐8的整数倍
对象属性
属于对象内容了,不是对象头
int的属性占4字节
对象类型的存的是引用的地址,占4字节
数组长度
如果不是数组则无该部分
demo
Object对象布局
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
String对象布局
java.lang.String object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) da 02 00 f8 (11011010 00000010 00000000 11111000) (-134216998)
12 4 char[] String.value []
16 4 int String.hash 0
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) da 02 00 f8 (11011010 00000010 00000000 11111000) (-134216998)
12 4 char[] String.value []
16 4 int String.hash 0
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
synchronized
特性
锁的是对象不是代码(this T.class)
能加在方法上,代码块
加速在jdk1.6之后就做了锁优化,会有锁升级的优化过程
保证原子性和可见性
可重入锁
注意事项
不要锁基础类型,如String常量,Integer,Long等
实现
源码synchronized
ACC_SYNCHRONIZED字节码
monitorenter,monitorexit
监视器锁
Mutex Lock(互斥锁)
重量级锁,内核态与用户态切换,性能消耗大
锁升级(hotspot实现)
new
偏向锁
记录当前线程的ID(hashCode)
轻量级锁/自旋锁
基于cas实现
自适应自旋
10次自旋
所谓自适应自旋锁就是线程空循环等待的自旋次数并非是固定的,而是会动态着根据实际情况来改变自旋等待的次数
执行时间短并且线程数少的
重量级锁
OS锁
内核态和用户态切换,消耗性能
执行时间长的用OS锁
jdk1.6对锁做了优化
锁只能升级没法降级
锁消除/锁细化
StringBuffer vs StringBuilder
StringBuffer的append方法时线程安全的
StringBuffer a = new StringBuffer();
a.append('111').append('bbb'').append('ccc')
a.append('111').append('bbb'').append('ccc')
在同一个方法内的sb a的append只有一个线程去访问的时候就会将append内的synchronized锁给消除掉
锁粗化
StringBuffer a = new StringBuffer();
for(int i=0;i<1000;i++){
a.append("i"+i);
}
for(int i=0;i<1000;i++){
a.append("i"+i);
}
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
如果append执行1000次,则会粗化锁到
synchronized (a){
for(int i=0;i<1000;i++){
a.append("i"+i);
}
}
for(int i=0;i<1000;i++){
a.append("i"+i);
}
}
volatile
特性
保证变量在多线程中的可见性
MESI - CPU缓存一致性协议
Modify,修改缓存
当前cpu缓存已经被修改,与内存中数据不一致
Exclusive,独占缓存
当前CPU的缓存和内存中数据保持一致,而且其他处理器并没有可使用的缓存数据
Share,共享缓存
和内存保持一致的一份拷贝,多组缓存可以同时拥有针对同一内存地址的共享缓存段
Invalid,失效缓存
当前cpu缓存已经不能使用
缓存行cache line
64个字节宽
当修改volatile变量时,会给cpu发送一个信号告诉其他cpu这个变量已修改,当其他cpu调用这个变量时,就会先检查是否有收到修改该变量的信号,有则重新从内存中读取。volatile是无锁的,类似于乐观锁的机制。
在没有MESI的时候,用的是锁总线的方式,比较重
禁止指令重排
实现
源码volatile
ACC_VALATILE字节码
内存屏障
ReadRead
LoadLoad
ReadLoad
LoadRead
JVM的hotspot实现采用较兼容的汇编指令lock addl
没有使用cpu的原语ifence,mfence
不能保证原子性
new Object
count++
CPU指令乱序执行
指令A
指令B
有可能指令B先执行完,A再执行完,这总现象称之为乱序执行
前提是该CPU是多核的
JIT
及时编译-just in time
热点代码会被编译成汇编语言,加快执行
四种引用
强软弱虚
强引用
String a = new String();
内存不足,gc时也不会回收strong reference
软引用
SoftReference<T>
内存不足时,gc会将软引用回收
弱引用
WeakReference<T>
无论内存足不足,gc时都会将弱引用回收
应用在ThreadLocal
虚引用
PhantomReference<T>
应用在管理堆外内存,java nio里有DirectByteBuffer
DCL
Double check lock双重锁校验
单例模式之双重校验方式的变量还需要用volatile修饰吗?
需要,禁止指令重拍,得到初始化完整对象
Object obj = new Object()
NEW java/lang/Object
申请内存
INVOKESPECIAL java/lang/Object.<init> ()V
执行构造方法
ASTORE 1
将obj指向内存空间
如果不加可能拿到半初始化状态的对象,导致业务出错
class SingletTon {
private static volatile SingletTon instance = null;
private SingletTon(){}
public static SingletTon getInstance(){
if(null == instance) {
synchronized (SingletTon.class) {
if(null == instance){
instance = new SingletTon();
}
}
}
return instance;
}
}
private static volatile SingletTon instance = null;
private SingletTon(){}
public static SingletTon getInstance(){
if(null == instance) {
synchronized (SingletTon.class) {
if(null == instance){
instance = new SingletTon();
}
}
}
return instance;
}
}
ThreadLocal
线程间隔离
实现
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
每个线程的ThreadLocal作为key存放在hashMap里,互相隔离
tab[i] = new Entry(key, value);
map里的行Entry继承了WeakReference
防止tl=null后,threadlocal无法被gc回收的问题
但是如果map里的key=null,value还指向了其他对象,也会有一行无法被回收,因此需要手动调用tl.remove
线程Thread
概念
程序
d:/qq/qq.exe
进程
qq.exe进程
线程
thread
协程/纤程
创建
Thread
Runable
lambda方式,其实也是runable
Excutor.newFixedPool线程池,其实也是thread或者runable之一
api
sleep
休眠,进入睡眠,时间过后自动复活回到就绪态
yield
礼让,让出一下cpu,返回到就绪状态
join
t1线程里调t2.join,等t2运行完,t1再运行
stop
线程运行完成后,就等于停止
setDeamon(true)
线程状态
new
runable
ready
running
timedWating
waiting
blocked
teminated
线程池
线程池创建类
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
// 省略...
}
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
// 省略...
}
Excutors6大线程池
newCachedThreadPool
创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程。
newFixedThreadPool
创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待。
newScheduledThreadPool
创建一个周期性的线程池,支持定时及周期性执行任务。
ScheduledExecutorService类的schedule()方法调度
newSingleThreadExecutor
创建一个单线程的线程池,可保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
newSingleThreadScheduledExecutor
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行
newWorkStealingPool
newWorkStealingPool线程池的实现用到了ForkJoinPool,用到了分而治之,递归计算的算法,
4种拒绝策略
AbortPolicy 拒绝策略
这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现。
DiscardPolicy 丢弃任务
丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃
DiscardOldestPolicy
丢弃队列最前面的任务,然后重新提交被拒绝的任务
CallerRunsPolicy
由调用线程处理该任务
递增解决方案
Atomic
sync
LongAdder
新的锁
可重入锁ReentrantLock
lock.lock()
支持公平
newCondition
等待队列多个
notifyAll 一个等待队列
门闩CountDownLatch
countdown
循环栅栏CyclicBarrier
满人发车
分段Phaser
读写锁ReadWriteLock
共享锁
读锁
排他锁/互斥锁
写锁
ReentrantReadWriteLock
可用做读写分离场景
信号量Semaphore
s.acquire()阻塞方法
s.release()释放
控制同时执行线程的数量
支持公平
可用做限流
交换器Exchanger
exchange() 会阻塞
2个线程交换数据的
可用做交易的场景
锁支持LockSupport
ls.park()
ls.unpark()
同步容器
Collections.synchroizedList(list)
AQS - AbstractQueuedSynchronizer
volatile state + CAS
线程队列
如何阅读源码
LinkedBlockingQueue
相关知识点
脏读dirtyRead
写同步
读不同步
解决方式:读也加同步
可重入锁
synchroized m1(){m2()}
synchroized m2()
如果不重入,就会死锁
同一个线程,m1方法调用m2方法;或者子类调用父类的构造方法
去一道锁就减一
异常释放锁
锁中出现异常,默认情况是会释放锁的
asm
字节码操作框架
分布式锁
redis锁实现redssion
zookeeper锁curator
悲观锁/乐观锁
悲观锁总是假设最坏的情况,所以一定会上锁
乐观锁总是假设最好的情况,所以不会上锁,会用条件判断或者cas的方式
ReentrantLock 和 Synchroized(升级到os锁时)是悲观锁
Atomic原子类型和其他cas实现的锁时乐观锁
CAS vs Synchroized
CAS 适用于读多的场景
sync适用于写多的场景
notify()不释放锁,wait()会释放锁
JVM
监控工具
命令
jps
jstat
jinfo
jmap
jhat
jstack
jcmd
可视化
JConsole
VisualVM
VisualGC
FullGC
会出现stop the world
应该避免
jxl的包,在WorkBook.close()方法里会显示调用System.gc()
可以在jvm运行前禁用掉System.gc()不做响应
-XX:-+DisableExplicitGC
监控组件
cat
大从点评
zabbix
问题相关
内存
内存溢出
内存泄露
jmap
Mat分析
CPU
死锁
线程异常挂起
Jstack
top -p paid -H
查看某个jvm线程运行情况
Top
1
查看cpu各核心状态
h
进入帮助
Arthas
jvm调优神器——arthas
https://arthas.aliyun.com/doc/quick-start.html
Tomcat
了解及说明
servlet规范
servlet容器
servlet
wrapper
context
host
engine
架构图
部署方式
描述符部署
文件夹部署
war包部署
支持的IO模型
JIO
java IO其实就是BIO
NIO
APR
@Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.setProtocol("org.apache.coyote.http11.Http11AprProtocol");
tomcat.addContextLifecycleListeners(new AprLifecycleListener());
return tomcat;
}
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.setProtocol("org.apache.coyote.http11.Http11AprProtocol");
tomcat.addContextLifecycleListeners(new AprLifecycleListener());
return tomcat;
}
整理web服务器从请求到响应的节点过程
tomcat调优
JVM优化
-server:启用 JDK的 server 版本;
-Xms:Java虚拟机初始化时堆的最小内存,一般与 Xmx配置为相同值,这样的好处是GC不必再为扩展内存空间而消耗性能;
-Xmx:Java虚拟机可使用堆的最大内存;
-XX:PermSize:Java虚拟机永久代大小;
-XX:MaxPermSize:Java虚拟机永久代大小最大值;
Connector优化
maxThreads 客户请求最大线程数
minSpareThreads Tomcat初始化时创建的 socket 线程数
maxSpareThreads Tomcat连接器的最大空闲 socket 线程数
enableLookups 若设为true, 则支持域名解析,可把 ip 地址解析为主机名
redirectPort 在需要基于安全通道的场合,把客户请求转发到基于SSL 的 redirectPort 端口
acceptAccount 监听端口队列最大数,满了之后客户请求会被拒绝(不能小于maxSpareThreads )
connectionTimeout 连接超时
minProcessors 服务器创建时的最小处理线程数
maxProcessors 服务器同时最大处理线程数
URIEncoding URL统一编码
minSpareThreads Tomcat初始化时创建的 socket 线程数
maxSpareThreads Tomcat连接器的最大空闲 socket 线程数
enableLookups 若设为true, 则支持域名解析,可把 ip 地址解析为主机名
redirectPort 在需要基于安全通道的场合,把客户请求转发到基于SSL 的 redirectPort 端口
acceptAccount 监听端口队列最大数,满了之后客户请求会被拒绝(不能小于maxSpareThreads )
connectionTimeout 连接超时
minProcessors 服务器创建时的最小处理线程数
maxProcessors 服务器同时最大处理线程数
URIEncoding URL统一编码
缓存优化
compression 打开压缩功能
compressionMinSize 启用压缩的输出内容大小,这里面默认为2KB
compressableMimeType 压缩类型
connectionTimeout 定义建立客户连接超时的时间. 如果为 -1, 表示不限制建立客户连接的时间
compressionMinSize 启用压缩的输出内容大小,这里面默认为2KB
compressableMimeType 压缩类型
connectionTimeout 定义建立客户连接超时的时间. 如果为 -1, 表示不限制建立客户连接的时间
子主题
IO优化
BIO,NIO,APR
线程池设置
<Executor
name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="500"
minSpareThreads="30"
maxIdleTime="60000"
prestartminSpareThreads = "true"
maxQueueSize = "100"
/>
name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="500"
minSpareThreads="30"
maxIdleTime="60000"
prestartminSpareThreads = "true"
maxQueueSize = "100"
/>
maxThreads:最大并发数,默认设置 200,一般建议在 500 ~ 800,根据硬件设施和业务来判断
minSpareThreads:Tomcat 初始化时创建的线程数,默认设置 25
maxIdleTime:如果当前线程大于初始化线程,那空闲线程存活的时间,单位毫秒,默认60000=60秒=1分钟。
prestartminSpareThreads:在 Tomcat 初始化的时候就初始化 minSpareThreads 的参数值,如果不等于 true,minSpareThreads 的值就没啥效果了
maxQueueSize:最大的等待队列数,超过则拒绝请求
minSpareThreads:Tomcat 初始化时创建的线程数,默认设置 25
maxIdleTime:如果当前线程大于初始化线程,那空闲线程存活的时间,单位毫秒,默认60000=60秒=1分钟。
prestartminSpareThreads:在 Tomcat 初始化的时候就初始化 minSpareThreads 的参数值,如果不等于 true,minSpareThreads 的值就没啥效果了
maxQueueSize:最大的等待队列数,超过则拒绝请求
IO
相关词
网络IO
磁盘IO
文件IO 具体
网络IO
同步 vs 异步
针对数据读取
如果是程序自己去调用内核的recv读取数据的,是同步的
如果是内核自己将数据读取到程序指定的buffer中,程序从buffer中读的,这样叫异步
ISO7层模型
内核发展
BIO 阻塞IO
NIO 非阻塞IO
select
poll
epoll
AIO 异步IO
linux kernel的aio不成熟
win iocp真正实现
POSIX aio
glibc aio
kernel native aio
libeio
netty
三种线程模型
boss boss
混合模式
boss worker
如何拆包和粘包
默认回车符号
redis
为什么有
数据变大
硬盘慢
内存快,容量小,断电掉数据
特点
二进制安全
redis存的是byte数组,字节数组
不会因为客户端编码而变化
内存型,可持久化到磁盘
rdb快照
aof日志
混合使用
KV
与memcached比,支持本地方法
计算向数据移动
rpush k1 xx aa bb cc
取出第二个元素
lindex k1 1
worker单线程,计算串行化
IO多线程,IO thread
redis6.0支持
应用场景
热点数据缓存
基于list列表做消息队列
基于数字计算做秒杀
基于set的snumber做随机事件的抽奖
基于set的集合运算做业务推荐,如共同好友推荐,可能认识好友等
基于bitmap做最近活跃用户列表,12306座位可买计算等
分布式锁
5种数据类型
string
本地方法
set/get
decr/incr
秒杀
应用场景
bitmap 是string的一种实现,可以做用户登录视窗(年)
秒杀场景
list
做消息队列
子主题
hash
键值对 hashMap
缓存对象时,避免数据的大量io
set
无序的key为null的hashMap
应用场景
业务推荐
共同好友
可能认识的人
随机抽奖
zset(sorted set)
属性
rank
score
数据类型
ziplist
skiplist 在数据量大后会优化为跳跃表来提升性能
object encoding foo
查看foo的数据类型
3种高级数据类型
Bitmaps
HyperLogLog
统计信息
GEO
地理位置
持久化
rdb快照
一次全量备份
存储的是二进制
触发机制
手动
save命令
bgSave命令
自动
1.设置自动触发规则
save <seconds> <changes>
2.如果服务器没有开启aof模式,在shutdown的时候会自动执行一次bgSave
3.主从复制
子主题
执行流程
原理
Redis 使用操作系统的多进程 cow(Copy On Write) 机制来实现RDB快照持久化
子主题
优点
RDB文件小,非常适合定时备份,用于灾难恢复
RDB文件存储的某个时刻的内存数据,能快速装载。
缺点
无法做到实时备份
其中cow机制,会阻塞主线程
存在老版本的Redis不兼容新版本RDB格式文件的问题
aof日志
连续日志增量备份
append only file
存储的是时间段内数据修改的指令文本
默认关闭,配置开启
appendonly yes
fsync
linux内核里的glibc下提供fsync函数,刷新buffer数据到磁盘
同步选型
always
每次修改操作,都同步一次到磁盘
everysec
每秒刷新一次buffer
no
redis不主动刷新buffer,由操作系统完成
Aof的rewrite机制
aof会随着时间越来越大,所以需要对aof文件做瘦身处理。
触发机制
手动
bgrewriteaof命令
自动
根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机
auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认为64MB(我们线上是512MB)。
auto-aof-rewrite-percentage:代表当前AOF文件空间(aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的值
auto-aof-rewrite-percentage:代表当前AOF文件空间(aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的值
优点
AOF只是追加写日志文件,对服务器性能影响较小,速度比RDB要快,消耗的内存较少
缺点
AOF方式生成的日志文件太大,需要不断AOF重写,进行瘦身。
即使经过AOF重写瘦身,由于文件是文本文件,文件体积较大(相比于RDB的二进制文件)。
AOF重演命令式的恢复数据,速度显然比RDB要慢。
混合使用
Redis4.0后
- 大量数据使用粗粒度(时间上)的rdb快照方式,性能高,恢复时间快。
- 增量数据使用细粒度(时间上)的AOF日志方式,尽量保证数据的不丢失。在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。
另外,可以使用下面这种方式。Master使用AOF,Slave使用RDB快照,master需要首先确保数据完整性,它作为数据备份的第一选择;slave提供只读服务或仅作为备机,它的主要目的就是快速响应客户端read请求或灾切换。
集群
主从
哨兵
集群
zookeeper
子主题
Kafka
消息队列中间件
点对点模式
轮询拉取消息
立即删除消息
一对一
发布/订阅模式
队列主动推送
不会删除消息,默认保存7天
一对多
好处
解耦
异步
削峰
架构
Zookeeper
注册中心,可集群
0.9版本前offset记录在zk中
Broker
kafka服务器,可集群
broker 0
broker 1
broker 2
没有leader之分
Producer
生产者
ACK
-1
消息发送后,leader和所有的follwer都反馈成功
0
消息只发送一次,不需要反馈
1
消息发送后,只要leader反馈成功
ISR
每一个分区都有一个ISR(in sync replica)集合,由leader维护
判断存活
节点与zk心跳正常
如果节点是follwer,能保持和lader同步写操作,不能卡住太久
配置
replica.log.max.messages
replica.log.time.max.ms
超过时间,则卡住
HW
high watermark
标记了分区副本集中的一个最低的offset
LEO
log end offset
标记当前副本的最后一个offset
Consumer
消费者
拉取数据
分区分配策略
轮询
ran ge
Topic
消息主题
Partition
分区
副本
数据冗余,防止丢失
kafka实现高吞吐
顺序写
优化写入速率
零拷贝
减少用户态内核态切换
压缩批量发送
减少IO
数据库(mysql)优化
统计信息;针对count(1)等
索引;b-tree,hash
分区表;partition
子查询;with as
pgsql on conflict;不存在就插入,存在就更新
hint;强制使用索引
作为面试官
数据结构
HashMap的底层实现?
1.7是数组加链表
1.8做了优化,是数组加链表,链表长度超过8优化为红黑树
HashMap的线程不安全主要体现在下面两个方面:
1.在JDK1.7中,当并发执行扩容操作时会造成环形链和数据丢失的情况。
2.在JDK1.8中,在并发执行put操作时会发生数据覆盖的情况。
1.在JDK1.7中,当并发执行扩容操作时会造成环形链和数据丢失的情况。
2.在JDK1.8中,在并发执行put操作时会发生数据覆盖的情况。
和ConcurrentHashMap的区别是什么?
hashMap在多线程并发下put方法可能会出现循环链表,导致死锁
ConcurrentHashMap是同步的,线程安全的
设计模式
代理模式分为哪2种,有什么区别?
动态代理和静态代理
静态代理是在源代码上编程,实现业务方法的代理。而动态代理可以通过反射增强一个无源码的方法。
动态代理的2种实现方式及区别
JDK动态代理
只能代理实现了InvocationHandler接口的类
cglib动态代理
通过asm修改类的字节码来完成代理
区别:JDK代理针对的是接口,cglib是类,但是无法代理final修饰的类
多线程高并发
应用场景
锁
你了解并使用过哪些锁?
synchrozied
深入锁升级
对象头
底层实现
monitorenter
monitorexit
ReentrantLock
请解释下可重入
底层实现?
CAS
ABA问题如何解决的
加版本
参考
https://blog.csdn.net/weixin_41050155/article/details/88047556
线程池?
如何创建?
有哪些参数
如何解决高并发
更好的硬件
CPU
内存
硬盘
软件架构
应用服务器最先抗不住
加代理服务器NGINX,做负载均衡
应用服务器抗住了,数据库服务器压力大
做数据库的读写分离,分库分表Mycat
分库分表(业务数据量过大)
https://zhuanlan.zhihu.com/p/137368446
读写分离后,如果读的流量加大
加入缓存集群redis
加入缓存集群后,读压力抗住了,写压力还是很大
加入消息队列Mq,做异步写入
IO
IO发展
IO模型
BIO
NIO
select
poll
epoll
AIO
分布式
参考
https://www.cnblogs.com/workstation-nigoudongma/p/9546801.html
分布式事务
产生原因
多个事务分散在不同数据源上
业务场景
下单
支付
解决方案
分阶段提交协议
分布式事务实现XA,阿里巴巴Seata
消息队列,消息可靠性
发送端可靠性
先写入消息表,发送成功则删除记录,不成功则重试发送
接收端可靠性
消息中间件的ack=-1,如Kafka
处理业务幂等性
负载均衡
算法
轮询
加权轮询
最小连接
加权最小连接
随机
实现
DNS解析
二级域名,如dc.xx.com,user.xx.com
修改MAC地址,LVS解析
修改IP地址
在网络层修改请求的目标IP地址
HTTP重定向
反向代理
正向代理
发生在客户端,是由用户主动发起的。比如翻墙,客户端通过主动访问代理服务器,让代理服务器获得需要的外网数据,然后转发回客户端
反向代理
发生在服务器端,用户不知道发生了代理。
分布式锁
单进程/多线程
sync 和 jdk的lock
多进程
使用分布式锁
实现方案
数据库分布式锁
基于数据库唯一索引实现
如果删除数据库锁记录失败,则其他线程都无法获取到锁,造成死锁
使用乐观锁,加版本号做更新
Redis分布式锁
基于 SETNX、EXPIRE
设置过期时间,防止死锁
RedLock
Redis Distributed Lock
使用场景
多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击);
高可用
用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时还可用
实现原理
尝试从 N 个相互独立 Redis 实例获取锁,如果一个实例不可用,应该尽快尝试下一个。
计算获取锁消耗的时间,只有当这个时间小于锁的过期时间,并且从大多数(N/2+1)实例上获取了锁,那么就认为锁获取成功了。
如果锁获取失败,会到每个实例上释放锁。
redission框架
RLock lock = redisson.getLock("lockName");
try{
// 1. 最常见的使用方法
//lock.lock();
// 2. 支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁
//lock.lock(10, TimeUnit.SECONDS);
// 3. 尝试加锁,最多等待2秒,上锁以后8秒自动解锁
boolean res = lock.tryLock(2, 8, TimeUnit.SECONDS);
if(res){ //成功
//处理业务
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
RLock lock = redisson.getLock("lockName");
try{
// 1. 最常见的使用方法
//lock.lock();
// 2. 支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁
//lock.lock(10, TimeUnit.SECONDS);
// 3. 尝试加锁,最多等待2秒,上锁以后8秒自动解锁
boolean res = lock.tryLock(2, 8, TimeUnit.SECONDS);
if(res){ //成功
//处理业务
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
Zookeeper分布式锁
为分布式应用提供一致性服务的软件
基于zk的临时有序节点,加监听实现
会话超时会自动删除掉临时节点,下一个节点就能获取到锁,因此不会产生死锁
羊群效应
每一个节点只监听自己的上一个节点
分布式Session
原因
分布式部署后,A用户登录了第一台机器,下一次被分发到第二台机器上被拦截到登陆页
粘性Session
原理
负债均衡将A用户锁定分配到某一台机器上,不会分配到另一台机器
优点
不需对session做处理
缺点
缺乏容错性,当前粘性的机器down掉,被分配到新的机器上时用户信息会丢失
适用场景
发生故障对客户产生的影响较小;
服务器发生故障是低概率事件。
服务器发生故障是低概率事件。
服务端Session复制
原理
任何一个服务器上的 Session 发生改变,该节点会把这个 Session 的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要 Session,以此来保证 Session 同步。
优点
可容错,各个服务器间 Session 能够实时响应。
缺点
会对网络负荷造成一定压力,如果 Session 量大的话可能会造成网络堵塞,拖慢服务器性能。
实现方式
设置 Tomcat 的 server.xml 开启 tomcat 集群功能。
在应用里增加信息:通知应用当前处于集群环境中,支持分布式,即在 web.xml 中添加 选项。
在应用里增加信息:通知应用当前处于集群环境中,支持分布式,即在 web.xml 中添加 选项。
Session共享
使用分布式缓存方案比如 Memcached、Redis,但是要求 Memcached 或 Redis 必须是集群。
粘性 Session 共享机制
原理
和粘性 Session 一样,一个用户的 Session 会绑定到一个 Tomcat 上。Memcached 只是起到备份作用。
非粘性 Session 共享机制
原理
Tomcat 本身不存储 Session,而是存入 Memcached 中。Memcached 集群构建主从复制架构。
优点
可容错,session实时共享
实现方式
用开源的 msm 插件解决 Tomcat 之间的 Session 共享:Memcached_Session_Manager(MSM)
存到分布式缓存redis中
分布式
多机部署
CAP
一致性
可用性
分区容错性
集群
主从高可用
负载均衡
源码
spring
mybatis
框架
Spring
spring是如何实现aop的
Springboot
SpringCloud
中间件
Redis
Redis的数据类型
Redis支持持久化吗?有哪几种方式
rdb和aof
zookeeper
子主题
kafka消息中间件
如何确认kafka发送消息成功了?(是不是问消息发送可靠性)
ack
fastdfs分布式存储
tracker
storage
group
ElasticSearch
nginx
是哪个国家开发的
俄罗斯
openresty是哪个国家开发的
国人
章亦春,现居美国全职openresty项目
为什么选nginx做网关?
代理服务
负载均衡
HTTPS配置
子主题
微服务
dubbo
rpc
dubbo的工作原理
dubbo的心跳机制
dubbo心跳时间heartbeat默认是60s,超过heartbeat时间没有收到消息,就发送心跳消息(provider,consumer一样),如果连着3次(heartbeatTimeout为heartbeat*3)没有收到心跳响应,provider会关闭channel,而consumer会进行重连;不论是provider还是consumer的心跳检测都是通过启动定时任务的方式实现;
提供者和消费者向注册中心发送心跳,定时任务方式发送,默认60秒,3次超时关闭长连接
springclound
http
其他问题
跨域问题产生和解决方式
跨域产生
请求不同源
解决方式
jsonp
服务端设置允许跨域
代理服务到相同源下
分库分表
分表是如何做的
业务注解hash(散列)
0 条评论
下一页
为你推荐
查看更多