面试题大部分来源自科骨铭星感谢大佬!!!
一、Java 基础
1. JDK 和 JRE 有什么区别?
JRE包含了java虚拟机、java基础类库,是使用java语言的编写程序的运行锁需要的软件环境。而 JDK 是程序员开发java程序所需要的开发工具包,提供给程序员使用。
2. == 和 equals 的区别是什么?
- ==是元素符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。
- equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。
3. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
错,不同的两个值,hashCode可能会碰撞出现hashCode()相同
4. final 在 java 中有什么作用?
- 如果形容引用对象,那么该引用不能被改变
- 如果修饰方法,该方法不能被重写
- 如果修饰类,该类不能被继承
- 如果修饰属性,该属性不能被重新赋值
5. java 中的 Math. round(-1. 5) 等于多少?
-1
6. String 属于基础的数据类型吗?
不属于,它属于引用数据类型
7. java 中操作字符串都有哪些类?它们之间有什么区别
- String ,StringBuffer,StringBuilder
- String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
- StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
8. String str="i"与 String str=new String(“i”)一样吗?
不一样 使用String str=“i”,java虚拟机会把它分配到常量池中,而 String str=new String(“i”)创建了一个对象,会被分到堆内存中。
9. 如何将字符串反转?
- 用 StringBuild(str). reverse()
- 转为字符串数组,用空字符串拼接
10. String 类的常用方法都有那些?
length,equals,subString, indexOf,tostring,
11. 抽象类必须要有抽象方法吗?
不是必须的,可以有普通方法
12. 普通类和抽象类有哪些区别?
- 抽象类不可以被实例化,普通类可以被实例化
- 类中有抽象方法一定是抽象类,且抽象类可以有普通方法;
- 普通类不可以有抽象方法,只能有普通方法;
13. 抽象类能使用 final 修饰吗?
不能,因为 final修饰过的不可以被继承
14. 接口和抽象类有什么区别?
- 接口的方法是全部抽象的,不能有普通方法;抽象类能有普通方法和抽象方法
- 接口可以多继承,抽象类只能单继承
- 接口是定义一种功能规范,不做具体实现
15. java 中 IO 流分为几种?
- 按照流的流向分,可以分为输入流和输出流;
- 按照操作单元划分,可以划分为字节流和字符流;
- 按照流的角色划分为节点流和处理流。
16. BIO、NIO、AIO 有什么区别?
- BIO 同步并阻塞
- NIO同步非阻塞
- AIO 异步非阻塞
- Files的常用方法都有哪些?
- exists()检测文件路径是否存在
- createFile()创建文件
- createDirectory()创建文件夹
- delete()删除一个文件或目录
- copy()复制
二、容器
1. java 容器都有哪些?
ArrayList,LinkedList,Vecotr,HashSet,LinkedHashSet,LinkedHashMap,TreeMap,ConcurrentHashMap,HashTable
2. Collection 和 Collections 有什么区别?
Collection是集合的顶级父类, Collections是集合的工具类
3. List、Set、Map 之间的区别是什么?
- List是单列集合,有序不唯一
- Set是单列集合,无序唯一
- Map是键值对结构,Key唯一,Value不唯一 无序
4. HashMap 和 Hashtable 有什么区别?
- Hashtable 同步,线程安全;HashMap非同步,非线程安全
- Hashtable 不允许 "null" 键或值;HashMap 允许一个"null" 键和任意数量的“null”值。
- HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类
5. 如何决定使用 HashMap 还是 TreeMap?
- HashMap基于散列桶(数组和链表)实现;TreeMap基于红黑树实现。
- HashMap不支持排序;TreeMap默认是按照Key值升序排序的,可指定排序的比较器,主要用于存入元素时对元素进行自动排序。
- HashMap大多数情况下有更好的性能,尤其是读数据。在没有排序要求的情况下,使用HashMap。
- 两个都是非线程安全
6. 说一下 HashMap 的实现原理?
hashMap 实现了 Map接口,是存储键值对的接口,key不能重复,value 可以重复。一个键值对成为一个Node对象,。
- HashMap的实现基于哈希表(即数组+链表)
- JDK1. 8中做了优化(即数组+链表+二叉树(红黑树)),当链表长度大于8的时候,把链表转换为红黑树。
- 默认加载因子是0. 75(即默认认为当数组占用75%时达到上限,需要重新散列),默认数组大小是16。
- 存储方式:把key对象通过hash()方法计算出hash值,通过寻址算法:(n - 1) & hash(n为数组长度)一个key的hash值采用了与运算代( & 两个都是1,结果为1;不然是0 )替了取模(因为对于现代的处理器来说,除法和求余数(模运算)是最慢的动作)来决定该对key对象在数组中的存储位置,当该位置有多个对象时,以链表结构存储,在JDK1. 8中当链表长度大于8时,链表将转换为红黑树结构存储。
7. 说一下 HashSet 的实现原理?
- HashSet是基于HashMap实现的,HashSet 底层使用HashMap来保存所有元素
- 因此HashSet 的实现比较简单,相关HashSet 的操作,基本上都是直接调用底层HashMap的相关方法来完成,HashSet不允许有重复的值,并且元素是无序的。
8. ArrayList 和 LinkedList 的区别是什么?
- 底层数据结构不同:ArrayList底层基于数组实现,LinkedList底层基于链表实现
- 适用场景不同: ArrayList更适合随机查找,LinkedList更适合删除和添加
- ArrayList和LinkedList都实现了List接口,但是LinkedList还额外实现了Deque接口,所以LinkedList还可以当双端队列来使用。
9. 如何实现数组和 List 之间的转换?
Array. toList() 转为List; toArray()转为数组;
10. ArrayList 和 Vector 的区别是什么?
- Vector是线程安全的,也就是说它的方法直线是线程同步的,而ArrayList是线程不安全的,它的方法之间是线程不同步的
- ArrayList和Vector可以设置初始的存储空间的大小,Vector还以设置增长空间大小,而ArrayList不可以。
- Vector是增加原来存储空间的两倍,ArrayList没有明文规定,但是从源码中可以看出增长原来存储空间的1. 5倍
11. Array 和 ArrayList 有何区别?
长度:
- Array是数组,声明好之后,其长度就已经固定;- ArrayList底层是用数组实现的,但是ArrayList的长度是可变的,在每次添加时,如果发现空间不足的话,会创建一个长度大概是原来1. 5倍的新数组(java8源码),然后把原来的数组元素复制过去。
12. 在 Queue 中 poll()和 remove()有什么区别?
- remove() 和 poll()都是用来从队列头部删除一个元素。
- 在队列元素为空的情况下,remove() 方法会抛出NoSuchElementException异常,poll()方法只会返回null。
13. 哪些集合类是线程安全的?
- Vectory,HashTable,Stack
- java. util. concurrent包下的所有集合类比如ConcurrentHashMap,CopyOnWriteArryList
14. 迭代器 Iterator 是什么?
迭代器像是游标,专门用来遍历处理集合的
15. Iterator 怎么使用?有什么特点?
集合调用iterator()方法,返回Iterator对象,可以通过hasNext 判断是否有下一元素,调用 next()方法返回元素值
16. Iterator 和 ListIterator 有什么区别?
- ListIterator有add()方法,可以向List中添加对象,而Iterator不能
- ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
- ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
- 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。
17. 怎么确保一个集合不能被修改?
- 可以采用Collections包下的unmodifiableMap(Map)方法,返回的map是不可以修改的。他会报java. lang. UnsupportedOperationException错。
- Collections. unmodifiableList(List) 返回的list是不可以修改的
- Collections. unmodifiableSet(Set) 返回的set是不可以修改的
三、多线程
1. 并行和并发有什么区别?
- 并行是多个处理器同一时刻执行多个不同的任务;
- 并发是一个处理器同时处理多个任务,cpu快速轮转,表现为同时执行。
2. 线程和进程的区别?
- 线程是进程的执行单元实体,任何一个进程都至少有一个线程
- 进程是系统进行资源分配和调度的一个独立单位。多线程的进程程序能表现出更高的并发现
3. 守护线程是什么?
守护线程是一种特殊的线程,他用来服务与其他线程,只有当虚拟机停止,他才退出。
4. 创建线程有哪几种方式?
继承Thread
实现Runnerbale接口
实现Callable接口
ThredPoolExecutor 线程池
- ThreadPoolExecutors 参数详解
- corePoolSize:核心线程池数,核心线程数一直存活,即便没有任务执行。- maximumPoolSize:当核心线程数已满,阻塞队列已满时候,会继续创建线程总线程数不超过 max- keepAliveTime 线程空闲时间,当线程空闲时间超过就销毁,最少保留核心线程数- Unit 空闲时间单位- workQueue 阻塞队列- rejectedExecutionHandler 拒绝策略
5. 说一下 runnable 和 callable 有什么区别?
- Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果;
- Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛;
6. 线程有哪些状态?
- 新建状态,new Thread()
- 就绪状态调用了 start()等待cpu执行
- 运行状态
- 阻塞状态因为某一种原因放弃CPU ,比如 sleep,join
- 死亡状态
7. sleep() 和 wait() 有什么区别?
- sleep ()是线程的方法 ,wait()是Object的方法
- sleep ()可以在任何地方使用,wait()只能在同步方法或者同步代码块中使用,
- wait()会释放锁资源,sleep()不会。
8. notify()和 notifyAll()有什么区别?
notify() 随机唤醒等待这个锁的线程,notifyAll()是唤醒所有
9. 线程的 run()和 start()有什么区别?
- run() 是一个普通方法,直接调用会在当前线程中执行run()中的代码,不会创建新线程。
- 当程序调用start()方法,将会创建一个新线程去执行run()方法中的代码。
- 另外当一个线程启动之后,不能重复调用start(),否则会报IllegalStateException异常。但是可以重复调用run()方法。
10. 创建线程池有哪几种方式?
Excutors线程池工具类,使用ThreadpoolExcutor
11. 线程池都有哪些状态?
- RUNNING:运行状态,线程池创建好之后就会进入此状态,如果不手动调用关闭方法,那么线程池在整个程序运行期间都是此状态。
- SHUTDOWN:关闭状态,不再接受新任务提交,但是会将已保存在任务队列中的任务处理完。
- STOP:停止状态,不再接受新任务提交,并且会中断当前正在执行的任务、放弃任务队列中已有的任务。
- TIDYING:整理状态,所有的任务都执行完毕后(也包括任务队列中的任务执行完),当前线程池中的活动线程数降为 0 时的状态。到此状态之后,会调用线程池的 terminated() 方法。
- TERMINATED:销毁状态,当执行完线程池的 terminated() 方法之后就会变为此状态。
默认情况下,如果不调用关闭方法,线程池会一直处于 RUNNING 状态,而线程池状态的转移有两个路径:当调用 shutdown() 方法时,线程池的状态会从 RUNNING 到 SHUTDOWN,再到 TIDYING,最后到 TERMENATED 销毁状态;当调用 shutdownNow() 方法时,线程池的状态会从 RUNNING 到 STOP,再到 TIDYING,最后到 TERMENATED 销毁状态。
12. 线程池中 submit()和 execute()方法有什么区别?
接收参数不一样
- execute()方法只能接收Runnable类型的参数- submit()方法可以接收Callable、Runnable两种类型的参数。Callable类型的任务是可以返回执行结果的,而Runnable类型的任务不可以返回执行结果。
submit()提交任务后会有返回值,而execute()没有
submit()方便Exception处理
- execute()方法在启动任务执行后,任务执行过程中可能发生的异常调用者并不关心。- submit()方法返回的Future对象(异步执行实例),可以进行异步执行过程中的异常捕获。
在ThreadPoolExecutor类的实现中,内部核心的任务提交方法是execute()方法,虽然用户程序通过submit()也可以提交任务,但是实际上submit()方法中最终调用的还是execute()方法。
13. 线程池的原理?
当调用线程池的 execute() 方法时,线程池会做出以下判断:
- 如果当前运行的线程小于线程池的核心线程数,那么马上创建线程完成这个任务。
- 如果运行中的线程数大于等于线程池的核心线程数,那么将线程放进任务队列等待。
- 如果此时任务队列已满,且正在运行的线程数小于最大线程数,立即创建非核心线程执行这个任务。
- 如果此时任务队列已满,且正在运行的线程数等于最大线程数,则线程池会启动饱和拒绝策略来执行。
当一个任务完成时,它会从任务队列的对头去出下一个任务来执行。
当一个线程空闲超过一定时间时,线程池会判断当前运行线程数是否大于核心线程数,如果大于核心线程数,该线程就会被停掉,直至当前线程数等于核心线程数。
14. 线程池的参数应该怎么设置比较合理?
Java线程池中各个参数的合理设置方法 - 开发技术 - 亿速云
15. 在 java 程序中怎么保证多线程的运行安全?
- 互斥同步,同一时刻只让一个线程运行一段代码,阻塞同步,比如synconized,Lock
- 非阻塞同步:基于乐观的想法,先去执行,后进行校验是否与修改前一致,他的实现是CAS
- 线程本低存储如 ThreadLocal,数据不共享
- 还有可能不涉及数据共享,也就不需要管了,自然就是安全的。
16. 多线程锁的升级原理是什么?
锁升级的原理
没有优化以前,synchronized是重量级锁(悲观锁),使用 wait 和 notify、notifyAll 来切换线程状态非常消耗系统资源;线程的挂起和唤醒间隔很短暂,这样很浪费资源,影响性能。所以 JVM 对 synchronized 关键字进行了优化,把锁分为 无锁、偏向锁、轻量级锁、重量级锁 状态。
锁的级别从低到高依次为:无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级。
17. 什么是死锁?
所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁。如下图所示:
产生死锁的必要条件:
- 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
- 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
- 环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。
18. 怎么防止死锁?
预防死锁–针对死锁的必要条件进行预防
- 破坏占有且等待条件,一次性申请进程所需要的所有资源。改进:允许进程只获得运行初期的资源,在运行过程中逐步释放使用完毕的资源,申请需要的资源。- 破坏不可抢占条件:当一个进程申请需要的资源没有被满足时,释放掉所占有的所有资源。- 破坏循环等待条件:给每个资源编号,当一个进程占有某个资源时,只能申请比这个编号大的资源
- 避免死锁–在分配资源之前判断是否会出现死锁
- 若一个进程的请求会导致死锁,则不启动。
19. ThreadLocal 是什么?有哪些使用场景?
ThreadLocal 是什么?有哪些使用场景?_ConstXiong的博客-CSDN博客_threadlocal是什么
ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。
经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection; 还有 Session 管理 等问题。
20. ThreadLocal的实现原理?
ThreadLocal原理详解--终于弄明白了ThreadLocal_三七有脾气的博客-CSDN博客_threadlocal原理
ThreadLocal存入值时使用当前ThreadLocal实例作为key,存入当前线程对象中的Map中去。最开始在看源码之前,我以为是以当前线程对象作为key将对象存入到ThreadLocal中的Map中去…
21. ThreadLocal的内存泄露是怎么回事?怎么解决?
如果ThreadLocal没有外部强引用,那么在发生垃圾回收的时候,ThreadLocal就必定会被回收,而ThreadLocal又作为Map中的key,ThreadLocal被回收就会导致一个key为null的entry,外部就无法通过key来访问这个entry,垃圾回收也无法回收,这就造成了内存泄漏
解决方案:
解决办法是每次使用完ThreadLocal都调用它的remove()方法清除数据,或者按照JDK建议将ThreadLocal变量定义成private static,这样就一直存在ThreadLocal的强引用,也就能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值,进而清除掉。
22. 说一下 synchronized 底层实现原理?
真正从底层理解 Synchronized 实现原理 - 张贤同学 - 博客园
23. synchronized 和 volatile 的区别是什么?
应用范围:volatile-变量;synchronized -方法以及代码块
是否保证原子性:volatile 可以保证可见性和有序性,不能保证原子性,禁止指令重排;synchronized在保证可见性和有序性的基础上,还可以保证原子性。
- volatile变量的原子性与synchronized的原子性是不同的。synchronized的原子性是指,只要声明为synchronized的方法或代码块,在执行上就是原子操作,synchronized能保证被锁住的整个代码块的原子性。而volatile是不修饰方法或代码块的,它只用来修饰变量,对于单个volatile变量的读和写操作都具有原子性,但类似于volatile++这种复合操作不具有原子性。所以volatile的原子性是受限制的。所以,在多线程环境中,volatile并不能保证原子性。
使用场景:volatile主要用于解决共享变量的数据可见性问题,而synchronized主要用于保证访问数据的同步性(同时也能保证可见性)
保证有序性的方式:
- volatile的有序性是通过禁止指令重排序来实现的- synchronized无法禁止指令重排,但是可以通过单线程机制来保证有序性。由于synchronized修饰的代码,在同一时刻只能被一个线程访问,从根本上避免了多线程的情况。而单线程环境下,在本线程内观察到的所有操作都是天然有序的,所以synchronized可以通过单线程的方式来保证程序的有序性。
性能方面:
- volatile是线程同步的轻量级实现,性能高于synchronized。- 多线程访问volatile修饰的变量时不会发生阻塞(主要是因为volatile采用CAS加锁),而访问synchronized修饰的资源时会发生阻塞。
24. synchronized 和 Lock 有什么区别?
- synchronized是内置的java关键字,Lock是一个java类。
- synchronized无法判断是否获取到了锁,Lock可以判断是否获取到了锁。
- synchronized会自动释放锁,Lock必须手动释放锁。
25. synchronized 和 ReentrantLock 区别是什么?
- synchronized 可用来修饰方法、和代码块,而 ReentrantLock 只能用在代码块上
- synchronized 会自动加锁和释放锁; 而 ReentrantLock 需要手动加锁和释放锁
- synchronized 属于非公平锁,而 ReentrantLock 既可以是公平锁也可以是非公平锁
26. 说一下 atomic 的原理?
atomic通过CAS (Compare And Wwap)乐观锁机制-自旋锁(它的实现很简单,就是用一个预期的值和内存值进行比较,如果两个值相等,就用预期的值替换内存值,并返回 true。否则,返回 false。)保证原子性,【通过降低锁粒度(多段锁)增加并发性能。这一点是java8做出的改进】从而避免 synchronized 的高开销,执行效率大为提升。
27. 线程同步的方式有哪些?
- java 同步线程方式_延成的博客-CSDN博客_java线程的同步方式
28. AQS原理?AQS中为什么要使用双向队列?为什么AQS中的状态用volatile修饰? 说一下volatile的原理
AQS(AbstractQueuedSynchronizer)抽象队列式同步器原理:
如果被请求的资源是共享的空闲的,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待 以及 被唤醒时 锁分配的 机制,这个机制 AQS 是用state 和 CLH 队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
用大白话来说,AQS就是基于CLH队列,用volatile修饰共享变量state,线程通过CAS去改变状态符,成功则获取锁成功,失败则进入等待队列,等待被唤醒。
AQS中为什么要使用双向队列:
中断
- 用于在AQS#acquireInterruptibly(int arg)获取锁的过程中处理中断信号。- 我们知道,相比于线程获取synchronized锁的过程中不能被中断,基于AQS实现的ReentrantLock是在获取锁的过程中是可被中断的。
唤醒
- AQS对CLH进行了改进,后继获取锁的线程在经过有限次的轮询后,依旧获取不到锁将陷入阻塞。优点:减少轮询无效操作;缺点:后继线程Node在阻塞后无法感知前一个线程Node的状态,锁被释放时将无法主动醒来。- 于是AQS使用了双指针,在CLH的prev基础上增加了next。AQS维护了next指针,以便活跃线程释放锁后主动唤醒后续阻塞线程去竞争锁。
为什么AQS中的状态用volatile修饰:
volatile + CAS实现非阻塞式线程同步:通过Syncronized的方式当然可以实现线程同步,但是消耗太大;AQS框架使用volatile + CAS实现非阻塞式线程同步,线程同步需要保证3个方面:可见性、有序性、原子性,volatile保证了变量的可见性和有序性,用CAS操作保证变量的原子性。
volatile原理:
工作内存Work Memory其实就是对CPU寄存器和高速缓存的抽象,或者说每个线程的工作内存也可以简单理解为CPU寄存器和高速缓存。
那么当写两条线程Thread-A与Threab-B同时操作主存中的一个volatile变量i时,Thread-A写了变量i,那么:
- Thread-A发出LOCK#指令- 发出的LOCK#指令锁总线(或锁缓存行),同时让Thread-B高速缓存中的缓存行内容失效- Thread-A向主存回写最新修改的i
- Thread-B读取变量i,那么:
- Thread-B发现对应地址的缓存行被锁了,等待锁的释放,缓存一致性协议会保证它读取到最新的值
由此可以看出,volatile关键字的读和普通变量的读取相比基本没差别,差别主要还是在变量的写操作上。
29. CAS原理?
阿里二面,面试官:说说 Java CAS 原理?_爱笑的架构师的博客-CSDN博客
CAS 主要包括两个操作:Compare和Swap,有人可能要问了:两个操作能保证是原子性吗?可以的。
CAS 是一种系统原语,原语属于操作系统用语,原语由若干指令组成,用于完成某个功能的一个过程,并且原
30. 有哪些拒绝策略?
juc - 线程池之四种拒绝策略 - 简书
- AbortPolicy:直接抛出异常,默认策略;
- CallerRunsPolicy:用调用者所在的线程来执行任务;
- DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
- DiscardPolicy:直接丢弃任务;
31. 我有一个需求,多个线程同时执行,最终要等所有线程跑完,再把多个线程的结果数据合并,可以怎么实现?
ForkJoin或者CompletableFuture (待补充)
32. 我想先执行线程1,线程1执行完之后,拿线程1的结果传到线程2继续处理,怎么实现?
CompletableFuture (待补充)
四、反射
1. 什么是反射?
运行状态下,对于任意一个类,都能够知道它所有的属性和方法,对于任意一个对象,都能够调用他的属性和方法,这种能力就是反射
2. 什么是 java 序列化?什么情况下需要序列化?
就是把java对象存储在某一个地方,比如硬盘或者网络上,把内容进行流化。
当你需要把对象在网络上传输,或者保存在文件上,就需要进行序列化
3. 动态代理是什么?有哪些应用?
在程序运行期间,创建目标对象的代理对象,并对目标对象中的方法进行功能扩展;AOP就是动态代理的一种应用
4. 怎么实现动态代理?
定义一个代理对象类,声明静态获取instance实例目标方法,返回 Proxy. newProxyInstance, 重写 invoke方法
五、对象拷贝
1. 为什么要使用克隆?
能够快速复制对象内容
2. 如何实现对象克隆?
类实现CloneAble接口,重写 clone 方法
3. 深拷贝和浅拷贝区别是什么?
深拷贝是复制出新的对象,浅拷贝是复制了引用,对象还是同一块内存
六、Java Web
1. jsp 和 servlet 有什么区别?
- Servlet在Java代码中可以通过HttpServletResponse对象动态输出HTML内容。
- JSP是在静态HTML内容中嵌入Java代码,然后Java代码在被动态执行后生成HTML内容。
2. jsp 有哪些内置对象?作用分别是什么?
Application
- application对象代表应用程序上下文,它允许JSP页面与包括在同一应用程序中的任何Web组件共享信息。
config
- Config对象允许将初始化数据传递给一个JSP页面。
Exception
- Exception对象含有只能由指定的JSP“错误处理页面”访问的异常数据。
Out
- Out对象代表提供输出流的访问。
Page
- Page对象代表JSP页面对应的Servlet类实例
PageContext
- PageContext对象是Jsp页面本身的上下文,它提供唯一一组方法来管理具有不同作用域的属性。
Request
- Request对象提供对Http请求数据的访问,同时还提供用于加入特定请求数据的上下文
Response
- Response对象允许直接访问HttpServletResponse对象
Session
- Session对象可能是状态管理上下文中使用最多的对话
3. 说一下 jsp 的 4 种作用域?
page域
- 即pageContext。page对象的作用范围仅限于用户请求的当前页面。如果把变量放到pageContext里,就说明它的作用域page,它的有效范围只在当前jsp页面里。
request域
- request里的变量可以跨越forward前后的两页。但是只要刷新页面,它们就重新计算了。如果把变量放到request里,就说明它的作用域是request,它的有效范围是当前请求周期。因为请求对象对于每一个客户请求都是不同的,所以对于每一个新的请求,都要重新创建和删除这个范围内的对象。主要用于一次请求在不同页面间的操作及参数传递,如表单的参数传递。
session域
- 如果把变量放到session里,就说明它的作用域是session,它的有效范围是当前会话,即从用户打开浏览器开始,到用户关闭浏览器这中间的过程。session的生命周期是在服务器正常的情况下,在第一次调用request. getSession()方法时到程序调用HttpSession. invalidate()销毁该session时结束。当然你也可以在网页F12控制台删除session。主要是网站用户的信息。
application域
- application即是ServeltContext,它的有效范围是整个应用,即整个web适用。ServletContext生命周期在服务器启动时创建,在服务器关闭时销毁。主要用于每个用户都可以访问的数据或多个客户端共享的数据
4. session 和 cookie 有什么区别?
- 数据存储位置:cookie数据存放在客户的浏览器上,session数据放在服务器上。
- 安全性:cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
- 服务器性能:session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
- 数据大小:单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- 信息重要程度:可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。
5. 说一下 session 的工作原理?
https://www.jb51.net/article/191825.htm
- 用户第一次请求服务器时,服务器端会生成一个sessionid
- 服务器端将生成的sessionid****返回给客户端,通过set-cookie
- 客户端收到****sessionid会将它保存在cookie中,当客户端再次访问服务端时会带上这个sessionid
- 当服务端再次接收到来自客户端的请求时,会先去检查是否存在sessionid,不存在就新建一个sessionid重复1,2的流程,如果存在就去遍历服务端的session文件,找到与这个sessionid相对应的文件,文件中的键值便是sessionid,值为当前用户的一些信息
- 此后的请求都会交换这个 Session ID,进行有状态的会话。
6. 如果客户端禁止 cookie 能实现 session 还能用吗?
不能。服务器端调用了requet. getSession()的时候, 产生session对象。创建session的同时 生成sessionId(代表唯一sesssion的字符串), 服务器自动通过Cookie的方式写给浏览器。下次浏览器携带cookie(SessionId)找到对应的session使用。如果用户禁用cookie,则cookie(SessionId)无法存储,浏览器每次访问都不携带任何cookie,包括cookie(SessionId)。
7. spring mvc 和 struts 的区别是什么?
Springmvc与Struts区别? - 牧码良匠 - 博客园
spring mvc 和 struts2的加载机制不同:SpringMVC的入口是Servlet,而Struts2是Filter。
拦截机制
- Struts2框架是类级别的拦截,每次请求就会创建一个Action,一个Action对应一个Request- SpringMVC是方法级别的拦截,**一个方法对应一个Request **
SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。
8. 如何避免 sql 注入?
- 过滤掉关键字:select、insert、update、delete、and等;
- 执行 sql语句时使用系统函数addslashes进行** sql语句转换**
- 提高数据库命名技巧,对于一些重要字段根据程序特点命名,取不易猜到的(lcuuid as uuid)
- 对于常用的方法加以封装,避免直接暴露sql语句,例如 orm
- 开启安全模式,safe_mode=on
- 打开magic_quotes_gpc=off,默认是关闭的,它打开后自动把用户提交的sql语句进行转换(加上\转义),这对防止sql注入有很大作用;on
- Sql语句书写尽量不要省略双引号和单引号
- 关键日志错误信息不要暴漏到页面,转到系统中去
9. 什么是 XSS 攻击,如何避免?
XSS攻击及防御_高爽 Coder的博客-CSDN博客_xss攻击的防御
XSS又称CSS,全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性。
避免:
- 使用Apache的commons-lang. jar
- StringEscapeUtils. escapeHtml(str);// 汉字会转换成对应的ASCII码,空格不转换
- 自己实现转换,只转换部分字符
- private static String htmlEncode(char c) {
switch(c) {
case '&':
return "&";
case '<':
return "<";
case '>':
return ">";
case '"':
return """;
case ' ':
return " ";
default:
return c + "";
}
}
10. 什么是 CSRF 攻击,如何避免?
什么是 CSRF 攻击?如何防范 CSRF 攻击?_不可爱仙女的博客-CSDN博客_检测到csrf攻击
CSRF攻击指的是跨站请求伪造
避免:
- 同源检测- CSRF Token- 双重Cookie验证- 在设置Cookie属性的时候设置Samesite
七、异常
1. throw 和 throws 的区别?
- Throw 是在方法内使用,抛出的是具体异常对象实例。
- Throws 是在方法声明上使用,申明抛出了什么异常,或者有哪些可能发生需要捕捉的异常
2. final、finally、finalize 有什么区别?
- final是修饰符,修饰方法,变量,类,无法被修改或者被重写;
- finally是异常捕捉后必然执行的代码块;
- finalize是 gc回收前调用该对象这finalize()的方法
3. try-catch-finally 中哪个部分可以省略?
Catch 和finally可以省略,但是不能同时省略
4. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
会执行。try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗.
5. 常见的异常类有哪些?
什么是异常以及常见的异常类型有哪些_菜鸟也学大数据的博客-CSDN博客_异常类型有哪些
- ArithmeticException 算数异常
- NullPointException 空指针异常
- ArrtIdexOutOfBoundException 数组越界异常
- InsexOutOfBoundException 索引越界异常
- ClassCastException 类型转换异常
- InputFormatException 输入类型不匹配
- IOException 输入输出异常
- SQLException SQL异常
- IllegalArgumentException 非法参数异常
八、网络
1. http 响应码 301 和 302 代表的是什么?有什么区别?
http 协议的 301 和 302 状态码都代表重定向。
区别:
- 301 表示被请求 url 永久转移到新的 url;302 表示被请求 url 临时转移到新的 url。
- 301 搜索引擎会索引新 url 和新 url 页面的内容;302 搜索引擎可能会索引旧 url 和 新 url 的页面内容。
2. forward 和 redirect 的区别?
foward是服务器内部的重定向,客户端地址不变,无感知。Redirect客户端新的跳转页面,有请求状态
3. 简述 tcp 和 udp的区别?
TCP和UDP的区别_ZJE_ANDY的博客-CSDN博客_tcp和udp区别
- TCP是面向连接的,UDP是面向无连接的
- TCP是可靠的,UDP是不可靠的
- TCP是面向字节流的,UDP是面向报文的
- TCP只有一对一的传输方式,而UDP不仅可以一对一,还可以一对多,多对多
- UDP的头部开销小,TCP的头部开销大
4. tcp 为什么要三次握手,两次不行吗?为什么?
TCP为什么是三次握手?两次、四次握手不行吗?
两次握手只能保证单向连接是畅通的。因为TCP是一个双向传输协议,只有经过第三次握手,才能确保双向都可以接收到对方的发送的数据。
5. 说一下 tcp 粘包是怎么产生的?
TCP粘包产生的原因、解决办法_HIT文峯的博客-CSDN博客_tcp 粘包
tcp 粘包可能发生在发送端或者接收端:
- 发送端粘包:发送端需要等缓冲区满才发送出去,造成粘包;- 接收方粘包:接收方不及时接收缓冲区的包,造成多个包接收。
6. OSI 的七层模型都有哪些?
java网络:6、OSI 的七层模型都有哪些?_JAVA小摩托不堵车的博客-CSDN博客
7. get 和 post 请求有哪些区别?
get请求和post请求的区别(全面讲解)_心动的偏执的博客-CSDN博客_get请求和post请求的区别
- get请求一般是去取获取数据(其实也可以提交,但常见的是获取数据);post请求一般是去提交数据。
- get因为参数会放在url中,所以隐私性,安全性较差,请求的数据长度是有限制的;post请求是没有的长度限制,请求数据是放在body中
- get请求刷新服务器或者回退没有影响,post请求回退时会重新提交数据请求。
- get请求可以被缓存,post请求不会被缓存。
- get请求只能进行url编码(appliacation-x-www-form-urlencoded),post请求支持多种(multipart/form-data等)。
8. 如何实现跨域?
你应该知道的10 种跨域解决方案(附终极方案)_高级盘丝洞的博客-CSDN博客_后端跨域问题解决方案
CORS
- 跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器「不同的域、协议或端口」请求一个资源时,资源会发起一个「跨域 HTTP 请求」。
Node 正向代理
- 代理的思路为,利用服务端请求不会跨域的特性,让接口和当前站点同域。
Nginx 反向代理
- Nginx 则是通过反向代理的方式,(这里也需要自定义一个域名)这里就是保证我当前域,能获取到静态资源和接口,不关心是怎么获取的。
9. 说一下 JSONP 实现原理?
JSONP的实现原理_过客尘烟的博客-CSDN博客_jsonp如何实现
由于浏览器的安全性(同源策略)限制,不允许AJAX访问 协议不同、域名不同、端口号不同的 数据接口,浏览器认为这种访问不安全;
可以通过动态创建script标签的形式,把script标签的src属性,指向数据接口的地址,因为script标签不存在跨域限制,这种数据获取方式,称作JSONP(注意:根据JSONP的实现原理,知晓,JSONP只支持Get请求);
具体实现过程:
- 先在客户端定义一个回调方法,预定义对数据的操作;- 再把这个回调方法的名称,通过URL传参的形式,提交到服务器的数据接口;- 服务器数据接口组织好要发送给客户端的数据,再拿着客户端传递过来的回调方法名称,拼接出一个调用这个方法的字符串,发送给客户端去解析执行;- 客户端拿到服务器返回的字符串之后,当作Script脚本去解析执行,这样就能够拿到JSONP的数据了;
10. 如何解决重复提交:
幂等问题 8种方案解决重复提交 - 掘金
前端控制提交按钮的禁用启用
Post-Redirect-Get (PRG)模式。在提交后执行页面重定向
session-隐藏域
- 在服务器端,生成一个唯一的标识符,将它存入session, 同时将它写入表单的隐藏字段中,然后将表单页面发给浏览器, 用户录入信息后点击提交,在服务器端,获取表单中隐藏字段 的值,与session中的唯一标识符比较,相等说明是首次提交, 就处理本次请求,然后将session中的唯一标识符移除;不相等 说明是重复提交,就不再处理。
借助分布式Redis锁
- opsForValue(). setIfAbsent(key,value)它的作用就是如果缓存中没有当前 Key 则进行缓存同时返回 true 反之亦然;当缓存后给 key 在设置个过期时间,防止因为系统崩溃而导致锁迟迟不释放形成死锁; 那么我们是不是可以这样认为当返回 true 我们认为它获取到锁了,在锁未释放的时候我们进行异常的抛出
九、设计模式
1. 说一下你熟悉的设计模式?
- (1) 单例模式:保证一个类只有一个实例(Spring中bean的作用域默认就是单例的(Singleton))(懒汉式、饿汉式、双重检查机制、静态内部类)
- 工厂模式:工厂类根据条件生成不同的子类,这些子类有一个公共的抽象父类并且实现了相同的方法,同时这些方法针对不同的数据有不同的操作,即多态方法。(当得到子类的实例后,开发人员可以调用基类中的方法而不需要考虑返回的是哪一个子类的实例) 解耦代码
- 代理模式:给对象提供一个代理对象,由这个代理对象控制原对象的引用。
2. 简单工厂和抽象工厂有什么区别?
简单工厂模式
- 是由一个工厂对象创建产品实例,简单工厂模式的工厂类一般是使用静态方法,通过不同的参数的创建不同的对象实例- 可以生产结构中的任意产品,不能增加新的产品
抽象工厂模式
- 提供一个创建一系列相关或相互依赖对象的接口,而无需制定他们具体的类,生产多个系列产品- 生产不同产品族的全部产品,不能新增产品,可以新增产品族
十、Spring/Spring MVC
1. 为什么要使用 spring?
- 方便解耦,便于开发,
- spring支持 AOP可以方便的实现对程序进行添加额外非系统性业务逻辑
- 支持声明式事务
- 提供了大量的API 降低了开发难度,
- 易于集成其他框架
2. 解释一下什么是 AOP?
他是面向切面的简称,通过动态代理模式在程序运行期间,给程序统一添加功能的一种技术。
前置通知、后置通知、返回通知、异常通知、环绕通知
3. 解释一下什么是IOC?
在java中我们以new 关键字进行创建对象,有IOC后让 spring容器帮我们创建需要的依赖对象,我们只需要告诉spirng你需要创建的对象是什么,可以通过 @Bean 或者 @Compent等注解被spring容器扫描读取
4. spring 有哪些主要模块?
- Spring core 提供了IOC容器,对bean进行管理
- Spring context
- Spring DAO 提供了 jdbc
- Spring ORM 提供了常用的对象映射层,与 JPA、mybatis、hebernate 集成
- Spring Web 提供了web开发的上下文信息,提供了与其他Web集成的环境
- Spring AOP
- Spring mvc 提供了 model-view -controller的mvc 结构的实现
5. spring 常用的注入方式有哪些?
- 构造方法注入
- 属性注入 @Autowird
- Set 注入给 set方法增加 @Autowid注解
6. spring 中的 bean 是线程安全的吗?
在Spring中,只有有状态的单例Bean才会存在线程安全问题。
Spring 创建的bean 是有作用域的,默认的spirng bean的作用域都是单例。
单例分为无状态和有状态的,在Spring 中创建的Service. Dao这些对象,只是查询不做修改,是无状态的,也就没有线程风险。在多线程操作中如果需要对Bean中的成员变量进行数据更新操作,这样的Bean称之为有状态Bean,所以,有状态的单例Bean就可能存在线程安全问题。
而多例的,每次线程访问都会创建新的类型,所以不存在数据共享的问题
7. spring 支持几种 bean 的作用域?
- singleton(单例模式)
- prototype(原型模式)
- request(HTTP请求)
- session(会话)
- global-session(全局会话)
8. spring 自动装配 bean 有哪些方式?
spring 自动装配 bean 有哪些方式?_begefefsef的博客-CSDN博客_spring自动装配bean有哪些方式
- default - 默认的方式和 “no” 方式一样
- no - 不自动装配,需要使用 节点或参数
- byName - 根据名称进行装配
- byType - 根据类型进行装配
- constructor - 根据构造函数进行装配
9. spring 事务实现方式有哪些?
spring事务实现的几种方式_沉泽·的博客-CSDN博客_spring事务有几种方式
- 编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
- 基于 TransactionProxyFactoryBean的声明式事务管理
- 基于 @Transactional 的声明式事务管理
- 基于Aspectj AOP配置事务
10. 说一下 Spring 的事务隔离?
Spring 事务隔离_春风化作秋雨的博客-CSDN博客_spring事务隔离
ISOLATION_DEFAULT
- 使用数据库设置的隔离级别,数据库设置的是什么就用什么。
READ_UNCOMMITTED (读未提交)
- 读未提交,最低隔离级别。事务未提交前,数据就可被其他事务读取(会出现幻读、脏读、不可重复读)。
READ_COMMITTED (读已提交)
- 读已提交,一个事务提交后,才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别。
REPEATABLE_READ (可重复读)
- 可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别。
SERIALIZABLE(串行化)
- 序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读
11. 说一下 Spring mvc 运行流程?
- 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获(捕获);
- DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;(查找handler);
- DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller), Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象(执行handler);
- DispatcherServlet 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver) (选择ViewResolver);
- 通过ViewResolver 结合Model和View,来渲染视图,DispatcherServlet 将渲染结果返回给客户端。(渲染返回);
快速记忆技巧:
核心控制器捕获请求、查找Handler、执行Handler、选择ViewResolver,通过ViewResolver渲染视图并返回;
12. Spring mvc 有哪些组件?
- 前端控制器
- 处理器映射器
- 处理器适配器
- 视图解析器
- 视图渲染
13. @RequestMapping 的作用是什么?
用来处理请求地址映射的注解
- 类级别:表示映射请求的URL地址;- 方法级别:表示映射请求的URL地址以及对应的HTTP请求方法。
14@Autowired 的作用是什么?
@Autowired是Spring对组件自动装配的一种方式。常用于在一个组件中引入其他组件
十一、Spring Boot
1. 什么是 spring boot?
他是基于spring+maven项目的快速整合构建框架,提供了各种启动器,能快速整合框架,不需要繁琐的配置文件
2. 为什么要用 spring boot?
- 可以独立运行,不需要依赖外界容器
- 减少了mven依赖,被打包到starter了,
- 能够自动装配,无需繁琐的xml文件
3. spring boot 核心配置文件是什么?
application. properties文件,存储的是键值对的数据信息
4. Spring boot 配置文件有哪几种类型?它们有什么区别?
两种。. properties 和. yml文件;前者是属性通过. 来连接,后者是显示为有层级结构的形式,更容易观察
5. spring boot 有哪些方式可以实现热部署?
有热部署 jar springboot-dev-toos
十二、Spring Cloud
「面试必背」Spring Cloud面试题(2022最新版)_柚子茶1990的博客-CSDN博客_springcloud面试题
1. 什么是微服务架构?
微服务架构就是将单体的应用程序分成多个应用程序,这多个应用程序就成为微服务,每个微服务运行在自己的进程中,并使用轻量级的机制通信。
2. ** Spring Cloud 是什么?**
Spring Cloud就是微服务系统架构的一站式解决方案,是各个微服务架构落地技术的集合体, 俗称微服务全家桶
3. SpringCloud的优缺点
优点:
- 耦合度比较低。不会影响其他模块的开发。
- 减轻团队的成本,可以并行开发,不用关注其他人怎么开发,先关注自己的开发。
- 配置比较简单,基本用注解就能实现,不用使用过多的配置文件。
- 微服务跨平台的,可以用任何一种语言开发。
- 每个微服务可以有自己的独立的数据库也有用公共的数据库。
- 前后端拆分,后端暴露接口,通过组件进行服务通信。
缺点:
- 部署较麻烦,给运维工程师带来一定的麻烦。
- 针对数据的管理较麻烦,因为微服务可以每个微服务使用一个数据库。
- 系统集成测试较麻烦
- 性能的监控较麻烦。【最好开发一个大屏监控系统】
总的来说优点大过于缺点,目前看来Spring Cloud是一套非常完善的分布式框架,目前很多企业开始用微服务、Spring Cloud的优势是显而易见的。因此对于想研究微服务架构的同学来说,学习Spring Cloud是一个不错的选择。
4. SpringBoot和SpringCloud的区别?
SpringBoot专注于快速方便的开发单个个体微服务。
SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,
- 为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
SpringBoot可以离开SpringCloud独立使用开发项目, 但是SpringCloud离不开SpringBoot ,属于依赖的关系
SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。
5. Spring Cloud和SpringBoot版本对应关系
6. SpringCloud有哪些
7. Spring Cloud 和Dubbo区别?
服务调用方式:
- Dubbo使用RPC (Remote Procedure Call)远程过程调用- Spring Cloud使用Rest Api
注册中心:
- Dubbo使用了Zookeeper注册中心- Spring Cloud可以选择使用 EureKa,Zookeeper,Consul,Nacos
服务网关:
- Dubbo本身没有实现,只能通过其他第三方技术整合- Spring Cloud有Zuul路由网关(或者GetWay),作为路由服务器,进行消费者的请求分发,Spring Cloud支持断路器,与Git完美集成配置文件支持版本控制,事物总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素
8. 服务注册和发现是什么意思?Spring Cloud 如何实现?
服务在发布时 指定对应的服务名(服务名包括了IP地址和端口) 将服务注册到注册中心;注册中心对注册的服务进行管理
可以使用Eureka,Consul,Nacos,Zookeeper
9. Eureka怎么实现高可用?
- 集群,注册多台Eureka,然后把SpringCloud服务互相注册,客户端从Eureka获取信息时,按照Eureka的顺序来访问。
10. 什么是Eureka的自我保护模式?
默认情况下,如果Eureka Service在一定时间内没有接收到某个微服务的心跳,Eureka Service会进入自我保护模式,在该模式下Eureka Service会保护服务注册表中的信息,不在删除注册表中的数据,当网络故障恢复后,Eureka Servic 节点会自动退出自我保护模式
11. DiscoveryClient的作用?
从注册中心中根据服务别名获取注册的服务器信息。
12. Eureka和Zookeeper的区别?
CAP原则: 一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)
- Eureka遵从AP原则,追求可用性,分区容错性;Zookeeper遵从CP原则,追求一致性,分区容错性;
- 体现在获取服务注册列表上,当Zookeeper的master挂掉后,会触发选举机制,选举期间无法从Zookeeper获取服务列表信息,这就是为了一致性放弃了可用性;Eureka则追求可用性,只存在Eureka Server,就可以获取到服务注册列表信息,但是可能获取到不是最新的,这就是为了可用性放弃了一致性;
- Eureka本质上是一个工程,而Zookeeper只是一个进程
13. Eureka和Nacos的区别:
- Eureka只能遵从AP原则
- Nacos同时支持CP和AP原则,支持切换,AP模式下服务以临时实例注册,CP模式下服务以永久实例注册,Nacos集成了配置中心的功能。
14. 什么是网关?
网关相当于一个网络服务架构的入口,所有网络请求必须通过网关转发到具体的服务。
15. 网关的作用是什么?
统一管理微服务请求,权限控制、负载均衡、路由转发、监控、安全控制黑名单和白名单等
16. 什么是Spring Cloud Zuul(服务网关)?
17. 网关与过滤器有什么区别
网关是对所有服务的请求进行分析过滤,过滤器是对单个服务而言。
18. 常用网关框架有那些?
Nginx、Zuul、Gateway
19. Zuul与Nginx有什么区别?
- Zuul是java语言实现的,主要为java服务提供网关服务,尤其在微服务架构中可以更加灵活的对网关进行操作。
- Nginx是使用C语言实现,性能高于Zuul,但是实现自定义操作需要熟悉lua语言,对程序员要求较高,可以使用Nginx做Zuul集群。
20. 如何实现动态Zuul网关路由转发?
通过path配置拦截请求,通过ServiceId到配置中心获取转发的服务列表,Zuul内部使用Ribbon实现本地负载均衡和转发。
21. Zuul网关如何搭建集群?
使用Nginx的upstream设置zuul服务集群,通过location拦截请求并转发到upstream,默认使用轮询机制对Zuul集群发送请求.
22. 负载平衡的意义什么?
避免单一应用由于并发等原因,导致应用宕机从而导致系统整体无法使用,多负载同时工作,可以很好的解决高并发的问题,实现服务的高可用。
23. Ribbon是什么?
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
24. Nginx与Ribbon的区别?
- Ribbon属于客户端负载,及在调用服务器以前,客户端自己根据策略,选择调用服务;
- Nginx属于服务端负载,服务只管调用负载地址即,负载会自己选择服务端调用
25. Ribbon底层实现原理?
Ribbon使用discoveryClient从注册中心读取目标服务信息,对同一接口请求进行计数,使用%取余算法获取目标服务集群索引,返回获取到的目标服务信息。
26. @LoadBalanced注解的作用
开启客户端负载均衡。
27. 什么是断路器?
当一个服务调用另一个服务由于网络原因或自身原因出现问题,调用者就会等待被调用者的响应当更多的服务请求到这些资源导致更多的请求等待,发生连锁效应(雪崩效应)
断路器有三种状态
- 打开状态: 一段时间内达到一定的次数无法调用并且多次监测没有恢复的迹象断路器完全打开那么下次请求就不会请求到该服务
- 半开状态:短时间内有恢复迹象断路器会将部分请求发给该服务,正常调用时断路器关闭。
- 关闭状态:当服务一直处于正常状态能正常调用
28. 什么是 Hystrix?
防雪崩利器,具备服务降级,服务熔断,依赖隔离,监控(Hystrix Dashboard)
29. 谈谈服务雪崩效应?
雪崩效应是在大型互联网项目中,当某个服务发生宕机时,调用这个服务的其他服务也会发生宕机,大型项目的微服务之间的调用是互通的,这样就会将服务的不可用逐步扩大到各个其他服务中,从而使整个项目的服务宕机崩溃.
发生雪崩效应的原因有以下几点
- 单个服务的代码存在bug
- 请求访问量激增导致服务发生崩溃(如大型商城的抢红包,秒杀功能)
- 服务器的硬件故障也会导致部分服务不可用.
30. 在微服务中,如何保护服务?
一般使用使用Hystrix框架,实现服务隔离来避免出现服务的雪崩效应,从而达到保护服务的效果。当微服务中,高并发的数据库访问量导致服务线程阻塞,使单个服务宕机,服务的不可用会蔓延到其他服务,引起整体服务灾难性后果,使用服务降级能有效为不同的服务分配资源,一旦服务不可用则返回友好提示,不占用其他服务资源,从而避免单个服务崩溃引发整体服务的不可用.
31. 谈谈服务降级、熔断、服务隔离
- 服务降级: 当客户端请求服务器端的时候,防止客户端一直等待,不会处理业务逻辑代码,直接返回一个友好的提示给客户端。
- 服务熔断: 在服务降级的基础上更直接的一种保护方式,当在一个统计时间范围内的请求失败数量达到设定值requestVolume Threshold)或当前的请求错误率达到设定的错误率阈值(errorThresholdPercentage)时开启断路,之后的请求直接走fallback方法,在设定时间(sleepWindowlnMilliseconds)后尝试恢复。
- 服务隔离: Hystrix为隔离的服务开启一个独立的线程池,这样在高并发的情况下不会影响其他服务。服务隔离有线程池和信号量两种实现方式,一般使用线程池方式。
32. 服务降级底层是如何实现的?
Hystrix实现服务降级的功能是通过重写HystrixCommand中的getFallback()方法,当Hystrix的run方法或construct执行发生错误时转而执行getFallback()方法。
33. 什么是Feign?
声明一个代理接口,服务调用者通过调用这个代理接口的方式来调用远程服务。
什么是Feign?_罗彬桦的博客-CSDN博客_feign
34. SpringCloud有几种调用接口方式?
两种。spring-cloud调用服务有两种方式,一种是Ribbon+RestTemplate, 另外一种是Feign。
35. Ribbon和Feign调用服务的区别?
- 启动类使用的注解不同,Ribbon 用的是@RibbonClient,Feign 用的是@EnableFeignClients。
- 服务的指定位置不同,Ribbon 是在@RibbonClient 注解上声明,Feign 则是在定义抽象方法的接口中使用@FeignClient 声明。
- 调用方式不同,Ribbon 需要自己构建 http 请求,模拟 http 请求然后使用 RestTemplate 发送给其他服务,步骤相当繁琐。
36. 什么是 Spring Cloud Bus?
在微服务架构的系统中,我们通常会使用轻量级的消息代理来构建一个共用的消息主题让系统中所有微服务实例都连接上来,由于该主题中产生的消息会被所有实例监听和消费,所以我们称它为消息总线。Spring Cloud Bus就像一个分布式执行器,用于扩展的Spring Boot应用程序,但也可以用作应用程序之间的通信通道。Spring Cloud Bus支持RabbitMQ和Kafka。
37. 什么是Spring Cloud Config?
Spring Cloud Config是一个统一管理微服务配置的一个组件,具有集中管理、不同环境不同配置、运行期间动态调整配置参数、自动刷新等功能。
spring cloud 的config 介绍_健康平安的活着的博客-CSDN博客_spring-cloud-config
38. 分布式配置中心有那些框架?
- Apollo
- SpingCloud Config
- Disconf (百度)
- Diamod (阿里)
40. 分布式配置中心的作用?
- 可以对需要配置的文件进行统一的管理,不管是在同一环境还是在不同环境,都可以直接一键对文件进行部署或者是更新等操作。
- 即使在程序的运行期间也可以对程序实现动态化的管理,这样就不需要依次在每个服务器上进行文件的修改,只需要在总服务器上进行修改就可以了。
41. SpringCloud Config 可以实现实时刷新吗?
可以
【SpringCloud深入浅出系列】SpringCloud组件之集成Config实现配置自动刷新_奔跑吧邓邓子的博客-CSDN博客
42. 什么是Spring Cloud Gateway?
Gateway是在spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot2和Project Reactor等技术。Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:反向代理、熔断、限流、重试等。
十三、Hibernate
1. 为什么要使用 hibernate?
- hibernate 是对 jdbc 的封装,大大简化了数据访问层的繁琐的重复性代码。
- hibernate 是一个优秀的 ORM 实现,很多程度上简化了 DAO 层的编码功能。 可以很方便的进行数据库的移植工作。 提供了缓存机制,是程序执行更改的高效。
2. 什么是 ORM 框架?
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。ORM框架是连接数据库的桥梁,只要提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。
3. hibernate 中如何在控制台查看打印的 sql 语句?
在 Config 里面把hibernate. show_SQL 设置为 true 即可。
4. hibernate 有几种查询方式?
HQL (Hibernate Query Language)
- 语法类似sql- 把sql语句的表名换成了类名,把字段名换成实体类中的属性- 具有跨数据库的优点
QBC (Query By Criteria)
- 这种方式比较面向对象方式,重点是有三个描述条件的对象:Restrictions,Order,Projections。使用QBC查询,一般需要以下三个步骤 (只有"DetachedCriteria离线查询"不同, 详见示例) :- 使用Session实例的createCriteria(XXX. class)方法创建Criteria对象;- 使用工具类Restrictions的方法为Criteria对象设置查询条件,Order工具类的方法设置排序方式,Projections工具类的方法进行统计和分组;- 使用Criteria对象的list()方法进行查询并返回结果。
SQL (Structured Query Language)
- 违背了hibernate的跨平台优点,不易维护,不面向对象。不推荐使用。
5. hibernate 实体类可以被定义为 final 吗?
可以
6. 在 hibernate 中使用 Integer 和 int 做映射有什么区别?
Integer 类型为对象,它的值允许为 null,而 int 属于基础数据类型,值不能为 null。
7. hibernate 是如何工作的?
hibernate的工作原理_皓月星辰_w的博客-CSDN博客_hibernate原理机制
- 读取并解析配置文件。
- 读取并解析映射信息,创建SessionFactory。
- 打开Session
- 创建事务Transaction。
- 持久化操作。
- 提交事务。
- 关闭Session。
- 关闭SessionFactory。
8. get( )和 load( )的区别?
get( )
- 当get方法被调用的时候会立刻发出sql语句去数据库查询,返回的是真实对象- 根据id没有查询到对象的时候,会返回null
load( )
延迟加载:当load()方法被调用的时候不会立刻发出sql语句,当调用除ID外的属性时候,才会发出sql语句
当load()方法被调用的时候,返回的是代理对象,这个代理对象只储存了目标对象的ID值
根据id没有查询到对象的时候,返回ObjectNotFoundException
9. 说一下 hibernate 的缓存机制?
hibernate 缓存机制_@sun林深不见鹿的博客-CSDN博客_hibernate缓存
一级缓存–session
- 在hibernate中,oid主键标识,当在session管理权限内,当第二次在使用某个对象时会从session 缓存中获取
二级缓存—sessionFactory
- 内置缓存:hibernate自带的,不可卸载的,通常是在hibernate初始化阶段,hibernate会把映射元数据/预定于sql放到sessionFactory缓存中,内置缓存时只读的。- 外置缓存:一个可以配置的缓存插件,可以由用户自定义配置选择缓存提供商,默认情况下sessionFactory不会启用缓存插件- 外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存也可以是硬盘
10. hibernate 对象有哪些状态?
Hibernate中对象的三种状态_敲得码黛的博客-CSDN博客_hibernate对象的三种状态
- 瞬时状态(Transient):刚创建的普通对象,不存在session的缓存之中的对象,被称作为瞬时对象。
- 持久状态(Persistent):已经被持久化的对象,session缓存中有对应记录的对象称为持久化对象。
- 游离状态(Detached):已经被持久化,但是不存在与session缓存中的对象称为游离对象。
11. 在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
- **getCurrentSession() **会绑定当前线程; openSession() 不会绑定当前线程。
- getCurrentSession() 事务由 Spring 控制的,且不需要手动关闭;openSession() 需开发者手动开启和提交事务。
12. hibernate 实体类必须要有无参构造函数吗?为什么?
必须要,在Hibernate中的实体类实例化时,这个对象是由Hibernate框架创建的,其不会提供默认的无参构造器
十四、Mybatis
1. mybatis 中 #{}和 ${}的区别是什么?
- #{ }为参数占位符,即sql预编译;#{ } 预处理时,可以防止sql注入,在sql中的#{}替换为, 通过调用PreparedStatement的set方法来赋值
- ${ }为字符串替换;${}不能防止sql注入,并且是直接替换成变量的值
2. mybatis 有几种分页方式?
- 数组分页
- sql分页(使用Limit)
- PageHelper等插件帮助分页
- RowBounds分页
3. RowBounds 是一次性查询全部结果吗?为什么?
不是,RowBounds 表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为 MyBatis 是对 jdbc 的封装,在 jdbc 驱动中有一个 Fetch Size 的配置,它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行 next()的时候,去查询更多的数据。就好比你去自动取款机取 10000 元,但取款机每次最多能取 2500 元,所以你要取 4 次才能把钱取完。只是对于 jdbc 来说,当你调用 next()的时候会自动帮你完成查询工作。这样做的好处可以有效的防止内存溢出。 Fetch Size 官方相关文档:http://t. cn/EfSE2g3
4. mybatis 逻辑分页和物理分页的区别是什么?
逻辑分页
- 是一次性从数据库查询很多数据,然后再在结果中检索分页的数据。- 弊端:需要消耗大量的内存、有内存溢出的风险、对数据库压力较大。
物理分页
- 是从数据库查询指定条数的数据。- 好处:弥补了一次性全部查出的所有数据的缺点,比如需占用大量内存,数据库查询压力较大等问题。
5. mybatis 是否支持延迟加载?延迟加载的原理是什么?
Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?_三郎君的博客-CSDN博客_mybatis 是否支持延迟加载?延迟加载的原理是什么?
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。
延迟加载的原理: 使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,
6. 说一下 mybatis 的一级缓存和二级缓存?
Mybatis一级缓存和二级缓存 - blayn - 博客园
MyBatis 的一级缓存是基于数据库会话(SqlSession 对象)的,默认开启。二级缓存是基于全局(nameSpace的,开启需要配置。
一级存sql,二级存数据
7. mybatis 和 hibernate 的区别有哪些?
hibernate是全自动,而mybatis是半自动。
- hibernate完全可以自动生成sql。而mybatis仅有基本的字段映射,仍然需要通过手写sql来实现和管理。
hibernate数据库移植性远大于mybatis。
- hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(oracle、mysql等)的耦合性,而mybatis由于需要手写sql,移植性也会随之降低很多,成本很高。
hibernate拥有完整的日志系统,mybatis则欠缺一些。
- hibernate日志系统非常健全,涉及广泛,而mybatis则除了基本记录功能外,功能薄弱很多。
mybatis相比hibernate需要关心很多细节
- hibernate配置要比mybatis复杂的多,学习成本也比mybatis高。但也正因为mybatis使用简单,才导致它要比hibernate关心很多技术细节。mybatis由于不用考虑很多细节,开发模式上与传统jdbc区别很小,hibernate则正好与之相反。但是如果使用hibernate很熟练的话,实际上开发效率丝毫不差于甚至超越mybatis。
sql直接优化上,mybatis要比hibernate方便很多
- 由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,无法直接维护sql;总之写sql的灵活度上hibernate不及mybatis。
8. mybatis 有哪些执行器(Executor)?
mybatis有三种基本的Executor执行器:
SimpleExecutor
- 每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
PauseExecutor
- 执行update或select,以sql做为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而且放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor
- 执行update,将所有sql通过addBatch()都添加到批处理中,等待统一执行executeBatch(),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
9分页插件的实现原理是什么?
基于拦截器,在执行sql前进行拦截sql,根据数据库方言重写sql
10. mybatis 如何编写一个自定义插件?
MyBatis 如何编写一个自定义插件?_ConstXiong的博客-CSDN博客_mybatis 如何编写一个自定义插件
十五、RabbitMQ
1. 有哪些工作模式
有五种:
- 简单模式: 一个队列只有一个消费者 生产者 - -> 队列 - -> 消费者
- 工作模式: 轮询的方式发给每个消费者
- 发布订阅模式:也叫广播模式,绑定相同交换机的所有队列都能消费相同的一份消息
- 路由模式下:多个队列绑定同一个交换机,指定路由可筛选队列
- 匹配路由模式也叫主题模式
2. 消息手动确认 basicAck
消息队列手动确认Ack_漫天雪_昆仑巅的博客-CSDN博客_手动ack
3. rabbitmq 的使用场景有哪些?
RabbitMq使用场景解析以及优缺点_苗先生的PHP记录的博客-CSDN博客_rabbitmq 的使用场景
- 秒杀订单-流量削峰
- 解耦-刷新内存
- 订单支付成功-发布订阅
4. rabbitmq 有哪些重要的角色?
- 生产者:消息的创建者,负责创建和推送数据到消息服务器
- 消费者:消息的接收方,用于处理数据和确认消息
- 代理:就是RabbitMQ本身,用于扮演快递的角色,本身并不生产消息
5. rabbitmq 有哪些重要的组件?
- ConnectionFactory(连接管理器):应用程序与RabbitMQ之间建立连接的管理器
- Channel(信道):消息推送使用的通道
- Exchange(交换器):用于接受、分配消息
- Queue(队列):用于存储生产者的消息
- RoutingKey(路由键):生产者将消息发送给交换器的时候,会指定一个RoutingKey,用来指定这个消息的路由规则,这个RoutingKey需要与交换器类型和绑定键(BindingKey)联合使用才能最终生效。
- BindKey(绑定键):用于把交换器的消息绑定到队列上
6. rabbitmq 中 vhost 的作用是什么?
Vhost 相当于一个微小的rabbitmq服务,可以按照vhost进行独立隔离权限控制,
7. rabbitmq 的消息是怎么发送的?
生产者 - -> 交换机 - -> 队列 - -> 消费者
- 生产者将消息生产出来,并将消息发送到 RabbitMQ Server 上,即我们发到 RabbitMQ 中的消息,会首先置于 RabbitMQ Server 中;
- RabbitMQ Server 根据客户端所发来的连接请求,判断将消息传递到哪个 Virtual Host 中,如果我们在连接 RabbitMQ Server 时,没有设置要连接的 Virtual Host 地址,则 RabbitMQ Server 会将我们的消息传递到地址为 “/” 的 Virtual Host 中去;
- 在将消息传递到对应的 Virtual Host 中后,Virtual Host 会继续解析我们的连接请求,并在这一步解析出我们需要的 Exchange 的类型,以及 Channel 的名称,Queue 的名称,以及消息和 Exchange 之间是否有 routing_key ,Channel 和 Queue 之间是否有 bidding_key 这些信息;
- Virtual Host 会根据解析出来的这些信息,将消息和 Exchange 进行匹配,相应的,Exchange 也会和对应的 Channel 进行匹配,并最终将 Queue 和 Channel 进行绑定,使消息进入到对应的消息队列中去;
- 待消息进入到对应的消息队列中之后,RabbitMQ Server 会返回给我们一个确认应答(确认应答后续会进行介绍),来通知我们,消息已经成功被 RabbitMQ Server 所发送,于是,消费者变回根据一定的策略来从消息队列中获取消费,并最终将该消息消费掉,消息消费之后,也会给我们返回一个确认应答(确认应答后续会进行介绍),告诉我们消息已经成功消费掉了。
8. rabbitmq 怎么保证消息的稳定性?
得保证生产者发送消息到达了MQ
- 解决:设置发送到MQ回调确认机制
MQ收到消息得保证到达了交换机
交换机发布消息保证到了队列并进行了持久性
- 没有路由到队列,设置returnscallback回调函数
消费者保证收到了消息,并进行了消费
- 配置队列被持久化,避免MQ宕机消息丢失默认是持久化springboot2- 配置交换机持久化,避免重启交换机丢失 默认已经是持久化了- 消费者手动确认消息- 消息持久化,默认是持久化的springboot
- rabbitmq 怎么避免消息丢失?
rabbitMQ如何避免消息丢失_m0_54850825的博客-CSDN博客_rabbitmq避免消息丢失
跟可靠性稳定这个问题一样的
总结:
- 交换机、队列、消息都进行持久化
- 发送到MQ的消息需要回调机制确认setConfirmCallback
- 路由到队列的消息需要退回回调机制
- 消费者消费消息需要手动确认消息已经消费 ack
9. 要保证消息持久化成功的条件有哪些?
- 声明队列必须设置持久化 durable 设置为 true.
- 消息推送投递模式必须设置持久化,deliveryMode 设置为 2(持久)。
- 消息已经到达持久化交换器。
- 消息已经到达持久化队列。
以上四个条件都满足才能保证消息持久化成功。
10. rabbitmq 持久化有什么缺点?
降低了吞吐量,因为使用了硬盘而不是内存。可尽量使用 ssd 硬盘来缓解吞吐量的问题。
11. rabbitmq 有几种广播类型?
- 发布订阅模式
- 路由模式
- 主题模式
12. rabbitmq 怎么实现延迟消息队列?
RabbitMQ 延迟队列实现 - 以梦为码 - 博客园
可以通过rabbitmq自带机制实现:TTL+死信队列(通过设置消息或者队列的TTL,过期后进行消息的投递,从而达到delay的效果)。
- 但存在问题:- 设置队列TTL:同一个队列的所有消息从入队列到TTL的时间,过期后会投递到相应死信交换机。这样如果消息的过期时间不尽相同,会创建n个不同TTL的队列。- 设置消息TTL:虽然每个消息的TTL不同,但是投递到相同队列,队列的先进先出原则,可能排在后边的消息早就过期了。
插件: rabbitmq_delayed_message_exchange(好像3. 5. 7版本以上支持)
- 原理:将消息发送到延迟交换机中,消息达到自己的延迟时间,则会被投递到相应队列。- 使用:mq安装插件rabbitmq-plugins. bat enable rabbitmq_delayed_message_exchange
13. rabbitmq 集群有什么用?
主要用于实现高可用与负载均衡。
**高可用: **如果集群中的某些MQ服务器不可用,客户端还可以连接到其他MQ服务器。不至于影响业务。
**负载均衡:**在高并发场景下,单台MQ服务器能处理的消息有限,可以分发给多台服务器。减少消息延迟。
14. rabbitmq 节点的类型有哪些?
- 磁盘节点:消息会存储到磁盘。
- 内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型。
15. rabbitmq 集群搭建需要注意哪些问题?
RabbitMQ 集群搭建注意事项_|正心|的博客-CSDN博客_rabbitmq 集群搭建需要注意哪些问题?
- 保证各个节点 erlang 版本一致。
- 可以跨操作系统建立集群。
- 如果节点加入集群失败,请根据 给出的错误原因 对症解决。
- 如果应用中连接超时,一般有以下两个原因:
16. rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?
不是,原因有以下两个:
- 存储空间的考虑:如果每个节点都拥有所有队列的完全拷贝,这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据;
- 性能的考虑:如果每条消息都需要完整拷贝到每一个集群节点,那新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟。
17. rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?
不能进行以下操作:
- 不能创建队列
- 不能创建交换器
- 不能创建绑定
- 不能添加用户
- 不能更改权限
- 不能添加和删除集群节点
唯一磁盘节点崩溃了,集群是可以保持运行的,但你不能更改任何东西。
18. rabbitmq 对集群节点停止顺序有要求吗?
RabbitMQ 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后再关闭磁盘节点。如果顺序恰好相反的话,可能会造成消息的丢失。
十六、Kafka
kafka 可以脱离 zookeeper 单独使用吗?为什么?
kafka 有几种数据保留的策略?
kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?
什么情况会导致 kafka 运行变慢?
使用 kafka 集群需要注意什么?
十七、Zookeeper
zookeeper 是什么?
zookeeper 都有哪些功能?
zookeeper 有几种部署模式?
zookeeper 怎么保证主从节点的状态同步?
集群中为什么要有主节点?
集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
说一下 zookeeper 的通知机制?
十八、MySql
MySQL数据库面试题(2021优化版)
1. 数据库的三范式是什么?
- 第一范式:任何一张表都应该有自己的主键,并且每一个字段的原子性都是不可再分的。
- 第二范式:在第一范式的基础上,要求所有的非主键字段完全依赖主键,不能产生部分依赖。
- 第三范式:在第二范式的基础上,所有非主键只能依赖于主键,不能产生传递依赖.。
2. 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?
INNODB 把最大的自增id记录在内存,重启会丢失,重新获取最大,id是6
一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysql的情况下),这条记录的id是8;但是如果重启(文中提到的)MySQL的话,这条记录的ID是6。因为InnoDB表只把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。
但是,如果我们使用表的类型是MylSAM,那么这条记录的ID就是8。因为MylSAM表会把自增主键的最大ID记录到数据文件里面,重启MYSQL后,自增主键的最大ID也不会丢失。
注:如果在这7条记录里面删除的是中间的几个记录(比如删除的是3,4两条记录),重启MySQL数据库后,insert一条记录后,ID都是8。因为内存或者数据库文件存储都是自增主键最大ID
3.如何获取当前数据库版本?
select version();
4. 说一下 ACID 是什么?
原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)
5. char 和 varchar 的区别是什么?
char 是一种固定长度的存储方式,不够用空格填充,而varchar长度不固定
6. float 和 double 的区别是什么?
单精度、双精度
7. mysql 的内连接、左连接、右连接有什么区别?
- 内连接:显示两个表中有联系的所有数据;
- 左连接:以左表为参照,显示所有数据,右表中没有则以null显示
- 右连接:以右表为参照显示数据,,左表中没有则以null显示
8.mysql 索引是怎么实现的?
MySQL的索引是如何实现的_LiveEveryDay的博客-CSDN博客_mysql 索引是怎么实现的
9. 怎么验证 mysql 的索引是否满足需求?
explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。 explain 语法:explain select * from table where type=1。
10. MySQL有哪些隔离级别?每种隔离级别会有什么问题?
READ UNCOMMITTED 读未提交
- 可读取到未提交数据,产生脏读
READ COMMITTED 读提交
- 可读取到提交数据,但未提交数据不可读,产生不可重复读,即可读取到多个提交数据,导致每次读取数据不一致
REPEATABLE READ 可重复读
- 可重复读,多次读取数据都一致,产生幻读,即读取过程中,即使有其它提交的事务修改数据,仍只能读取到未修改前的旧数据。此为MySQL默认设置。
SERIALIZABLE 串行读
- 可串行化,未提交的读事务阻塞修改事务(加读锁,但不阻塞读事务),或者未提交的修改事务阻塞其它事务的读写(加写锁,其它事务的读,写都不可以执行)。会导致并发性能差
11. 你用过哪些存储引擎?除了MyIsam和InnoDB还用过其他引擎吗?有什么特点?
MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY) - 于果alpha - 博客园
INNORDB 、MyISAM 、MEMORY。
- InnoDB:支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。
- MyISAM:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比 较低,也可以使用。
- MEMORY:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。
- 注意,同一个数据库也可以使用多种存储引擎的表。如果一个表要求比较高的事务处理,可以选择InnoDB。这个数据库中可以将查询要求比较高的表选择MyISAM存储。如果该数据库需要一个用于查询的临时表,可以选择MEMORY存储引擎。
12.MyIsam和InnoDB有什么区别?说五个
MyISAM与InnoDB 的区别(9个不同点)_Chackca的博客-CSDN博客_myisam
- InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;
- InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;
- InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
- InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快(注意不能加有任何WHERE条件);
- Innodb不支持全文索引,而MyISAM支持全文索引,在涉及全文索引领域的查询效率上MyISAM速度更快高;PS:5.7以后的InnoDB支持全文索引了
- MyISAM表格可以被压缩后进行查询操作
- InnoDB支持表、行(默认)级锁,而MyISAM支持表级锁
- InnoDB表必须有唯一索引(如主键)(用户没有指定的话会自己找/生产一个隐藏列Row_id来充当默认主键),而Myisam可以没有
- Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI
- Innodb:frm是表定义文件,ibd是数据文件- Myisam:frm是表定义文件,myd是数据文件,myi是索引文件
13.说一下 mysql 的行锁和表锁?
- 表锁:会锁定整个表,开销小,加锁快,锁的粒度大,并发支持小。不会出现死锁
- 行锁:会锁定单个表,开销大,加索满,所得力度小,并发支持大
14. 说一下乐观锁和悲观锁?
- 乐观锁:先进行业务操作,在实际更新的时候再去拿锁
- 悲观锁:先获取锁,在进行业务操作,确保获取锁成功才进行业务操作
15. mysql 问题排查都有哪些手段?
- 使用 show processlist 命令查看当前所有连接信息。
- 使用 explain 命令查询 SQL 语句执行计划。
- 开启慢查询日志,查看慢查询的 SQL。
16. 说一下MySQL索引原理,为什么使用B+树不用B树?
MySQL用B+树(而不是B树)做索引的原因_Janson_Lin的博客-CSDN博客_mysql为什么用b+树不用b树
- B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。
- B+树的查询效率更加稳定:由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
- B+树更便于遍历:由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。
- B+树更适合基于范围的查询:B树在提高了IO性能的同时并没有解决元素遍历的我效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低。
17. 什么是聚簇索引,什么是非聚簇索引?
MySQL-InnoDB聚簇索引与非聚簇索引 - 走看看
聚簇索引:
- 一个表有且仅有一个聚簇索引- 聚簇索引B+树的叶子节点存储的行数据- 聚簇索引建立的列规则,按照优先级为:主键->第一个非空唯一列->InnoDB创建一个隐式row-id作为聚簇索引- 聚簇索引的存储顺序与物理数据顺序一致
非聚簇索引:
- 也叫普通索引或者辅助索引,一个表可以有0-n个非聚簇索引- 索引B+树叶子节点存储的是主键值
18. 覆盖索引、回表这些了解过吗?什么是索引下推?
mysql索引回表、索引覆盖、索引下推 - 简书
- 回表: 在innodb中,如果采用主键进行查询则会直接访问到数据,也就是只需要进行一次查表
- 索引覆盖: 其实就是一种避免回表的方式,只需要在一棵索引树上就能获取SQL所需的所有列数据。
- 索引下推: 索引条件下推优化(Index Condition Pushdown (ICP) )是MySQL5.6添加的,用于优化数据查询。
19. 复合索引为什么要使用最左前缀原则?
联合索引在B+树上的存储结构及数据查找方式_问北的博客-CSDN博客_b+树 联合索引
之所以会有最左前缀匹配原则和联合索引的索引构建方式及存储结构是有关系的。
20. 大数据下怎么分页?
limit偏移量不变,随着查询记录量越来越大,所花费的时间也会越来越多。
limit查询记录数不变,随着查询偏移的增大,尤其查询偏移大于10万以后,查询时间急剧增加。
(1) 原因分析
select * from user where sex = 1 limit 100,10
由于 sex 列是索引列,MySQL会走 sex 这棵索引树,命中 sex=1 的数据。
然后又由于非聚簇索引中存储的是主键 id 的值,且查询语句要求查询所有列,所以这里会发生一个回表的情况,在命中 sex 索引树中值为1的数据后,拿着它叶子节点上的值也就是主键 id 的值去主键索引树上查询这一行其他列(name、sex)的值,最后返回到结果集中,这样第一行数据就查询成功了。
最后这句 SQL 要求limit 100, 10,也就是查询第101到110个数据,但是 MySQL 会查询前110行,然后将前100行抛弃,最后结果集中就只剩下了第101到110行,执行结束。
小结一下,在上述的执行过程中,造成 limit 大偏移量执行时间变久的原因有:
- limit a, b会查询前a+b条数据,然后丢弃前a条数据
MySQL数据库的查询优化器是采用了基于代价的方式,而查询代价的估算是基于CPU代价和IO代价。如果MySQL在查询代价估算中,认为全表扫描方式比走索引扫描的方式效率更高的话,就会放弃索引,直接全表扫描。
(2) 优化方式
t5表有200万数据,id为主键,text为普通索引
1> 使用覆盖索引
如果一条SQL语句,通过索引可以直接获取查询的结果,不再需要回表查询,就称这个索引为覆盖索引。
在MySQL数据库中使用explain关键字查看执行计划,如果extra这一列显示Using index,就表示这条SQL语句使用了覆盖索引。
让我们来对比一下使用了覆盖索引,性能会提升多少吧。
没有使用覆盖索引
select * from t5 order by text limit 1000000, 10;
这次查询花了3.690秒,让我们看一下使用了覆盖索引优化会提升多少性能吧。
使用了覆盖索引
select id, `text` from t5 order by text limit 1000000, 10;
从上面的对比中,超大分页查询中,使用了覆盖索引之后,花了0.201秒,而没有使用覆盖索引花了3.690秒,提高了18倍多,这在实际开发中,就是一个大的性能优化了。
2> 子查询优化
因为实际开发中,用SELECT查询一两列操作是非常少的,因此上述的覆盖索引的适用范围就比较有限。
所以我们可以通过把分页的SQL语句改写成子查询的方法获得性能上的提升。
select * from t5 where id>=(select id from t5 order by text limit 1000000, 1) limit 10;
其实使用这种方法,提升的效率和上面使用了覆盖索引基本一致。
但是这种优化方法也有局限性:
- 这种写法要求主键ID必须是连续的- Where子句不允许再添加其他条件
3> 延迟关联
和上述的子查询做法类似,我们可以使用JOIN,先在索引列上完成分页操作,然后再回表获取所需要的列。
select a.* from t5 a inner join (select id from t5 order by text limit 1000000, 10) b on a.id=b.id;
21. 什么是MySQL事务?
事务是逻辑上的一组操作,要么都执行,要么都不执行。
22. 什么是MVCC?
MVCC(Multi Version Concurrency Control的简称),代表多版本并发控制。与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。
MVCC最大的优势:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能
MVCC是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号(system version number)。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。
InnoDB 中 MVCC 的实现方式为:每一行记录都有两个隐藏列:DATA_TRX_ID、DATA_ROLL_PTR(如果没有主键,则还会多一个隐藏的主键列)。
23. 你知道MySQL的锁吗?MySQL有哪些锁?他们有什么区别?
虾皮二面:MySQL 中有哪些锁?表级锁和行级锁有什么区别?
当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。
MyISAM 仅仅支持表级锁(table-level locking),一锁就锁整张表,这在并发写的情况下性非常差。
InnoDB 不光支持表级锁(table-level locking),还支持行级锁(row-level locking),默认为行级锁。行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说, InnoDB 的性能更高。
- 表级锁****: MySQL 中锁定粒度最大的一种锁,是针对非索引字段加的锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。
- 行级锁****: MySQL 中锁定粒度最小的一种锁,是针对索引字段加的锁,只针对当前操作的记录进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。
24. 怎么优化SQL?
sql优化的N种方法_持续更新_王会举的博客-CSDN博客_sql优化
性能分析
show global status like 'com_______'
通过该命令可以查看当前数据库下的增删改查的使用次数,来采取对应的优化处理. value值就是执行的次数.-show variables like '%slow_query_log%';
慢查询日志-profile分析
SELECT @@profiling;
查看profile是否可用-SET profiling = 1;
开启profile:-show profiles;
查看当前会话下的所有sql执行时间:-show profiles for query xx;
这个xx是show profiles;
的query_id 查看具体sql的每个步骤消耗时间-show profiles cpu for query xx;
比上个步骤多了一个cpu字段 查看具体sql的cpu消耗时间
explain关键字
- id: 可以认为是查询序列号,每一个id代表一个select,一句sql有两个select,就会有两列,两个id.,不同的id代表不同子查询,id越大优先级越高,越先被解析,如果id相同,则按照从上到下的顺序查找.- select_type**: **查询的类型- table: 输出结果集的表- type: 表的连接类型- possible_keys: 查询时,可能使用的索引- key: 表示实际使用的索引- key_len: 索引字段的长度- ref: 列与索引的比较- rows: 扫描出的行数(估算的行数)- Extra: 执行情况的描述和说明
正确的建立索引
IN包含的值不应过多
SELECT语句务必指明字段名称:
只查询一条数据的时候,使用limit 1
避免在where子句中对字段进行null值判断:
避免在where子句中对字段进行表达式操作:
对于联合索引来说,要遵守最左前缀法则:
尽量使用inner join,避免left join
不建议使用%前缀模糊查询:
25. 如何做 mysql 的性能优化?
- Sql语句中in包含的值不宜过动
- Select 语句指定要查询的字段名称,避免使用*
- 当只需要一条语句时候,加上limit 1;
- 排序字段也最好加上索引,否则尽量少排序
- Or两边的字段如果有一个不是索引字段则不走索引
- 合理书写 in 和extis ;in是应用里面数据少,extis 是应用外面小
- 其他索引容易失效的情况
26. mysql索引
数据结构****角度
- B+树索引(O(log(n))):关于B+树索引,可以参考 MySQL索引背后的数据结构及算法原理- hash索引:
- 仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询- 其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引- 只有Memory存储引擎显示支持hash索引
- FULLTEXT索引(现在MyISAM和InnoDB引擎都支持了)- R-Tree索引(用于对GIS数据类型创建SPATIAL索引)
物理存储角度
聚集索引(clustered index)
非聚集索引(non-clustered index)
- 聚集索引和非聚集索引的区别如下: 1) 聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致,聚集索引表记录的排列顺序与索引的排列顺序一致,优点是查询速度快,因为一旦 具有第一个索引值的纪录被找到,具有连续索引值的记录也一定物理的紧跟其后。 2) 聚集索引的缺点是对表进行修改速度较慢,这是为了保持表中的记录的物理顺序与索 引的顺序一致,而把记录插入到数据页的相应位置,必须在数据页中进行数据重排, 降低了执行速度。非聚集索引指定了表中记录的逻辑顺序,但记录的物理顺序和索引的顺序不一致,聚集索引和非聚集索引都采用了B+树的结构,但非聚集索引的叶子层并不与实际的数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针的方式。
逻辑角度
- 主键索引:主键索引是一种特殊的唯一索引,不允许有空值- 普通索引或者单列索引- 多列索引(复合索引):复合索引指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用复合索引时遵循最左前缀集合- 唯一索引或者非唯一索引- 空间索引:空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON。MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MYISAM的表中创建
十九、Redis
1. redis 是什么?都有哪些使用场景?
Redis 是一个基于内存可以持久化的非关系型数据库,他经常配置关系型数据库来做缓存
使用场景: 数据共享,因为是独立的服务器;分布式锁、计数器、点赞 、排行榜
2. redis 有哪些功能?
- 多种数据类型。
- Redis持久化。
- Redis主从复制。
- Redis哨兵。
- Redis集群。
3. redis 、memcached 、mongoDB 有什么区别?
Redis、memcache、MongoDB 对比_四猿外的博客-CSDN博客_memcache mongo redis
4. redis 为什么是单线程的?
因为redis是基于内存的,限制他的效率的因素是内存的大小,全部在内存中,那么单线程就是最快的
5. redis缓存穿透、缓存击穿、缓存雪崩?
Redis缓存穿透、缓存雪崩和缓存击穿_这是一条海鱼的博客-CSDN博客_缓存击穿 缓存穿透 缓存雪崩
缓存穿透: 就是用户想要查询一个数据,在 redis 中查询不到,即没有在缓存中命中,那么就会直接去持久化的 mysql 中进行查询,发现也没有这个数据,那么本次查询就失败了. 当用户巨多的时候,查询缓存都没有查询到,那么这些全部都去查询持久化的 mysql 数据库,压力全部打到 mysql 上面,这就是缓存穿透
- 对空值缓存:如果一个查询返回的数据为空(不管数据是否存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。- 设置可访问的白名单:使用bitmaps;类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmaps里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问- 采用布隆过滤器:布隆过滤器(Bloom Filter)是由Howard Bloom在1970年提出的一种比较巧妙的概率型数据结构,它可以告诉你某种东西一定不存在或者可能存在。当布隆过滤器说,某种东西存在时,这种东西可能不存在;当布隆过滤器说,某种东西不存在时,那么这种东西一定不存在。 布隆过滤器相对于Set、Map 等数据结构来说,它可以更高效地插入和查询,并且占用空间更少,它也有缺点,就是判断某种东西是否存在时,可能会被误判。但是只要参数设置的合理,它的精确度也可以控制的相对精确,只会有小小的误判概率。
缓存击穿:指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力(有点像一把尖刀瞬间击穿到数据库)
- 预先设置热门数据:在redis高峰访问前,把一些热门数据提前存入redis中,加大这些热门数据key的时长实时调整 现场监控哪些数据是热门数据,实时调整key的过期时长- 使用分布式锁: 就是在缓存失效的时候(判断拿出来的值为空),不是立即去查数据库,先使用缓存工具的某些带成功操作返回值的操作。比如redis的setnx去set一个mutex key,当操作返回成功时(分布式锁),在查数据库,并回设缓存,最后删除mutex key. 当操作返回失败,证明有线程在查询数据库,当前线程睡眠一段时间在重s试整个get缓存的方法
**缓存雪崩: **指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
- 构建多级缓存架构:nginx缓存+redis缓存+其他缓存(ehcache等)- 使用锁或队列:使用锁或在队列的方式来保证不会有大量的线程对数据库进行读写,从而避免失效时大量的并发请求到底层存储系统上,不适用高并发情况- 设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存- 将缓存失效时间分散开:设置缓存过期时间时加上一个随机值,避免缓存在同一时间过期
6. redis 支持的数据类型有哪些?
String(字符串 用法: 键 值),Hash(哈希 类似Java中的 map 用法: 键 键值对), List(列表 用法:键 集合 不可以重复),Set(集合 用法:键 集合 可以重复),Zset(sorted set 有序集合 用法: 键 值 值)
7. redis 支持的 java 客户端都有哪些?
Lettucter、jedis、Redisson
8. jedis 和 redisson 有哪些区别?
Jedis 只是简单的封装了 Redis 的API库,可以看作是Redis客户端,它的方法和Redis 的命令很类似。Redisson 不仅封装了 redis ,还封装了对更多数据结构的支持,以及锁等功能,相比于Jedis 更加大。但Jedis相比于Redisson 更原生一些,更灵活。
9. 怎么保证缓存和数据库数据的一致性?
https://www.jb51.net/article/224160.htm#_label1
采用延时双删策略
- 基本思路: 在写库前后都进行删除缓存操作,并且设置合理的超时时间2. 基本步骤: 先删除缓存–再写数据库—休眠一段时间—再次删除缓存 注:休眠的时间是根据自己的项目的读数据业务逻辑的耗时来确定的。这样做主要是为了保证在写请求之前确保读请求结束,写请求可以删除读请求造成的缓存脏数据。
该方案的弊端: 集合双删策略+缓存超时策略设置,这样最差的结果就是在超时时间内数据存在不一致,又增加了写请求的耗时。
一步更新缓存(基于订阅Binlog的同步机制)
- 基本思路: mysql Binlog增强订阅消费+消息队列+增量数据更新到redis—读redis:热数据基本上都在redis—写mysql:增删改都是操作mysql—更新redis数据:mysql的数据操作Binlog,来更新redis
10. redis 持久化有几种方式?
- **RDB **: 会根据配置文件里的 900秒发生一次变化,或则300秒发生10次,或则60秒发生10000次的改变,就会触发自动保存全量快照进行更新到 rdb文件中
- AOF: 记录每次写的命令日志,当文件达到一定程度会进行重写命令。
区别:
- **RDB: **适合备份,和恢复. 效率高,可能丢失的数据的多
- **AOF: ** 效率低,占用文件大,优点是几乎没有数据丢失
11. redis 怎么实现分布式锁?
如何用Redis实现分布式锁?_小夏陌的博客-CSDN博客_redis怎么实现分布式锁
- 获取锁的时候,使用setnx加锁,key为锁名,value值为一个随机生成的UUID。
- 获取锁成功后,使用expire命令为锁添加一个超时时间,若超过这个时间则放弃获取锁。
- 释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放。
12. MySQL分布式锁、Redis分布式锁、Zookeeper分布式锁区别?
分布式锁的几种使用方式(redis、zookeeper、数据库)_南北雪树的博客-CSDN博客
分布式锁的作用及实现(Redis)_LiQiyaoo的博客-CSDN博客_分布式锁的作用
从理解的难易程度角度(从低到高)
- 数据库 > 缓存 > Zookeeper
从实现的复杂性角度(从低到高)
- Zookeeper > 缓存 > 数据库
从性能角度(从高到低)
- 缓存 > Zookeeper >= 数据库
从可靠性角度(从高到低)
- Zookeeper > 缓存 > 数据库
13. redis 如何做内存优化?
- 缩减key和value的长度。key尽量简写如s:a:id。value不存储不需要数据。
- 开启共享内存池,纯数字数据可以公用内存。但是无法使用过lru的内存淘汰策略
- 如果编辑数据长度变化较大,尽量删除后重新存储。因为redis的预分配机制,追加操作,将会预留更大的存储空间。
- 尽量使用复杂度更低的编码方式,编码方式不可逆。如果数据变简单,情况允许,可以重新创建。
- 控制hash中键的数量。数量最好不要超过1000。因为ziplist编码,超过1000后,cpu消耗增加
14. redis 内存淘汰策略?
Redis内存淘汰策略_超级码里喵的博客-CSDN博客_redis内存淘汰策略
- noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
- allkeys-lru:在主键空间中,优先移除最近未使用的key。(推荐)
- volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
- allkeys-random:在主键空间中,随机移除某个key。
- volatile-random:在设置了过期时间的键空间中,随机移除某个key。
- volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
15. redis 常见的性能问题有哪些?该如何解决?
- master写内存快照,seve命令调度rdbsave函数,会阻塞主线程的工程,当快照比较大的时候对性能的影响是非常大的,会间断性暂停服务 。所以master最好不要写内存快照。
- master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响master重启时的恢复速度。master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个slave开启AOF备份数据,策略每秒为同步一次。
- master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂的服务暂停现象。
- redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,slave和master最好在同一个局域网内。
16. redis的zset有什么场景吗?
Redis ZSet 的几种使用场景_渣一个的博客-CSDN博客_redis zset使用场景
延迟队列、排行榜、限流
17. redis跳跃表?
Redis-跳跃表(skip List)_养歌的博客-CSDN博客_redis跳跃表
跳表全称叫做跳跃表,简称跳表。跳表是一个随机化的数据结构,
跳跃表(skiplist)是一个用于有序元素序列快速搜索的随机化的数据结构
18. redis事务?
Redis之事务(详细解析)_故明所以的博客-CSDN博客_redis 事务
redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令
redis事务没有隔离级别,不保证原子性
19. redis主从原理, 哨兵原理, 集群原理
一文读懂Redis的四种模式,单机、主从、哨兵、集群 - 爱码网
Redis集群原理详解_张维鹏的博客-CSDN博客_redis集群
主从原理:
- Slave启动成功连接到master后会发送一个sync命令- Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步- 全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。- 增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步- 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行
哨兵原理:
- 哨兵机制每个10s时间只需要配置监听我们的主节点就可以获取当前整个Redis集群的环境列表,采用info 命令形式。- 哨兵不建议是单机的,最好每个Redis节点都需要配置哨兵监听。- 哨兵集群原理是如何:多个哨兵都执行同一个主的master节点,订阅到相同都通道,有新的哨兵加入都会向通道中发送自己服务的信息,该通道的订阅者可以发现新哨兵的加入,随后相互建立长连接。- Master的故障发现 单个哨兵会向主的master节点发送ping的命令,如果master节点没有及时的响应,哨兵会认为该master节点为“主观不可用状态”会发送给其他都哨兵确认该Master节点是否不可用,当前确认的哨兵节点数>=quorum(可配置),会实现重新选举。
集群原理:
- Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。- 集群中的每个节点负责处理一部分哈希槽。 举个例子, 一个集群可以有三个哈希槽, 其中:
- 节点 A 负责处理 0 号至 5500 号哈希槽。- 节点 B 负责处理 5501 号至 11000 号哈希槽。- 节点 C 负责处理 11001 号至 16384 号哈希槽。
这种将哈希槽分布到不同节点的做法使得用户可以很容易地向集群中添加或者删除节点。
二十、JVM
1. 说一下 jvm 的主要组成部分?及其作用?
JVM主要组成部分及其作用_小猫的秋刀鱼的博客-CSDN博客_jvm组成
JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载器)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地库接口)。
- **Class loader(类加载器)**:根据给定的全限定名类名(如:java.lang.Object)来装载class文件到运行时数据区中的方法区;
- Execution engine(执行引擎):执行引擎也叫解释器,负责解释命令,交由操作系统执行;
- **Native Interface(本地接口)**:与native libraries交互,是其它编程语言交互的接口。
- **Runtime data area(运行时数据区域)**:这就是我们常说的JVM的内存,我们所有所写的程序都被加载到这里,之后才开始运行。
作用 :首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能
2. 说一下 jvm 运行时数据区?
JVM运行时数据区了解一下?_索码理的博客-CSDN博客_说一下jvm 运行时数据区
运行时数据区包括堆、方法区、栈、本地方法栈、程序计数器。
- 堆
堆解决的是对象实例存储的问题,垃圾回收器管理的主要区域。
- 方法区
方法区可以认为是堆的一部分,用于存储已被虚拟机加载的信息,常量、静态变量、即时编译器编译后的代码。
- 栈
栈解决的是程序运行的问题,栈里面存的是栈帧,栈帧里面存的是局部变量表、操作数栈、动态链接、方法出口等信息。
- 栈帧
- 每个方法从调用到执行的过程就是一个栈帧在虚拟机栈中入栈到出栈的过程。
- 局部变量表
- 用于保存函数的参数和局部变量。
- 操作数栈
- 操作数栈又称操作栈,大多数指令都是从这里弹出数据,执行运算,然后把结果压回操作数栈。
- 本地方法栈
与栈功能相同,本地方法栈执行的是本地方法,一个Java调用非Java代码的接口。
- 程序计数器(PC寄存器)
程序计数器中存放的是当前线程所执行的字节码的行数。JVM工作时就是通过改变这个计数器的值来选取下一个需要执行的字节码指令。
3. 说一下堆栈的区别?
- 物理地址
堆的物理地址是不连续的,性能相对较慢,是垃圾回收区工作的区域。在GC时,会考虑物理地址不连续,而使用不同的算法,比如复制算法,标记-整理算法,标记-清楚算法等。
栈中的物理地址是连续的,LIFO原则,性能较快。
- 内存分别
堆因为是不连续的,所以分配的内存是在运行期确认的,因此大小不固定,一般堆大小远远大于栈。
栈是固定大小的,所以在编译期就确认了。
- 存放内容
堆中存放的是对象实例和数组,该区域更关注的是数据的存储
( 静态变量放在方法区,静态对象仍然放在堆中)
栈中存放的是局部变量,栈针,操作数栈,返回结果等。该区更关注的是程序方法的执行。
- 程序的可见度
堆是线程共有的,栈是线程私有的。
- 异常错误
如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError。而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError。
-Xss选项设置栈内存的大小。-Xms选项可以设置堆的开始时的大小,-Xmx选项可以设置堆的最大值
4. 队列和栈是什么?有什么区别?
栈和队列的概念_伟大的车尔尼的博客-CSDN博客_什么是栈和队列
栈和队列是常见的数据结构。栈的特点是后进先出,添加元素、删除元素和查看元素都在栈顶操作。队列的特点是先进先出,添加元素在队尾操作,删除元素和查看元素在队首操作。
区别:
- 操作的名称不同。队列的插入称为入队,队列的删除称为出队。栈的插入称为进栈,栈的删除称为出栈。
- 可操作的方式不同。队列是在队尾入队,队头出队,即两边都可操作。而栈的进栈和出栈都是在栈顶进行的,无法对栈底直接进行操作。
- 操作的方法不同。队列是先进先出(FIFO),即队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾(不能从中间插入),每次离开的成员总是队列头上(不允许中途离队)。而栈为后进先出(LIFO),即每次删除(出栈)的总是当前栈中最新的元素,即最后插入(进栈)的元素,而最先插入的被放在栈的底部,要到最后才能删除。
5. 什么是双亲委派模型?
一文搞懂双亲委派模型_许大侠0610的博客-CSDN博客_双亲委派模型
双亲委派模型,其实就是一种类加载器的层次关系。当一个类加载器收到类加载任务时,会先交给自己的父加载器去完成,因此最终加载任务都会传递到最顶层的BootstrapClassLoader,只有当父加载器无法完成加载任务时,才会尝试自己来加载。
6. 说一下类加载的执行过程?
- 类的加载过程(类的生命周期)详解_幻の心的博客-CSDN博客_类加载过程
7. 怎么判断对象是否可以被回收?
- 引用计数算法(已被淘汰的算法)
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。
目前主流的java虚拟机都摒弃掉了这种算法,最主要的原因是它很难解决对象
之间相互循环引用的问题。尽管该算法执行效率很高。
- 可达性分析算法
目前主流的编程语言(java,C#等)的主流实现中,都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如下图所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。
在Java语言中,可作为GC Roots的对象包括下面几种:
虚拟机栈(栈帧中的本地变量表)中引用的对象。
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)引用的对象。
8. java 中都有哪些引用类型?
强引用,软引用,弱引用,虚引用
四种级别由高到低依次为: 强引用 > 软引用 > 弱引用, 虚引用
**强引用 **
- 类似“Objectobj=new Object()”这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。
**软引用 **
- 如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
弱引用
- 只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
虚引用
- 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。
9. 说一下 jvm 有哪些垃圾回收算法?
浅谈一下JVM常用的四种垃圾回收算法_Java世界上最好的语言的博客-CSDN博客_jvm垃圾回收算法有哪些
标记-清除算法
- 分为标记和清除两个阶段,首先标记出所有需要回收的对象,标记完成后统一回收所有被标记的对象- 缺点:标记和清除两个过程效率都不高;标记清除之后会产生大量不连续的内存碎片。
复制算法
- 把内存分为大小相等的两块,每次存储只用其中一块,当这一块用完了,就把存活的对象全部复制到另一块上,同时把使用过的这块内存空间全部清理掉,往复循环- 缺点:实际可使用的内存空间缩小为原来的一半,比较适合。
标记-整理算法
- 先对可用的对象进行标记,然后所有被标记的对象向一段移动,最后清除可用对象边界以外的内存
分代收集算法
- 把堆内存分为新生代和老年代,新生代又分为 Eden 区、From Survivor 和 To Survivor。一般新生代中的对象基本上都是朝生夕灭的,每次只有少量对象存活,因此采用复制算法,只需要复制那些少量存活的对象就可以完成垃圾收集;老年代中的对象存活率较高,就采用标记-清除和标记-整理算法来进行回收。
10. 说一下 jvm 有哪些垃圾回收器?
说一下 jvm 有哪些垃圾回收器?_哪 吒的博客-CSDN博客_jvm有哪些垃圾回收器
- 串行垃圾收集器
在JDK1.3之前,单线程回收器是唯一的选择。它的单线程意义不仅仅是说它只会使用一个CPU或一个手机线程去完成垃圾收集工作。而且它进行垃圾回收的时候,必须暂停其它所有的工作线程(Stop The World,STW),直到它收集完成。它适合Client模式的应用,在单CPU环境下,它效率高效,由于没有线程交互的开销,专心垃圾收集自然可以获得最高的单线程效率。
- 并行垃圾回收器
并行垃圾回收器是通过多线程进行垃圾收集的。也会暂停其它所有的工作线程(Stop The World,STW)。适合Server模式以及多CPU环境。一般会和JDK1.5之后出现的CMS搭配使用。
- CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获得最短回收停顿时间为目标的收集器。从名字就能知道它是标记-清除算法的。但是它比一般的标记-清除算法要复杂一些,分为以下4个阶段:
- 初始标记:标记一下GC Roots能直接关联到的对象,会"Stop The World"。
- 并发标记:GC Roots Tracing,可以和用户线程并发执行。
- 重新标记:标记期间产生的对象存活的再次判断,修正对这些对象的标记,执行时间相对并发标记短,会“Stop The World”。
- 并发清除:清除对象,可以和用户线程并发执行。
- G1垃圾收集器
G1从整体看还是基于标记-清除算法的,但是局部上是基于复制算法的。
11. 详细介绍一下 CMS 垃圾回收器?
CMS垃圾收集器详解_一枚深蓝的博客-CSDN博客_cms垃圾收集器
CMS全程为Concurrent Mark Sweep,即 并发标记清除,对比以上的收集器,最大的区别在于 并发:在GC线程工作的时候,用户线程 不会完全停止,用户线程在 部分场景下与GC线程一起并发执行。但是,无论是什么垃圾收集器,Stop the world是一定无法避免的。CMS只是在 部分的GC场景下可以让GC线程与用户线程并发执行。
CMS的涉及目的是为了避免【老年代GC】出现长时间的卡顿(stop the word)。
CMS主要是实现了标记清除垃圾回收算法,可分为5个步骤:
- 初始标记
- 并发标记
- 并发预清理
- 重新标记
- 并发清除
12. 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1
新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。
13. 简述分代垃圾回收器是怎么工作的?
分区:分代垃圾回收器分为两个区:新生代、老生代。
占比:新生代默认占总空间的 1/3,老生代默认占总空间的 2/3。
新生代,使用复制算法,新生代又分为 3 个区:Eden、From Survivor、To Survivor,默认比例是 8:1:1,执行流程如下:
- 把 Eden + From Survivor 存活的对象转移至 To Survivor 区。【迁移】
- 清空 Eden 、 From Survivor 两个分区。【清空】
- From Survivor 和 To Survivor 分区进行交换。【交换】
- 存活的对象从 From Survivor 到 To Survivor ,每移动一次,年龄就自动加1岁,当年龄到达 15(默认配置是 15)时,升级为老生代;大对象也会直接进入老生代。【升级】
- 当老生代空间占用到达某个值时,即会触发全局垃圾收回,一般使用标记-整理算法执行垃圾回收。【全局GC】
- 以上流程循环往复,就构成了整个分代垃圾回收的整体执行流程。
14. 说一下 jvm 调优的工具?
常用调优工具分为两类,
- jdk自带监控工具:jconsole和jvisualvm,
- 第三方有:MAT(Memory AnalyzerTool)、GChisto。 jconsole,Java Monitoring and Management
Console是从java5开始,在JDK中自带的java监控和管理控制台,用于对JVM中内存, 线程和类等的监控。
jvisualvm,jdk自带全能工具,可以分析内存快照、线程快照;监控内存变化、GC变化等。
MAT,Memory Analyzer Tool,一个基于Eclipse的内存分析工具,是一个快速、功能丰富的Javaheap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。
GChisto,一款专业分析gc日志的工具。
15. 常用的 jvm 调优的参数都有哪些?
-Xms2g
- 初始化推大小为 2g
-Xmx2g
- 堆最大内存为 2g
-XX:NewRatio=4
- 设置年轻的和老年代的内存比例为 1:4
-XX:SurvivorRatio=8
- 设置新生代 Eden 和 Survivor 比例为 8:2
–XX:+UseParNewGC
- 指定使用 ParNew + Serial Old 垃圾回收器组合
-XX:+UseParallelOldGC
- 指定使用 ParNew + ParNew Old 垃圾回收器组合
-XX:+UseConcMarkSweepGC
- 指定使用 CMS + Serial Old 垃圾回收器组合
-XX:+PrintGC
- 开启打印gc信息
-XX:+PrintGCDetails
- 打印 gc 详细信息
版权归原作者 dorisPotter 所有, 如有侵权,请联系我们删除。