学习整理

https://github.com/Snailclimb/JavaGuide#%E5%9F%BA%E7%A1%80

https://github.com/CyC2018/CS-Notes

问题一:jdk提供的各种锁session

解答:https://www.cnblogs.com/jyroy/p/11365935.html

理解:无锁 偏向锁 轻量级锁 重量级锁 》syn

公平 非公平 》renteentlock

可重入不可重入 》 rent/ syn

悲观锁和乐观锁  rent/syn

独享和共享锁 》Reentrantlock 和 ReentrantReadWriteLock

释放:获取:锁的状态,类型(重入synchronized: 可重入 不可中断 非公平Lock: 可重入 可判断 可公平(两者皆可))

底层实现:

synchronized: 底层使用指令码方式来控制锁的,映射成字节码指令就是增加来两个指令:monitorenter和monitorexit。

锁升级在1.7 中 有了四种,无锁,偏向 ,轻量级,重量级
未升级的1.6是只有重量级的所以会出现锁住的资源比运行的时间还有长的情况

偏向锁是在对象头上的markword区域中记录线程的id,然后cas之前先判断有没有id有则直接进入

jvm优化使用-XX:-UseBiasedLocking=false 开启偏向锁,不使用sync默认是轻量级锁

Lock: 底层是CAS乐观锁,依赖AbstractQueuedSynchronizer类,把所有的请求线程构成一个CLH队列。而对该队列的操作均通过Lock-Free(CAS)操作。

公平锁和非公平锁,都是继承了sync类,而sync类继承了aqs类。实现相同的方法,实现逻辑不一致,traqare()主要区别是公平锁加的限制:hasQueuedPredecessors()
基本逻辑是:如果getstate资源为0的话,那就cas方式获取资源(但是公平锁的话会判断是不是有队列了,有队列排队,非公平不排队),如果不是0的话(说明有资源)判断是否是可冲入的,可重入那就state增加,返回true

可重入锁外面方法有sync 内部方法也有sync 一个线程执行外部方法 还要执行内部方法, 非重入锁会认为已经持有锁要求释放,但是可重入锁会将state值+1,然后释放只有state为0才最终释放

独占和共享:
state一般是0.1 int值,在可重入锁中,state可能很多表示该线程有多少个锁
int 就是4个字节 8位 :32位, 分高低16位,高为读,低为写
必须确保写锁的操作对读锁可见,如果允许读锁在已被获取的情况下对写锁的获取,那么正在运行的其他读线程就无法感知到当前写线程的操作。

1. 如果有一个线程已经占用了读锁,则此时其他线程如果要申请读锁,可以申请成功。

2. 如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁,因为读写不能同时操作。

3. 如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,都必须等待之前的线程释放写锁,同样也因为读写不能同时,并且两个线程不应该同时写。

所以我们用一句话总结:要么是一个或多个线程同时有读锁,要么是一个线程有写锁,但是两者不会同时出现。也可以总结为:读读共享、其他都互斥(写写互斥、读写互斥、写读互斥)。

问题二:volitile关键字存在jvm那个空间,堆还是方法区

方法区是线程共享的内存区域,它用于保存系统的类信息,比如类的字段、方法、常量池等。

问题三:redis扩容

sentail(哨兵):哨兵最少三个

cluster(集群):最少三主三从 6 个节点

1.创建节点,创建两个节点的文件夹,修改redis.conf文件

2.向集群中添加主节点

./src/redis-cli --cluster add-node 172.26.237.83:7002(新增的实例端口地址) 172.26.237.83:7000(集群中已存在的任意实例的地址) -a 0123456789通过cluster info (进入该节点执行 info replication看节点信息 )查看集群的健康状态和节点状态

3.分配哈希槽

ip:port 为当前redis集群任意节点ip和port,-a后面加密码(./src/redis-cli --cluster reshard ip:port -a 密码)

(16384个节点)两种方式将所有的节点用作哈希槽饿源节点,在指定的节点拿出指定数量的哈希槽分配到目标的节点

type:done指定源的id,从源id转移solts,all:从所有的节点转移solts

4.添加从节点

7007:master

7008:slave

./src/redis-cli --cluster add-node --cluster-slave --cluster-master-id db10a9d5c1662d9e3cee21c5776f2e9709f76619 127.0.0.1:7008 127.0.0.1:7007

(删除节点)

5.del-node192.168.127.130:7007991ed242102aaa08873eb9404a18e0618a4e37bd

要先把要删除节点的槽给移动到别的节点再进行删除。


问题四:aqs怎么实现的     是一个线程同步的框架

java.util.concurrent.locks包下的(抽象的队列式同步器)

AQS的核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态;如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,AQS是将每一条请求共享资源的线程封装成一个CLH锁队列(虚拟的双向队列)的一个结点(Node),来实现锁的分配。

AQS维护两种资源共享的方式:

exclusive:独占 (ReentrantLock); share:共享(semaphore,cyclicBarrier)

问题5“:并发工具

https://blog.csdn.net/jisuanji12306/article/details/86363390

信号量Semaphore final Semaphore semp = new Semaphore(5);顺序执行

psvm
ExecutorService exec = Executors.newCachedThreadPool();
final Semaphore semp = new Semaphore(5);

Runnable run = new Runnable(){
run(){
获取信号量
semp .acauire();
执行业务
释放信号量
semp .release();

}

}

 CycliclBarrier;保证一组线程在同一时刻执行

// 栅栏到了执行的操作
CyclicBarrier cbRef =newCyclicBarrier(5,new Runnable() {
run(){
sout:都到了
}
})

Thread_01[] threads =newThread_01[5];
fori
threads[i] =new Thread_01(cbRef);
threads[i].start();

publicclassThread_01extends Thread {
this.cbRef = cbRef;
@Override
publicvoid run() {
Thread.sleep((int) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName() + "到了!" + System.currentTimeMillis());
cbRef.await();
}

}

countDownLatch(1) ;顺序执行
1.CountDownLatch countDownLatch = new CountDownLatch(1);
2. Thread threadA = new Thread(() -> {

Thread.sleep(500);
countDownLatch.countDown();

});
Thread threadB = new Thread(() -> {

countDownLatch.await();
System.out.println("线程B收到通知,开始执行自己的业务...");

});
threadB .start();
threadA .start();

lockSupport(park,unpark) 。。。。
Thread threadA = new Thread(() -> {

Thread.sleep(500);
LockSupport.unpark(threadB);

})

Thread threadB = new Thread(() -> {

(前置条件)LockSupport.park();
System.out.println("线程B收到通知,开始执行自己的业务...");

})

wait notify ;volatile;。。。。

问题六:三次握手四次挥手


seq与小ack对应 seq 来时是x 回去就是ack = x+1 seq是序号,ack是确认号


问题7:closewait解决方法



问题8:select poll 和epoll的区别:培昆博客

select :intselect(intn,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,structtimeval*timeout);

select 允许应用程序监视一组文件描述符,等待一个或者多个描述符成为就绪状态,从而完成 I/O 操作。

fd_set 使用数组实现,数组大小使用 FD_SETSIZE 定义,所以只能监听少于 FD_SETSIZE 数量的描述符。有三种类型的描述符类型:readset、writeset、exceptset,分别对应读、写、异常条件的描述符集合。

poll:

structpollfd {intfd;/*file descriptor*/shortevents;/*requested events*/shortrevents;/*returned events*/};

select 的描述符类型使用数组实现,FD_SETSIZE 大小默认为 1024,因此默认只能监听少于 1024 个描述符。如果要监听更多描述符的话,需要修改 FD_SETSIZE 之后重新编译;而 poll 没有描述符数量的限制;

poll 提供了更多的事件类型,并且对描述符的重复利用上比 select 高。

epoll:epoll_create  epoll_ctl  epoll_wait

epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符。

从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获得事件完成的描述符。




问题9:http和https ssl加密,  非对称加密

补充问题:

一个http请求从clinet 》 server都走过哪些流程

client  > WWW.BAIDU.COM

>DNS服务器,解析域名 > 10.10.10.1 访问

进行tcp建立链接三次握手

发送http请求request:如果请求中包含动态语言,服务器会调用动态语言的解释器引擎进行解释  

服务端dispacther 》 handlermapping 》 handleradapter 》 handler  》 视图modelandView进行渲染

返回客户端

4次挥手

补充问题2:滑动窗口问题及流量控制问题

待补充::::

滑动窗口:控制数据传输的数量,当服务端的窗口为0时候,客户单就发不了数据

拥塞控制:发送数据的速率。慢开始,拥塞避免,快恢复快重传

慢开始:一开始只有1个 然后指数增长*2*2

拥塞避免:达到拥塞避免的值以后,缓慢增长 每次增长 1个报文

快恢复:当m1m2m3m4 服务端只相应了m1m2 ,一直对m3未收到相应,超三次,客户端就会进行重传

问题10:可以看到1.8默认的是 UseParallelGCParallelGC 默认的是 Parallel Scavenge(新生代)+ Parallel Old(老年代)

1.9是G1

miniorGC :华为笔记

记住paraller scavenge和cms作用不同,关注点不同一个是para是关注的吞吐量

吞吐量(代码运行时间/(代码运行时间+gc时间))

cms关注的是最小停顿时间

:记住初始标记stw, 并发标记,重新标记stw,并发清理

拓展补充G1:

垃圾回收年轻代老年代都是用的G1不向1.8 分别是parealler svc 和 pall old 

cms:初始 并发标记 重新 并发清理

g1跟cms前几种流程类似:初始标记,并发标记最终标记,筛选回收

不同的是cms是一个中标记清理策略,g1是标记整理清楚策略, 不会和cms一样使内存出现大量的不连续空间

问题11:

在java语言中,什么对象可作为GCRoot的对象?

    a. java虚拟机栈中的引用的对象。 

    b.方法区中的类静态属性引用的对象。 (一般指被static修饰的对象,加载类的时候就加载到内存中。)

    c.方法区中的常量引用的对象。 

    d.本地方法栈中的JNI(native方法)引用的对象



12:

当时选型为什么要用rocketmq不用kafaka、

消息挤压,有些业务场景下要保证数据的一致性,较kafuka比较为轻量级框架

rocket支持分布式事务

补充:怎样实现分布式事务。哪些分布式锁

13:消息不丢失三个组件和顺序一致性如何实现queue

不丢失:https://blog.csdn.net/leeasony/article/details/104857576

简单来说在三个方面阐述:

1.producer:a同步阻塞的方式发送,checkstatus判断是否是发送成功

b采用事务的方式进行发送    

c,rocketmq支持索引的方式,发送超时,producer端可以通过查comitlog进行查询,看数据是否在broker中存储成功

2broker:支持集群形式,一主多从。可以进行同步或者异步的数据同步,同步复制即便mater宕机了数据也不会丢失

支持同步及异步的刷盘形式(项目中采用同步复制异步刷盘的形式)

3consumer:同步消费,处理成功后回复broker

consumer维护一个持久的offset,标记成功    消费或者已经 成功发回到broker的消息下标,即便consumer宕机重启也会继续从offset进行消费

顺序性:

1。producer保证发送端发送到同一个队列使用MessageQueueSelector(),选择队列

consumer使用    MessageListenerOrderly()保证消费同一个队列

问题:topic和queue的关系

Queue是Topic在一个Broker上的分片等分为指定份数后的其中一份,是负载均衡过程中资源分配的基本单元。

问题:新增一个consumer该从何处开始消费?

18:一个新的rocketmq消费者加入集群他是如何进行消费的


14:raft 和zab(原子广播)

分布式一致性算法:raft(强一致性、去中心化、高可用的分布式协议)

三个组件之间的关系,可以看出follow没有直接到leader的

选举的详细流程:一开始的follower超过了time out 就会变成选举人,选举人进行投票,先给自己一票同时给别人一票

三种结果:收到大部分人的投票成为leader。收到leader的通知成为follower,或者都没有收到大部分,重新选举

脑裂不存在:即是安全选举:

1一个节点一个任期内最多只投一票

2.只有获得大部分的票的节点才会成为leader

ZAB 

记住zab解决了两个问题:1如何将数据从leader更新到follower上的?(消息广播)——2.如果leader是失效了咋办(故障恢复)

消息广播:leader为每一个follower提供一个fifo队列,

leader给fllower的命令都会放到队列中给随从,当随从返回的ack的消息超过了半数以上

leader会发送commit消息

故障恢复:牢记zxid,又高32位的epoch和地32位的proposal(提案id)

通常选主的id即zxid最大的节点作为新的leader,

(保证已经处理的消息不能丢失)恢复的时候leader与follow之间建立新的fifo把follow缺失的proposal的消息提供给follow并将commit提供给fifo队列

(保证被丢弃的消息不能重现):同理,原来收到消息的proposal成为follow以后,新的leader由于处于的epoch(任期)不同,会抹去之前他为leader时未提交的proposal


补充问题:分布式一致性算法 hash一致性等

首先解释下分布式hash,数据量增加,缓存量增加,所以我们出现了分布式缓存系统,最早的如memchached的分布式缓存,其实现的方式是HASH(KEY)%N ,这个n是服务器的数量。其所用的是客户端分布式缓存的实现,出现的问题是如果新增一台缓存机器,n会变。那样会出现大量的缓存无法命中的问题。所以出现了一致性hash算法

一致性hash:

常用于负载均衡,他的出现解决了server增加节点,hash(key)大量无法命中的情况

一致性hash算法是将整个hash空间呈现为一个虚拟的圆,可以用服务器的ip及主机名作为关键字进行hash部署在环上。寻址的时候进行,hash(key)按照顺时针进行查找,找到第一个节点即为该值所在服务器节点,这样做的几遍某一台服务器异常了,影响的节点不是全部的数据,只是该节点到前一个节点的数据

这样存在的问题是会出现部署不均匀地情况,所以出现了虚拟节点的情况:每个节点计算多个hash部署在环上

redis环装节点有16384个槽,为什么要用2^14次方

集群内部将所有的key部署在16384个槽中,每个redis实例部署一部分槽,判断哪一个key是属于那个槽的通过crc16(key)%16384 crc算法并取余

为什么是16384:1.槽位如果是65535的情况下的话,发送心跳的消息头达到8k,redis需要发送一定数量的ping包作为消息头,65535的情况下ping包太大
2.节点越多,心跳包带有的数据越多,作者不建议cluster使用的数量大于1000,所以默认16384个槽合理
3.槽位越小。节点少的情况下。压缩率高:hash槽是通过bitmap进行存储的,传输过程中对bitmap进行压缩。如果节点很少,压缩槽很高的话就会导致压缩率降低


15:rocket的pull和push

(感觉挺多的单独整理一章)



16:mq的高效读写:kafak rocketmq :0拷贝 的计数:dma 和 mmap



17:rocketmq和kfk的区别


20:redis:清除策略

定时,定期,惰性

redis6种key的清除策略

1.永不删除
2.设置了expire随机删除
3.所有的值随机删除
4.所有的最近最少使用的
5.设置了expire最近最少使用的
6.设置了expire剩余时间最短的
4.0新加
7.lfu 最不频繁使用的
8.设置了expire的lfu 最不频繁使用的

21:

先删缓存再删数据库

22

22rides的跳表

23redis的使用场景

1.String : 微博粉丝数

2.hash:用户及商品信息

3list.粉丝列表,关注列表

4set.共同关注共同喜好去重

5zset.排行榜


24为什么用rpc、retsful不行么

1.传输协议上:长连接 序列化protubuffer都是支持的
2.效率上 tcp 优于http
3.rpc面向服务的高级封装:服务发现/重试/熔断;http不具备


25dubbo使用



28:spring的作用域:简单说5种

request single proproty session globlesession

29:写一个doublecheck

if == null

加锁

if == null 

new

30:三级缓存的概念

spring三级缓存:


32

33

33 有哪些索引、

主键 唯一 普通 复合 全局

34覆盖索引的理解及回表的理解

非聚簇索引查询值刚好是主键,然后就不需要进行回表
比如有一个值是name为索引,然后我查询的刚好是name,就不需要进行回表


35:分库分表

36:mybatis流程:

Configuration (mybatis-config.xml Mapper.xml)> SqlSessionFactory > sqlsession >sqlsession 持有executor > STATEMENTHANDLER > 输入输出

sqlsession是提供给应用的一个接口,不是真正的执行sql的对象
sqlsession持有executor 封装数据库操作
sqlsession.getmapper 执行statement(对数据库真正的操作)

具体如何执行的呢:

1.创建statmenthandler(包含ParameterHandler 和 ResultSetHandler)
2.创建statement-prepareStatement()对语句进行预编译
3.执行jdbc包中的PreparedStatement
4.对结果集进行处理 resultStatement

mybatis 和 mysql 结合看

simple:简单的执行类,每次执行一次update或者select都会开启一个statement的对象,用完立刻关闭statement对象

batch:不支持select,将所有的sql都添加到批处理中,等统一执行executeBatch,缓存了多个statement的对象,每个对象都是addbatch完毕后,等待逐一执行executeBatch

reuse:定义了一个map 以sql作为key进行查询statement对象,存在就是用不存在就重新创建

mybatis的cache:

MyBatis跟缓存相关的类都在cache包里面,其中有一个Cache接口,只有一个默

认的实现类PerpetualCache,它是用HashMap实现的


项目中的德鲁伊druid:各个配置

一级缓存:sqlsession:BaseExecutor的构造函数中持有了PerpetualCache。

必须要在同一个sqlsession内才有用,在事务内每次只创建个sqlsession,不在一个事务内的话只会创建一个sqlsession    

二级缓存:namespace通过CachingExecutor( 事务不提交,二级缓存不存在)cacheEnabled=true开启

Mybatis的二级缓存是默认关闭的,它指的是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享其二级缓存


com.alibaba.druid.wall.WallFilter:防御SQL注入攻击

com.alibaba.druid.filter.stat.StatFilter:Druid内置提供一个StatFilter,用于统计监控信息。

slowSqlMillis用来配置SQL慢的标准执行时间超过slowSqlMillis的就是慢。

阻塞和非阻塞 同步和异步

同步和异步关注的是消息通信机制:就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回

阻塞和非阻塞关注的是程序在等待调用结果的状态:阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

设计一个单机缓存所要注意的点

1.数据结构:
数据应该如何存储,用什么样的数据结构,最简单的如map,复杂的如redis一样提供了多种数据类型,如hash,集合,列表,有序集合

2.对象上限:
本地缓存,内存上限,指定缓存对象的数量

3.清除策略
数据达到上限以后,清除策略,如LRU

4.过期时间
本地缓存需要一个过期时间,比如redis可以给每一个key设置一个过期时间,到达时间后直接删除

5.线程安全
currenthashmap

6.阻塞机制
如果有其他线程读取数据库了,该线程应该阻塞,而不是频繁读取数据库

7.实用的接口
提供一个傻瓜接口,对于缓存使用者,简单明了很有必要

8.是否需要持久化
看是否是必须的

补充:设计一个分布式缓存所要注意的点


数据库表设计

遵循三大范式3NF

(1.保证原子
2.不能部分依赖(联合主键)
3.不能传递依赖)

第一范式:确保每列保证原子性

第二范式:确保表中的每列都和主键相关
也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中

第三范式:确保每列都和主键列直接相关,而不是间接相关

java 泛型

该机制允许程序员在编译时检测到非法的类型
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数

Java 的泛型是伪泛型,这是因为 Java 在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。

泛型一般有三种使用方式:泛型类、泛型接口、泛型方法。


接口


方法


ioc的初始化流程


https://javadoop.com/post/spring-ioc


spring中的设计模式

https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485303&idx=1&sn=9e4626a1e3f001f9b0d84a6fa0cff04a&chksm=cea248bcf9d5c1aaf48b67cc52bac74eb29d6037848d6cf213b0e5466f2d1fda970db700ba41&token=255050878&lang=zh_CN#rd

1.工厂模式肯定存在的,使用beanFactory 》ClasspathxmlApplication
容器启动的时候,不管你用没用到,一次性创建所有 bean

2.单利模式:线程池,缓存池只需要一个多个出现问题。spring默认是单例

3.代理

4.观察者 ApplicationEvent ioc启动会停止时都会出现ContextStartedEvent、ContextStoppedEvent

5适配器:DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由HandlerAdapter 适配器处理

6装饰着 inputstream 或者 bufferinputstream

7.模板模式 jdbcTemplete

Spring 事务



什么是Spring 事务传播

就是多个事务方法相互调用时,事务如何在这些方法间传播


spring 事务失效

1.数据库检索引擎不支持

2.不是public

3.没有被spring管理

4.异常被捕获没有抛出

5事务传播中不以事务运行  not_supported

6.掉用同一个类中的方法,A 调用本类的B(加了注释)无论是public还是priviate / 因为是动态代理的所以只能外部类调用本类


spring 事务

回滚

aspjectJ 和 springAop


ZK

主节点 所有的写操作都要通过

zk使用场景



clock是自己维护的一个时钟,用于统计与其他节点是否在同一个时间线

选举完成后的



集群启动选举

1.投票给自己
(每次投票都有三个数字,钟表 被选举zxid 被选举的myid)
2.更新选票
3.根据选票确定角色

Follow新加入集群选举

1.进入looking状态
2.发起投票,收到leader的leading状态和其他节点的following状态,将自己置位follow
3.同步leader数据

leader失效选举

还是按照zxid和myid进行选举

未commit的不会出现, 已commit的不会消失

如果一个提议被选举后的大多数节点接收,就会发commit,如果是小部分就删除,follow同步新leader的zxid

消息广播会维护一个fifo队列



1.通过zxid选举出新的leader肯定有commit

2.丢弃,原来的主节点失联了以后,commit未给follow提交,从新成为新的主节点的从节点,同步新主节点的事务,所以这个commit会被撤回

个人理解zk=文件系统+通知机制。 2、zk是一个分布式的应用程序协调服务



TCC分布式事务

try + confirm + cancel



DUBBO的负载均衡

1.RandomLoadBalance权重随机选择

2.LeastActiveLoadBalance最小活跃数负载均衡

3.一致性Hash负载均衡策略

4.加权轮询负载均衡。

跟权重随机的是一个是看概率,一个是阉割按照轮询的策略


MQ顺序发送

MessageQueueSelector

顺序发送提供端

MessageListenerOrderly()

顺序发送消费端


在 RocketMQ 中,一个队列只会被一个消费者消费 ,



Broker 主从节点无法切换,主节点负责读写,从节点只负责读,所以主节点挂了之后,生产者无法生产消息,消费者可以消费消息

多个主从无法保证严格顺序


上文中我们提到了如何保证的消息顺序性是通过将一个语义的消息发送在同一个队列中,使用 Topic 下的队列来保证顺序性的。如果此时我们主节点A负责的是订单A的一系列语义消息,然后它挂了,这样其他节点是无法代替主节点A的,如果我们任意节点都可以存入任何消息,那就没有顺序性可言了。

MYBATIS 流程


解析映射文件流程


spring springboot springcloud之间的区别

Spring 不能认为是一个单纯的框架 而一个java的技术生态体系

Spring Boot 是基于spring的一站式开发框架 简化spring应用的配置

Spring Cloud是一套基于Spring Boot的微服务解决方案


tomcat使用


sql优化,为什么这样优化

5点:

1.where 和 order by 建立索引

2.不要查询语句中进行非null判断(!= null),会出现放弃索引全文扫描

3.尽量不用or进行连接:必须前后都符合最左前缀才会走索引否者不会走索引
使用union 替换or

4.like %*** 会扫描全表不会走索引 改为 XXX%

5.查询语句中不要用逻辑运算,将不会走索引走全表扫描

6.select  少使用* 查询具体字段

7.in 和 not in会出现全表扫描 应根据场景使用exist 或者 between

8..索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,    

因为 insert 或 update 时有可能会重建索引

索引

https://www.cnblogs.com/shoshana-kong/p/10517488.html

数据结构 hash b+

物理存储: 聚簇

逻辑主键 唯一 普通 复合 全文(mysiam)

queue

https://javadoop.com/post/java-concurrent-queue

array 必须设置,不会扩容

link可以不设置

priority必须设置会自动扩容

ArrayList和linklist区别


是不是只有这几个?????????????????????????????????????

araraylist 扩容 用 grow() 扩容为原来的1.5倍

arraylist添加元素

空间不足之后调用grows():将数组扩容为之前的1.5倍

hashmap


1.7前查,1.8尾插

curenthashmap

1.7

1.8


1.8curhashmap:插入

1.计算hash值

2.是否进行初始化

3.定位到node,如果为空的话就cas自旋保证数据插入

4.如果有值,(list 、 tree)

5.相同覆盖否则尾插

6.如果连边>8 转换为红黑树


无锁 偏向锁 轻量级锁 重量级锁


三级缓存

https://blog.csdn.net/u012098021/article/details/107352463/


spring启动流程

https://zhuanlan.zhihu.com/p/32830470


启动流程+三级缓存


FignClient

通过EnableFignClints中的inmortSelector方法调用FeignClientsRegistrar

将带有@FeignClinet注解的bean加载到ioc容器中

当从applicationContexr中获取该bean 的时候实际上调用其getObject方法,返回调用其getTarget方法

生成一个代理类:FeignInvocationHandler该实现了动态代理的接口invocvationHandler

调用invoke方法实际上执行的是executeAndDecode方法进行调用

executeAndDecode实际上执行的是封装了RequestTemplate的远程调用

zuulFliter

执行过程:请求》zuulservlet》中的zuulRunner对象》该对象初始化一个ReauestContext》其中包含请求的数据被所有的fliter共享;》通过FilterProcessor管理执行zuulfliter(pre post route error)


限流算法


redis如何实现可重入锁

用key-value key作为线程的id。

线程池的shutdown 和shutdownNow

qps:

限流和熔断区别

innodb 、MYSIAM

INNODB:是 表结构 + (数据+索引)聚簇索引

netty的零拷贝

https://www.cnblogs.com/xys1228/p/6088805.html


compositByteBuf

wrap:合并一个非buf对象为一个buf

slice :wrap多个bytebuf 合并为一个,slice切分开

类似于逻辑分开:切分的多个bytebuf对象共享同一个原始bytebuf对象

进入老年代:

fullGC 触发


序列化:

io/nio区别

流与块的形式:io用流。nio用块 一次处理大量数据

通道, nio有channel,可以用于读或者写

选择器:selector,轮训channel是否有新数据产生,打开,注册,服务端死轮询

支持mmap 和 sendfile

nio是非阻塞的

Arraylist和linklist

arraylist起始为10


oom

https://blog.csdn.net/axin1240101543/article/details/105142141

https://zhuanlan.zhihu.com/p/109870776?from_voters_page=true

jprofile:
点一个占用多的class
然后看reference 》  use  select object(看incomming reference 谁引用这个对象)
找到相关的类
检查代码 

#出现 OOME 时生成堆 dump: 

-XX:+HeapDumpOnOutOfMemoryError

#生成堆文件地址:

-XX:HeapDumpPath=/home/xxx/logs/

linux命令


  springmvc


该图所示是 Server 启动的过程以及服务被客户端调用时,服务器的响应过程。从图中我们可以看到,程序调用了 TThreadPoolServer 的 serve 方法后,server 进入阻塞监听状态,其阻塞在 TServerSocket 的 accept 方法上。当接收到来自客户端的消息后,服务器发起一个新线程处理这个消息请求,原线程再次进入阻塞状态。在新线程中,服务器通过 TBinaryProtocol 协议读取消息内容,调用 UserServiceImpl 的 getUser 方法,并将结果写入 getUser_result 中传回客户端。

tprotocol: 

TBinaryProtocol —— 二进制编码格式进行数据传输
TCompactProtocol —— 高效率的、密集的二进制编码格式进行数据传输
TJSONProtocol —— 使用 JSON 的数据编码协议进行数据传输
TSimpleJSONProtocol —— 只提供 JSON 只写的协议,适用于通过脚本语言解析

传输层:

阻塞TSocket 
非阻塞TNonblockingServerTransport
TTransport transport = new TFramedTransport(new TSocket("localhost", 10005));

服务端类型

TSimpleServer —— 单线程服务器端使用标准的阻塞式 I/O

TThreadPoolServer —— 多线程服务器端使用标准的阻塞式 I/O

TNonblockingServer —— 多线程服务器端使用非阻塞式 I/O

四层、七层负载均衡的区别

四层通过虚拟IP+端口接收请求,然后再分配到真实的服务器;七层通过虚拟的URL或主机名接收请求,然后再分配到真实的服务器。

行锁 间隙锁

MySQL InnoDB支持三种行锁定方式:InnoDB的默认加锁方式是next-key 锁。

1:行锁(Record Lock):锁直接加在索引记录上面,锁住的是key。

2:间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙不变。间隙锁是针对事务隔离级别为可重复读或以上级别而已的。

3:Next-Key Lock :行锁和间隙锁组合起来就叫Next-Key Lock。

当InnoDB扫描索引记录的时候,会首先对索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。加上间隙锁之后,其他事务就不能在这个间隙修改或者插入记录。

间隙锁在InnoDB的唯一作用就是防止其他事务的插入操作,以此防止幻读的发生。

什么时候使用间隙锁

(1)必须在Repeatable Read级别下

(2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加) 

间隙锁的目的是为了防止幻读,其主要通过两个方面实现这个目的:

(1)防止间隙内有新数据被插入

(2)防止已存在的数据,更新成间隙内的数据(例如防止numer=3的记录通过update变成number=5)


eureka如何解决服务发现的

也就是说第一次注册成功后会获取server的数据,本地进行缓存,降低服务端压力


Eureka自我保护模式:

如果在15分钟内超过85%的客户端节点都没有正常的心跳,Eureka Server自动进入自我保护模式。不再剔除任何服务

阈值更新,多少时间,阈值低于多少,开始自我保护
自己设置保活时间

ROCKETMQ:实现分布式事务:

生产者:自定义监听器

生产者需要设置监听器,TransactionListener接口,然后要实现TransactionListener

具体实现
实现TransactionListener接口

重写方法executeLocalTransaction / checkLocalTransaction
这两个接口,第一接口判断事务是否成功LocalTransactionState.COMMIT_MESSAGE; (提交事务)LocalTransactionState.ROLLBACK_MESSAGE;(回滚事务)return LocalTransactionState.UNKNOW;(需要broker进行回查)

回查使用checkLocalTransaction,只有返回成功或者回滚

消费者

thrift

https://www.cnblogs.com/sea520/p/12165790.html

数据交换格式
传输协议

redolog(重做) 和 binlog(归档)

mysql执行流程:

connect层
1.客户端 》 链接器(管理链接,权限验证)

server层
2.查询缓存 》 命中直接返回结果
3.分析器:词法分析及语法分析
4.执行优化器:执行计划生成及索引的选择
5.执行器executor:操作引擎(innodb)

存储引擎层:innodb:查询存储数据。对外提供读写接口

redolog:下面的存储引擎层被innodb独有

重点:redolog保持了MySQL得持久性
记录事务的操作的变化,记录的是数据修改之后的值。不管事务是否成功都会记录,当数据库断电,innodb会使用redolog急性数据恢复

数据更新的流程:innodb会将数据先写到redolog中,然后更新内存,在空闲的时候按照设定的策略将redolog中的日志存入到磁盘中(先写日志再写磁盘)、

binlog是server上边的

是一个二进制日志。属于逻辑日志
binlog的主要作用是记录数据库中表的更改,它只记录改变数据的sql,不改变数据的sql不会写入,比如select语句一般不会被记录,因为他们不会对数据产生任何改动。

区别

redo是物理日志,记录的是数据页的更新内容,binlog是逻辑日志,记录的内容是这个更新语句的原始逻辑

binlog可以进行主从复制。redolog是数据恢复使用,系统异常宕机

binlog说的是主从复制:二进制数据 ,中继日志,数据存到slave数据库

redolog支持数据楷书恢复,crash-safe保持数据的持久性,数据先写到redolog中在空闲时候刷到磁盘中

格式不一致:一个是数据页的更新内容,一个是二进制逻辑数据

数据恢复用binlog,主从复制搭建;redolog用于异常宕机恢复

 https://www.cnblogs.com/fengtingxin/p/11104758.html


https://blog.csdn.net/nrsc272420199/article/details/103204119
https://blog.csdn.net/nrsc272420199/article/details/103192081

追踪spring装配bean的源码到AbstractAutowireCapableBeanFactory类,里面有一个方法doCreateBean为真正创建bean的方法

实例化bean》populateBean(@autowired)》初始化postprocessor
在实例化之后 postProcessAfterInstantiation之后设置属性通过populateBean调用autowireByName/autowireByType() 通过反射注入到ioc容器中

在执行完populateBean(beanName, mbd, instanceWrapper)方法,当前bean里要@Autowired的属性已经全部被注入到了当前bean对象里。

设置完属性之后进行bean的初始化before/after Initialization

实例化 (实例化的时候执行@component注解)之后进行方法是populateBean@autowired 之后初始化(前置) init initlializing afterPropertiesSet @postconstruct 》 后置

生命周期:

(1) (实例化)最先执行构造方法 —> 对应于对象的创建,此时也可能会向bean里设置(设置并非注入)一些属性,比如通过@Bean向IOC容器里注入如下对象时:

(2)接着会将所有标有@Autowired的属性全部注入到当前bean设置属性

(3)遍历所有的BeanPostProcessor,并调用每一个processor的postProcessBeforeInitialization方法

(4)执行InitializingBean、initMethod或@PostConstruct对应的方法 

5)遍历所有的BeanPostProcessor,并调用每一个processor的postProcessAfterInitialization方法

https://my.oschina.net/u/4006148/blog/2876618
https://www.jianshu.com/p/3c5d7f09dfbd

从表面上看ThreadLocal相当于维护了一个map,key就是当前的线程,value就是需要存储的对象
这里的这个比喻是不恰当的,实际上是ThreadLocal的静态内部类ThreadLocalMap为每个Thread都维护了一个数组table,ThreadLocal确定了一个数组下标,而这个下标就是value存储的对应位置。


一个Thread来说只有持有一个ThreadLocalMap,但是可以有多个ThreadLocalMap的实例threadLocals

get则是计算索引直接从数组中对应位置读取value

https://blog.csdn.net/weixin_42754971/article/details/113805590
https://blog.csdn.net/qq_37935909/article/details/111992300
submit是ExecutorService中声明的方法,在ThreadPoolExecutor中没有重写,直接向线程池提交任务,submit是可以返回任务结果
他和execute不同。execute是Executor接口唯一的一个方法,没有返回值

实际上submit提交任务最终也是执行得execute方法,不过是先封装成futureTask,执行execute方法,
1.execute只能接受Runnable的类型参数,而submit可以接受callable类型的参数


dubbo的轮询:

负载均衡策论随机:
权重随机
加权轮训
最小活跃
一致性hash的负载均衡

容错方式:
重试 :failover默认三次 reties =2 默认三次
快速失败 :failfast
失败之后记录日志 : 安全失败 failback
安全失败failsafe:出现错误不报错

广播出去,任何一台失败则失败
并行调用多个服务,有一个成功就可以


客户端配置熔断机制,如果是安全失败failsafe会被吞掉不走mock
服务端的配置

cluste都有的话以clinet优先

循环引用的时候client 》 server 'server 》client 以下两种方式使得实现一边先起来


dubbo配置注册中心


https://www.jianshu.com/p/d4e4de2ad3aa
ribbon / feign轮询策略
随机
重试
轮询
可用轮询(过滤可用的服务端)
响应时间权重(响应时间越短,权重越搞)
最小并发(把任务分配给并发量少的服务)(最小活跃)


以客户端为主


https://blog.csdn.net/weixin_30650059/article/details/112401184

https://www.jianshu.com/p/853701433b3a


java程序对类的使用方式
-----何时进行初始化

创建类的实例
访问某个类或接口的静态变量,或者对该静态变量赋值
调用类的静态方法
反射创建类的实例
初始化一个类的子类----初始化一个父类的子类,也是对这个父类的主动使用
Java虚拟机启动时被标注为启动的类

以上6种情况,而且是第1次主动使用才会在初始化。其他情况,如被动使用,或第二次主动使用,都不会执行类的初始化


静态变量在准备时候进行产生,在初始化的时候赋值,静态代码块 父 子 》 父非静态。。。。

什么时候是类初始化


springmvc 及 父子容器

Spring系列(一):Spring MVC bean 解析、注册、实例化流程源码剖析 - 知乎 (zhihu.com)
Spring 系列(二):Spring MVC的父子容器 - 知乎 (zhihu.com)
Spring 系列(三):你真的懂@RequestMapping吗? - 知乎 (zhihu.com)、

DispatchServlet继承自Servlet,那所有的请求都会在service()方法中进行处理。
doGet(req, resp);/ doPost(req, resp)
processRequest
doService(request, response);
doDispatch(request, response);

为什么把所有的包括controller的bean 都放在父容器中,http请求会出现404为什么

写到spring.xml中时,所有的bean其实都实例化在了Spring父容器中。

但是配置了@ReqestMapping中的inithandler只是对spring mvc容器的bean进行处理,并没有去查父容器,因此不会对父容器中含有@RequestMapping注解的bean进行解析,所有找不到handler

https://juejin.cn/post/6946240170278518798


rocketmq的延迟消费

长知识:

1.rocketmq支持分布式事务
2.rocketmq支持延迟队列,开源版本支持18个leveal

分为18个leveal
流程为:
1.生产者设置等级:

2.broker保存消息的时候替换topic放到定时任务的topic中,起定时任务轮训,此时是将topic和quneueid封装到消息中

3.定时任务ScheduleMessageService.DeliverDelayedMessageTimerTask

轮训topic,当达到延迟时间的时候,取出message,将其topic和queue重新替换,存入到commitlog中,最后被真正的消费

延迟消费原理流程及简单介绍

1.消息的写入/消息的shedule
2.消息的写入:
写入的时候如果是延迟消息,消息的topic和queueid会被替换,会将消息放入到sheduleConsumeQueue,这个队列中的消息不会被消费
消息是存在commitlog中的
3.定时任务的sheduleServie,从sheduleConsumequeue中读取数据,时间到了,取出数据,重新设置topic和quneue存入相应的consumerQueue队列中供comsume消费

优点:
1.不同的level是存在不同的queue(sheduleQueue)中的可以保证顺序消费
2.同一个level的话也是在同一个queue中所以会顺序消费
3.因为level的数量固定的18个,每个level有自己的额shedule

DelayQueue与timeWheel

https://blog.csdn.net/ma_ru_long/article/details/106209007

1.普通业务中使用shedulexecutor使用延迟
2.还可以使用qutarz框架实现定时执行
3.@enableshedule cron(*?)注解
4.rocketmq中,延迟实现是通过setDelaylevel,放到延迟队列,起轮训任务到点放到真实的queue
5.kfk 实现有timeWheel
通过时间轮
概念

1.rickms:基本时间跨度
2.指针:当前运行时间:currentTime
3.总体跨度:基本跨度*圈大小
4.实现通过每个单元跨度里面存在TimerTasklist,中间通过双向链表来实现,将任务放到链表最后,指针直到进行工作

时间轮的总体跨越长度在当前时间和总时间之间 currentTime + interval

kafka中存在着比如800ms执行延迟执行,存在层级时间轮的概念,超过当前时间轮所能代表的时间以后就会升级到上层的时间轮中


DefaultListableBeanFactory:一个基于bean定义对象的完整的bean工厂;默认


FactoryBean:

一般情况下通过反射机制利用的class属性指定实现类实例化bean,在某些情况下实例化bean过程比较复杂,需要在xml的配置文件中配置大量信息、,配置方式的灵活性受限,
比如spring就提供了factoryBean,用户可以通过实现定制化bean 的逻辑

比如就是实现initilazationBean重写afterPropertiesSet方法

用afterPropertiesSet实现对该类中所有的方法都做一个拦截




redis選舉

https://blog.csdn.net/qq_38630810/article/details/106356837?utm_term=redis%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F%E9%80%89%E4%B8%BE&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-0-106356837&spm=3001.4430

https://www.cnblogs.com/qdhxhz/p/11167025.html

内存屏障

https://blog.csdn.net/weixin_30650059/article/details/112401184


eanFactory是个Factory,也就是IOC容器或对象工厂;FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
但对于FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,他的实现与设计模式中的工厂模式和装饰器模式类似。


线程池参数的设置:

核心线程数

服务注册与发现:zk VS eureka

https://www.cnblogs.com/clarino/p/13035358.html


1.一致性

2.时效性,zk立刻通知,rureka定时拉取信息

3.选举方式zab

rocketmq在什么场景下会出现数据重复的情况而不是因为业务引起?

1.producer发数据同步发送,但是发出去之后,网络异常没有收到响应,会重复发送,那broker会出现问题
2.consumer接收数据,收到后offset更改了,但是呢,网络波动,没有给broker响应,会重复投递,也会出现数据重复的问题

索引是什么

是一种高效的获取数据的存储结构

特性:1.单节点可以存储更多的数据,io次数少
2.叶子节点有序,便于范围查找
3.聚簇索引叶子节点直接包含数据,非聚簇索引叶子节点存储数据地址的指针

什么是回表查找


thrift和dubbo的区别

https://blog.csdn.net/JustKian/article/details/102495650

1.网络通讯自研 / netty 

2.序列化方式,dubbo支持各种协议protobuf等。thrift:二进制,压缩格式。json


1.协议:二进制,json

2.传输:阻塞非阻塞 文件传输,压缩传输

3.支持的服务模型:单线程:多线程阻塞式;多线程非阻塞

dubbo作为网络通信层实现以下功能:使用netty交互,客户端服务端保持长链接,tcp链接心跳自动重连

redis的hash数据格式使用场景:zset使用场景

通过String 获取 token值
jedis.set(“20位id” , “token”);
jedis.get("20位id"),比对你token

通过jedis的操作hash:

场景设备共享

jedis.hset(“20位id”,“devID”,“info信息”)
jedis.hget(“20位id”,“编码1”) = info消息:
根据编码判断是否是共享出去的设备:
Map user = jedis . hgetAll("user");

Set keySet = user.keySet();
for(String key : keySet){
String value = user.get(key);

}

set和zset的操作区别就是一个是sadd/zadd 

zset场景录像查询:
将贡献给某个外遇的信息用redis zset存储

jedis.zadd(“外遇id”,时间戳10位(score最大支持16位),录像信息)
外遇播放录像的时候从redis查询该设备是否给外域共享了;只返回前三条数据

获取分别是:jedis.smembers();
jedis.zadd(姓名,30,hh)
zset:jedis.zrange(“姓名”,0,-1);‘’-

thrift做负载均衡

做软负载,有三个ia,分别做三个线程池,查看池子的活跃线程数,通过实现PooledObjectFactory实现的自定义连接池,通过getactiveObject查看有几个ttransport对象,然后判断最小的,放入到该连接池里,以此实现负载均衡

thrift的注册中心使用的zk


跳表的实现原理

条表

zet底层及跳表的实现原理

oom快速定位

jmap -heap 10765:可以查看新生代,老生代堆内存的分配大小以及使用情况

jmap -histo:live 10765 | more 对于实例数较多,占用内存大小较多的实例/类,相关的代码就要针对性review了。

查看进程创建的线程数,以及网络连接数,如果资源耗尽,也可能出现OOM

 ll /proc/${PID}/fd | wc -l

就能知道进程打开的句柄数和线程数。

redis的主从复制

https://www.cnblogs.com/chaichaichai/p/14705486.html

1.salveof 》 发送自己的ip获取master的ip,鉴权,发ping 收到pong

2.全量复制:salve发送psync信令,master执行bgsave,salve全量同步,salve后续从缓冲区同步

数据不一致后:从节点接收master来的数据然后执行bgrewriteaof回复数据

数据库如何实现acid

1.undolog实现原子

回滚日志必须先于数据持久化到磁盘。
通过rollback实现数据的回滚

2.redolog实现持久

3.mvcc 读写锁实现隔离
另一个靠这三个保证

你可能感兴趣的:(学习整理)