基础:
Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)?
优点:反射具有解耦性,
缺点:反射属于解释型代码,性能比直接编码慢。
谈谈对 Java 注解的理解,解决了什么问题?
1.节省配置,减少配置文件的大小。
2.编译时即可查看正确与否,提高效率
内部类了解吗?匿名内部类了解吗?
内部类:内部类是十分简单的,我们根据其字里行间的意义就可以知道内部类应该是一个类当中的一个类,相当于一个类进行了嵌套,就如同循环的嵌套一般。
匿名内部类:
实例化接口,或者抽象类
BIO和NIO区别,4核cpu,100个http连接,用BIO和NIO分别需要多少个线程
BIO一百个连接,需要一百个线程,四核cpu每核处理25个线程。
NIO的话一个线程就够了。
假如我们需要存500个数需要多大的HashMap?
假如没有产生hash碰撞需要扩容六次,HashMap的size是1024.
HashMap的负载因子。
0.75,因为提高空间利用率和 减少查询成本的折中,主要是泊松分布,0.75的话碰撞最小
集合 结构
HashMap 数组加链表(1.8+红黑树)
LinkedList 双向链表
ArrayList 数组
HashSet HashMap
TreeSet TreeMap,红黑树
TreeMap 红黑树,自平衡二叉树,这样可以保证当需要快速检索指定节点
项目中使用到的设计模式: 创建型,行为型,结构型
单例模式(控制实例数目):当工具只需要一个实例可运行时使用,比如时间格式类等等
原型模式(克隆生成对象):复制对象属性时使用
门面模式(封装交互,简化调用):外观模式的目的不是给予系统添加新的功能接口,而是为了让外部减少与子系统内部多个模块的交互
装饰模式:动态的给对象添加新的功能。
代理模式:为其他对象提供一个代理以便控制这个对象的访问。
Vue有什么组件:
vue-cli:快速构建单个页面应用脚手架
vue-router:路由
vuex:全局安全
axios:Http请求
JBoos和tomcat的区别:
JBoos内嵌tomcat,在其基础上新增了一些功能,他们的默认端口都是8080
CyclicBarrier和CountDownLatch的区别?
CyclicBarrier:多线程计数器
CountDownLatch:闭锁
相同点:都是用于多个线程执行,等待多个线程执行完毕后执行继续操作的。
不同点:
1.CyclicBarrier是加计数,CountDownLatch是减计数
2.CyclicBarrier可以重复使用,CountDownLatch是一次性的
jvm:
jvm 内存结构
线程共享:
堆: 对象实例
年轻代:
eden:
survivor
survivor
老年代:
方法区:静态变量,常量,类信息
线程独有:
虚拟机栈:对象引用,局部变量,操作数栈,动态连接,方法返回地址
本地方法栈:操作本地JVM组件
程序计数器:记录程序执行阶段
jvm 调优参数
年轻代大小选择
响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择).在此种情况下,年轻代收集发生的频率也是最小的.同时,减少到达年老代的对象.
吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度.因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用.
避免设置过小.当新生代设置过小时会导致:1.YGC次数更加频繁 2.可能导致YGC对象直接进入旧生代,如果此时旧生代满了,会触发FGC.
年老代大小选择
响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数.如果堆设置小了,可以会造成内存碎 片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间.最优化的方案,一般需要参考以下数据获得:
并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例。
吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代.原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象.
什么是类加载?
类加载的过程主要分为三个部分:
加载:将class字节码文件加载到内存中,并将这些数据在转换成方法区中的运行时数据(静态变量,静态代码块,常量池等),在堆中生成一个class类对象代表这个类(反射),作为方法区类数据的访问入口。
链接:将java类的二进制代码合并到JVM的运行状态之中。
验证:确保加载的类信息符合JVM规范,没有安全方面的问题。
准备:正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配,注意此时的设置初始值为默认值,具体赋值在初始化阶段完成。
解析:虚拟机产量池内的符合引用替换为直接引用(地址引用)的过程。
初始化:运行类构造器,和静态语句块。
当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要初始化其父类。
父类静态代码块->子类静态代码块->父类非静态代码块->父类构造方法->子类非静态代码块->子类构造方法
使用:
卸载:
何时类加载?
java的类加载流程?
知道哪些类加载器。类加载器之间的关系?
类加载器之间的关系?
类加载器的双亲委派 (结合tomcat说一下双亲委派)
为什么需要双亲委派
保证代码安全可靠性,不被篡改和重写
Java内存模型
处理器 <-> 高速缓存 <->
处理器 <-> 高速缓存 <-> 缓存一致性协议 <->主内存
处理器 <-> 高速缓存 <->
栈中存放什么数据,堆中呢?
栈中存放对象引用,局部变量,对象头信息等
堆中存放对象实体
大对象放在哪个内存区域
年轻代可以放下就放年轻代,年轻代放不下就放老年代,老年代放不下就内存溢出
堆区如何分类
年轻代
Eden
survivor1
survivor2
老年代
永久代
JVM垃圾判定算法:
1.引用计数法
2.可达性算法
垃圾回收有哪些算法
1标记—清除算法:
优点:1.相比于 引用计数法,标记清楚算法中每个活着的对象的引用只需要找到一个即可,找到一个就可以判断它为活着。
2.此外,这个算法比引用计数法更全面,在指针操作上也没有和太多的花销。更重要的是,这个算法并不移动对象的位置
缺点:1.很长的幽灵时间,判断对象已经四万,消耗了很多时间,这样从对象死亡到对象被回收之间的时间过长。
2.每个活着的对象都要在标记阶段遍历一遍;所有对象都要在清除阶段扫描一遍,因此算法复杂度较高。
3.没有移动对象,导致可能出现很多碎片空间无法利用的情况。
2.复制算法:
优点:1.实现简单,不产生碎片
缺点:1.每次运行,总有一半的内存是空的,导致可使用的内存空间只有原来的一半
3.标记—整理算法:
4.分代收集算法
新生代:由于新生代产生很多临时对象,大量对象需要进行回收,所以采用复制算法是最高效的。
老年代:回收的对象很少,都是经过几次标记后都不是可回收的状态转移到老年代的,所以仅有少量对象需要回收,故采用标记清除或者标记整理算法。
GC的全流程
Eden -> Survivor -> Tenured -> Full GC -> OutOfMemoryError
复制算法 标记清除算法
标记整理算法
GC中老年代用什么回收方法?
标记清除算法,标记整理算法
多线程:
Java线程池有哪些参数?阻塞队列有几种?拒绝策略有几种?
1.核心线程数,最大线程数,线程最大空闲时间,时间单位,拒绝策略,创建工厂,阻塞队列
2.阻塞队列有三种:
无界队列:队列大小无限制,常用的为无界的LinkedBlockingQueue,当任务耗时较长时可能会导致大量新任务在队列中堆积最终导致OOM
有界队列:一类是遵循FIFO原则的队列如ArrayBlockingQueue(先进先出),另一类是优先级队列如PriorityBlockingQueue(自然顺序升序排)
同步移交队列:如果不希望任务在队列中等待而是希望将任务直接移交给工作线程,可使用SynchronousQueue作为等待队列(只有在使用无界线程池或者有饱和策略时才建议使用该队列)
3.拒绝策略有四种:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
创建线程有几种方式:
1.线程池
2.继承Thread
3.实现Ruannable
4.实现Callable
Runnable和Callable的区别:
相同点:
都是接口,都可以实现多线程,都采用Thread.start启动线程
不同点:
Runnable没有返回值,Callable可以返回执行结果,结果是个泛型,和Future,FutureTask配合可以用来获取异步执行结果
Callable接口的call()方法允许抛出异常,Runnable的run()方法异常只能在内部消化,不能往上继续抛
注:Callalble的接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞
线程池有几种创建方式都有什么参数:
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, //核心线程池大小
10, //最大核心线程池大小
200, //当线程数大于核心时,多于的空闲线程最多存活时间
TimeUnit.MICROSECONDS, //时间单位
new ArrayBlockingQueue<Runnable>(5) // 阻塞队列
// SynchronousQueue<Runnable>:此队列中不缓存任何一个任务。向线程池提交任务时,如果没有空闲线程来运行任务,则入列操作会阻塞。当有线程来获取任务时,出列操作会唤醒执行入列操作的线程。从这个特性来看,SynchronousQueue是一个无界队列,因此当使用SynchronousQueue作为线程池的阻塞队列时,参数maximumPoolSizes没有任何作用。
//LinkedBlockingQueue<Runnable>:顾名思义是用链表实现的队列,可以是有界的,也可以是无界的,但在Executors中默认使用无界的。
threadFactory, //创建新线程时使用的工厂
handler, //拒绝策略
);
重入锁:
ReentrantLock:表示可重新反复进入的锁,但仅限于当前线程
公平锁:各个线程之间公平竞争资源
非公平锁:独占锁,只有当线程主动释放锁,其他线程才能争抢资源
死锁:满足四个条件就会产生死锁,缺一个就不会产生
1.互斥条件 : 当一个线程在操作该资源的时候,其他线程无法操作
2.不可掠夺条件: 当一个线程在操作该资源的时候,其他线程无法前行夺走
3.请求与保持条件: 当一个线程已经保持了至少一个资源,但是又提出了新的资源请求,而该资源已被其他进程占有,此时进程阻塞
4.循环等待条件: 存在一种进程资源循环等待链,链中每一个进程已获得的资源同时被链下一个进程所请求
设计模式:
阅读Spring源码的时候什么设计模式最让你影响深刻?如何使用?
单例模式,单例模式的使用场景
观察者模式,观察者模式的使用场景
Spring
Spring
spring boot和spring的区别
ioc 和 aop(ioc流程、aop实现原理)、spring aop异常处理、当一段代码被try catch后再发生异常时,aop的异常通知是否执行,为什么?
spring bean的创建方式说一下
1.配置文件
2.注解
3.java配置
spring bean的作用范围:
常用的就是单例和多例
singleton:单例(默认)
prototype:多例
request:作用域web请求范围
session:作用于web请求范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群则自动使用session
spring bean的生命周期说一下
单例对象:
出生:当容器创建时对象出生,加载配置文件时创建
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象:
出生:当使用对象时spring框架为我们创建,加载配置文件时不创建,使用时创建
活着:对象只要是在使用过程中就一直活着,即使关闭了容器也存在
死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
mybatis底层是什么?
mybatis底层是封装了jdbc的调用,主要简化了,创建连接池等过程,还要简化SQL调用过程
Mybatis执行SQL的时候,会采用动态代理的方式实例化接口并调用接口方法返回数据
spring data jpa底层是什么?
hibernate和mybatis区别
hibernate是orm框架直接面向对象操作,操作使用的是HQL
mybatis是半orm框架是面向sql操作,操作使用的是SQL
spring boot 过滤器
spring boot 拦截器
Spring动态代理默认用哪一种
写出spring jdk动态代理的实现。
画出spring boot处理一个http请求的全过程
Spring Cloud为什么弃用zuul使用getway
1.zuul1是基于servlet框架构建,采用的是阻塞的多线程方式,即一个线程处理一次连接请求,这种方式在内部延迟严重,
设备故障较多的情况下会引起存活的连接增多和线程增加的情况发生
2.zuul不支持任意长连接如:WebSockert
3.zuul社区非常不活跃,基本上没有在维护了
4.zuul功能没有gateWay完善,gateway内部有实现限流,负载均衡等功能,而zuul需要手动实现,zuul功能比较单一
Spring Cloud zuul和gateway的区别
zuul1基于servlet 同步多线程阻塞模型 没条线程处理一个请求
zuul2基于Netty Server支持前端异步,后端用Netty Client代替Http Client目的是支持后端异步
getway基于Netty异步IO(底层也是Servlet但是在上面封装了一层Netty)
Spring事务的七中传播行为
保证同一个事务中:
PROPAGATION_REQUIRED(默认) 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 支持当前事务,如果当前没有事务,就抛出异常。
保证没有在同一个事务中:
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PRORAGATION_NESTED 支持当前事务,方法在当前事务内运行,嵌套事务可独立提交或回滚,如果当前事务不存在,则与PROPAGATION_REQUIRED一样创建事务
Dubbo
Zookeeper注册中心挂了可以继续通信吗?
1.可以通信的,启动dubbo时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用;
2.注册中心对等集群,任意一台宕机后,将会切换到另一台;注册中心全部宕机后,服务的提供者和消费者仍能通过本地缓存通讯。
服务提供者无状态,任一台 宕机后,不影响使用;服务提供者全部宕机,服务消费者会无法使用,并无限次重连等待服务者恢复;
3.挂掉是不要紧的,但前提是你没有增加新的服务,如果你要调用新的服务,则是不能办到的。
Dubbo的原理是什么
第一层:service层,接口层,给服务提供者和消费者来实现的
第二层:config层,配置层,主要是对dubbo进行各种配置的
第三层:proxy层,服务代理层,透明生成客户端的stub和服务单的skeleton
第四层:registry层,服务注册层,负责服务的注册与发现
第五层:cluster层,集群层,封装多个服务提供者的路由以及负载均衡,将多个实例组合成一个服务
第六层:monitor层,监控层,对rpc接口的调用次数和调用时间进行监控
第七层:protocol层,远程调用层,封装rpc调用
第八层:exchange层,信息交换层,封装请求响应模式,同步转异步
第九层:transport层,网络传输层,抽象mina和netty为统一接口
第十层:serialize层,数据序列化层
工作流程:
1.provider向注册中心去注册
2.consumer从注册中心订阅服务,注册中心会通知consumer注册好的服务
3.consumer调用provider
4.consumer和priovider都会异步通知监控中心
Dubbo支持哪些通讯协议
dubbo协议(默认): 单一长连接,NIO异步通讯,基于hessian的序列化协议,
适用场景是,传输数据量很小(每次请求在100kb之内),但是并发量很高
rmi协议: 短连接,基于java二进制协议序列化,
适合消费者和提供者数量差不多,适用于文件传输
hessian协议:(一般较少用) 多个短连接,
适用于提供者数量比消费者数量还多,适用于文件传输
http协议:(一般较少用) 走json序列化
webservice协议(一般较少用) 走SOAP文本序列化协议
Dubbo支持哪些序列化协议
hessian 优点 缺点
Dubbo为什么不使用java为默认序列化
1.阿里未开发出较成熟的java序列化
2.默认序列化是经过阿里修改过的hessian lite
3.json序列化:目前有两种实现,一种是阿里的fastjson,另一种是采用dubbo中自己实现的简单json库,但其实都不是特别成熟,
而且JSON这种序列化性能一般比不上上面两种二进制序列化
4.java序列化:主要采用JDK自带的java序列化实现,性能很不理想
Dubbo负载均衡有什么策略:
1.random loadbalance(默认):权重
2.roudrobin loadbalance:轮询
3.leastactive loadbalance:自动感知机器性能,性能强接收请求多,性能弱接受请求少
4.consistanhash loadbalance:一致性Hash 当进行调用时候根据调用方法的哪几个参数生成key,并根据key来通过一致性hash算法来选择调用结点。例如调用方法invoke(String s1,String s2); 若hash.arguments为1(默认值),则仅取invoke的参数1(s1)来生成hashCode。
Dubbo集群容错策略:
1.failover策略(默认):失败自动切换,自动重试其他机器
2.failfast cluster策略:一次调用失败就立即报错,常见于写操作
3.failsage cluster模式:出现异常时忽略掉,常用于不重要的接口调用,比如记录日志
4.failbackc cluster模式:失败了后台自动记录请求,然后定时重发,比较适合于写消息队列
5.forking cluster模式:并行调用多个provider,只要一个成功就立即返回
6.broadcacst cluster:逐个调用所有的provider
Dubbo动态代理策略:
默认使用javassist动态字节码生成,创建代理类
但是可以通过spi扩展机制配置自己的动态代理策略
SPI机制:
Dubbo定义了一套接口SPI是用来指定由哪个接口进行实例化
JDK的SPI机制用于JDBC的实例化,mysql采用mysql-jdbc-connction.jar,oracle用oracle-jdbc-connction.jar
Dubbo提供了很多可扩展的功能如何扩展:协议扩展,调用拦截扩展,引用监听扩展,暴露监听扩展,集群扩展,路由扩展,负载均衡扩展
编写实现类,打成jar包,在客户端配置文件中配置
推荐
手写实现Spring核心功能:https://github.com/jinzzzzz/spring-demo
微服务/分布式
为什么要网关?
限流的算法有哪些?
为什么要分布式 id ?分布式 id 生成策略有哪些?
了解RPC吗?有哪些常见的 RPC 框架?
如果让你自己设计 RPC 框架你会如何设计?
Dubbo 了解吗?Spring Cloud 了解吗?
数据库
非关系型数据库和关系型数据库的区别?
非关系型数据库 mongodb,redis,HBase 非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。
关系型数据库 mysql,oracle,postgreSQL 关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织
事务的四大特性
原子性:事务中所有操作要么全部成功,要么全部失败
一致性:数据库状态与其他业务保持一致
隔离性:并发操作中,不同事务之间不会互相干扰
持久性:事务提交成功,所有操作被持久化到数据库中,即使数据库奔溃,在数据库重启时,数据也能恢复
事务的并发问题a ?
脏读:事务A读取了事务B更新的数据,然后B回滚了操作,那么A读取到的数据是脏数据
不可重复读:事务A多次读取同一数据,事务B对该数据进行了操作,导致多次读取数据不一致
幻读:在一个事务中从查询多次数据笔数不一致,可能有另外的事务在此新增了数据
小结:不可重复读和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除
解决不可重复读问题只需锁住满足条件的行,解决幻读需要锁表
MySQL 事务隔离级别?默认是什么级别?
脏读 不可重复读(锁行) 幻读(锁表)
读提交: √ √ √
不可重复读: × √ √
重复读: × × √
串行化: × × ×
乐观锁与悲观锁的区别
乐观锁:假设数据 一般情况霞不会造成冲突
实现:
版本号机制:修改时不加锁在数据库设设置版本号,修改提交时版本号加一,如果数据库版本号大于等于当前加一的版本号时请求被驳回
CAS算法(即比较再交换):对CAS的理解,CAS是一种无锁算法,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
悲观锁:假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁
Mysql数据库两种存储引擎的区别
InnoDB: 支持主外键,支持事务 索引类型是主键索引,通过主键找到文档
Mysaim 不支持主外键,不支持事务 索引类型是文档索引
最左前缀匹配原则及它的原因
在mysql建立联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配
优点:
减少开销 每多一个索引,都会增加写操作的开销和磁盘空间的开销,对于大量数据的表,使用联合索引会大大的减少开销!
效率高 索引列越多,通过索引筛选出的数据越少
大表优化的思路
where和having的区别
分库分表
explain 命令
主从复制如何保证数据的强一致性:
MySql5.5开始,MySQL以插件的形式支持半同步复制。
主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。
MySQL一个表最多支持多少个索引?
16个单索引
BTree与Hash索引的区别?
查找方式 功能
BTree BTree索引可能需要多次运用折半查找来找到对应的数据库块 模糊查询,排序,范围查找,联合索引中最左匹配规则
Hash Hash索引是通过Hash函数,计算出Hash值,在表中找到对应的数据 单个查找
MariaDB和MySQL如何选择?
MariaDB是Mysql的是个分支,Maria是Mysql创始者女儿的名字。
MariaDB提供大量的存储引擎,而MySQL只提供八个存储引擎
MariaDB提供线程池,而在MySQL社区版中,线程数是固定的,在MySQL企业版中有增加线程池的功能
MariaDB可以同步Mysql的数据,而Mysql不能同步MariaDB的数据
MySql有几种锁?
行锁:
间隙锁:
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE
表锁:
意向共享锁:
意向排他锁:
页锁:
死锁:
MyISAM表锁是无死锁的,因为MyISAM总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。
Mysql数据库配置优化:
1.sync_binlog:表示每次事务提交,MySQL都会把binlog刷下去,是最安全但是性能损耗最大的设置。
2.long_query_time:记录慢查询语句
3.
分库分表后如何生成全局ID?
1.通过一个唯一库作为ID生成库,记录每次每次的ID并返回,然后其他库再插入这个ID
2.在系统中生成UUID
3.snowflake算法:推特开源的分布式ID生成算法
定义一个64为的Long型ID, 由 时间戳的二进制,机房编号的二进制,机器的二进制,序列号组成
如果在同一毫秒,同一个机房,同一台机器来了第二条请求,则序列化加一
索引
如何加快数据库查询速度
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断,可以在num上设置默认值0,确保表中num列没有null值
3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描
4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描
5.in 和 not in 也要慎用,否则会导致全表扫描,如:select id from t where num in(1,2,3)对于连续的数值,能用 between 就不要用 in 了
6.硬件性能调整
7.调整数据库(建立索引,调整字段类型)
8.使用存储过程(一次性被设计,编码,测试并再次使用,这样不仅可以模块化,同事提高响应速度,减少网络流量)
聚集索引和非聚集索引的区别
什么时候不该使用索引?
索引底层的数据结构?
B+树做索引比红黑树好在哪里?
红黑树是一种自平衡二叉树,不适合用于索引,因为一旦当数据多起来的时候,二叉树的深度会非常深
而B+树是B-树的变种,一种多路平衡查找树,
MySql索引结构为什么使用B+树不使用B-树?
B+树是B-树的变种,他们两都是多路平衡查找树,他们都是可以在每个节点保存多个范围数据,这使树的深度大大缩减,减少每次查询时的磁盘IO
B+和B-树的区别呢,B+树只有最底层才会存储实际数据,其他层只会保存索引,而B-树每个节点都会保存实际数据和索引,树节点的大小是有限的,所以B+树每个节点储存的索引数,比B-数多很多,所以B+数所做的查询操作会比B-树减少很多
Redis:
项目中 redis 是怎么用的?解决了什么问题?
项目中Redis主要是作为缓存使用,解决并发量高冲击数据到导致数据库压力大,以及加快服务响应速度。
说一下有缓存情况下查询的流程以及有缓存情况下修改的流程。
1.数据查询,先查询缓存中是否命中数据,命中则直接返回,没命中则查询DB数据库
2.数据修改,先验证数据准确性,再删除缓存中数据,再插入数据库
redis有哪些数据结构
list 队列,hash 哈希,String 字符串,Set 集合,Zset 有序集合
redis内存满了怎么办
Redis内部会有一个内存回收机制,回收不常用数据
redis内存淘汰算法除了lru还有哪些
分布式缓存可能出现的问题
数据不一致,高可用
缓存穿透问题
大量请求无法命中缓存,导致流量直接击打到DB数据库,到时数据库宕机。
解决方法:1.使用布隆算法对请求进行过滤。
布隆算法:请求可能误判为已发送过,但是绝对不会错过为发送过的请求。
2.将查询到的null数据也缓存起来,过期时间设置短一点,下次同意请求访问时就可以命中缓存
网络
计算机网络的一些常见状态码
404服务未找到,500服务器错误,200请求成功,400请求数据错误
ping 所使用的协议
ICMP(TCP/IP的子协议)
TCP的三次握手与四次挥手的内容
ack syn
TCP为什么连接是三次握手而断开是四次握手
因为TCP连接就可以确定线路的连通,虽然也无法保证一定没有问题,但是再多次数都无法保证肯定没问题,而四次挥手需要四次才能确定客户端和服务的都关闭了。
TCP与UDP的区别及使用场景
TCP长连接 消息可靠 不易丢失 数据多,请求次数少
UDP短连接 消息不可靠 可能会丢失 数据少量,请求次数多
一次完整的HTTP请求所经的步骤
http 如何保存登录信息(没太搞懂意思)
Cookie 和 Session的关系
Cookie是保存在浏览器
Session是保存在服务器
算法和数据结构
算法
LRU 算法了解吗?你能实现一个吗?
写排序算法(快排、堆排)
数据结构
布隆过滤器了解吗?
设计题
假如有10亿个数,只有一个重复,内存只能放下5亿个数,怎么找到这个重复的数字?
如何设计一个秒杀系统(服务端、数据库、分布式)?分布式系统的设计?
有一个服务器专门接收大量请求,怎么设计?
如果让你自己设计 RPC 框架你会如何设计?
怎么快速出现一个stackoverflow错误?
并发:
Redis分布式锁和ZK分布式锁的优缺点:
消息队列:
消息队列的优点:解耦,异步,削峰
消息队列的缺点:增加运行成本,多出许多需要关注的东西,比如消息丢失,消息重复发送,消息堆积等等,并且消息队列一旦宕机系统将无法运行。
消息队列选型:
名称 吞吐量 社区活跃度 消息可靠性 使用场景
activeMQ: 万级 不活跃 有较低的概率丢失数据 非常稳定,但是社区不活跃后期18年后就没更新了 缺点:社区很不活跃,2018年到至今都没有新版本发布了
rabbitMQ: 万级 活跃 有较低的概率丢失数据 使用erlang语言开发,并发能力很强,性能及其好,延时很低。并且带有可视化管理界面,非常适合中小系统 缺点:吞吐量会低一些,这是因为实现机制比较重
rocketMQ: 十万级 活跃 经过参数优化配置,可以做到0丢失 阿里开源,接口简单易用,日处理上百亿之多,分布性扩展性也很好,支持大规模的topic数量,支持复杂MQ业务场景 缺点:可能到时候阿里不维护这个项目到时候就很难搞
Kafka: 单机万级 活跃 经过参数优化配置,可以做到0丢失 提供较少的核心功能,但是提供超高的吞吐量,ms级的延迟,极高的性能以及可靠性,分布式可以随意扩展 缺点:消息可能重复消费
Kafka如何保证消息的顺序?
存入顺序:kafka内部维护了一个partition的队列,从生产者发送到partition中的数据一定是有序的。
可以指定一个key将这个key的数据全部发送到一个partition中这样就可以保证顺序。
取出后多线程保证顺序:可以定义多个内存queue,具有相同key的数据都到同一个内存queue中,然后每个线程分别对应消费一个内存queue即可
Kafka如何保证消息不丢失?
生产端:配置acks参数,producer要求leader在考虑完成请求之前收到的确认数,用于控制发送记录在服务端的持久化,其值可以为如下:
acks = 0 生产者不会等待来自服务器的任何确认,该记录将记录添加到套接字缓冲区并视为已发送。这种无法保证服务器已收到记录,并且重试配置将不会生效(因为客户端通常不会知道任何故障),为每条记录返回的偏移量始终设置为-1。
acks = 1 保证leader会将记录写入本地日志就返回成功,这种情况下leader在确认记录后立即失败,但数据未复制到follewer,此时记录将会丢失。
acks = -1 保证leader完整的同步副本集才会确认记录,这保证了只要至少一个同步副本仍然存活,记录就不会丢失,这是最强有力的保证。
消费端:关闭自动提交offset,业务处理完之后才改变偏移量。
Kafka消息大量堆积如何处理?
1.创建一个新得Topic设置protition的数量是原来的十倍,然后修改旧的consumer旧的是执行落库操作,修改为将数据插入新的topic中,向公司申请大量机器,去消费新的topic
服务器:
nginx反向代理如何配置:
在nginx.conf中添加如下配置:
server{
listen 80;
server_name www.123.com;
location / {
proxy_pass http://127.0.0.1:8080;
index index.html index.htm index.jsp
}
}
nginx负载均衡算法:
轮询(默认): 轮询
weight: 权重方式
ip_hash: 依据IP分配方式
least_conn: 最少连接方式
fair(第三方): 响应时间
url_hash(第三方): 依据URL分配方式
nginx常用配置:
worker_processes 启动进程,通常设置成和cpu的数量相等
error_log 全局错误日志以及PID文件
events epoll 工作模式已经连接上限(peoll多路复用IO可以大大提高nginx的性能)
worker_connections 单个后台worker process进程的最大并发连接数
keepalive_timeout 连接超时时间
client_header_buffer_size 128k 设置缓冲
tomcat的四种模式:
BIO:tomcat6之前只有BIO,连接数较少的固定架构
NIO:适用于连接数目多且连接比较短(轻操作)的架构
APR(默认):并发最高,首选 利用INI调用本地API,大幅提高了tomcat的IO性能,但是要使用ARP就要安装对应的组件
AIO:Tomcat8以上,用于连接数据多连接比较长(重操作)的结构,充分调用OS参与并发操作
Tomcat优化:
1.IO优化,根据情况选择对应的IO模式
2.线程池优化:开启线程池,设置合适的最大线程数量和,初始最小线程数量
maxThreads:最大线程数
minSpareThreads:初始最小线程数量
3.Connector本身调优:
1.关闭DNS解析,减少性能损耗
2.服务器启用时创建最小线程数
3.最大创建线程数
4.线程池中的线程都被占用,允许放到队列中的请求数
4.禁用AJP连接器,因为使用的Nginx+tomcat的动静态分离架构,所以用不着AJP协议。
tomcat和其他服务器的集成,就是通过ajp协议来完成的。
其他问题:
自我介绍
说说你的项目中的亮点有哪些。
画一下你的项目的架构图。
Restful 了解吗?简单说一下自己对它的认识,如果我要返回一个 boolean 类型的数据怎么办?