Java面试题

java基础

2、面向对象的三大特性?分别解释下?
4、重载和重写的区别?
8、在 Java 中定义一个不做事且没有参数的构造方法有什么作用?
9、Java 中创建对象的几种方式?
10、抽象类和接口有什么区别?
15、switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上?
byte、short、char 都可以隐式转换为 int,所以,这些类型以及这些类型的包装类型也都是可以的。而 long 和 String 类型都不符合 switch 的语法规定,并且不能被隐式的转换为 int 类型,所以,它们不能作用于 switch 语句中。不过,需要注意的是在 JDK1.7 版本之后 switch 就可以作用在 String 上了。
18、String、StringBuilder、StringBuffer 的区别?
19、String 字符串修改实现的原理?
21、String 类的常用方法都有那些?

indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。

22、final 修饰 StringBuffer 后还可以 append 吗?
23、Object 的常用方法有哪些?

clone 方法:用于创建并返回当前对象的一份拷贝;
getClass 方法:用于返回当前运行时对象的 Class;
toString 方法:返回对象的字符串表示形式;
finalize 方法:实例被垃圾回收器回收时触发的方法;
equals 方法:用于比较两个对象的内存地址是否相等,一般需要重写;
hashCode 方法:用于返回对象的哈希值;
notify 方法:唤醒一个在此对象监视器上等待的线程。如果有多个线程在等待只会唤醒一个。
notifyAll 方法:作用跟 notify() 一样,只不过会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
wait 方法:让当前对象等待

24、为什么 wait/notify 方法放在 Object 类中而不是 Thread 类中?
25、final、finally、finalize 的区别?
26、finally 块中的代码什么时候被执行?
finally 块里的代码也是在 return 之前执行的,如果 try-finally 或者 catch-finally 中都有 return,那么 finally 块中的 return 将会覆盖别处的 return 语句,最终返回到调用者那里的是 finally 中 return 的值。
30、static 关键字的作用?

1)静态变量:又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份;
(2)静态方法:静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。只能访问所属类的静态字段和静态方法,方法中不能有 thissuper 关键字;
(3)静态语句块:静态语句块在类初始化时运行一次;
(4)静态内部类:非静态内部类依赖于外部类的实例,而静态内部类不需要。静态内部类不能访问外部类的非静态的变量和方法;
存在继承的情况下,初始化顺序为:
1. 父类(静态变量、静态语句块)
2. 子类(静态变量、静态语句块)
3. 父类(实例变量、普通语句块)
4. 父类(构造函数)
5. 子类(实例变量、普通语句块)
6. 子类(构造函数)

31、super 关键字的作用?
(1)访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。
(2)访问父类的成员:如果子类重写了父类的某个方法,可以通过使用 super 关键字来引用父类的方法实现。
(3)this 和 super 不能同时出现在一个构造函数里面,因为 this 必然会调用其它的构造函数,其它的构造函数必然也会有 super 语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。

37、Java 中的参数传递时传值呢?还是传引用?

  • Java 的参数是以值传递的形式传入方法中,而不是引用传递。
  • 当传递方法参数类型为基本数据类型(数字以及布尔值)时,一个方法是不可能修改一个基本数据类型的参数。
  • 当传递方法参数类型为引用数据类型时,一个方法将修改一个引用数据类型的参数所指向对象的值。即使 Java 函数在传递引用数据类型时,也只是拷贝了引用的值罢了,之所以能修改引用数据是因为它们同时指向了一个对象,但这仍然是按值调用而不是引用调用。

41、运行时异常与受检异常有何异同?

  • 运行时异常:如:空指针异常、指定的类找不到、数组越界、方法传递参数错误、数据类型转换错误。可以编译通过,但是一运行就停止了,程序不会自己处理;
  • 受检查异常:要么用 try … catch… 捕获,要么用 throws 声明抛出,交给父类处理。

44、主线程可以捕获到子线程的异常吗?(不可以除非进行设置)
45、Java 的泛型是如何工作的 ? 什么是类型擦除 ?

  • 泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如:List 在运行时仅用一个 List 来表示。这样做的目的,是确保能和 Java 5 之前的版本开发二进制类库进行兼容。
  • 类型擦除:泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 < T > 则会被转译成普通的 Object 类型,如果指定了上限如 < T extends String > 则类型参数就被替换成类型上限。

48、如何实现对象的克隆?
(1)实现 Cloneable 接口并重写 Object 类中的 clone() 方法;
(2)实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深克隆。

52、Java 中的反射是什么意思?有哪些应用场景?
反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。 Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:

(1)Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
(2)Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
(3)Constructor :可以用 Constructor 创建新的对象。
应用举例:工厂模式,使用反射机制,根据全限定类名获得某个类的 Class 实例。
53、反射的优缺点?
58、BIO、NIO、AIO 有什么区别?

集合

3、ArrayList 实现 RandomAccess 接口有何作用?为何 LinkedList 却没实现这个接口?

  1. RandomAccess 接口只是一个标志接口,只要 List 集合实现这个接口,就能支持快速随机访问。通过查看 Collections 类中的 binarySearch() 方法,可以看出,判断 List 是否实现 RandomAccess 接口来实行indexedBinarySerach(list, key) 或 iteratorBinarySerach(list, key)方法。再通过查看这两个方法的源码发现:实现 RandomAccess 接口的 List 集合采用一般的 for 循环遍历,而未实现这接口则采用迭代器,即 ArrayList 一般采用 for 循环遍历,而 LinkedList 一般采用迭代器遍历;
  2. ArrayList 用 for 循环遍历比 iterator 迭代器遍历快,LinkedList 用 iterator 迭代器遍历比 for 循环遍历快。所以说,当我们在做项目时,应该考虑到 List 集合的不同子类采用不同的遍历方式,能够提高性能。

21、 Iterator 和 ListIterator 有什么区别?
Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。ListIterator 实现了 Iterator 接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引等等。
23、fail-fast 与 fail-safe 有什么区别?
Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。
24、Collection 和 Collections 有什么区别?

  • Collection:是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素。它的直接继承接口有 List,Set 和 Queue。

  • Collections:是不属于 Java 的集合框架的,它是集合类的一个工具类/帮助类。此类不能被实例化, 服务于 Java 的 Collection 框架。它包含有关集合操作的静态多态方法,实现对各种集合的搜索、排序、线程安全等操作。

java并发

14、说一说自己对于 synchronized 关键字的了解?
20、谈一下你对 volatile 关键字的理解?
24、乐观锁的缺点有哪些?(ABA问题,循环时间长开销大,只能保证一个共享变量的原子操作)
26、简单说下对 Java 中的原子类的理解?

  • 这里 Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。所以,所谓原子类说简单点就是具有原子操作特征的类。
  • 27、atomic 的原理是什么?
  • Atomic 包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引用类型)变量进行操作时,具有排他性,即当多个线程同时对该变量的值进行更新时,仅有一个线程能成功,而未成功的线程可以向自旋锁一样,继续尝试,一直等到执行成功。

29、AQS 的原理是什么?
30、AQS 对资源的共享模式有哪些?
35、创建线程池的参数有哪些?
36、如何创建线程池?
方式一:通过 ThreadPoolExecutor 的构造方法实现:
方式二:通过 Executor 框架的工具类 Executors 来实现:
37、线程池中的的线程数一般怎么设置?需要考虑哪些问题?
38、执行 execute() 方法和 submit() 方法的区别是什么呢?
42、谈谈对 BlockingQueue 的理解?分别有哪些实现类?

  • ArrayBlockingQueue 是 BlockingQueue 接口的有界队列实现类,底层采用数组来实现。ArrayBlockingQueue一旦创建,容量不能改变。
  • LinkedBlockingQueue 底层基于单向链表实现的阻塞队列,可以当做无界队列也可以当做有界队列来使用,同样满足FIFO的特性,与ArrayBlockingQueue 相比起来具有更高的吞吐量
  • PriorityBlockingQueue 是一个支持优先级的无界阻塞队列。

JVM

1、说一下 Jvm 的主要组成部分?及其作用?

1. 类加载器(ClassLoader)
2. 运行时数据区(Runtime Data Area)
3. 执行引擎(Execution Engine)
4. 本地库接口(Native Interface)
  • 程序在执行之前先要把java代码转换成字节码(class文件),jvm首先需要把字节码通过一定的方式 类加载器(ClassLoader) 把文件加载到内存中 运行时数据区(Runtime Data Area) ,而字节码文件是jvm的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器 执行引擎(Execution Engine) 将字节码翻译成底层系统指令再交由CPU去执行,而这个过程中需要调用其他语言的接口 本地库接口(Native Interface)来实现整个程序的功能,这就是这4个主要组成部分的职责与功能。

4.堆栈分离的好处
5、 为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗?
8、对象的访问定位的两种方式?
11、被标记为垃圾的对象一定会被回收吗?
13、谈谈对内存泄漏的理解?
内存泄漏就是存在一些不会再被使用确没有被回收的对象,这些对象有下面两个特点:
1. 这些对象是可达的,即在有向图中,存在通路可以与其相连;
2. 这些对象是无用的,即程序以后不会再使用这些对象。
14、内存泄露的根本原因是什么?
长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是因为长生命周期持有它的引用而导致不能被回收,这就是 Java 中内存泄漏的发生场景。
15、举几个可能发生内存泄漏的情况?

1. 静态集合类引起的内存泄漏;
2. 当集合里面的对象属性被修改后,再调用 remove() 方法时不起作用;
3. 监听器:释放对象的时候没有删除监听器;
4. 各种连接:比如数据库连接(dataSourse.getConnection()),网络连接(socket) 和 IO 连接,除非其显式的调用了其 close() 方法将其连接关闭,否则是不会自动被 GC 回收的;
5. 内部类:内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放;
6. 单例模式:单例对象在初始化后将在 JVM 的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部的引用,那么这个对象将不能被 JVM 正常回收,导致内存泄漏。

16、尽量避免内存泄漏的方法?

1. 尽量不要使用 static 成员变量,减少生命周期;
2. 及时关闭资源;
3. 不用的对象,可以手动设置为 null。

27、说下你用过的 JVM 监控工具?线程死锁检测(jps,jstack)?

1. jvisualvm:虚拟机监视和故障处理平台
2. jps :查看当前 Java 进程
3. jstat:显示虚拟机运行数据
4. jmap:内存监控
5. jhat:分析 heapdump 文件
6. jstack:线程快照
7. jinfo:虚拟机配置信息

28、如何利用监控工具调优?
29、JVM 的一些参数?
30、谈谈你对类文件结构的理解?有哪些部分组成?

1. 魔数(magic):每个 Class 文件的头 4 个字节称为魔数(Magic  Number),它的唯一作用是确定这个文件是否为一个能被虚拟机接受的Class 文件,即判断这个文件是否符合 Class 文件规范。
2. 文件的版本:minor_version 和 major_version。
3. 常量池:constant_pool_count 和 constant_pool:常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic  References)。
4. 访问标志:access_flags:用于识别一些类或者接口层次的访问信息。包括:这个 Class 是类还是接口、是否定义了 Public 类型、是否定义为 abstract 类型、如果是类,是否被声明为了 final 等等。
5.类索引、父类索引与接口索引集合:this_class、super_class和interfaces。
6. 字段表集合:field_info、fields_count:字段表(field_info)用于描述接口或者类中声明的变量;fields_count 字段数目:表示Class文件的类和实例变量总数。
7. 方法表集合:methods、methods_count
8. 属性表集合:attributes、attributes_count

31、谈谈你对类加载机制的了解?
35、谈谈你对双亲委派模型的理解?工作过程?为什么要使用?
36、怎么实现一个自定义的类加载器?需要注意什么?
继承 java.lang.ClassLoader 类,并且重写其 findClass() 方法即可。
37、为什么要自定义类加载器?
(1)加密:Java代码可以轻易的被反编译,如果你需要把自己的代码进行加密以防止反编译,可以先将编译后的代码用某种加密算法加密,类加密后就不能再用Java的ClassLoader去加载类了,这时就需要自定义ClassLoader在加载类的时候先解密类,然后再加载。
(2)从非标准的来源加载代码:如果你的字节码是放在数据库、甚至是在云端,就可以自定义类加载器,从指定的来源加载类
37、怎么打破双亲委派模型?

  1. 自己写一个类加载器;
  2. 重写 loadClass() 方法
  3. 重写 findClass() 方法
    这里最主要的是重写 loadClass 方法,因为双亲委派机制的实现都是通过这个方法实现的,先找父加载器进行加载,如果父加载器无法加载再由自己来进行加载,源码里会直接找到根加载器,重写了这个方法以后就能自己定义加载的方式了。

41、说下你对 Java 内存模型的理解?

  • Java 内存模型(Java Memory Model,JMM):屏蔽掉了各种硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致性的内存访问效果
  • 主内存与工作内存

计算机网络

1、TCP 协议如何保证可靠传输
2、ARQ协议(停止等待ARQ协议、连续ARQ协议)
3、TCP 滑动窗口和流量控制
4、TCP粘包和拆包(1. 特殊字符控制;2. 在包头首都添加数据包的长度。)
5、与与 IP 协议配套使用的还有三个协议

地址解析协议 ARP(Address Resolution Protocol)
网际控制报文协议 ICMP(Internet Control Message Protocol)
网际组管理协议 IGMP(Internet Group Management Protocol)

6、路由选择协议:自治系统内部的路由选择:RIP 和 OSPF;自治系统间的路由选择:BGP
7、HTTP请求报文和响应报文
8、GET方法与POST方法的区别
9、常见的HTTP相应状态码
10、什么是Http协议无状态协议?怎么解决Http协议无状态协议?

3、ARP 协议的工作原理?
7、TCP 和 UDP 的区别?(连接,可靠,传输形式,报文头,效率,一对一,实现可靠传输)
12、Server 端收到 Client 端的 SYN 后,为什么还要传回 SYN?

  • 接收端传回发送端所发送的 SYN 是为了告诉发送端,我接收到的信息确实就是你所发送的信号了。

13、传了 SYN,为什么还要传 ACK?

  • 双方通信无误必须是两者互相发送信息都无误。传了 SYN,证明发送方到接收方的通道没有问题,但是接收方到发送方的通道还需要 ACK 信号来进行验证。

29、forward 和 redirect 的区别?

1.从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
2.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.
redirect:不能共享数据.
3.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.
4.从效率来说
forward:.
redirect:.

35、谈下你对 HTTP 长连接和短连接的理解?分别应用于哪些场景?
36、谈下 HTTP 1.0 和 1.1、1.2 的主要变化?(虚拟主机)
37、HTTPS 的工作过程?

  1. 客户端发送自己支持的加密规则给服务器,代表告诉服务器要进行连接了;

  2. 服务器从中选出一套加密算法和 hash 算法以及自己的身份信息(地址等)以证书的形式发送给浏览器,证书中包含服务器信息,加密公钥,证书的办法机构;

  3. 客户端收到网站的证书之后要做下面的事情:
    3.1 验证证书的合法性;
    3.2 果验证通过证书,浏览器会生成一串随机数,并用证书中的公钥进行加密;
    3.3 用约定好的 hash 算法计算握手消息,然后用生成的密钥进行加密,然后一起发送给服务器。

  4. 服务器接收到客户端传送来的信息,要做下面的事情:
    4.1 用私钥解析出密码,用密码解析握手消息,验证 hash 值是否和浏览器发来的一致;
    4.2 使用密钥加密消息;

  5. 如果计算法 hash 值一致,握手成功。

40、什么是数字签名?

  • 为了避免数据在传输过程中被替换,比如黑客修改了你的报文内容,但是你并不知道,所以我们让发送端做一个数字签名,把数据的摘要消息进行一个加密,比如 MD5,得到一个签名,和数据一起发送。然后接收端把数据摘要进行 MD5 加密,如果和签名一样,则说明数据确实是真的。

41、什么是数字证书?

  • 对称加密中,双方使用公钥进行解密。虽然数字签名可以保证数据不被替换,但是数据是由公钥加密的,如果公钥也被替换,则仍然可以伪造数据,因为用户不知道对方提供的公钥其实是假的。所以为了保证发送方的公钥是真的,CA 证书机构会负责颁发一个证书,里面的公钥保证是真的,用户请求服务器时,服务器将证书发给用户,这个证书是经由系统内置证书的备案的。

操作系统

2、同步、异步、阻塞、非阻塞的概念
4、进程与线程的区别?
7、进程间的通信方式有哪些?
12、解决死锁的基本方法?(Java用Jps/jstack)

  1. 预防死锁(破坏四个条件)
  2. 避免死锁(银行家算法找到安全序列)
  3. 检测死锁
  4. 解除死锁(1. 资源剥夺2. 撤销进程3. 进程回退)

17、什么是虚拟内存技术?
18、分页和分段的区别
19、孤儿进程和僵尸进程
20、硬链接和软连接的区别

数据库

1、两段锁协议(加锁和解锁分为两个阶段进行)
2、事务特性(ACID)和隔离级别
3、MVCC的目的和原理(创建版本号和删除版本号),快照读和当前读

  • 快照读: 使用 MVCC 读取的是快照中的数据,这样可以减少加锁所带来的开销。
  • 当前读:读取的是最新的数据,需要加锁。以下第一个语句需要加 S 锁,其它都需要加 X 锁

4、InnoDB有三种行锁的算法:Next-Key Lock:1+2,除了锁住记录本身,还要再锁住索引之间的间隙。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。
5、内连接、外连接(左右全)、自然连接select p.,v. from productinfo as p natural join vendors as v
6、视图的含义和优点:

  • 视图是虚拟的表,本身不包含数据,也就不能对其进行索引操作。

7、B-树、B+树、B+树优点、与红黑树比较(更少的查询次数(树高);利用磁盘的预读性)
8、MyISAM和InnoDB 的区别(事务,主键、外键、表锁、行数、自动增长字段、聚簇索引、)
9、分库分表:水平切分和垂直切分
10、主从复制(主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程)和读写分离

  • 读写分离常用代理方式来实现,,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
  • 主从服务器负责各自的读和写,极大程度缓解了锁的争用;
  • 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销
  • 增加冗余,提高可用性

11、RedoLog和UndoLog

  • Redo log
    记录的是新数据的备份。在事务提交前,只要将Redo Log持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是RedoLog已经持久化。系统可以根据RedoLog的内容,将所有数据恢复到最新的状态。
  • UndoLog用于在实例故障恢复时,借助undo log将尚未commit的事务,回滚到事务开始前的状态。

12、现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?(停机迁移方案;双写迁移方案)link

  • 双写迁移方案
    简单来说,就是在线上系统里面,之前所有写库的地方,增删改操作,除了对老库增删改,都加上对新库的增删改,这就是所谓的双写,同时写俩库,老库和新库。

  • 然后系统部署之后,新库数据差太远,用之前说的导数工具,跑起来读老库数据写新库,写的时候要根据 gmt_modified 这类字段判断这条数据最后修改的时间,除非是读出来的数据在新库里没有,或者是比新库的数据新才会写。简单来说,就是不允许用老数据覆盖新数据。

  • 导完一轮之后,有可能数据还是存在不一致,那么就程序自动做一轮校验,比对新老库每个表的每条数据,接着如果有不一样的,就针对那些不一样的,从老库读数据再次写。反复循环,直到两个库每个表的数据都完全一致为止。

13、分库分表之后,id 主键如何处理?link

  • 基于数据库的实现方案
    数据库自增 id
    设置数据库 sequence 或者表自增字段步长
  • UUID
    好处就是本地生成,不要基于数据库来了;不好之处就是,UUID 太长了、占用空间大,作为主键性能太差了;更重要的是,UUID 不具有有序性
  • snowflake 算法
    snowflake 算法是 twitter 开源的分布式 id 生成算法,采用 Scala 语言实现,是把一个 64 位的 long 型的 id,1 个 bit 是不用的,用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。

14、MySQL 主从复制原理、MySQL 主从同步延时问题(精华)

  • MySQL 实际上在这一块有两个机制,一个是半同步复制,用来解决主库数据丢失问题;一个是并行复制,用来解决主从同步延时问题。

  • 这个所谓半同步复制,也叫 semi-sync 复制,指的就是主库写入 binlog 日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入自己本地的 relay log 之后,接着会返回一个 ack 给主库,主库接收到至少一个从库的 ack 之后才会认为写操作完成了。

  • 所谓并行复制,指的是从库开启多个线程,并行读取 relay log 中不同库的日志,然后并行重放不同库的日志,这是库级别的并行。

MySQL 主从同步延时问题(精华)

分库,将一个主库拆分为多个主库,每个主库的写并发就减少了几倍,此时主从延迟可以忽略不计。
打开 MySQL 支持的并行复制,多个库并行复制。如果说某个库的写入并发就是特别高,单库写并发达到了 2000/s,并行复制还是没意义。
重写代码,写代码的同学,要慎重,插入数据时立马查询可能查不到。
如果确实是存在必须先插入,立马要求就查询到,然后立马就要反过来执行一些操作,对这个查询设置直连主库。不推荐这种方法,你要是这么搞,读写分离的意义就丧失了。

2、一条 SQL 语句在数据库框架中的执行流程?

  1. 应用程序把查询 SQL 语句发送给服务器端执行;
  2. 查询缓存,如果查询缓存是打开的,服务器在接收到查询请求后,并不会直接去数据库查询,而是在数据库的查询缓存中找是否有相对应的查询数据,如果存在,则直接返回给客户端。只有缓存不存在时,才会进行下面的操作;
  3. 查询优化处理,生成执行计划。这个阶段主要包括解析 SQL、预处理、优化 SQL 执行计划;
    (分析器-》优化器-》执行器)
  4. MySQL 根据相应的执行计划完成整个查询;
  5. 将查询结果返回给客户端。

13、谈谈你对联合索引和覆盖索引的认识?
联合索引是由多个字段组成的索引
**如果一个索引包含了满足查询语句中字段与条件的数据就叫做覆盖索引。**具有以下优点:

  1. 索引通常远小于数据行的大小,只读取索引能大大减少数据访问量。
  2. 一些存储引擎(例如:MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用(通常比较费时)。
  3. 对于 InnoDB 引擎,若辅助索引能够覆盖查询,则无需访问主索引。

15、怎么知道创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?
使用 Explain 命令来查看语句的执行计划,MySQL 在执行某个语句之前,会将该语句过一遍查询优化器,之后会拿到对语句的分析,也就是执行计划,其中包含了许多信息。可以通过其中和索引有关的信息来分析是否命中了索引,例如:possilbe_key、key、key_len 等字段,分别说明了此语句可能会使用的索引、实际使用的索引以及使用的索引长度。
16、什么情况下索引会失效?即查询不走索引?

1. 索引列参与表达式计算:
2. 函数运算: 
3. %词语%--模糊查询: 
4、类型错误,如字段类型为varchar,where条件用number。
5. 查询条件中有 or ,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引:
6. 正则表达式不使用索引。
7. MySQL 内部优化器会对 SQL 语句进行优化,如果优化器估计使用全表扫描要比使用索引快,则不使用索引。

17、查询性能的优化方法?

减少请求的数据量
1. 只返回必要的列:最好不要使用 SELECT * 语句。
2. 只返回必要的行:使用 LIMIT 语句来限制返回的数据。
3. 缓存重复查询的数据:使用缓存可以避免在数据库中进行查询,特别在要查询的数据经常被重复查询时,缓存带来的查询性能提升将会是非常明显的。
减少服务器端扫描的行数
1. 最有效的方式是使用索引来覆盖查询。

28、说一下 MySQL 的行锁和表锁?

表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。
行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。

30、MySQL 问题排查都有哪些手段?

1. 使用 show processlist 命令查看当前所有连接信息;
2. 使用 Explain 命令查询 SQL 语句执行计划;
3. 开启慢查询日志,查看慢查询的 SQL。

31、MySQL 数据库 CPU 飙升到 500% 的话他怎么处理?

4. 列出所有进程  show processlist,观察所有进程,多秒没有状态变化的(干掉)5. 查看超时日志或者错误日志 (一般会是查询以及大批量的插入会导致 CPU与 I/O 上涨,当然不排除网络状态突然断了,导致一个请求服务器只接受到一半。

Redis

1、五种数据类型
2、Redis 与 Memcached
3、过期时间和数据淘汰策略(6种)
4、持久化方式(RDB、AOF)、AOF文件重写

  • 由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式,不过RDB持久化仍然有其用武之地。

5.Redis的LRU实现

  • ==在3.0的时候,又改进了一版算法,首先第一次随机选取的key都会放入一个pool中(pool的大小为16),pool中的key是按lru大小顺序排列的。接下来每次随机选取的keylru值必须小于pool中最小的lru才会继续放入,直到将pool放满。放满之后,每次如果有新的key需要放入,需要将pool中lru最大的一个key取出。
  • 淘汰的时候,直接从pool中选取一个lru最小的值然后将其淘汰==

6、主从复制原理
7、三种集群策略(主从复制、哨兵、集群)

  • 当需要在Redis集群存放一个数据(key-value)时,redis会先对这个key进行crc16算法,然后得到一个结果。再把这个结果对16384进行求余,这个余数会对应[0-16383]其中一个槽,进而决定key-value存储到哪个节点中。所以一旦某个节点挂了,该节点对应的slot就无法使用,那么就会导致集群无法正常工作。

8、Redis快的主要原因
9、为什么Redis单进程单线程方式

  • 因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,所以就采用单线程
  • 代码更清晰,处理逻辑更简单
  • 不用去考虑各种锁的问题,不存在加锁释放锁操作
  • 不存在多进程或者多线程导致的切换而消耗CPU
    10、多路I/O复用模型
  • Redis是用”单线程-多路复用IO模型”来实现高性能的内存数据服务的,这种机制避免了使用锁,但是同时这种机制在进行sunion之类的比较耗时的命令时会使redis的并发下降。所以可以通过主哨从、哨兵、集群建立分布式Redis解决问题

11、为什么要用 redis 而不用 map/guava 做缓存?
12、Redis常见的性能问题都有哪些?如何解决?

  • 1.Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。
  • Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
  • Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。
  • Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内

13、缓存雪崩、缓存穿透、缓存击穿解决链接

缓存雪崩
事前:redis 高可用,主从+哨兵,redis cluster,避免全盘崩溃。
事中:本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死。
事后:redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。
  • 用户发送一个请求,系统 A 收到请求后,先查本地 ehcache 缓存,如果没查到再查 redis。如果 ehcache 和 redis 都没有,再查数据库,将数据库中的结果,写入 ehcache 和 redis 中。

  • 限流组件,可以设置每秒的请求,有多少能通过组件,剩余的未通过的请求,怎么办?走降级!可以返回一些默认的值,或者友情提示,或者空白的值。

缓存击穿

  • 缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。

  • 解决方式也很简单,可以将热点数据设置为永远不过期;或者基于 redis or zookeeper 实现互斥锁,等待第一个请求构建完缓存之后,再释放锁,进而其它请求才能通过该 key 访问数据。

14、如何保证缓存和数据库的一致性?(更新的时候,先更新数据库,再删除缓存)
15、Redis实现分布式锁?如果一个持有锁的客户端失败或崩溃了不能释放锁,该怎么解决?
16、redis 的并发竞争问题是什么?如何解决这个问题?了解 redis 事务的 CAS 方案吗?

  • 某个时刻,多个系统实例都去更新某个 key。可以基于 zookeeper 实现分布式锁。每个系统通过 zookeeper 获取分布式锁,确保同一时间,只能有一个系统实例在操作某个 key,别人都不允许读和写。
  • 你要写入缓存的数据,都是从 mysql 里查出来的,都得写入 mysql 中,写入 mysql 中的时候必须保存一个时间戳,从 mysql 查出来的时候,时间戳也查出来。
    每次要写之前,先判断一下当前这个 value 的时间戳是否比缓存里的 value 的时间戳要新。如果是的话,那么可以写,否则,就不能用旧的数据覆盖新的数据。

17、Redis热点Key发现及常见解决方案!link

  1. 服务端缓存方案
    首先 Client 会将请求发送至 Server 上,而 Server 又是一个多线程的服务,本地就具有一个基于 Cache LRU 策略的缓存空间。
    当 Server 本身就拥堵时,Server 不会将请求进一步发送给 DB 而是直接返回,只有当 Server 本身畅通时才会将 Client 请求发送至 DB,并且将该数据重新写入到缓存中。
    缓存失效,多线程构建缓存问题
    缓存丢失,缓存构建问题
    脏读问题

  2. 使用 Memcache、Redis 方案

  3. 使用本地缓存方案
    使用本地缓存则存在以下问题:
    需要提前获知热点
    缓存容量有限
    不一致性时间增长
    热点 Key 遗漏

传统的热点解决方案都存在各种各样的问题,那么究竟该如何解决热点问题呢?

  1. 读写分离方案解决热读
    架构中个节点的作用:
    1)SLB层做负载均衡
    2)Proxy层做读写分离自动路由
    3)Master负责写
    4)ReadOnly节点负责读请求
    5)Slave节点和Master节点做高可用
    实际过程中Client将请求传到SLB,SLB又将其分发至多个Proxy内,通过Proxy对请求的识别,将其进行分类发送。例如,将同为Write的请求发送到Master模块内,而将Read的请求发送至ReadOnly模块。而模块中的节点具有可以进一步扩充的优点,可以有效解决热点数据多的问题。读写分离同时具有可以灵活扩容读热点能力、可以存储大量热点Key和对客户友好等优点。
  2. 热点数据解决方案
    与上述方案不同,该方案通过主动发现热点并对其进行存储来解决热点Key的问题。首先Client也会访问SLB,并且通过SLB将各种请求分发至Proxy中,Proxy会按照基于路由的方式将请求转发至后端的Redis中。
    在热点key的解决上是采用在服务端增加缓存的方式进行。具体来说就是在Proxy上增加本地缓存,本地缓存采用LRU算法来缓存热点数据,后端db节点增加热点数据计算模块来返回热点数据。
    Proxy 架构的主要有以下优点:
    • Proxy 本地缓存热点,读能力可水平扩展
    • DB 节点定时计算热点数据集合
    • DB 反馈 Proxy 热点数据
    • 对客户端完全透明,不需做任何兼容

18、热点 key 处理(17中的热点数据解决方案)link

  1. 热点数据的读取
    在这里插入图片描述
    1. 在热点 Key 的处理上主要分为写入跟读取两种形式,在数据写入过程当 SLB 收到数据 K1 并将其通过某一个 Proxy 写入一个 Redis,完成数据的写入。
    2. 假若经过后端热点模块计算发现 K1 成为热点 key 后, Proxy 会将该热点进行缓存,当下次客户端再进行访问 K1 时,可以不经 Redis。
    3. 最后由于 proxy 是可以水平扩充的,因此可以任意增强热点数据的访问能力。
  2. 热点数据的发现
    在这里插入图片描述
    对于 db 上热点数据的发现,首先会在一个周期内对 Key 进行请求统计,在达到请求量级后会对热点 Key 进行热点定位,并将所有的热点 Key 放入一个小的 LRU 链表内,在通过 Proxy 请求进行访问时,若 Redis 发现待访点是一个热点,就会进入一个反馈阶段,同时对该数据进行标记。
    DB 计算热点时,主要运用的方法和优势有:
    1、基于统计阀值的热点统计
    2、基于统计周期的热点统计
    3、基于版本号实现的无需重置初值统计方法
    4、DB 计算同时具有对性能影响极其微小、内存占用极其微小等优点

消息队列

1、消息队列的主要作用?

应用解耦(系统拆分)
异步处理(预约挂号业务处理成功后,异步发送短信、推送消息、日志记录等)
流量削峰
顺序保证

2、消息队列的优缺点?
4.如何确保消息正确地发送至RabbitMQ? 如何确保消息接收方消费了消息?(发送方确认模式;2.消息队列丢数据;接收方确认机制)
5.如何避免消息重复投递或重复消费?

  • 在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重的依据(消息投递失败并重传),避免重复的消息进入队列;
  • 在消息消费时,要求消息体中必须要有一个bizId(对于同一业务全局唯一,如支付ID、订单ID、帖子ID等)作为去重的依据,避免同一条消息被重复消费。
    所以第二个问题来了,怎么保证消息队列消费的幂等性?
    其实还是得结合业务来思考,我这里给几个思路:

比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。
比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。
比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个 id 写 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。
比如基于数据库的唯一键来保证重复数据不会重复插入多条。 因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。

6.消息基于什么传输?
-由于TCP连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈。 RabbitMQ使用信道的方式来传输数据。信道是建立在真实的TCP连接内的虚拟连接,且每条TCP连接上的信道数量没有限制

7.消息如何分发?
9.如何确保消息不丢失?(消息持久化,当然前提是队列必须持久化)
10、如何保证消息的顺序性?

1、单线程消费来保证消息的顺序性;
2、对消息进行编号,消费者处理时根据编号判断顺序。 

11、如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?
12、RabbitMQ 怎么实现延迟消息队列?
-综合上述两个特性,设置了TTL规则之后当消息在一个队列中变成死信时,利用DLX特性它能被重新转发到另一个Exchange或者Routing Key,这时候消息就可以重新被消费了。
13、如果让你写一个消息队列,该如何进行架构设计?说一下你的思路

1、分布式
2、消息持久化,顺序写,这样就没有磁盘随机读写的寻址开销,磁盘顺序读写的性能是很高的,这就是kafka 的思路。
3、mq 的可用性。消息发送和消费的确认

Dubbo

1、RPC通过jdk的动态代理的方式来实现调用远程服务的

首先消费方从代理类中获取服务提供的接口,当消费方调用服务的时候回执行invoke方法,实现远程调用
2. Dubbo能做什么?
1.透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
2.软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
3、Dubbo执行流程

0.服务容器负责启动,加载,运行服务提供者。
1.服务提供者在启动时,向注册中心注册自己提供的服务。
2.服务消费者在启动时,向注册中心订阅自己所需的服务。
3.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
4.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
5.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

4、Dubbo默认协议:

连接个数:单连接
连接方式:长连接
传输协议:TCP
传输方式:NIO异步传输
序列化:Hessian二进制序列化
适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串。
适用场景:常规远程服务方法调用

5、Dubbo 的负载均衡策略

3.2.1 Random LoadBalance(默认,基于权重的随机负载均衡机制)
3.2.2 RoundRobin LoadBalance(不推荐,基于权重的轮询负载均衡机制)
3.2.3 LeastActive LoadBalance,最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
3.2.4 ConsistentHash LoadBalance,一致性 Hash,相同参数的请求总是发到同一提供者。(如果你需要的不是随机负载均衡,是要一类请求都到一个节点,那就走这个一致性hash策略。)

6、dubbo服务集群配置(集群容错模式)

FailoverCluster:(默认)失败自动切换,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。
FailfastCluster:快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作。
FailbackCluster:失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作。
FailsafeCluster:失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作。
ForkingCluster: 并行调用,只要一个成功即返回,通常用于实时性要求较高的操作,但需要浪费更多服务资源。
BroadcastCluster: 广播调用。遍历所有Invokers, 逐个调用每个调用catch住异常不影响其他invoker调用
MergeableCluster: 分组聚合, 按组合并返回结果,比如菜单服务,接口一样,但有多种实现,用group区分,现在消费方需从每种group中调用一次返回结果,合并结果返回,这样就可以实现聚合菜单项。
AvailableCluster: 获取可用的调用。遍历所有Invokers判断Invoker.isAvalible,只要一个有为true直接调用返回,不管成不成功

7、为什么要消费者比提供者个数多:

  • 因dubbo协议采用单一长连接,
    假设网络为千兆网卡(1024Mbit=128MByte),
    根据测试经验数据每条连接最多只能压满7MByte(不同的环境可能不一样,供参考),
    理论上1个服务提供者需要20个服务消费者才能压满网卡。

8、为什么不能传大包:

  • 因dubbo协议采用单一长连接,
    如果每次请求的数据包大小为500KByte,假设网络为千兆网卡(1024Mbit=128MByte),每条连接最大7MByte(不同的环境可能不一样,供参考),
    单个服务提供者的TPS(每秒处理事务数)最大为:128MByte / 500KByte = 262。
    单个消费者调用单个服务提供者的TPS(每秒处理事务数)最大为:7MByte / 500KByte = 14。
    如果能接受,可以考虑使用,否则网络将成为瓶颈。

9、dubbo通信协议dubbo协议为什么采用异步单一长连接:

  • 因为服务的现状大都是服务提供者少,通常只有几台机器,
    而服务的消费者多,可能整个网站都在访问该服务,
    比如Morgan的提供者只有6台提供者,却有上百台消费者,每天有1.5亿次调用,
    如果采用常规的hessian服务,服务提供者很容易就被压跨,
    通过单一连接,保证单一消费者不会压死提供者,
    长连接,减少连接握手验证等,
    并使用异步IO,复用线程池,防止C10K问题。

9、Dubbo在安全机制方面是如何解决的

  • Dubbo通过Token令牌防止用户绕过注册中心直连,然后在注册中心上管理授权。Dubbo还提供服务黑白名单,来控制服务所允许的调用方。

10、服务降级及Dubbo如何实现服务降级

  • 当我服务器的压力比较大的时候,我们可以通过服务降级功能 临时屏蔽某个出错的非关键服务,并定义降级后的返回策略,屏蔽掉不重要的服务如广告服务等,来降低核心业务的压力

  • 可以通过服务降级功能,临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。
    向注册中心写入动态配置覆盖规则:

  • mock=force:return+null,表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。

  • mock=fail:return+null,表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

  • dubbo 服务降级的真实含义:并不是对 provider 进行操作,而是告诉 consumer,调用服务时要做哪些动作。

11、四 zookeeper宕机与dubbo直连的情况

  • 在实际生产中,假如zookeeper注册中心宕掉,一段时间内服务消费方还是能够调用提供方的服务的,实际上它使用的本地缓存进行通讯,这只是dubbo健壮性的一种提现。
  • 在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连, 点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表,

12、服务提供者能实现失效踢出是什么原理?

  • 服务失效踢出基于zookeeper的临时节点原理。

13、为什么使用微服务:

1、降低复杂度:将原来偶合在一起的复杂业务拆分为单个服务,规避了原本复杂度无止境的积累。
2、可独立部署;由于微服务具备独立的运行进程,所以每个微服务可以独立部署。
3、容错
在微服务架构下,当某一组件发生故障时,故障会被隔离在单个服务中。 通过限流、熔断等方式降低错误导致的危害,保障核心业务正常运行。
4、扩展
单块架构应用也可以实现横向扩展,就是将整个应用完整的复制到不同的节点。当应用的不同组件在扩展需求上存在差异时,微服务架构便体现出其灵活性,因为每个服务可以根据实际需求独立进行扩展。
5.易于开发与维护
微服务相对小,易于理解;
启动时间短,开发效率高。

zookeeper

1、什么是zookeeper?

  • 定义:ZooKeeper 是一个开源的分布式应用程序协调服务
  • ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。

2、znode(ACL,data,child,stat)
在这里插入图片描述
3、watch机制 说一下 zookeeper 的通知机制

  • 我们可以理解成是注册在特定Znode上的触发器。当这个Znode发生改变,也就是调用了create,delete,setData方法的时候,将会触发Znode上注册的对应事件,请求Watch的客户端会接收到异步通知。
1.客户端调用getData方法,watch参数是true。服务端接到请求,返回节点数据,并且在对应的哈希表里插入被Watch的Znode路径,以及Watcher列表。
2.当被Watch的Znode已删除,服务端会查找哈希表,找到该Znode对应的所有Watcher,异步通知客户端,并且删除哈希表中对应的Key-Value。

3、重要概念总结
在这里插入图片描述
4、会话session
在这里插入图片描述
5、ZXID

  • 对于来自客户端的每个更新请求,ZooKeeper 都会分配一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序,应用程序可以使用 ZooKeeper 这个特性来实现更高层次的同步原语。 这个编号也叫做时间戳——zxid(Zookeeper Transaction Id)
  • 在ZAB协议中,每个消息都被赋予了一个zxid,zxid全局唯一。zxid有两部分组成:高32位是epoch,低32位是epoch内的自增id,由0开始。每次选出新的Leader,epoch会递增,同时zxid的低32位清0。 这其实像极了咱们古代封建王朝的君主更替,每一次的江山易主,君王更替。

6、 ZAB 协议两种基本的模式:崩溃恢复;消息广播

  • ZAB(ZooKeeper Atomic Broadcast 原子广播) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。 在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性, 基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。
崩溃恢复
1.Leader election(选举阶段):节点在一开始都处于选举阶段,只要有一个节点得到超半数节点的票数,它就可以当选准 leader。
2.Discovery(发现阶段):在这个阶段,followers 跟准 leader 进行通信,同步 followers 最近接收的事务提议。用于在从节点中发现最新的ZXID和事务日志
3.Synchronization(同步阶段):同步阶段主要是利用 leader 前一阶段获得的最新提议历史,同步集群中所有的副本。同步完成之后,准 leader 才会成为真正的 leader。

消息广播
4.Broadcast(广播阶段):到了这个阶段,Zookeeper 集群才能正式对外提供事务服务,并且 leader 可以进行消息广播。同时如果有新的节点加入,还需要对新节点进行同步。

7、zookeeper如何实现分布式锁
在这里插入图片描述

Spring、SpringMVC、Mybatis

1、列举一些重要的Spring模块?
2、谈谈自己对于 Spring IoC 和 AOP 的理解

  • IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IoC 在其他语言中也有应用,并非 Spirng 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
  • AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
  • Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:
  • AOP实现的方式有动态代理也叫运行时增强,比如jdk代理、CGLIB;静态代理是在编译时进行织入或类加载时进行织入,比如AspectJ

3、依赖注入

  • 这里的DI也就是依赖注入,就是实现控制反转的方式。
  • 一个对象的创建往往会涉及到其他对象的创建,比如一个对象A的成员变量持有着另一个对象B的引用,这就是依赖,A依赖于B。IOC机制既然负责了对象的创建,那么这个依赖关系也就必须由IOC容器负责起来。负责的方式就是DI——依赖注入,通过将依赖关系写入配置文件,然后在创建有依赖关系的对象时,由IOC容器注入依赖的对象,如在创建A时,检查到有依赖关系,IOC容器就把A依赖的对象B创建后注入到A中(组装,通过反射机制实现),然后把A返回给对象请求者,完成工作。

4、Spring 常用的注入方式有哪些?(设值注入、构造器注入、注解注入)
5、Spring AOP 和 AspectJ AOP 有什么区别?

  • Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

6、Spring 中的 bean 的作用域有哪些?(singleton :prototype;request;session)
7、Spring 中的单例 bean 的线程安全问题了解吗?

  • 单例 bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。
  • 常见的有两种解决办法:
    • 在Bean对象中尽量避免定义可变的成员变量(不太现实)。
    • 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。
    • 你也可以把Controller的scope改成prototype,实际上Struts2就是这么做的,但有一点要注意,Spring MVC对请求的拦截粒度是基于每个方法的,而Struts2是基于每个类的,所以把Controller设为多例将会频繁的创建与回收对象,严重影响到了性能。
    • 不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。

8、Spring 中的事务隔离级别?(默认+4种)
9、Spring 中的事物传播行为?(6种:支持当前事务的情况+不支持当前事务的情况)

TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

10、@Component 和 @Bean 的区别是什么?

作用对象不同: @Component 注解作用于类,而@Bean注解作用于方法。

11、Spring 框架中用到了哪些设计模式?

工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
装饰者模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller

12、将一个类声明为Spring的 bean 的注解有哪些?
13、TransactionDefinition接口介绍

1)事务隔离级别(定义了一个事务可能受其他并发事务影响的程度):(五种)
(2)事务传播行为(为了解决业务层方法之间互相调用的事务问题):
(3) 事务超时属性(一个事务允许执行的最长时间)
(4) 事务只读属性(对事物资源是否执行只读操作)
(5) 回滚规则(定义事务回滚规则)

SpringMVC

1、SpringMVC 工作原理了解吗?

客户端(浏览器)发送请求,直接请求到 DispatcherServlet。
DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。
解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。
HandlerAdapter 会根据 Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。
ViewResolver 会根据逻辑 View 查找实际的 View。
DispaterServlet 把返回的 Model 传给 View(视图渲染)。
把 View 返回给请求者(浏览器)

2、springmvc的五个常用注解?(@RequestMapping,@RequestParam,@PathViriable,@ResponseBody,@ModelAttribute,@SessionAttributes)

3、SpringMVC 的重要组件有哪些?
4、 SpringMVC怎样设定重定向和转发 ,转发和重定向的区别?

  • 在返回值的前面加”forward”,就可以实现让结果转发;
    在返回值的前面加上”redirect”,就可以让返回值重定向
    5、为什么要在 Spring MVC 中使用适配器模式?

6、SpringMVC 的控制器是不是单例模式,如果是,有什么问题,怎么解决?

  • 默认情况下是单例模式,
    在多线程进行访问的时候,有线程安全问题.
    但是不建议使用同步,因为会影响性能.
    解决方案,是在控制器里面不能写成员变量.
  • 万一必须要定义一个非静态成员变量时候,则通过注解@Scope(“prototype”),将其设置为多例模式。或者通过ThreadLocal实现

7、Controller为什么设计成单例设计模式?

1.性能(不用每次请求都创建对象)
2.不需要多例(不要在控制器中定义成员变量)

8、SpringMVC 里面拦截器是怎么写的?

  • 1) 写一个java类,实现HandlerInterceptor接口; 2) 在接口方法当中,实现处理逻辑。 3) 配置拦截器 4) 拦截器还可以设置优先级:依据配置的顺序来执行

9、拦截器和过滤器的区别

  ①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
  ②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
  ③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
  ④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  ⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
  ⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

10、SpringMVC 用什么对象从后台向前台传递数据的?

1.使用Map、Model和ModelMap的方式
2.使用ModelAndView的方式:

11、Spring MVC核心技术(数据验证、拦截器、类型转换器、异常处理、请求转发和重定向、文件上传)

Mybatis

1、JDBCStatement和PreparedStatement的异同及优缺点

  • PreparedStatement的预编译是数据库进行的,编译后的函数key是缓存在PreparedStatement中的,编译后的函数是缓存在数据库服务器中的。预编译前有检查sql语句语法是否正确的操作。只有数据库服务器支持预编译功能时,JDBC驱动才能够使用数据库的预编译功能,否则会报错。
    在这里插入图片描述
    2、sql预编译在这里插入图片描述
    3、JDBC编程步骤在这里插入图片描述
    4、MyBatis 中 #{} 和 ${} 的区别
    在这里插入图片描述
    5、Mybatis 有几种分页方式?
    在这里插入图片描述
    6、Mybatis 是否支持延迟加载?延迟加载的原理是什么?
    在这里插入图片描述
    7、说一下 Mybatis 的一级缓存和二级缓存?
    在这里插入图片描述
    8、Mybatis 和 Hibernate 的区别有哪些?
    在这里插入图片描述
    9、Mybatis 有哪些执行器(Executor)
  • 答:Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。1)SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。2)ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map 3)BatchExecutor:完成批处理。执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。

10、Mybatis 分页插件的实现原理是什么?
在这里插入图片描述

设计模式

1、工厂方法模式和抽象工厂模式有什么区别?
工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。 一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。 一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类可以创建多个具体产品类的实例。

抽象工厂(AbstractFactory)角色 :是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
具体工厂类(ConreteFactory)角色 :这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
抽象产品(Abstract Product)角色 :工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
具体产品(Concrete Product)角色 :抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。在抽象工厂中创建的产品属于同一产品族,这不同于工厂模式中的工厂只创建单一产品,我后面也会详解介绍到。

区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

2、请手写一下单例模式?
3、解释器、迭代器、观察者、适配器、组合、外观、代理等模式的原理是什么?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值