java高频面试题汇总

Java 基础

Java 中的序列化和反序列化是什么?

序列化是将 Java 对象转换为字节流的过程,以便可以将其存储在文件中或通过网络进行传输。反序列化则是将字节流恢复为 Java 对象的过程。通过实现 Serializable 接口,Java 对象可以支持序列化。

什么是 Java 中的不可变类?

不可变类是指其对象一旦创建就不能被修改的类。Java 中的 String 类是一个典型的不可变类。不可变类通常通过:

  • 所有字段使用 final 修饰。
  • 没有 setter 方法。
  • 返回对象的属性时返回深拷贝。

Java 中 Exception 和 Error 有什么区别?

ExceptionError 都是 Throwable 类的子类,但它们有不同的含义:

  • Exception 是可捕获的异常,表示程序可以处理的异常情况。
  • Error 是严重的错误,通常是 JVM 级别的错误,如内存不足,程序无法恢复。比如

你认为 Java 的优势是什么?

Java 的优势包括:

  1. 跨平台性:依赖 JVM 的"编译一次,运行多处"。
  2. 丰富的类库:提供了丰富的标准库和第三方库支持。
  3. 强大的社区支持:有活跃的开发者社区。
  4. 自动内存管理:垃圾回收机制减少了内存泄漏问题。
  5. 安全性:内置的安全机制,防止内存泄露和非法操作。

什么是 Java 的多态特性?

多态是指同一个方法或对象在不同的上下文中表现出不同的行为。Java 支持两种多态:

  • 编译时多态(方法重载)。
  • 运行时多态(通过继承与接口实现,动态绑定)。

Java 中的参数传递是按值还是按引用?

Java 中的参数传递是按值传递的。对于基本数据类型,传递的是数值的副本;对于对象,传递的是对象引用的副本,但不影响原对象的引用地址。

java 复制代码
public static void main(String[] args) {
    User user = new User().setId(0L);
    long id = 123L;
    System.out.println(user.getId());// 0
    setId(user, id);
    System.out.println(user.getId());// 123L
}

private static void setId(User user, long id){
    user.setId(user, id);
}

为什么 Java 不支持多重继承?

Java 不支持类的多重继承,因为它会导致"钻石问题",即多个父类具有相同的方法时,子类无法决定调用哪一个方法。Java 通过接口解决了这一问题,允许类实现多个接口。

Java 面向对象编程与面向过程编程的区别是什么?

  • 面向对象编程 (OOP):基于对象的概念,强调封装、继承和多态,通过对象交互来设计程序。
  • 面向过程编程:以过程(函数)为中心,强调任务的顺序和步骤。

Java 方法重载和方法重写之间的区别是什么?

  • 方法重载:同一个类中定义多个同名方法,但参数列表不同,属于编译时多态。
  • 方法重写:子类重新定义父类的方法,方法签名相同,属于运行时多态。

什么是 Java 内部类?它有什么作用?

内部类是在一个类的内部定义的类,分为成员内部类、局部内部类、匿名内部类和静态内部类。作用包括:

  1. 增加封装性。
  2. 能够访问外部类的成员。
  3. 实现接口时,可以通过匿名内部类快速实现。

JDK8 有哪些新特性?

JDK8 引入了多个重要的新特性:

  1. Lambda 表达式:简化函数式编程。
  2. Stream API:简化集合操作的功能。
  3. 默认方法:接口中可以包含有默认实现的方法。
  4. Optional 类 :避免 null 引发的 NullPointerException

Java 中 String、StringBuffer 和 StringBuilder 的区别是什么?

  • String:不可变类,每次修改都会创建新对象。
  • StringBuffer:可变类,线程安全,适用于多线程环境。
  • StringBuilder :可变类,非线程安全,适用于单线程环境,性能优于 StringBuffer

Java 的 StringBuilder 是怎么实现的?

StringBuilder 是通过内部的可变字符数组实现的,它通过动态扩展数组的大小来提高字符串拼接的效率。它的操作是非线程安全的,因此适用于单线程环境。

Java 中包装类型和基本类型的区别是什么?

基本类型是 Java 提供的内置类型,例如 intchar,直接存储数据值。包装类型是对应的类,例如 IntegerCharacter,用于封装基本类型并提供额外的功能。

接口和抽象类有什么区别?

  • 接口:所有方法默认为抽象方法,类可以实现多个接口。
  • 抽象类:可以有具体实现的方法,类只能继承一个抽象类。

JDK 和 JRE 有什么区别?

  • JDK(Java Development Kit)是用于开发 Java 应用程序的工具包,包含了编译器、调试工具等。
  • JRE(Java Runtime Environment)是用于运行 Java 程序的环境,包含了 JVM 和运行库。

你使用过哪些 JDK 提供的工具?

常用的 JDK 工具包括:

  • javac:Java 编译器。
  • java:运行 Java 应用程序的工具。
  • javadoc:生成 Java 文档的工具。
  • jstack:用于查看线程堆栈的工具。
  • jmap:用于生成堆转储的工具。

Java 中 hashCode 和 equals 方法是什么?它们与 == 操作符有什么区别?

  • hashCode:返回对象的哈希值,用于哈希表等数据结构。
  • equals:判断两个对象是否"逻辑上"相等。
  • ==:比较变量在栈中的值(对象类型的值为引用地址)。

Java 中的 hashCode 和 equals 方法之间有什么关系?

在 Java 中,两个对象如果通过 equals 方法判断相等,那么它们的 hashCode 值必须相同。否则,在使用哈希表时会出现问题。

什么是 Java 中的动态代理?

动态代理允许在运行时为接口生成代理类,并为代理类的方法调用提供自定义的处理逻辑。JDK 提供了 Proxy 类来实现动态代理。

JDK 动态代理和 CGLIB 动态代理有什么区别?

  • JDK 动态代理:只能为接口生成代理类。
  • CGLIB 动态代理 :基于继承,能够为类生成代理,但不能代理 final 方法。

Java 中的注解原理是什么?

Java 的注解是一种元数据,注解通过反射在运行时被解析和处理。注解可以通过自定义注解和反射机制来实现自定义功能。

你使用过 Java 的反射机制吗?如何应用反射?

是的,反射允许在运行时获取类的信息,并操作类的字段和方法。常用于框架和库中,例如对象的动态创建和方法调用。通过 ClassMethod 等类来实现反射。

什么是 Java 的 SPI(Service Provider Interface)机制?

SPI 是 Java 提供的一种服务发现机制,通过在 META-INF/services 目录下的配置文件声明服务接口的实现类,允许模块化应用程序动态加载服务提供者。

Java 泛型的作用是什么?

泛型允许类、接口和方法能够操作任意类型的数据,提供了编译时类型检查,并避免了强制类型转换。

Java 泛型擦除是什么?

泛型擦除是指 Java 在编译时会移除泛型类型信息,在运行时,泛型类型信息不再存在。这是为了保持向后兼容性。

什么是 Java 泛型的上下界限定符?

  • 上界限定符 :使用 <? extends T> 表示泛型类型必须是 TT 的子类。
  • 下界限定符 :使用 <? super T> 表示泛型类型必须是 TT 的父类。

Java 中的深拷贝和浅拷贝有什么区别?

  • 浅拷贝:复制对象的引用,修改副本会影响原对象。
  • 深拷贝:复制对象及其所有子对象,完全独立。

什么是 Java 的 Integer 缓存池?

Java 为了优化 Integer 对象的使用,缓存了 -128 到 127 之间的 Integer 对象。当这些范围内的 Integer 被创建时,会从缓存中返回对象,而不是创建新对象。

Java 的类加载过程是怎样的?

Java 的类加载过程包括以下阶段:

  1. 加载 :将 .class 文件加载到 JVM 中。
  2. 链接:验证、准备和解析类。
  3. 初始化:执行静态初始化块和静态变量赋值。

什么是 Java 的 BigDecimal?

BigDecimal 是 Java 提供的用于处理高精度计算的

类,通常用于金融计算中。它能够处理任意精度的小数运算,避免浮点数精度丢失问题。

使用 new String("yupi") 语句在 Java 中会创建多少个对象?

会创建两个对象:

  1. 字符串常量池中的 "yupi"
  2. 堆中的 String 对象。

Java 中 final、finally 和 finalize 各有什么区别?

  • final:用于修饰类、方法或变量,表示不可变或不可继承。
  • finally :用于 try-catch 语句中,确保无论是否有异常,都会执行其中的代码。
  • finalize:在对象被垃圾回收前由 JVM 调用的方法。

为什么在 Java 中编写代码时会遇到乱码问题?

Java 在处理字符集时,如果源文件的编码格式与系统或运行时的编码不一致,可能会导致乱码问题,尤其是在跨平台开发时。

为什么 JDK 9 中将 String 的 char 数组改为 byte 数组?

为了节省内存,JDK 9 中将 String 的底层实现由 char[] 改为 byte[],并引入了 Compact Strings,根据实际字符集选择合适的编码。

如何在 Java 中调用外部可执行程序或系统命令?

可以通过 Runtime.getRuntime().exec()ProcessBuilder 来执行外部可执行程序或系统命令。

如果一个线程在 Java 中被两次调用 start() 方法,会发生什么?

会抛出 IllegalThreadStateException 异常,因为线程只能启动一次。

栈和队列在 Java 中的区别是什么?

  • :后进先出(LIFO),常用的实现是 Stack 类。
  • 队列 :先进先出(FIFO),常用的实现是 Queue 接口及其子类。

Java 的 Optional 类是什么?它有什么用?

Optional 是 JDK 8 引入的类,用来避免 null 引发的 NullPointerException。通过 Optional,可以显式地表示值的存在或缺失。

Java 的 I/O 流是什么?

Java 的 I/O 流用于读取和写入数据。按处理数据类型分为字节流(InputStreamOutputStream)和字符流(ReaderWriter)。

什么是 Java 的网络编程?

Java 提供了 java.net 包用于网络编程,通过 SocketServerSocket 实现 TCP/IP 通信,通过 DatagramSocket 实现 UDP 通信。

Java 中的基本数据类型有哪些?

Java 提供了 8 种基本数据类型:byteshortintlongfloatdoublecharboolean

什么是 Java 中的自动装箱和拆箱?

自动装箱是指将基本数据类型自动转换为相应的包装类型,拆箱是指将包装类型转换为基本数据类型。

什么是 Java 中的迭代器(Iterator)?

Iterator 是用于遍历集合元素的接口。通过 Iterator 可以安全地在遍历时移除元素。

Java 运行时异常和编译时异常之间的区别是什么?

  • 编译时异常 :在编译阶段被捕获,必须处理,如 IOException
  • 运行时异常 :在程序运行时抛出,不强制要求处理,如 NullPointerException

什么是 Java 中的继承机制?

继承机制允许一个类继承另一个类的属性和方法,从而实现代码复用。子类可以重写父类的方法。

什么是 Java 的封装特性?

封装是面向对象编程的基本特性之一,通过将对象的属性和行为隐藏起来,并提供公共的访问方法,控制对数据的访问和修改。

Java 中的访问修饰符有哪些?

Java 中的访问修饰符包括:

  • public:对所有类可见。
  • protected:对同包类和子类可见。
  • default:对同包类可见。
  • private:仅对本类可见。

Java 中静态方法和实例方法的区别是什么?

  • 静态方法:属于类而不属于对象,可以通过类名调用。
  • 实例方法:属于对象,必须通过对象调用。

Java 中 for 循环与 foreach 循环的区别是什么?

  • for 循环:可以自定义循环条件和步进,灵活性强。
  • foreach 循环 :简化集合或数组的遍历,但无法获取索引。foreach 是通过迭代器Itr implements Iterator实现的语法糖,它只允许通过当前Itr对集合进行修改。

什么是 Java 中的双亲委派模型?

双亲委派模型是一种类加载机制,每个类加载器在加载类时,首先会请求其父加载器进行加载,只有当父加载器找不到时,才会尝试自己加载。

Java 中 wait() 和 sleep() 的区别?

  • wait() :释放锁,线程进入等待状态,需通过 notify()notifyAll() 唤醒。
  • sleep():不释放锁,线程暂停指定时间后自动恢复。

Java 和 Go 的区别

  • Java:是一种面向对象的跨平台语言,拥有丰富的生态系统,依赖 JVM 运行。
  • Go:是一种面向系统编程的语言,简洁高效,支持并发,编译成本地代码运行。

Java Object 类中有什么方法,有什么作用?

Object 类是所有类的父类,提供了 equals()hashCode()toString()clone() 等方法,用于比较、哈希、输出对象信息、克隆对象等操作。

Java 中的字节码是什么?

Java 字节码是由 Java 编译器生成的中间代码,存储在 .class 文件中。字节码可以在任何支持 JVM 的平台上执行,由 JVM 解释或编译为机器码运行。

Java 集合

说说 Java 中 HashMap 的原理?

HashMap 是基于散列表(哈希表)实现的,它通过 keyhashCode() 值来快速定位存储值的位置。HashMap 使用数组来存储键值对,数组中的每个元素称为一个"桶"(bucket)。当多个键的 hashCode 值相同时,它们会被存储在同一个桶中,形成一个链表(在 JDK 1.8 中,当链表长度超过一定阈值时,会将链表转换为红黑树)。当插入、删除、查找元素时,通过计算键的哈希值来快速确定存储位置。

使用 HashMap 时,有哪些提升性能的技巧?

  1. 设置合理的初始容量 :如果可以预估存储的元素数量,设置合理的初始容量可以减少 HashMap 的扩容次数,提升性能。
  2. 适当调整负载因子 :默认负载因子为 0.75,表示当 HashMap 达到容量的 75% 时会扩容。如果对性能要求较高且存储空间充足,可以减小负载因子,减少哈希冲突。
  3. 避免使用复杂的 key 对象keyhashCode() 方法和 equals() 方法的效率会影响性能,复杂对象的计算可能会导致性能瓶颈。
  4. 选择合适的哈希函数 :确保 hashCode() 方法能够生成良好的哈希分布,以避免哈希碰撞。

什么是 Hash 碰撞?怎么解决哈希碰撞?

Hash 碰撞 是指不同的键通过哈希函数计算后得到相同的哈希值,这种情况下会将多个键值对存储在同一个桶中。在 Java 的 HashMap 中,通常通过链地址法(链表或红黑树)来解决碰撞问题。当冲突过多时,会将链表结构转换为红黑树以优化查找效率。

Java 的 CopyOnWriteArrayList 和 Collections.synchronizedList 有什么区别?分别有什么优缺点?

CopyOnWriteArrayListCollections.synchronizedList 都是线程安全的列表实现,但实现方式不同:

  • CopyOnWriteArrayList:每次对列表进行修改时,都会创建列表的副本。优点是读操作不需要加锁,性能高;缺点是修改操作开销大,不适合频繁修改的场景。
  • Collections.synchronizedList:使用同步锁实现线程安全,所有读写操作都会被同步。优点是修改操作性能较好;缺点是读操作也需要加锁,导致性能下降。

Java 中有哪些集合类?请简单介绍

  1. List :有序、可重复的集合,如 ArrayListLinkedList
  2. Set :无序、不可重复的集合,如 HashSetTreeSet
  3. Map :键值对形式的集合,如 HashMapTreeMap
  4. Queue :先进先出的队列集合,如 LinkedListPriorityQueue
  5. Deque :双端队列,如 ArrayDeque

数组和链表在 Java 中的区别是什么?

  • 数组:支持快速随机访问,查找效率高,但增删操作效率低(需要移动元素)。
  • 链表:不支持随机访问,但插入和删除操作效率高(只需改变节点指针)。

Java 中的 List 接口有哪些实现类?

List 接口的常见实现类有:

  • ArrayList
  • LinkedList
  • Vector
  • CopyOnWriteArrayList

Java 中 ArrayList 和 LinkedList 有什么区别?

  • ArrayList:基于数组实现,支持快速随机访问,但插入和删除元素时可能需要移动大量元素,增删操作效率较低。
  • LinkedList:基于链表实现,增删元素效率较高,但不支持快速随机访问,查找效率较低。

Java ArrayList 的扩容机制是什么?

ArrayList 在容量不够时会自动扩容,默认扩容策略是将容量增加为原来的 1.5 倍(即 newCapacity = oldCapacity + (oldCapacity >> 1))。

Java 中的 HashMap 和 Hashtable 有什么区别?

  • HashMap 是线程不安全的,而 Hashtable 是线程安全的。
  • HashMap 允许 null 键和值,而 Hashtable 不允许 null 键和值。
  • HashMap 性能更高,因为它不需要同步机制。

Java 中的 HashSet 和 HashMap 有什么区别?

  • HashSet 是基于 HashMap 实现的,HashSet 内部使用 HashMap 来存储元素。
  • HashSet 只存储元素,而 HashMap 存储键值对。

Java 中 HashMap 的扩容机制是怎样的?

HashMap 的扩容机制是当元素数量超过阈值(容量 * 负载因子)时,数组会扩展到原来的两倍,并重新分配桶中元素的位置。

为什么 HashMap 在 Java 中扩容时采用 2 的 n 次方倍?

因为扩容为 2 的幂次方能够保证哈希值取模操作可以通过位运算(& 操作)快速计算,从而提高效率。

为什么 Java 中 HashMap 的默认负载因子是 0.75?

负载因子 0.75 是性能与空间之间的折中选择,它在保证查找性能的同时,减少了哈希碰撞的概率,并且在容量利用率上比较理想。

为什么 JDK 1.8 对 HashMap 进行了红黑树的改动?

在 JDK 1.8 中,当链表长度超过 8 时,会将链表转换为红黑树,以避免链表过长导致的查找性能下降。

JDK 1.8 对 HashMap 除了红黑树还进行了哪些改动?

JDK 1.8 中,HashMap 的桶不再是数组+链表的单一形式,改为了链表+红黑树。同时,重新优化了哈希分布算法,以减少哈希碰撞。

Java 中的 LinkedHashMap 是什么?

LinkedHashMapHashMap 的子类,它保留了元素的插入顺序或访问顺序,通过双向链表来维护这种顺序。

Java 中的 TreeMap 是什么?

TreeMap 是基于红黑树实现的有序 Map,它按照键的自然顺序或自定义顺序对元素进行排序。

Java 中的 IdentityHashMap 是什么?

IdentityHashMap 是一种特殊的 Map,它使用 == 而不是 equals() 来比较键的相等性,适用于需要严格区分对象引用的场景。

Java 中的 WeakHashMap 是什么 ?

WeakHashMap 使用弱引用作为键,当键不再被引用时,键值对会被自动回收,适用于缓存等场景。

Java 中 ConcurrentHashMap 1.7 和 1.8 之间有哪些区别?

在 JDK 1.7 中,ConcurrentHashMap 使用了分段锁机制,而在 JDK 1.8 中,改为使用 CAS 和 synchronized 来提高并发性能,并引入了红黑树来优化冲突严重时的查找效率。

Java 中 ConcurrentHashMap 的 get 方法是否需要加锁?

ConcurrentHashMapget 方法是无锁的,因为它是通过 volatile 变量和 CAS 实现的,并不需要加锁。

为什么 Java 的 ConcurrentHashMap 不支持 key 或 value 为 null?

ConcurrentHashMap 不支持 null 键值的原因是,null 会导致在并发环境下无法判断返回的结果是 null 还是键不存在,可能会引起歧义和错误。

Java 中的 CopyOnWriteArrayList 是什么?

CopyOnWriteArrayList 是线程安全的 List 实现,它在修改时会复制整个数组,适用于读操作远多于写操作的场景。

你遇到过 ConcurrentModificationException 错误吗?它是如何产生的?

ConcurrentModificationException 是在迭代集合时,如果其他线程对集合进行了结构性修改(如增删元素),会抛出的异常。

Java 并发

新值,从而实现原子操作。

说说 AQS 吧?

AQS(AbstractQueuedSynchronizer)是 Java 中的一个框架,用于构建锁和同步器。它通过一个 FIFO 队列来管理线程的访问请求,提供了重入锁、读写锁等多种实现。

Java 中 ReentrantLock 的实现原理是什么?

ReentrantLock 是基于 AQS 实现的可重入锁,支持公平和非公平两种策略。它使用一个整数标志来记录锁的重入次数,并维护一个等待线程的队列。

Java 的 synchronized 是怎么实现的?

synchronized 是通过对象监视器实现的,底层使用 monitor 机制进行同步。进入 synchronized 方法或代码块时,线程会获取对象的锁,离开时释放锁。

Java 中的 synchronized 轻量级锁是否会进行自旋?

轻量级锁在竞争发生时会进行自旋,以减少线程上下文切换的开销,直到锁被成功获取或升级为重量级锁。

当 Java 的 synchronized 升级到重量级锁后,所有线程都释放锁了,此时它还是重量级锁吗?

一旦升级到重量级锁,锁对象会保持重量级锁的状态,直到所有持有锁的线程释放锁为止。

什么是 Java 中的锁自适应自旋?

锁自适应自旋是指在获取锁时,JVM 会根据线程竞争的情况自动决定自旋的时间长度,以减少上下文切换带来的开销。

Synchronized 和 ReentrantLock 有什么区别?

  1. 实现方式synchronized 是 JVM 实现的,ReentrantLock 是通过 AQS 实现的。
  2. 功能ReentrantLock 提供了更多的功能,如可重入、可中断和公平锁等。
  3. 性能 :在高竞争情况下,ReentrantLock 性能更优,因为它可以使用自旋锁。

如何优化 Java 中的锁的使用?

优化锁的使用可以采取以下方法:

  1. 减小临界区:尽量缩小加锁范围。
  2. 使用读写锁:对于读多写少的场景,使用读写锁提高并发性能。
  3. 减少锁的粒度:避免对整个对象加锁,尽可能细化锁定的对象。
  4. 使用非阻塞算法:例如 CAS 操作。

你了解 Java 中的读写锁吗?

读写锁是 ReentrantReadWriteLock 实现的一种锁,允许多个线程同时读取共享数据,但在写线程访问时禁止其他读写线程访问。适用于读多写少的场景。

什么是 Java 内存模型(JMM)?

Java 内存模型(JMM)定义了 Java 程序中线程如何与内存交互的规则,确保线程之间的可见性和有序性,帮助开发者理解多线程编程中的行为。

什么是 Java 中的原子性、可见性和有序性?

  • 原子性:保证操作的不可分割性,要么全部成功,要么全部失败。
  • 可见性:一个线程对共享变量的修改能够及时被其他线程看到。
  • 有序性:保证程序执行顺序的一致性,避免指令重排导致的错误。

什么是 Java 的 happens-before 规则?

Happens-before 规则是一组确定性规则,用于保证一个操作的结果对另一个操作可见,确保多线程环境中的可见性。

什么是 Java 中的指令重排?

指令重排是编译器或 CPU 为优化性能而改变指令执行顺序的过程。虽然可能影响程序的执行顺序,但 Java 内存模型确保了在正确的 happens-before 关系下,程序结果的一致性。

Java 中的 final 关键字是否能保证变量的可见性?

final 关键字可以保证对象的初始化安全,但不能单独保证对非 final 变量的可见性。

为什么在 Java 中需要使用 ThreadLocal?

ThreadLocal 提供了每个线程独立的变量副本,避免了共享数据引发的线程安全问题,常用于实现用户会话、数据库连接等。

Java 中的 ThreadLocal 是如何实现线程资源隔离的?

ThreadLocal 通过内部维护一个以当前线程为 key 的 Map,存储每个线程独立的变量,确保不同线程之间的数据隔离。

为什么 Java 中的 ThreadLocal 对 key 的引用为弱引用?

为了避免内存泄漏,ThreadLocal 的 key 使用弱引用,这样在没有其他强引用指向 ThreadLocal 对象时,可以被垃圾回收,确保资源的及时释放。

Java 中使用 ThreadLocal 的最佳实践是什么?

最佳实践包括:

  1. 仅在必要时使用 ThreadLocal。
  2. 在线程结束时显式清理 ThreadLocal,防止内存泄漏。
  3. 对 ThreadLocal 变量进行封装,避免直接暴露给外部。

Java 中的 InheritableThreadLocal 是什么?

InheritableThreadLocalThreadLocal 的子类,允许子线程继承父线程的值,适合需要在线程间共享数据的场景。

ThreadLocal 的缺点?

缺点包括:

  1. 可能导致内存泄漏,特别是在长时间运行的应用中。
  2. 对于大量线程,可能导致内存占用增加。
  3. 使用不当可能导致难以追踪的 bug。

为什么 Netty 不使用 ThreadLocal 而是自定义了一个 FastThreadLocal?

Netty 自定义 FastThreadLocal 主要是为了提高性能和减少内存开销,FastThreadLocal 通过减少数组长度和降低锁竞争来实现更高效的线程本地存储。

什么是 Java 的 TransmittableThreadLocal?

TransmittableThreadLocal 是一种扩展自 ThreadLocal 的类,支持在线程上下文之间传递值,适合用于异步调用场景。

Java 中 Thread.sleep 和 Thread.yield 的区别?

  • Thread.sleep(long millis):让当前线程暂停执行指定时间,进入阻塞状态。
  • Thread.yield():建议 JVM 暂停当前线程,允许其他同优先级线程获得执行机会,但不保证立即生效。

Java 中 Thread.sleep(0) 的作用是什么?

Thread.sleep(0) 通常用于让出 CPU 执行权,允许其他线程执行,但没有明确的时间限制。

Java 中的 wait、notify 和 notifyAll 方法有什么作用?

  • wait():使当前线程等待并释放锁,直到被其他线程唤醒。
  • notify():随机唤醒一个等待该对象锁的线程。
  • notifyAll():唤醒所有等待该对象锁的线程。

Java 中什么情况会导致死锁?如何避免?

死锁发生在两个或多个线程相互等待对方释放持有的锁。避免死锁的方法包括:

  1. 避免嵌套锁定。
  2. 采用定时锁。
  3. 按照固定顺序加锁。

Java 中 volatile 关键字的作用是什么?

volatile 关键字用于修饰变量,确保变量在多个线程间的可见性,禁止指令重排,但不保证原子性。

什么是 Java 中的 ABA 问题?

ABA 问题是指在执行 CAS 操作时,某个变量在比较后被其他线程修改,然后又被修改回原值,导致 CAS 操作成功,但实际状态已被改变。

在 Java 中主线程如何知晓创建的子线程是否执行成功?

主线程可以通过 Threadjoin() 方法等待子线程执行完毕,并通过子线程中的共享变量或返回值获取执行结果。

Java 虚拟机

Java 中有哪些垃圾回收算法?

Java 中常见的垃圾回收算法主要包括:

  1. 标记-清除算法:通过标记活跃对象,然后清除未标记的对象。简单但容易产生内存碎片。
  2. 标记-整理算法:与标记-清除类似,但在清除后整理存活对象,避免内存碎片。
  3. 复制算法:将内存分为两个相同的区域,每次只使用一个区域,回收时将存活对象复制到另一个区域。
  4. 分代收集算法:将堆内存分为新生代和老年代,根据对象存活时间不同选择不同的收集算法。

JVM 的 TLAB(Thread-Local Allocation Buffer)是什么?

TLAB 是每个线程在 Java 堆中分配的一块小内存区域,用于提高对象的分配效率。每当线程需要分配新对象时,会首先尝试在自己的 TLAB 中分配空间,避免了竞争和加锁的开销。

Java 是如何实现跨平台的?

Java 的跨平台能力主要通过 Java 虚拟机(JVM) 来实现。Java 程序首先编译成平台无关的字节码(.class 文件),然后由 JVM 在具体的操作系统上执行。不同平台上可以有不同实现的 JVM,使得同一份 Java 代码可以在多个平台上运行。

编译执行与解释执行的区别是什么?JVM 使用哪种方式?

  • 编译执行:将整个源代码编译成机器码,然后直接执行,速度较快。C 语言编译为可执行文件即为此方式。
  • 解释执行:逐行读取源代码并执行,速度较慢,但便于调试。Python 是典型的解释型语言。

JVM 采用 混合模式,既使用编译(JIT 编译)来提升性能,也使用解释执行来提高灵活性。

JVM 的内存区域是如何划分的?

JVM 的内存区域主要划分为以下几个部分:

  1. 方法区:存储类信息、常量、静态变量等。
  2. 堆区:用于存储对象实例,是 Java 中最大的内存区域。
  3. 栈区:每个线程独立的栈,用于存储局部变量、方法调用等。
  4. 本地方法栈:存储本地方法的栈帧。
  5. 程序计数器:每个线程的执行位置指示器。

Java 中堆和栈的区别是什么?

  • :用于动态分配内存,存储对象实例,生命周期由垃圾回收器管理。
  • :用于存储基本数据类型的局部变量和方法调用,具有严格的后进先出(LIFO)特性,内存由 JVM 自动管理。

什么是 Java 中的直接内存?

直接内存是 Java 中不属于堆或栈的内存,通常是通过 ByteBuffer 直接分配的。直接内存的访问速度快,适用于 I/O 操作,但管理较为复杂,容易引发内存泄漏。

什么是 Java 中的常量池?

常量池是 JVM 为了提高性能而维护的一块内存区域,存储编译时生成的常量(如字符串、数值等)。常量池分为 类常量池运行时常量池,前者存储类的静态常量,后者存储动态生成的常量。

你了解 Java 的类加载器吗?

Java 的类加载器负责加载类文件到 JVM 中,主要分为以下几种:

  1. 引导类加载器(Bootstrap ClassLoader):加载 Java 核心类库。
  2. 扩展类加载器(Extension ClassLoader):加载 JDK 扩展库。
  3. 应用类加载器(Application ClassLoader):加载用户类路径下的类。

什么是 Java 中的 JIT(Just-In-Time)?

JIT 是一种动态编译技术,JVM 在执行 Java 字节码时,将热点代码编译为本地机器码,缓存以便后续快速执行,从而提升性能。

什么是 Java 的 AOT(Ahead-Of-Time)?

AOT 是一种编译技术,在应用程序运行之前将 Java 字节码编译为本地机器码,减少了运行时编译的开销,通常用于提升启动时间和整体性能。

你了解 Java 的逃逸分析吗?

逃逸分析是 JIT 编译器的一种优化技术,通过分析对象的作用域,决定是否将对象分配在栈上而不是堆上,从而降低 GC 开销,提高性能。

Java 中的强引用、软引用、弱引用和虚引用分别是什么?

  1. 强引用:强引用是最常用的引用,GC 时不会回收。
  2. 软引用:用于缓存的引用,当内存不足时会被回收。
  3. 弱引用:只能在 GC 时被回收,适合用于监听器等。
  4. 虚引用:与对象的生存周期没有直接关系,用于跟踪对象的回收情况。

Java 中常见的垃圾收集器有哪些?

  1. Serial 垃圾收集器:单线程,适合小型应用。
  2. Parallel 垃圾收集器:多线程,适合大规模应用。
  3. CMS(Concurrent Mark-Sweep)垃圾收集器:并发收集,减少停顿时间。
  4. G1(Garbage-First)垃圾收集器:适合大堆内存,旨在减少停顿时间。
  5. ZGC(Z Garbage Collector):低延迟,高吞吐量的垃圾收集器。

Java 中如何判断对象是否是垃圾?不同垃圾回收方法有何区别?

Java 垃圾收集器通常使用 可达性分析 来判断对象是否是垃圾,即通过 GC 根(如栈中的引用)进行遍历,判断哪些对象是可达的。未被访问到的对象被视为垃圾。

不同的垃圾回收方法在算法和实现上有所不同,例如标记-清除、复制算法和分代收集等,这些方法会影响内存回收的效率和停顿时间。

为什么 Java 的垃圾收集器将堆分为老年代和新生代?

将堆分为老年代和新生代是为了根据对象的生命周期特性进行优化。新生代中的对象生命周期较短,适合使用复制算法,而老年代中的对象生命周期较长,适合使用标记-清除算法。

为什么 Java 8 移除了永久代(PermGen)并引入了元空间(Metaspace)?

Java 8 移除永久代的原因是它的大小是固定的,容易导致 OutOfMemoryError。元空间则是基于本地内存的,大小可动态调整,避免了这一问题。

为什么 Java 新生代被划分为 S0、S1 和 Eden 区?

新生代被划分为三个区域是为了优化垃圾收集效率。Eden 区用于存储新创建的对象,而 S0 和 S1 是 Survivor 区域,存储经过一次垃圾收集后仍然存活的对象,从而可以减少内存的复制开销。

什么是三色标记算法?

三色标记算法是一种用于垃圾回收的标记算法,将对象分为三种状态:

  1. 白色:未被标记的对象,可能是垃圾。
  2. 灰色:已标记但尚未处理的对象。
  3. 黑色:已标记并处理完的对象。

Java 中的 young GC、old GC、full GC 和 mixed GC 的区别是什么?

  • young GC:针对新生代的垃圾收集,通常使用复制算法。
  • old GC:针对老年代的垃圾收集,通常使用标记-清除算法。
  • full GC:对整个堆进行垃圾收集,包括新生代和老年代。
  • mixed GC:对新生代和部分老年代进行垃圾收集,适用于 G1 垃圾收集器。

什么条件会触发 Java 的 young GC?

当新生代(Eden 区)中的对象数量达到阈值时,会触发 young GC,以回收未存活的对象。

什么情况下会触发 Java 的 Full GC?

Full GC 会在以下情况下触发:

  1. 老年代内存不足。
  2. 显示调用 System.gc()
  3. JVM 内存配置调整。

什么是 Java 的 PLAB?

PLAB(Per-Thread Local Allocation Buffer)是每个线程的本地分配缓冲区,类似于 TLAB,旨在减少线程之间的竞争,提升对象分配的效率。

JVM 垃圾回收时产生的 concurrent mode failure 的原因是什么?

Concurrent Mode Failure 发生在 CMS

收集过程中,若内存不够,无法为活跃对象分配空间,导致需要转为 Full GC。这通常由于老年代空间不足导致。

为什么 Java 中 CMS 垃圾收集器在发生 Concurrent Mode Failure 时的 Full GC 是单线程的?

在发生 Concurrent Mode Failure 时,CMS 切换为 Full GC 是单线程的,因为该过程需要暂停所有用户线程,避免多线程并发造成的资源竞争和不一致性。

为什么 Java 中某些新生代和老年代的垃圾收集器不能组合使用?比如 ParNew 和 Parallel Old

因为一些垃圾收集器在实现上不兼容,不能同时使用。比如 ParNew 依赖于多线程的复制,而 Parallel Old 依赖于单线程的标记-清除,二者在设计上存在冲突。

JVM 新生代垃圾回收如何避免全堆扫描?

JVM 新生代垃圾回收通过分代收集的策略只针对新生代的对象进行回收,避免了全堆扫描,从而提升了回收效率。

Java 的 CMS 垃圾回收器和 G1 垃圾回收器在记忆集的维护上有什么不同?

CMS 使用 记忆集 来记录对象的引用,支持并发回收,但需要额外维护。G1 则通过将堆分成多个区域,使用分区方式更为灵活,减少了记忆集的管理复杂性。

为什么 G1 垃圾收集器不维护年轻代到老年代的记忆集?

G1 垃圾收集器不维护年轻代到老年代的记忆集,因为它通过分区管理来追踪对象的存活状态,避免了维护复杂的引用关系,提高了回收效率。

Java 中的 CMS 和 G1 垃圾收集器如何维持并发的正确性?

CMS 和 G1 都通过标记和拷贝过程维护并发的正确性,使用锁或无锁机制确保在垃圾回收期间,存活对象的引用不会被修改。

什么是 Java 中的 logging write barrier?

Logging Write Barrier 是一种用于记录对象写操作的机制,确保在对象被修改后,能够正确更新记忆集,以便在 GC 时维护对象的正确性。

Java 的 G1 垃圾回收流程是怎样的?

G1 垃圾回收的流程如下:

  1. 标记阶段:标记活跃对象。
  2. 整理阶段:根据存活对象的数量,选择合适的区域进行回收。
  3. 清理阶段:清除未标记的对象,回收内存。

Java 的 CMS 垃圾回收流程是怎样的?

CMS 垃圾回收的流程如下:

  1. 初始标记:标记 GC Roots 可达的对象,暂停用户线程。
  2. 并发标记:标记存活对象,用户线程并发执行。
  3. 重新标记:对初始标记和并发标记进行整合,暂停用户线程。
  4. 并发清除:清除未标记的对象,用户线程并发执行。

你了解 Java 的 ZGC(Z Garbage Collector)吗?

ZGC 是一种低延迟、高吞吐量的垃圾收集器,支持大堆内存,采用 分代回收记忆集 的管理方式,减少停顿时间。其主要目标是实现 不超过 10ms 的停顿

JVM 垃圾回收调优的主要目标是什么?

JVM 垃圾回收调优的主要目标是降低垃圾收集的停顿时间,提高应用程序的响应性,同时提高内存使用效率和吞吐量。

如何对 Java 的垃圾回收进行调优?

对 Java 垃圾回收的调优通常涉及以下方面:

  1. 选择合适的垃圾收集器(如 G1、CMS)。
  2. 调整堆内存大小、老年代和新生代比例。
  3. 监控和分析 GC 日志,识别瓶颈。
  4. 调整 GC 的参数(如 -Xmx-Xms-XX:NewRatio 等)。

常用的 JVM 配置参数有哪些?

常用的 JVM 配置参数包括:

  • -Xms:设置初始堆内存大小。
  • -Xmx:设置最大堆内存大小。
  • -XX:NewRatio:设置新生代与老年代的比例。
  • -XX:+UseG1GC:启用 G1 垃圾收集器。
  • -XX:+UseConcMarkSweepGC:启用 CMS 垃圾收集器。

你常用哪些工具来分析 JVM 性能?

常用的 JVM 性能分析工具包括:

  1. JVisualVM:可视化监控和分析工具。
  2. JConsole:用于监控和管理 Java 应用程序。
  3. Java Mission Control:用于性能监控和分析。
  4. YourKit:功能强大的性能分析工具。

如何在 Java 中进行内存泄漏分析?

内存泄漏分析通常通过以下步骤进行:

  1. 使用内存分析工具(如 Eclipse MAT、VisualVM)查看内存快照。
  2. 识别未被回收的对象及其引用链。
  3. 分析对象的生命周期,找到泄漏的原因。
  4. 通过代码审查、优化数据结构或移除不必要的引用来解决问题。

MySQL

MySQL 中的数据排序是怎么实现的?

MySQL 中的数据排序主要通过 ORDER BY 子句实现。在执行查询时,数据库会根据指定的列进行排序。排序算法通常使用的有快速排序(Quick Sort)和归并排序(Merge Sort)。在选择排序算法时,MySQL 会根据数据量、索引情况及排序字段的数据类型来选择最优的排序算法。对于使用索引的情况,MySQL 可以直接利用索引中的顺序来加速排序操作。

MySQL 的 Change Buffer 是什么?它有什么作用?

Change Buffer 是 InnoDB 存储引擎的一个特性,主要用于优化对二级索引的写入操作。当对索引进行插入、更新或删除时,这些修改会被暂时存储在内存中的 Change Buffer 中,而不是立即写入磁盘。这样可以减少对磁盘的随机写入,从而提高性能。稍后,后台线程会将 Change Buffer 中的变更合并到实际的索引结构中。

详细描述一条 SQL 语句在 MySQL 中的执行过程。

  1. 解析阶段:首先,MySQL 会解析 SQL 语句,检查语法和语义错误,并生成一个解析树。
  2. 优化阶段:生成的解析树会被优化器优化,优化器会选择最佳的执行计划,包括选择合适的索引和连接顺序。
  3. 执行阶段:根据优化后的执行计划,MySQL 会逐步执行 SQL 语句,访问数据、进行计算和返回结果。
  4. 结果返回:最后,执行的结果会被返回给客户端。

MySQL 的存储引擎有哪些?它们之间有什么区别?

MySQL 主要有以下几种存储引擎:

  • InnoDB:支持事务、行级锁和外键,适合高并发的 OLTP 应用。
  • MyISAM:不支持事务和外键,使用表级锁,适合读密集型应用。
  • MEMORY:将数据存储在内存中,访问速度快,但数据持久性差。
  • CSV:以逗号分隔的文件格式存储数据,适合导入导出。
  • ARCHIVE:适合存储大量的归档数据,不支持索引。

MySQL 的索引类型有哪些?

MySQL 中的索引类型主要包括:

  • 普通索引:最基本的索引类型。
  • 唯一索引:索引中的值必须唯一。
  • 主键索引:唯一索引的一种,不能有 NULL 值。
  • 全文索引:用于在文本中进行复杂的搜索。
  • 组合索引:由多个列组成的索引。

MySQL InnoDB 引擎中的聚簇索引和非聚簇索引有什么区别?

  • 聚簇索引:数据表的实际数据存储与索引结构是结合在一起的。每个表只能有一个聚簇索引,通常是主键索引,数据按照主键顺序存储。
  • 非聚簇索引:索引和数据存储是分开的,非聚簇索引的每一条索引记录都包含一个指向数据行的指针。一个表可以有多个非聚簇索引。

MySQL 中的回表是什么?

回表是指在使用非聚簇索引查询数据时,首先通过索引找到对应的记录,再通过索引中的指针去主表中查找实际数据的过程。这个过程增加了查询的时间开销,尤其在选择的字段没有被索引时。

MySQL 索引的最左前缀匹配原则是什么?

MySQL 的最左前缀匹配原则指的是,在组合索引中,只有从最左侧的列开始的索引才会被有效利用。例如,如果有一个组合索引 (a, b, c),那么可以使用索引进行的有效查询包括:

  • WHERE a = ?
  • WHERE a = ? AND b = ?
  • WHERE a = ? AND b = ? AND c = ?
    但不能只使用 bc

MySQL 的覆盖索引是什么?

覆盖索引是指查询时只需访问索引而不需回表就可以获得所有查询字段的数据。这样的查询能显著提高性能,因为不需要读取实际数据行。

MySQL 的索引下推是什么?

索引下推是 MySQL 5.6 引入的一项优化特性。在执行某些查询时,MySQL 可以在索引扫描过程中提前过滤掉不满足条件的行,减少需要回表的数据行数量,从而提高查询效率。

在 MySQL 中建索引时需要注意哪些事项?

  • 选择合适的列:索引应该建立在经常用于查询条件的列上。
  • 避免过多索引:每增加一个索引都会影响写入性能。
  • 监控索引的使用情况 :使用 EXPLAIN 分析索引的使用效果,避免无效索引。
  • 考虑字段的数据分布:高基数的列更适合建立索引。

MySQL 中使用索引一定有效吗?如何排查索引效果?

不一定有效。某些情况下,如小表的全表扫描、条件不适合索引、或索引列的基数低,索引可能不会提高性能。可以使用 EXPLAIN 语句来分析查询的执行计划,查看是否使用了索引,及其对性能的影响。

MySQL 中的索引数量是否越多越好?为什么?

索引数量并不是越多越好。虽然索引可以加速查询,但过多的索引会导致:

  • 写入性能下降,因为每次插入、更新或删除都需要维护索引。
  • 占用更多的存储空间。
    因此,应该根据实际的查询需求合理建立索引。

请详细描述 MySQL 的 B+ 树中查询数据的全过程

  1. 查找根节点:从根节点开始,根据查询的键值逐层查找。
  2. 向下查找:在每一层中,查找子节点,直到到达叶子节点。
  3. 定位数据:在叶子节点中,找到对应的记录或指针,获取实际数据。

为什么 MySQL 选择使用 B+ 树作为索引结构?

MySQL 选择 B+ 树作为索引结构是因为它具有:

  • 高效的查找速度:B+ 树的深度较小,查找速度快。
  • 良好的插入和删除性能:B+ 树能保持平衡,确保高效的插入和删除操作。
  • 范围查询高效:B+ 树的叶子节点按顺序连接,方便范围查询。

MySQL 是如何实现事务的?

MySQL 使用 InnoDB 存储引擎实现事务,遵循 ACID 原则。具体实现包括:

  • 原子性:通过日志记录确保事务的操作是一个整体,要么全部成功,要么全部失败。
  • 一致性:事务在执行前后,数据库的状态必须是有效的。
  • 隔离性:通过锁机制或 MVCC 实现事务之间的隔离。
  • 持久性:通过日志和数据的持久化确保一旦提交的数据不会丢失。

MySQL 中长事务可能会导致哪些问题?

长事务可能导致以下问题:

  • 锁竞争:长时间占用锁,导致其他事务无法执行,降低并发性能。
  • 事务日志膨胀:长事务需要维护更多的日志,增加磁盘空间使用。
  • 数据不一致:长事务在某些情况下可能导致数据的读取与写入不一致。

MySQL 中的 MVCC 是什么?

MVCC(多版本并发控制)是一种用于控制并发访问的机制,它允许多个事务并行运行而不互相阻塞。InnoDB 通过为每一行数据维护多个版本来实现 MVCC,从而允许读取旧版本的数据,确保读操作不被写操作阻塞。

如果 MySQL 中没有 MVCC,会有什么影响?

如果没有 MVCC,事务的并发性能将大幅下降,多个事务可能会相互阻塞,从而导致性能瓶颈。读操作可能需要等待写操作完成,造成响应时间延长,整体数据库性能降低。

MySQL 中的事务隔离级别有哪些?

MySQL 提供以下事务隔离级别:

  1. 读未提交(READ UNCOMMITTED):事务可以读取未提交的数据。
  2. 读已提交(READ COMMITTED):事务只能读取已提交的数据。
  3. 可重复读(REPEATABLE READ):在一个事务中,多次读取相同数据时,结果一致。
  4. 串行化(SERIALIZABLE):完全隔离,事务串行执行。

MySQL 默认的事务隔离级别是什么?为什么

选择这个级别?

MySQL 默认的事务隔离级别是可重复读(REPEATABLE READ)。选择这个级别的原因是:

  • 性能较高:相较于串行化,允许更高的并发。
  • 避免脏读和不可重复读:能有效避免脏读,并且在大多数应用场景中,确保数据一致性。

数据库的脏读、不可重复读和幻读分别是什么?

  • 脏读:一个事务读取到另一个未提交事务的数据。
  • 不可重复读:一个事务在执行过程中,读取到的数据在后续查询中被其他事务修改。
  • 幻读:一个事务在读取一系列数据时,另一事务插入或删除了某些行,导致原事务再次读取时结果不同。

MySQL 中有哪些锁类型?

MySQL 中主要有以下几种锁:

  • 共享锁(S锁):允许多个事务并发读取,但不允许修改。
  • 排他锁(X锁):一个事务获得后,其他事务无法读取或修改。
  • 意向锁:用于表级锁和行级锁之间的协调。
  • 自动锁:如 MySQL 的表级锁和行级锁。

MySQL 的乐观锁和悲观锁是什么?

  • 悲观锁:在操作数据时,假设会发生冲突,因此在操作前加锁,确保数据的一致性。
  • 乐观锁:在操作数据时,假设不会发生冲突,因此不加锁,而是在提交时检查数据版本。

MySQL 中如果发生死锁应该如何解决?

MySQL 会自动检测死锁并进行处理。通常情况下,InnoDB 会选择一个事务回滚,以解除死锁。应用程序也可以通过捕获异常并重试操作来处理死锁。

如何使用 MySQL 的 EXPLAIN 语句进行查询分析?

通过在查询前加上 EXPLAIN,可以获取查询的执行计划,包括使用的索引、行数估算、连接类型等信息,从而帮助分析查询性能问题。例如:

sql 复制代码
EXPLAIN SELECT * FROM table WHERE id = 1;

通过分析输出结果,确定查询的效率,是否合理使用了索引。

MySQL 中 count(*)、count(1) 和 count(字段名) 有什么区别?

  • count(*):计算结果集中所有行数,包括 NULL 值。
  • count(1):与 count(*) 类似,计算结果集中的所有行,但不关心列的具体值。
  • count(字段名):仅计算该字段非 NULL 值的行数。

MySQL 中 int(11) 的 11 表示什么?

int(11) 中的 11 表示该整数字段在某些情况下的显示宽度,不影响存储的范围。该宽度仅在使用 ZEROFILL 属性时有效,用于在输出时填充零。

MySQL 中 varchar 和 char 有什么区别?

  • char:固定长度字符串,存储时会填充空格,适合存储长度固定的数据。
  • varchar:可变长度字符串,节省存储空间,适合存储长度不固定的数据。

MySQL 中如何进行 SQL 调优?

SQL 调优的方法包括:

  1. 使用索引:为查询创建适当的索引。
  2. 简化查询:避免复杂的子查询和联接。
  3. 使用 EXPLAIN:分析执行计划,找出性能瓶颈。
  4. 合理使用缓存:如查询缓存和连接池。

如何在 MySQL 中避免单点故障?

可以通过以下方式避免单点故障:

  1. 主从复制:实现数据的备份与冗余。
  2. 负载均衡:使用负载均衡器分散请求。
  3. 数据备份:定期备份数据,确保数据安全。

如何在 MySQL 中实现读写分离?

读写分离可以通过以下方式实现:

  1. 主从复制:将写操作发送到主库,将读操作发送到从库。
  2. 负载均衡器:使用负载均衡器将请求分发到不同的数据库实例。

什么是 MySQL 的主从同步机制?它是如何实现的?

主从同步机制是指一个主数据库(主库)将数据变更同步到一个或多个从数据库(从库)。实现方式包括:

  • 二进制日志(binlog):主库记录所有数据变更到二进制日志,从库通过读取该日志来更新数据。
  • I/O 线程:从库的 I/O 线程连接主库,拉取 binlog。

如何处理 MySQL 的主从同步延迟?

处理主从同步延迟的方法包括:

  1. 优化主库的性能:减少写入延迟。
  2. 监控和调整 I/O 线程:确保从库及时拉取 binlog。
  3. 定期检查和清理 binlog:避免过多的日志影响性能。

什么是分库分表?分库分表有哪些类型(或策略)?

分库分表是将一个大表或数据库拆分成多个小表或数据库的技术。类型包括:

  • 垂直分库:将不同的表分到不同的数据库中。
  • 水平分库:将相同表的数据划分到不同的数据库中。
  • 分片:对大表按某个条件进行划分。

如果组长要求你主导项目中的分库分表,大致的实施流程是?

  1. 需求分析:了解系统的业务需求,确定分库分表的必要性。
  2. 设计分库分表策略:选择合适的分库分表方案。
  3. 数据库设计:设计新的数据库结构和表结构。
  4. 实现数据迁移:编写迁移脚本,将数据迁移到新数据库中。
  5. 更新应用代码:调整应用程序以支持新的数据库结构。
  6. 测试和上线:进行充分的测试,确保分库分表的稳定性。

对数据库进行分库分表可能会引发哪些问题?

  • 复杂性增加:应用逻辑变复杂,需要处理多个数据库的情况。
  • 跨库事务问题:事务跨多个数据库可能会面临一致性问题。
  • 数据查询困难:需要更复杂的查询逻辑来处理分散的数据。

从 MySQL 获取数据,是从磁盘读取的吗?

MySQL 中的数据获取通常是从内存中的缓存中读取,只有当数据不在内存中时,才会从磁盘读取。InnoDB 会将数据页缓存在缓冲池中,以减少磁盘 I/O 操作。

MySQL 的 Doublewrite Buffer 是什么?它有什么作用?

Doublewrite Buffer 是 InnoDB 的一种数据保护机制。在写入数据页之前,数据会先写入到 Doublewrite Buffer 中,确保在崩溃恢复时不会丢失数据,避免了部分页写入的情况。

MySQL 中的 Log Buffer 是什么?它有什么作用?

Log Buffer 是 InnoDB 用于暂存事务日志的内存区域。当事务提交时,日志首先被写入 Log Buffer,随后再批量写入磁盘,提升写入性能。

为什么在 MySQL 中不推荐使用多表 JOIN?

多表 JOIN 会导致性能下降,特别是在数据量大的情况下,查询复杂性增加,可能导致全表扫描,影响查询效率。此外,多个表的 JOIN 可能会增加内存消耗和 CPU 负载。

MySQL 中如何解决深度分页的问题?

深度分页可以通过以下方法解决:

  1. 使用索引优化:确保分页查询的字段有索引。
  2. 避免深度分页:通过缓存或其他方式减少需要分页的数据量。
  3. 使用关键字搜索:结合搜索功能,减少分页的需求。

如何在 MySQL 中监控和优化慢 SQL?

  1. 开启慢查询日志:记录执行时间超过指定阈值的 SQL 语句。
  2. 使用 EXPLAIN 分析:查看查询计划,找出性能瓶颈。
  3. 优化查询:对慢 SQL 进行索引优化、简化逻辑。

MySQL 中 DELETE、DROP 和 TRUNCATE 的区别是什么?

  • DELETE:删除表中的行,可以添加 WHERE 子句;删除时会逐行记录日志,慢。
  • DROP:删除整个表和表结构,数据不可恢复。
  • TRUNCATE:快速清空表中所有数据,不记录日志,重置自增值。

MySQL 中 INNER JOIN、LEFT JOIN 和 RIGHT JOIN 的区别是什么?

  • INNER JOIN:只返回两个表中匹配的记录。
  • LEFT JOIN:返回左表的所有记录,以及右表中匹配的记录,不匹配的部分为 NULL。
  • RIGHT JOIN:返回右表的所有记录,以及左表中匹配的记录,不匹配的部分为 NULL。

MySQL 中 `LIMIT 100000

000, 10LIMIT 10 的执行速度是否相同? 不相同。LIMIT 100000000, 10需要扫描前 1 亿条记录,才会返回 10 条数据,性能非常低下,而LIMIT 10` 则直接返回前 10 条记录,速度更快。

MySQL 中 DATETIME 和 TIMESTAMP 类型的区别是什么?

  • DATETIME:范围从 1000-01-01 到 9999-12-31,存储大小为 8 字节,未受时区影响。
  • TIMESTAMP:范围从 1970-01-01 00:00:01 UTC 到 2038-01-19 03:14:07 UTC,存储大小为 4 字节,受时区影响。

数据库的三大范式是什么?

  • 第一范式(1NF):每个字段只存储原子值,不能有重复的列。
  • 第二范式(2NF):符合 1NF,且每个非主属性完全依赖于主键。
  • 第三范式(3NF):符合 2NF,且没有非主属性依赖于其他非主属性。

在 MySQL 中,你使用过哪些函数?

常用函数包括:

  • 聚合函数 :如 SUM()AVG()COUNT()
  • 字符串函数 :如 CONCAT()SUBSTRING()
  • 日期函数 :如 NOW()DATE_ADD()

MySQL 中 TEXT 类型最大可以存储多长的文本?

TEXT 类型最大可以存储 65,535 字节的文本。

MySQL 中 AUTO_INCREMENT 列达到最大值时会发生什么?

当 AUTO_INCREMENT 列达到最大值时,会返回错误,无法插入新的行,除非重置值或更改字段类型。

在 MySQL 中存储金额数据,应该使用什么数据类型?

在 MySQL 中存储金额数据通常使用 DECIMAL 类型,以避免浮点数运算带来的精度问题。通常定义为 DECIMAL(10,2),其中 10 是总位数,2 是小数位数。

什么是数据库的视图?

视图是一个虚拟表,它是基于查询的结果集。视图可以简化复杂查询,提供数据安全性,限制用户对底层表的访问。

什么是数据库的游标?

游标是一个数据库对象,用于逐行处理查询结果。游标允许应用程序对查询结果进行循环操作。

为什么不推荐在 MySQL 中直接存储图片、音频、视频等大容量内容?

直接存储大容量内容会导致数据库体积膨胀,影响性能。推荐将文件存储在文件系统中,并在数据库中保存文件路径。

相比于 Oracle,MySQL 的优势有哪些?

  • 开源和免费:MySQL 是开源的,使用成本低。
  • 易于使用:用户界面友好,社区支持活跃。
  • 性能优化:在某些场景下,MySQL 性能更优。

MySQL 中 VARCHAR(100) 和 VARCHAR(10) 的区别是什么?

VARCHAR(100) 表示可以存储长度最长为 100 的可变长度字符串,而 VARCHAR(10) 只支持长度最长为 10 的字符串。存储空间根据实际使用长度而定。

在什么情况下,不推荐为数据库建立索引?

  • 数据变化频繁:频繁更新、删除操作会导致索引维护开销大。
  • 表数据量较小:小表的查询性能差异不大,索引反而增加了复杂性。
  • 查询不频繁:索引的维护成本不值得。

MySQL 中 EXISTS 和 IN 的区别是什么?

  • EXISTS:用于检查子查询是否返回结果,通常在子查询中使用,效率较高。
  • IN:用于检查某个值是否在一个列表或子查询的结果集中,性能相对较低。

什么是 Write-Ahead Logging (WAL) 技术?它的优点是什么?MySQL 中是否用到了 WAL?

WAL 是一种确保数据一致性的技术,在修改数据之前,先将操作记录到日志中。优点包括提高系统的可靠性和恢复能力。MySQL 的 InnoDB 引擎在事务日志中使用了类似的机制。

你们生产环境的 MySQL 中使用了什么事务隔离级别?为什么?

通常使用可重复读(REPEATABLE READ),因为它能有效避免脏读和不可重复读,同时在性能上能满足大部分业务需求。

为什么阿里巴巴的 Java 手册不推荐使用存储过程?

存储过程难以维护,调试困难,且与应用逻辑耦合较高。此外,存储过程的可移植性差,不利于在不同数据库之间的迁移。

如何实现数据库的不停服迁移?

可以通过以下步骤实现:

  1. 双写机制:在新旧数据库中同时写入数据。
  2. 数据同步:在后台将旧数据库的数据逐步迁移到新数据库。
  3. 流量切换:测试完成后,逐步切换流量到新数据库。
  4. 监控与回滚:确保新数据库稳定运行后,再彻底停止旧数据库服务。

MySQL 数据库的性能优化方法有哪些?

  • 优化查询:使用索引、减少子查询。
  • 配置优化:根据负载调整 MySQL 的配置参数。
  • 使用缓存:应用层和数据库层缓存,减少不必要的数据库访问。

MySQL 中 InnoDB 存储引擎与 MyISAM 存储引擎的区别是什么?

  • 事务支持:InnoDB 支持事务,MyISAM 不支持。
  • 数据安全性:InnoDB 使用外键约束,MyISAM 不支持。
  • 锁机制:InnoDB 支持行级锁,MyISAM 只支持表级锁。

MySQL 的查询优化器如何选择执行计划?

查询优化器会分析 SQL 语句,考虑表的统计信息、可用索引和连接方式等,选择成本最低的执行计划来优化查询性能。

什么是数据库的逻辑删除?数据库的物理删除和逻辑删除有什么区别?

  • 逻辑删除:通过更新标志位(如 is_deleted 字段)来标识数据已删除,数据仍然存在于表中。
  • 物理删除:直接从数据库中删除数据,数据不再存在。

逻辑删除保留了数据的完整性,适用于需要保留历史记录的场景,而物理删除则彻底清除了数据,适用于数据不再需要的情况。

Redis

1. Redis 主从复制的实现原理是什么?

Redis 的主从复制(Master-Slave Replication)是通过将数据从主节点复制到一个或多个从节点来实现的。主节点处理写请求,并将这些写请求的变更以追加的方式记录到复制缓冲区(replication buffer)。从节点在启动时会通过发送 PSYNC 命令向主节点请求数据,主节点则将当前的数据快照(RDB 文件)传送给从节点。此后,从节点会通过增量复制(使用二进制日志)获取主节点的新变更。主从复制使得读取请求可以分散到从节点上,增强了系统的可扩展性和容错能力。

2. Redis 集群的实现原理是什么?

Redis 集群通过分片(sharding)将数据分布在多个节点上。每个节点负责一部分键的存储,这样可以实现水平扩展。Redis 集群采用的是一种无中心化的架构,每个节点都是对等的,节点之间通过 gossip 协议来交换状态信息,以维护集群的健康状况和自动发现节点。在数据请求时,客户端首先会向任一节点发起请求,节点根据哈希槽(hash slot)机制来确定目标节点。如果目标节点不可用,集群会自动进行故障转移。

3. Redis 通常应用于哪些场景?

Redis 由于其高性能和灵活的数据结构,通常应用于以下场景:

  • 缓存:通过缓存热点数据减少数据库压力。
  • 会话存储:存储用户会话信息,支持快速读取和更新。
  • 实时分析:用于实时数据分析、统计和计数,如访问量统计。
  • 排行榜和计数器:支持快速的增减操作。
  • 消息队列:通过列表结构实现消息的生产和消费。
  • 分布式锁:实现对共享资源的互斥访问。

4. Redis 为什么这么快?

Redis 之所以快速,主要是由于以下几个因素:

  • 内存存储:数据完全存储在内存中,读写速度极快。
  • 单线程模型:通过单线程避免了多线程的上下文切换和锁竞争。
  • 高效的数据结构:使用高效的底层数据结构(如跳表、字典等),优化了数据的存取性能。
  • 异步IO:在处理请求时采用非阻塞 IO,允许多个请求并发执行。

5. 为什么 Redis 设计为单线程?6.0 版本为何引入多线程?

Redis 采用单线程设计是为了简化编程模型,避免多线程环境下的复杂性(如锁竞争)。单线程可以确保操作的原子性,从而避免数据不一致的问题。然而,这并不妨碍 Redis 在处理 IO 请求时使用异步方式。

在 Redis 6.0 中引入了多线程,主要是为了提高网络 I/O 的处理效率。多线程用于处理客户端请求和网络 I/O,特别是在处理大量并发连接时,可以显著提高性能。同时,Redis 仍然保持了核心数据结构的操作为单线程,以确保数据的一致性和安全性。

6. Redis 中常见的数据类型有哪些?

Redis 支持多种数据类型,主要包括:

  • 字符串(String):最基本的数据类型,可以存储任意类型的数据(如文本、二进制数据)。
  • 哈希(Hash):用于存储对象,包含多个键值对。
  • 列表(List):有序的字符串集合,支持插入、删除等操作。
  • 集合(Set):无序的字符串集合,支持交集、并集等操作。
  • 有序集合(Sorted Set):每个元素都有一个分数,自动按分数排序。
  • 位图(Bitmap)超日志(HyperLogLog)、**地理空间(Geo)**等高级数据结构。

7. Redis 中跳表的实现原理是什么?

跳表(Skip List)是一种多层链表结构,每一层都是对下一层的有序集合的简化,允许快速的插入、删除和查找操作。Redis 中使用跳表来实现有序集合(Sorted Set)。跳表通过在底层链表的基础上添加多层索引,使得查找时间复杂度降低到 O(log n),插入和删除操作也能保持在 O(log n) 的复杂度。

8. Redis 的 hash 是什么?

Redis 的哈希(Hash)是一种数据结构,用于存储键值对的集合。每个哈希可以包含多个字段,每个字段都可以映射到一个值。哈希特别适合存储对象或实体,例如用户信息等。它允许对单个字段的操作,而不需要对整个哈希进行操作,从而提高性能和效率。

9. Redis 和 Memcached 有哪些区别?

Redis 和 Memcached 的主要区别包括:

  • 数据结构:Redis 支持多种数据结构(如字符串、哈希、列表、集合等),而 Memcached 主要支持键值对。
  • 持久化:Redis 提供数据持久化机制(RDB 和 AOF),而 Memcached 是纯内存存储,重启后数据会丢失。
  • 功能:Redis 支持更多功能(如发布订阅、事务、Lua 脚本等),而 Memcached 功能相对较少。
  • 内存管理:Redis 具有更复杂的内存管理机制,支持内存淘汰策略,而 Memcached 主要采用 LRU 策略。

10. Redis 支持事务吗?如何实现?

Redis 支持事务,但与传统关系数据库的事务不同。Redis 的事务通过 MULTIEXECDISCARDWATCH 命令来实现:

  • MULTI:标记事务的开始。
  • EXEC:执行事务中的所有命令。
  • DISCARD:放弃事务。
  • WATCH:监视一个或多个键,当监视的键被修改时,事务会失败。

Redis 的事务不支持回滚功能。

11. Redis 数据过期后的删除策略是什么?

Redis 数据过期后的删除策略主要有两种:

  1. 定期删除:Redis 在每个周期内随机检查一部分键,删除已过期的键。
  2. 惰性删除:当访问某个键时,如果发现该键已过期,则立即将其删除。

这种组合策略确保了在大多数情况下能够及时删除过期数据,同时减少了不必要的性能开销。

12. Redis 中有哪些内存淘汰策略?

Redis 提供多种内存淘汰策略,以应对内存不足的情况,主要包括:

  • noeviction:不淘汰任何数据,返回错误。
  • allkeys-lru:从所有键中按 LRU(最少使用)策略淘汰。
  • volatile-lru:仅从设置了过期时间的键中按 LRU 淘汰。
  • allkeys-random:随机淘汰所有键中的任意一个。
  • volatile-random:随机淘汰设置了过期时间的键。
  • volatile-ttl:优先淘汰即将过期的键。

13. Redis 的 Lua 脚本功能是什么?如何使用?

Redis 的 Lua 脚本功能允许用户通过 Lua 脚本执行一系列命令,从而确保操作的原子性。Lua 脚本可以通过 EVAL 命令执行,语法如下:

lua 复制代码
EVAL "脚本内容" numkeys key1 key2 ... arg1 arg2 ...

其中,numkeys 指定键的数量,key1key2 等是需要操作的键,arg1arg2 等是传递给脚本的参数。

14. Redis 的 Pipeline 功能是什么?

Redis 的 Pipeline 功能允许客户端一次性发送多条命令,而无需等待每条命令的响应。这可以减少网络延迟,提高性能。使用 Pipeline 时,客户端将所有命令打包后一次性发送,最后再读取所有响应。这对于需要大量命令执行的场景非常有效。

15. Redis 中的 Big Key 问题是什么?如何解决?

Big Key 问题指的是在 Redis 中存储非常大的键或值,这会导致性能下降和内存浪费。大键的操作(如序列化、反序列化等)会增加 CPU 使用率,导致性能瓶颈。解决方案包括:

  • 避免存储大对象:将大对象拆分成多个小对象。
  • 使用合适的数据结构:根据数据访问模式选择合适的数据结构,避免冗余数据。
  • 监控和优化:使用 Redis 提供的工具监控键的大小和性能,及时调整。

16. 如何解决 Redis 中的热点 key 问题?

热点 key 问题

指的是某个键被大量请求,导致性能下降。解决方案包括:

  • 数据分片:将热点数据分散到多个键中。
  • 使用过期策略:对热点数据设置合理的过期时间,平衡访问。
  • 增加缓存层:在 Redis 之上增加一层缓存(如 Memcached)以减少对 Redis 的压力。
  • 异步更新:将对热点数据的写入操作改为异步方式,减轻即时压力。

17. Redis 的持久化机制有哪些?

Redis 提供了两种持久化机制:

  1. RDB(快照):定期将内存数据快照保存到磁盘,适合大规模数据的恢复。
  2. AOF(追加文件):将所有写操作追加到日志文件中,支持数据恢复。AOF 文件可以配置为每次写入后立即保存,或者按时间间隔保存。

用户可以根据需求选择合适的持久化方式,甚至可以同时使用 RDB 和 AOF。

18. Redis 在生成 RDB 文件时如何处理请求?

在生成 RDB 文件时,Redis 会使用 fork 创建一个子进程。主进程会继续处理客户端请求,而子进程负责将内存中的数据快照写入 RDB 文件。这样可以避免在持久化过程中阻塞主进程,确保服务的高可用性。

19. Redis 的哨兵机制是什么?

Redis 的哨兵(Sentinel)机制用于监控 Redis 服务器的状态并实现高可用性。哨兵可以自动检测主节点的故障,并在故障发生时进行故障转移(Failover),将某个从节点提升为主节点。此外,哨兵还负责通知客户端新的主节点地址,以便客户端能继续访问服务。哨兵模式使得 Redis 能够在不干预的情况下自动恢复服务。

20. Redis 集群会出现脑裂问题吗?

Redis 集群在某些情况下确实可能出现脑裂问题,尤其是在网络分区或节点失联的情况下。当集群中的节点无法确定哪个节点是主节点时,可能会出现两个主节点并同时接受写请求,导致数据不一致。为了解决这个问题,Redis 集群采用了投票机制和故障转移策略,通过实现 quorum(法定人数)原则来避免脑裂现象。

21. Redis 的订阅发布功能是什么?你了解吗?

Redis 的订阅发布(Pub/Sub)功能是一种消息通信模式,允许消息的发布者(Publisher)将消息发布到一个或多个频道(Channel),而订阅者(Subscriber)可以订阅这些频道以接收消息。当消息被发布时,所有订阅了该频道的客户端都会接收到消息。Pub/Sub 适用于实时聊天、通知系统等场景。

22. Redis 中如何实现分布式锁?

在 Redis 中实现分布式锁通常采用 SETNX 命令,该命令只在键不存在时设置键的值。例如:

  1. 客户端使用 SETNX lock_key unique_lock_id 尝试获取锁。
  2. 成功后,执行临界区代码。
  3. 最后使用 DEL lock_key 释放锁。

为了防止死锁,通常会设置一个超时时间,确保在超时后锁自动释放。

23. 分布式锁在未完成逻辑前过期怎么办?

如果分布式锁在未完成逻辑前过期,可以考虑以下解决方案:

  • 延长锁的有效期:在执行操作时,定期更新锁的过期时间。
  • 使用 Redisson 或 Zookeeper:使用这些成熟的分布式锁实现,提供更可靠的锁机制。
  • 设计合理的超时时间:根据业务逻辑合理设置锁的超时时间,确保在完成逻辑时不会过期。

24. Redis 的 Red Lock 是什么?你了解吗?

Red Lock 是一种分布式锁算法,由 Redis 创始人 Antirez 提出。其原理是通过在多个 Redis 节点上获取锁来确保安全性,算法步骤如下:

  1. 客户端向多个 Redis 实例请求锁。
  2. 只有在大多数节点上成功设置锁后,客户端才能确认获得锁。
  3. 锁的过期时间要比操作的最大时间长,以确保其他节点能够正确地处理锁。

这种机制可以在分布式环境中提供高可靠性的锁。

25. Redis 实现分布式锁时可能遇到的问题有哪些?

在 Redis 实现分布式锁时可能遇到的问题包括:

  • 网络故障:导致客户端无法获取锁或释放锁。
  • 锁超时:业务逻辑处理时间过长,导致锁意外失效。
  • 重复锁:同一客户端在未释放锁的情况下重复请求,导致其他客户端无法获取锁。
  • 分布式环境中的数据一致性问题:确保所有节点状态一致,以避免数据冲突。

26. Redis 中的缓存击穿、缓存穿透和缓存雪崩是什么?

  • 缓存击穿:指的是热点数据在缓存中不存在时,导致大量请求直击数据库,造成瞬间压力过大。解决方案包括使用互斥锁,避免同一时间多个请求去查询数据库。
  • 缓存穿透:指的是查询一个一定不存在的数据,导致每次请求都直接到达数据库,造成压力。可以通过布隆过滤器等方式拦截不合法请求。
  • 缓存雪崩:指的是大量缓存同时过期,导致瞬间请求全部打到数据库,造成崩溃。可以通过随机过期时间等手段来避免。

27. Redis 中如何保证缓存与数据库的数据一致性?

保证缓存与数据库的一致性通常采用以下策略:

  • 写入时更新:每次对数据库进行写操作时,同时更新缓存。
  • 失效策略:对缓存设置合理的过期时间,避免数据长期不一致。
  • 双写一致性:在高并发环境下,采用分布式事务保证数据的一致性。
  • 异步更新:在某些场景下,可以使用消息队列异步更新缓存。

28. Redis String 类型的底层实现是什么?

Redis 的字符串(String)类型底层实现使用了简单动态字符串(SDS,Simple Dynamic Strings)。SDS 是一种比 C 风格字符串更安全和高效的字符串实现,具备以下特点:

  • 长度信息:SDS 记录字符串的实际长度,避免重复计算。
  • 空间优化:采用二次分配策略,减少内存的频繁分配和释放。
  • 安全性:防止缓冲区溢出,避免内存安全问题。

29. 如何使用 Redis 快速实现排行榜?

Redis 提供了有序集合(Sorted Set)来实现排行榜。使用有序集合的分数(score)来代表用户的分数,用户的 ID 作为元素(member)。实现步骤如下:

  1. 使用 ZADD 命令添加用户及其分数。
  2. 使用 ZRANGEZREVRANGE 命令获取排行榜前 N 名用户。
  3. 使用 ZINCRBY 命令更新用户分数。

30. 如何使用 Redis 快速实现布隆过滤器?

布隆过滤器是一种空间效率高的概率数据结构,可以快速判断某个元素是否存在。Redis 提供了 BF.ADDBF.EXISTS 等命令来实现布隆过滤器。实现步骤如下:

  1. 使用 BF.RESERVE 创建布隆过滤器并设置期望插入数量和误判率。
  2. 使用 BF.ADD 插入元素。
  3. 使用 BF.EXISTS 检查元素是否存在。

31. 如何使用 Redis 统计大量用户唯一访问量(UV)?

可以使用 Redis 的 HyperLogLog 数据结构来高效统计唯一用户访问量(UV)。实现步骤如下:

  1. 使用 PFADD 命令将每个用户的标识符添加到 HyperLogLog。
  2. 使用 PFCOUNT 命令获取唯一用户的数量。

HyperLogLog 的空间效率非常高,适合于大规模数据的统计。

32. Redis 中的 Geo 数据结构是什么?

Redis 的 Geo 数据结构用于存储和查询地理位置信息。它支持根据经纬度进行范围查询和距离计算。实现步骤如下:

  1. 使用 GEOADD 命令添加地理位置信息。
  2. 使用 GEODIST 命令计算两点之间的距离。
  3. 使用 GEORADIUS 命令根据半径范围查找附近的点。

33. 你在项目中使用的 Redis 客户端是什么?

我在项目中使用的 Redis 客户端是 Jedis ,它是一个流行的 Java 客户端,提供了简单的 API 接口,适合与 Redis 进行交互。另一个常用的客户端是 Lettuce,它是基于异步和反应式编程的。

34. Redis 字符串

类型的最大值大小是多少?

Redis 中字符串类型的最大值大小为 512MB。这使得 Redis 能够存储较大的数据对象,例如图像或文件内容。

35. Redis 性能瓶颈时如何处理?

当 Redis 出现性能瓶颈时,可以考虑以下优化方案:

  • 水平扩展:通过增加更多 Redis 节点来分散负载。
  • 优化数据结构:根据访问模式优化数据存储结构,例如使用更合适的数据类型。
  • 合理设置过期时间:定期清理过期数据,保持内存的高效利用。
  • 监控和分析:使用 Redis 监控工具(如 Redis Monitor、Redis Insight)监控性能瓶颈,找出热点和慢查询。

36. Redis 中 EMBSTR 对象的阈值设置为何为 44?其调整历史是什么?

EMBSTR(Embedding String)是 Redis 中的一种优化字符串存储方式,当字符串长度小于等于 44 字节时,Redis 会将字符串与其元数据一起存储在同一内存块中,以减少内存分配的开销。这个阈值的历史变化是为了在性能与内存占用之间取得平衡,经过多次优化后最终设定为 44 字节,以适应大部分字符串的存储需求。

37. Redis 中原生批处理命令(MSET、MGET)与 Pipeline 的区别是什么?

  • MSET/MGET:这两个命令用于批量设置和获取键值对,Redis 会在一个请求中处理所有操作,适合于较小的批量操作。
  • Pipeline:允许客户端在一个请求中发送多个命令,而无需等待每个命令的响应,从而减少网络延迟。适合于大量命令的执行,性能更优。

38. Redis 主从复制的常见拓扑结构有哪些?

Redis 主从复制的常见拓扑结构包括:

  1. 主从结构:一个主节点对应多个从节点,从节点异步复制主节点的数据。
  2. 链式复制:一个从节点同时作为其他从节点的主节点,形成链状结构。
  3. 多主结构:多个主节点相互复制数据,适用于高可用性和负载均衡。

39. Redis List 类型的常见操作命令有哪些?

Redis List 类型的常见操作命令包括:

  • LPUSH:在列表左侧插入元素。
  • RPUSH:在列表右侧插入元素。
  • LPOP:从列表左侧弹出元素。
  • RPOP:从列表右侧弹出元素。
  • LRANGE:获取列表中指定范围的元素。

40. 如何在 Redis 中实现队列和栈数据结构?

  • 队列 :使用 List 类型的 LPUSHRPOP 命令实现先进先出(FIFO)的队列。
  • :使用 List 类型的 LPUSHLPOP 命令实现后进先出(LIFO)的栈。

41. Redis 中的 Ziplist 和 Quicklist 数据结构的特点是什么?

  • Ziplist:一种紧凑的内存数据结构,适用于小规模列表和哈希。通过压缩相邻元素来节省内存。
  • Quicklist:结合了双向链表和 ziplist 的优点,支持高效的插入和删除操作,适合大规模列表。适用于多种场景并具备较好的性能。

42. Redis 复制延迟的常见原因有哪些?

Redis 复制延迟的常见原因包括:

  • 网络延迟:主节点与从节点之间的网络不稳定。
  • 从节点负载过重:从节点处理请求的能力不足,导致延迟。
  • 慢查询:从节点执行复杂查询时造成响应时间延长。
  • 大数据量:如果主节点有大量数据变动,从节点需要时间进行同步。

43. Redis 事务与关系型数据库事务的主要区别是什么?

Redis 事务与关系型数据库事务的主要区别包括:

  • 原子性:Redis 事务采用 MULTI/EXEC 命令块实现原子性,但不支持回滚;关系型数据库支持回滚机制。
  • 隔离性:Redis 事务不支持事务隔离级别,而关系型数据库提供多种隔离级别。
  • 执行方式:Redis 事务是顺序执行,不支持并发,而关系型数据库可以并发执行。

44. Redis Cluster 模式与 Sentinel 模式的区别是什么?

  • Cluster 模式:Redis Cluster 提供数据分片和高可用性,支持水平扩展,通过自动分片机制实现节点之间的负载均衡。
  • Sentinel 模式:主要用于监控和故障转移,不支持数据分片,适用于单一主节点的高可用性场景。

45. Redis 的 ListPack 数据结构是什么?

ListPack 是 Redis 为 List 和 Hash 类型引入的一种新数据结构,旨在提高内存利用率和访问速度。它结合了压缩存储和快速访问的优势,适合于存储较小的列表和哈希数据。

46. Redis 中的内存碎片化是什么?如何进行优化?

内存碎片化是指内存中存在大量未被使用的小块空间,导致内存利用率降低。优化方法包括:

  • 定期重启 Redis 实例:释放碎片化内存。
  • 使用 Redis 的内存管理工具 :如 MEMORY PURGE 命令,释放未使用的内存。
  • 调整 Redis 的内存配置:根据需求合理配置内存策略。

47. Redis 的虚拟内存(VM)机制是什么?

Redis 的虚拟内存(VM)机制是一种将数据从内存转移到磁盘的方式。通过将不常用的数据移出内存,可以保持内存使用的高效性。但 Redis 2.0 后,虚拟内存机制被弃用,Redis 推荐使用更高效的持久化策略(如 RDB 和 AOF)。

48. 在 Redis 集群中,如何根据键定位到对应的节点?

在 Redis 集群中,键通过哈希槽(hash slot)定位到对应的节点。Redis 使用 CRC16 哈希算法将键映射到 0-16383 的槽中,槽与节点一一对应。具体步骤为:

  1. 计算键的哈希值。
  2. 通过哈希值确定对应的哈希槽。
  3. 根据槽找到对应的节点进行操作。

49. Redis 源码中有哪些巧妙的设计,举几个典型的例子?

Redis 源码中的巧妙设计包括:

  • 单线程模型:使用事件循环机制避免上下文切换,提高性能。
  • 多种数据结构的选择:如 ziplist、quicklist 和 hashtable 等,根据数据大小动态选择最优结构。
  • 简单而高效的持久化机制:结合 RDB 和 AOF 提供灵活的数据持久化方案。

50. 说说 Redisson 分布式锁的原理?

Redisson 是一个 Java 客户端,提供了分布式锁的实现。其原理基于 Redis 的 SETNX 命令,结合了一些优化策略,如:

  1. 使用 tryLockunlock 方法提供锁的获取和释放。
  2. 利用 Redis 的过期时间,确保锁在业务处理失败时能够自动释放。
  3. 在高并发环境下,采用重入锁的机制,确保同一线程可以多次获取锁而不会造成死锁。

Spring

什么是循环依赖(常问)?

循环依赖是指在对象创建过程中,两个或多个对象相互依赖,形成了一个闭环。例如,类 A 依赖于类 B,类 B 又依赖于类 A。这样在实例化时,就会导致无法完成对象的创建,因为每个对象都在等待另一个对象的创建完成。

Spring 如何解决循环依赖?

Spring 通过使用三级缓存来解决循环依赖的问题:

  1. 一级缓存singletonObjects,存放已创建的单例 Bean。
  2. 二级缓存earlySingletonObjects,存放尚未完全初始化但已创建的单例 Bean。这些 Bean 处于"半成品"状态,可以通过依赖注入使用。
  3. 三级缓存singletonFactoryObjects,存放 Bean 的 Factory,允许通过 ObjectFactory 获取未完成的 Bean 实例。

当 Spring 容器遇到循环依赖时,会首先将 Bean 注册到二级缓存中,以便在另一个 Bean 中注入时可以使用。

为什么 Spring 循环依赖需要三级缓存,二级不够吗?

二级缓存不能完全解决循环依赖问题,因为它仅仅存储已创建但未完全初始化的 Bean。在某些情况下,Bean 需要完全初始化后才能使用其依赖项,因此三级缓存提供了额外的灵活性,使得可以在依赖注入过程中允许获取到"半成品" Bean。

看过源码吗?说下 Spring 由哪些重要的模块组成?

Spring 框架由多个重要模块组成,主要包括:

  • Core Container:提供基本的功能,如 BeanFactory、ApplicationContext 等。
  • AOP:提供面向切面编程的支持。
  • Data Access/Integration:支持 JDBC、ORM、JPA 等数据库访问技术。
  • Web:提供与 Web 应用相关的功能,包括 Spring MVC。
  • Security:提供安全管理的支持。
  • Test:支持单元测试的模块。

什么是 Spring IOC?

Spring IOC(控制反转)是一种设计模式,它通过将对象的创建和依赖管理从应用程序代码中抽离出来,交由 Spring 容器来管理。开发者只需通过配置(如 XML 文件、注解等)定义 Bean 及其依赖关系,Spring 容器会负责创建和注入这些依赖。

Spring IOC 有什么好处?

  1. 解耦:减少了类与类之间的依赖关系,使得代码更易于维护和测试。
  2. 可配置性:可以通过外部配置轻松地更改对象的行为。
  3. 生命周期管理:Spring 负责管理 Bean 的生命周期,包括初始化和销毁。
  4. 便于测试:可以通过 Mock 对象轻松进行单元测试。

Spring 中的 DI 是什么?

DI(依赖注入)是实现 IOC 的一种方式。它通过构造函数、setter 方法或接口将依赖的对象传递给目标对象,使得目标对象不需要自己去创建依赖对象,而是由容器负责管理。

什么是 Spring Bean?

Spring Bean 是由 Spring 容器管理的对象,通常是应用程序中用到的服务、组件或数据访问对象。Bean 的生命周期由 Spring 容器控制。

Spring 中的 BeanFactory 是什么?

BeanFactory 是 Spring 的基础容器接口,负责 Bean 的创建和管理。它延迟加载 Bean,即只有在需要时才会创建 Bean,适用于资源有限的环境。

Spring 中的 FactoryBean 是什么?

FactoryBean 是一种特殊的 Bean,允许用户自定义 Bean 的创建逻辑。实现了 FactoryBean 接口的类可以返回一个新实例,而不是简单的 Bean 实例。

Spring 中的 ObjectFactory 是什么?

ObjectFactory 是 Spring 提供的一个接口,用于获取一个对象的实例。它通常用于实现懒加载和解决循环依赖。

Spring 中的 ApplicationContext 是什么?

ApplicationContext 是 Spring 的高级容器,继承了 BeanFactory 的功能,提供更多的功能,例如事件传播、国际化支持等。它是一个完整的 Spring IoC 容器。

Spring Bean 一共有几种作用域?

Spring Bean 主要有五种作用域:

  1. singleton:单例,整个应用程序中只创建一个 Bean 实例。
  2. prototype:原型,每次请求都会创建一个新的 Bean 实例。
  3. request:请求作用域,仅在 HTTP 请求内有效(Web 环境)。
  4. session:会话作用域,绑定到 HTTP 会话(Web 环境)。
  5. globalSession:全局会话,绑定到全局 HTTP 会话(用于 portlet 应用)。

Spring 一共有几种注入方式?

Spring 主要有三种注入方式:

  1. 构造器注入:通过构造函数传递依赖。
  2. setter 注入:通过 setter 方法设置依赖。
  3. 接口注入:通过实现特定接口设置依赖。

什么是 AOP?

AOP(面向切面编程)是一种编程范式,它通过定义切面(Aspect)将横切关注点(如事务管理、日志记录等)从业务逻辑中分离出来,从而增强代码的模块性。

Spring AOP 默认用的是什么动态代理,两者的区别?

Spring AOP 默认使用 JDK 动态代理和 CGLIB 代理:

  • JDK 动态代理:只能代理实现了接口的类。
  • CGLIB:可以代理任何类,不要求实现接口。

能说说 Spring 拦截链的实现吗?

Spring 拦截链通常是通过 AOP 机制实现的,拦截器可以在方法执行前后插入自定义逻辑。拦截器链中的每个拦截器都可以决定是否继续执行下一个拦截器。Spring 中的 HandlerInterceptorFilter 也可以实现类似功能。

Spring AOP 和 AspectJ 有什么区别?

  1. 实现方式
    • Spring AOP:基于代理,主要使用 JDK 动态代理和 CGLIB。
    • AspectJ:是一个独立的框架,通过字节码增强技术在编译时或运行时进行切面处理。
  2. 功能
    • Spring AOP:适合简单的切面需求。
    • AspectJ:提供更强大的切面编程能力,支持更复杂的切点表达式。

说下 Spring Bean 的生命周期?

Spring Bean 的生命周期主要包括以下几个阶段:

  1. 实例化:容器创建 Bean 实例。
  2. 属性填充:注入 Bean 的依赖。
  3. 初始化 :调用 @PostConstruct 方法和 InitializingBean 接口的 afterPropertiesSet 方法。
  4. 使用:Bean 进入正常使用阶段。
  5. 销毁 :调用 @PreDestroy 方法和 DisposableBean 接口的 destroy 方法。

说下对 Spring MVC 的理解?

Spring MVC 是一种基于 MVC(模型-视图-控制器)设计模式的 Web 框架。它通过 DispatcherServlet 作为前端控制器,处理请求并将其分发到相应的处理器(Controller),实现请求和响应的分离。

Spring MVC 具体的工作原理?

  1. 请求到达 DispatcherServlet:所有请求都由 DispatcherServlet 处理。
  2. 请求映射:DispatcherServlet 查找匹配的处理器。
  3. 调用处理器:找到合适的 Controller,调用相应的方法处理请求。
  4. 返回视图:处理完成后,返回视图名,DispatcherServlet 根据视图解析器将视图解析为具体视图对象。
  5. 渲染视图:最终将视图渲染到客户端。

SpringMVC 父子容器是什么知道吗?

在 Spring MVC 中,父子容器模式允许创建一个父 ApplicationContext,子 ApplicationContext 可以继承父容器中的 Bean 定义。这样可以实现模块化,便于管理和维护。

你了解的 Spring 都用到哪些设计模式?

Spring 框架中使用了多种设计模式,主要包括:

  1. 单例模式:Bean 默认是单例。
  2. 工厂模式:通过 FactoryBean 创建对象。
  3. 代理模式:AOP 使用的代理机制。
  4. 观察者模式:事件机制的实现。
  5. 模板方法模式:JdbcTemplate 等实现。

Spring 事务有几个隔离级别?

Spring 事务提供了以下四种隔离级别:

  1. DEFAULT:使用底层数据库的默认隔离级别。
  2. READ_UNCOMMITTED:允许脏读。
  3. READ_COMMITTED:禁止脏读,允许不可重复读。
  4. REPEATABLE_READ:禁止脏读和不可重复读,允许幻读。
  5. SERIALIZABLE:完全隔离,避免所有并发问题

Spring 有哪几种事务传播行为?

Spring 事务的传播行为主要包括:

  1. REQUIRED:默认传播行为,支持当前事务,如果没有则新建。
  2. REQUIRES_NEW:新建一个事务,暂停当前事务。
  3. NESTED:如果当前事务存在,则创建一个嵌套事务。
  4. SUPPORTS:支持当前事务,如果没有则以非事务方式执行。
  5. MANDATORY:当前必须存在事务,否则抛出异常。
  6. NEVER:以非事务方式执行,如果当前存在事务则抛出异常。
  7. NOT_SUPPORTED:以非事务方式执行,如果存在事务则挂起当前事务。

Spring 事务传播行为有什么用?

事务传播行为控制了事务在方法调用之间的传播方式,决定了在不同方法调用之间如何处理事务,以确保数据的一致性和完整性。例如,REQUIRED 可以避免重复开启事务,而 REQUIRES_NEW 可以在某些情况下强制新建事务。

Spring 的优点

  1. 灵活性:通过 IoC 和 AOP 提供灵活的开发方式。
  2. 易于集成:与多种框架和技术(如 Hibernate、JPA 等)兼容。
  3. 广泛的社区支持:拥有大量的文档和社区支持。
  4. 模块化:清晰的模块化设计,提高了代码的可维护性。

Spring AOP 相关术语都有哪些?

  1. 切面(Aspect):横切关注点的模块化。
  2. 连接点(Join Point):可以插入切面的程序点。
  3. 切点(Pointcut):定义在哪些连接点应用切面。
  4. 通知(Advice):切面在连接点处的具体操作。
  5. 目标对象(Target Object):被代理的对象。
  6. 代理(Proxy):实现了切面逻辑的对象。

Spring 通知有哪些类型?

Spring 通知主要包括:

  1. 前置通知(Before):在目标方法执行前执行。
  2. 后置通知(After):在目标方法执行后执行。
  3. 返回通知(After Returning):在目标方法成功返回后执行。
  4. 异常通知(After Throwing):在目标方法抛出异常后执行。
  5. 环绕通知(Around):在目标方法执行前后都执行的通知。

Spring IOC 容器初始化过程?

  1. 读取配置:加载 XML 文件或注解配置。
  2. 创建 BeanDefinition:将配置转化为 BeanDefinition。
  3. 注册 BeanDefinition:将 BeanDefinition 注册到容器中。
  4. 实例化 Bean:根据 BeanDefinition 创建 Bean 实例。
  5. 依赖注入:填充 Bean 的属性和依赖。

Spring Bean 注册到容器有哪些方式?

  1. XML 配置:在 XML 文件中定义 Bean。
  2. 注解配置 :使用 @Component@Service 等注解自动注册。
  3. Java 配置 :使用 @Configuration@Bean 注解定义 Bean。

Spring 自动装配的方式有哪些?

Spring 提供了几种自动装配的方式:

  1. 按类型自动装配(@Autowired)
  2. 按名称自动装配
  3. @Qualifier 注解:结合 @Autowired 指定具体 Bean。
  4. @Primary 注解:标记首选 Bean。

@Qualifier 注解有什么作用

@Qualifier 注解用于指定在自动装配时所需的具体 Bean,当存在多个同类型的 Bean 时,可以通过该注解精确指定所需的 Bean。

@Bean和@Component有什么区别?

  • @Bean:用于方法上,表明该方法返回的对象是一个 Bean。
  • @Component:用于类上,表明该类是一个 Bean,由 Spring 自动检测。

@Component、@Controller、@Repository和@Service 的区别?

  • @Component:通用的组件标识。
  • @Controller:用于表示控制器类,通常与 Spring MVC 一起使用。
  • @Repository:用于数据访问层,提供持久化支持。
  • @Service:用于服务层,表示业务逻辑。

Spring 事务在什么情况下会失效?

Spring 事务可能在以下情况下失效:

  1. 调用同一类中的另一个事务方法:因为 Spring 默认使用 AOP 代理,会导致事务无法生效。
  2. 非 Spring 管理的对象调用:如果事务方法在非 Spring 管理的对象中调用,事务将失效。
  3. 方法抛出 RuntimeException 以外的异常:默认情况下,事务只对 RuntimeException 进行回滚。

说说 Spring 启动过程?

Spring 启动过程主要包括以下步骤:

  1. 加载 Spring 配置文件:如 XML 或注解配置。
  2. 初始化 ApplicationContext:创建 Spring 容器。
  3. 创建和初始化 Bean:根据配置实例化 Bean。
  4. 处理依赖注入:填充 Bean 的属性。
  5. 启动上下文:完成 Bean 的初始化,准备服务。

Spring 的单例 Bean 是否有并发安全问题?

Spring 的单例 Bean 默认是线程安全的,因为 Spring 会在创建时将其初始化并缓存。但开发者需要确保在 Bean 内部的状态是不可变的,或使用适当的同步机制处理共享状态。

Spring中的@Primary注解的作用是什么?

@Primary 注解用于指示在自动装配时优先选择标记为 @Primary 的 Bean,尤其是在存在多个同类型的 Bean 时。

Spring中的@Value注解的作用是什么?

@Value 注解用于注入外部配置(如属性文件)中的值到 Spring Bean 的字段中,可以注入基本数据类型、字符串和表达式等。

Spring 中的 @Profile 注解的作用是什么?

@Profile 注解用于定义 Bean 的作用域,指定在特定的配置文件或环境下启用的 Bean,例如开发环境和生产环境的不同 Bean 配置。

Spring 中的 @PostConstruct 和 @PreDestroy 注解的作用是什么?

  • @PostConstruct:在 Bean 初始化后执行的方法。
  • @PreDestroy:在 Bean 销毁前执行的方法,用于释放资源。

Spring 中的 @RequestBody 和 @ResponseBody 注解的作用是什么?

  • @RequestBody:将 HTTP 请求体中的内容转换为 Java 对象。
  • @ResponseBody:将 Java 对象转换为 HTTP 响应体的内容。

Spring 中的 @PathVariable 注解的作用是什么?

@PathVariable 注解用于从请求 URL 中提取路径变量,并将其映射到方法参数上。

Spring中的 @ModelAttribute 注解的作用是什么?

@ModelAttribute 注解用于将请求参数绑定到方法参数或模型属性上,通常用于处理表单提交。

Spring 中的 @ExceptionHandler 注解的作用是什么?

@ExceptionHandler 注解用于定义处理特定异常的方法,以便在控制器层统一处理异常。

Spring 中的 @ResponseStatus 注解的作用是什么?

@ResponseStatus 注解用于定义 HTTP 响应的状态码,常用于异常处理时设置响应状态。

Spring 中的 @RequestHeader 和 @CookieValue 注解的作用是什么?

  • @RequestHeader:用于绑定请求头信息到方法参数。
  • @CookieValue:用于绑定 Cookie 值到方法参数。

Spring 中的 @SessionAttribute 注解的作用是什么?

@SessionAttribute 注解用于将模型属性存储在 HTTP 会话中,以便跨多个请求访问。

Spring 中的 @Validated 和 @Valid 注解有什么区别?

  • @Valid:由 JSR-303 提供,进行对象验证。
  • @Validated:是 Spring 的扩展,支持分组验证。

Spring 中的 @Scheduled 注解的作用是什么?

@Scheduled 注解用于定义定时任务,可以指定任务的执行频率和时间间隔。

Spring 中的 @Cacheable 和 @CacheEvict 注解的作用是什么?

  • @Cacheable:用于标记方法的返回值应缓存。
  • @CacheEvict:用于从缓存中移除某个数据。

Spring 中的 @Conditional 注解的作用是什么?

@Conditional 注解用于根据特定条件决定是否创建 Bean,可以用于环境配置或特定条件下的 Bean 加载。

Spring 中的 @Lazy 注解的作用是什么?

@Lazy 注解用于指定 Bean 采用懒加载的方式,只有在实际需要时才会创建 Bean。

Spring 中的 @PropertySource 注解的作用是什么?

@PropertySource 注解用于加载外部属性文件,允许通过 ${} 语法访问属性。

Spring 中的 @EventListener 注解的作用是什么?

@EventListener 注解用于定义事件监听器,当特定事件发布时触发相应的方法。

Spring 和 Spring MVC 的关系是什么?

Spring 是一个广泛的框架,提供了 Io

C、AOP 等功能,而 Spring MVC 是 Spring 的一个模块,专注于构建基于 MVC 设计模式的 Web 应用程序。

Spring WebFlux 是什么?它与 Spring MVC 有何不同?

Spring WebFlux 是 Spring 5 引入的响应式编程框架,支持非阻塞式 Web 应用。而 Spring MVC 是传统的阻塞式模型。WebFlux 适合处理高并发场景。

介绍下 Spring MVC 的核心组件?

Spring MVC 的核心组件包括:

  1. DispatcherServlet:前端控制器,负责请求的分发和处理。
  2. Controller:处理请求的核心组件,返回 ModelAndView。
  3. ViewResolver:根据逻辑视图名解析到具体视图。
  4. HandlerMapping:将请求映射到相应的 Controller。
  5. Interceptor:用于处理请求的拦截逻辑。

什么是 Restful 风格的接口?

Restful 风格的接口遵循 REST(Representational State Transfer)架构风格,使用 HTTP 协议,利用 HTTP 方法(如 GET、POST、PUT、DELETE)进行资源的操作。

Spring MVC中的Controller是什么?如何定义一个Controller?

Controller 是处理请求的组件,通常通过 @Controller 注解定义。定义方式如下:

java 复制代码
@Controller
public class MyController {
    @RequestMapping("/hello")
    public String hello() {
        return "hello";
    }
}

Spring MVC 中如何处理表单提交?

Spring MVC 通过 @RequestMapping 处理表单提交,将表单数据绑定到 Java 对象中。

Spring MVC 中的视图解析器有什么作用?

视图解析器用于将控制器返回的视图名解析为具体的视图实现,如 JSP 页面。

Spring MVC 中的拦截器是什么?如何定义一个拦截器?

拦截器用于处理请求的前后逻辑,如权限验证。定义拦截器需实现 HandlerInterceptor 接口,并注册到 WebMvcConfigurer 中。

Spring MVC 中的国际化支持是如何实现的?

Spring MVC 通过 MessageSourceLocaleResolver 提供国际化支持,可以根据用户的语言和地区加载不同的消息。

Spring MVC 中如何处理异常?

Spring MVC 通过 @ExceptionHandler 注解处理异常,或者使用 @ControllerAdvice 来统一处理异常。

Spring 中的 JPA 和 Hibernate 有什么区别?

  • JPA(Java Persistence API):是一个规范,定义了数据持久化的接口。
  • Hibernate:是实现 JPA 规范的具体框架,提供 ORM 功能。

这些问题和答案涵盖了 Spring 框架的多个重要方面,希望能帮助你更深入地理解 Spring 及其核心概念。

SpringBoot

以下是关于 Spring Boot 的详细解答:

说说 Springboot 的启动流程?

Spring Boot 的启动流程可以概括为以下几个步骤:

  1. 引导类(Main Class)
    • Spring Boot 应用程序以一个 @SpringBootApplication 注解的类为入口,该类通常包含 main 方法。
  2. 创建 Spring 应用上下文
    • main 方法中,调用 SpringApplication.run() 来启动应用。这会创建一个 SpringApplication 实例,并在其内部初始化一个 ApplicationContext(通常是 AnnotationConfigApplicationContextWebApplicationContext)。
  3. 加载环境配置
    • Spring Boot 会加载 application.propertiesapplication.yml 等配置文件,并解析环境变量及命令行参数。
  4. 自动配置
    • Spring Boot 根据项目的类路径和配置文件,自动配置相关的 Spring 组件,使用 @EnableAutoConfiguration 注解来实现。
  5. 创建 Bean
    • 解析配置后,Spring Boot 创建应用所需的 Bean,扫描并注册由 @Component, @Service, @Controller 等注解标识的类。
  6. 启动嵌入式服务器
    • 如果是 Web 应用,Spring Boot 会启动嵌入式 Web 服务器(如 Tomcat、Jetty 或 Undertow),并将应用注册到该服务器上。
  7. 事件发布
    • Spring Boot 会发布 ApplicationReadyEvent 事件,通知所有的监听器应用已经准备好。

什么是 Spring Boot?

Spring Boot 是一个基于 Spring 框架的开源 Java 应用程序框架,旨在简化 Spring 应用程序的开发和配置。它通过提供一系列约定优于配置的默认设置,帮助开发者快速搭建和部署应用程序。Spring Boot 还集成了嵌入式服务器,使得开发者可以不需要外部服务器就能运行 Web 应用。

Spring Boot 的核心特性有哪些?

Spring Boot 的核心特性包括:

  1. 自动配置:根据项目的类路径和 Bean 定义自动配置 Spring 应用程序。
  2. 起步依赖(Starter Dependencies):简化 Maven 依赖管理,提供一系列预配置的依赖集。
  3. 嵌入式服务器:支持嵌入式 Tomcat、Jetty 和 Undertow,简化 Web 应用的部署和运行。
  4. 生产就绪功能:内置健康检查、度量监控和审计功能,通过 Spring Actuator 提供。
  5. 简化的配置 :通过 application.propertiesapplication.yml 文件进行集中管理。

Spring Boot 是如何通过 main 方法启动 web 项目的?

Spring Boot 通过在 main 方法中调用 SpringApplication.run() 方法来启动 Web 项目。该方法会:

  1. 初始化 SpringApplication 实例。
  2. 创建和刷新 ApplicationContext
  3. 启动嵌入式 Web 服务器(如 Tomcat)。
  4. 扫描并注册应用中的 Spring Bean。
  5. 发布应用准备完成事件。

SpringBoot 是如何实现自动配置的?

Spring Boot 的自动配置依赖于 spring-boot-autoconfigure 模块。它通过 @EnableAutoConfiguration 注解触发,扫描应用的类路径,自动推断所需的 Bean,并根据配置文件提供的属性进行相应配置。每个自动配置类通常使用 @Conditional 注解来控制是否生效,从而确保仅在所需的条件下进行配置。

Spring Boot 支持哪些嵌入 Web 容器?

Spring Boot 支持以下嵌入式 Web 容器:

  1. Tomcat:默认嵌入式容器。
  2. Jetty:轻量级的 Servlet 容器。
  3. Undertow:高性能的 Web 服务器和 Servlet 容器。

开发者可以通过 Maven 或 Gradle 配置来选择所需的容器。

Spring Boot 中 application.properties 和 application.yml 的区别是什么?

  • 格式application.properties 是基于键值对的格式,而 application.yml 使用 YAML 格式,支持更复杂的层次结构。
  • 可读性:YAML 格式通常更易读,适合复杂配置。
  • 支持:两者都被 Spring Boot 支持,开发者可根据个人偏好选择使用。

如何在 Spring Boot 中定义和读取自定义配置?

  1. 定义配置
    • application.propertiesapplication.yml 中定义自定义属性,例如:
properties 复制代码
my.custom.property=value
  1. 读取配置
    • 使用 @Value 注解注入自定义配置:
java 复制代码
@Value("${my.custom.property}")
private String myProperty;
- 或者通过 `@ConfigurationProperties` 创建一个配置类:
java 复制代码
@ConfigurationProperties(prefix = "my.custom")
public class MyConfig {
    private String property;
}

Spring Boot 配置文件加载优先级你知道吗?

Spring Boot 配置文件的加载优先级从高到低依次为:

  1. 命令行参数:通过命令行启动时传入的参数。
  2. Java 系统属性 :使用 -D 参数传入的系统属性。
  3. 环境变量:操作系统的环境变量。
  4. application.properties** 和 **application.yml:在 classpath 中的配置文件。
  5. 默认值:在代码中定义的默认值。

Spring Boot 打成的 jar 和普通的 jar 有什么区别 ?

Spring Boot 打包的 JAR 文件具有以下特点:

  1. 可执行 JAR :包含了嵌入式的 Web 容器和所有依赖,允许直接通过 java -jar 命令运行。
  2. 重组结构:打包时会重新组织 JAR 文件的结构,确保所有依赖项正确加载。
  3. META-INF/MANIFEST.MF:包含了 Spring Boot 特有的启动配置。

Spring Boot 是否可以使用 XML 配置 ?

Spring Boot 支持使用 XML 配置,但不推荐这样做。它的设计理念是"约定优于配置",鼓励使用 Java 注解和属性文件来配置应用程序。如果需要 XML 配置,可以通过添加 @ImportResource 注解来导入 XML 配置文件。

SpringBoot 默认同时可以处理的最大连接数是多少?

Spring Boot 默认的最大连接数取决于所使用的嵌入式 Web 容器。对于 Tomcat,默认最大连接数是 200,通常可以通过在 application.properties 中配置来调整:

properties 复制代码
server.tomcat.max-connections=300

如何理解 Spring Boot 中的 starter?

Spring Boot 中的 Starter 是一组预先配置好的 Maven 依赖,可以简化项目配置。通过引入特定的 Starter,开发者可以快速获得相关功能,而不必手动配置每个依赖。例如,spring-boot-starter-web 提供了构建 Web 应用所需的所有依赖。

Spring Boot 如何处理跨域请求(CORS)?

Spring Boot 通过 @CrossOrigin 注解处理跨域请求。可以在控制器类或方法上添加该注解,指定允许跨域的源、请求方法等属性。例如:

java 复制代码
@CrossOrigin(origins = "http://example.com")
@RestController
public class MyController {
    // ...
}

也可以通过配置类全局设置 CORS 策略:

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("http://example.com");
    }
}

在 Spring Boot 中你是怎么使用拦截器的?

在 Spring Boot 中使用拦截器的步骤如下:

  1. 创建拦截器类 ,实现 HandlerInterceptor 接口。
java 复制代码
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 处理请求前逻辑
        return true; // 返回 true 继续处理请求
    }
}
  1. 注册拦截器 ,在配置类中实现 WebMvcConfigurer 接口:
java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

SpringBoot 中如何实现定时任务 ?

Spring Boot 通过 @Scheduled 注解来实现定时任务。步骤如下:

  1. 启用定时任务 ,在主类上添加 @EnableScheduling 注解。
java 复制代码
@SpringBootApplication
@EnableScheduling
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}
  1. 定义定时任务,使用 `@

Scheduled` 注解的方法:

java 复制代码
@Scheduled(fixedRate = 5000) // 每 5 秒执行一次
public void task() {
    // 定时执行的逻辑
}

什么是 Spring Actuator?它有什么优势?

Spring Actuator 是 Spring Boot 提供的一个功能模块,用于监控和管理 Spring Boot 应用。它提供了一系列的 REST API 端点,可以获取应用的健康状况、度量数据、环境信息等。其优势包括:

  1. 健康检查:可以快速检查应用的运行状态。
  2. 度量监控:提供应用性能指标和统计信息。
  3. 自定义端点:可以轻松添加自定义的管理端点。

Spring Boot 2.x 与 1.x 版本有哪些主要的改进和区别?

  1. 性能提升:2.x 在性能方面进行了优化。
  2. 依赖管理:更新了依赖版本,更好地支持最新的 Spring 生态系统。
  3. 配置简化:增强了自动配置的功能和灵活性。
  4. 新的特性 :引入了诸如 WebFlux 和响应式编程的支持。

Spring Boot 3.x 与 2.x 版本有哪些主要的改进和区别?

  1. Java 17 支持:3.x 版本要求最低 Java 17。
  2. 模块化:重构了某些模块,提供更好的性能和可维护性。
  3. 新的特性 :引入了 Spring Native 支持,增强了对 GraalVM 的支持。
  4. 不再支持某些过时的特性 :例如,移除了对 Spring Security 的一些老旧功能支持。

说说你对 Spring Boot 事件机制的了解?

Spring Boot 的事件机制基于 Spring 的事件发布/订阅模型。主要包括:

  1. 事件 :定义一个事件类,继承 ApplicationEvent
  2. 监听器 :创建一个监听器类,使用 @EventListener 注解或实现 ApplicationListener 接口来处理事件。
  3. 发布事件 :使用 ApplicationEventPublisher 发布事件。

示例:

java 复制代码
public class MyEvent extends ApplicationEvent {
    public MyEvent(Object source) {
        super(source);
    }
}

@Component
public class MyEventListener {
    @EventListener
    public void handleMyEvent(MyEvent event) {
        // 处理事件逻辑
    }
}

在 Spring Boot 中如何实现多数据源配置?

在 Spring Boot 中实现多数据源配置的步骤:

  1. 定义数据源配置类,分别为每个数据源创建配置:
java 复制代码
@Configuration
public class DataSourceConfig {
    @Bean(name = "dataSource1")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource1")
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dataSource2")
    @ConfigurationProperties(prefix = "spring.datasource2")
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }
}
  1. 配置属性 ,在 application.yml 中定义多个数据源:
yaml 复制代码
spring:
  datasource1:
    url: jdbc:mysql://localhost:3306/db1
    username: user1
    password: pass1
  datasource2:
    url: jdbc:mysql://localhost:3306/db2
    username: user2
    password: pass2
  1. 使用数据源 ,在 DAO 或 Repository 中使用 @Qualifier 注解来指定使用哪个数据源:
java 复制代码
@Autowired
@Qualifier("dataSource1")
private DataSource dataSource;

Spring Boot 中如何实现异步处理?

在 Spring Boot 中实现异步处理的步骤:

  1. 启用异步支持 ,在主类上添加 @EnableAsync 注解。
java 复制代码
@SpringBootApplication
@EnableAsync
public class MyApplication {
    // ...
}
  1. 定义异步方法 ,使用 @Async 注解标记:
java 复制代码
@Async
public CompletableFuture<String> asyncMethod() {
    // 异步执行的逻辑
    return CompletableFuture.completedFuture("result");
}
  1. 调用异步方法,直接调用该方法,它会在新的线程中执行。

如何在 SpringBoot 启动时执行特定代码?有哪些方式?

在 Spring Boot 启动时执行特定代码可以使用以下方式:

  1. CommandLineRunner :实现 CommandLineRunner 接口的方法会在 Spring 应用启动后执行。
java 复制代码
@Component
public class MyRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        // 启动时执行的逻辑
    }
}
  1. ApplicationRunner :类似于 CommandLineRunner,但可以获取应用上下文的信息。
java 复制代码
@Component
public class MyRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) {
        // 启动时执行的逻辑
    }
}
  1. @PostConstruct 注解:在 Bean 初始化完成后执行的方法。
java 复制代码
@Component
public class MyComponent {
    @PostConstruct
    public void init() {
        // 启动时执行的逻辑
    }
}

SpringBoot(Spring)中为什么不推荐使用 @Autowired?

在 Spring Boot 中,虽然 @Autowired 是常用的依赖注入方式,但不推荐过度使用主要是因为:

  1. 构造器注入的优势:构造器注入是更推荐的方式,因为它可以使依赖关系显式化,增强代码的可测试性和可读性。
  2. 避免循环依赖:使用构造器注入可以更好地防止循环依赖问题。
  3. 简化测试:构造器注入便于使用模拟对象进行单元测试,避免在测试中引入 Spring 上下文。

因此,在类中使用构造器注入而非字段注入是一种更佳的实践。

SpringCloud

什么是配置中心?有哪些常见的配置中心?

配置中心是一种集中管理应用程序配置的工具,允许开发人员和运维人员动态地更新和管理配置,避免硬编码和配置文件的分散管理。常见的配置中心包括:

  1. Spring Cloud Config:为 Spring 应用程序提供的集中配置管理解决方案。
  2. Nacos:阿里巴巴开源的动态服务发现、配置管理和服务管理平台。
  3. Consul:HashiCorp 开发的用于服务发现和配置的工具,支持健康检查和负载均衡。
  4. Zookeeper:Apache 提供的开源分布式协调服务,广泛用于配置管理和服务发现。

你知道 Nacos 配置中心的实现原理吗?

Nacos 的实现原理主要包括以下几个方面:

  • 配置管理:Nacos 将配置信息存储在内存和持久化存储中,可以通过 REST API 或 SDK 来进行配置的管理和发布。
  • 动态更新:支持动态配置更新,应用在运行时可以自动获取最新的配置。
  • 命名空间:通过命名空间来隔离不同环境的配置。
  • 健康监测:内置健康监测功能,确保服务的可用性。

为什么需要服务注册发现?

服务注册发现是微服务架构中的重要组成部分,其主要作用是:

  • 动态服务定位:服务实例可以随时上线和下线,服务注册中心可以动态更新服务列表。
  • 负载均衡:通过服务注册中心可以实现服务的负载均衡,提升系统的稳定性和性能。
  • 降低耦合:服务之间通过服务名而非具体地址进行调用,降低了服务之间的耦合度。

为什么需要在微服务中使用链路追踪?Spring Cloud 可以选择哪些微服务链路追踪方案?

链路追踪用于监控请求在微服务架构中的流转路径,主要原因包括:

  • 性能监控:能够快速定位性能瓶颈。
  • 故障排查:帮助开发人员理解问题发生的具体位置和原因。
  • 用户体验优化:通过监控请求延迟,优化用户体验。

Spring Cloud 可以选择的链路追踪方案有:

  • Spring Cloud Sleuth:集成链路追踪功能,自动为请求生成唯一的跟踪 ID。
  • Zipkin:开源的链路追踪系统,支持数据存储和分析。
  • Jaeger:另一种开源的分布式追踪系统,适用于大规模分布式系统。

Spring Cloud 的优缺点有哪些?

优点

  • 灵活性高:提供了丰富的组件,可以根据需求选择使用。
  • 社区支持:活跃的开源社区和文档,支持广泛。
  • 与 Spring 生态兼容:与 Spring Boot 紧密集成,简化配置和开发流程。

缺点

  • 学习曲线陡峭:微服务架构和相关技术的复杂性,可能增加学习成本。
  • 运维复杂性:需要额外的运维工作来管理服务的部署、监控和健康检查。
  • 性能开销:引入多个服务之间的网络通信,可能增加性能开销。

Spring Boot 和 Spring Cloud 之间的区别?

  • Spring Boot:是一个用于简化 Spring 应用程序开发的框架,主要关注快速构建独立的、生产级别的 Spring 应用。
  • Spring Cloud:是一个微服务开发的框架,提供了分布式系统中的通用功能(如服务注册与发现、负载均衡、配置管理等),主要在 Spring Boot 的基础上扩展功能。

Spring Cloud 由什么组成?

Spring Cloud 主要由以下几个核心组件组成:

  1. 服务发现:如 Eureka、Consul、Zookeeper。
  2. 配置管理:如 Spring Cloud Config、Nacos。
  3. 负载均衡:如 Ribbon、Feign。
  4. 断路器:如 Hystrix、Sentinel。
  5. API 网关:如 Zuul、Spring Cloud Gateway。
  6. 消息总线:如 Spring Cloud Bus。

你是怎么理解微服务的?

微服务是一种架构风格,强调将应用程序分解成小的、独立的服务。每个服务负责特定的功能,可以独立部署和扩展。微服务架构的主要特点包括:

  • 模块化:服务之间松耦合,便于维护和扩展。
  • 独立部署:每个服务可以独立部署和升级。
  • 多技术栈支持:不同服务可以使用不同的技术栈,适应不同的需求。

单体应用、SOA、微服务架构有什么区别?

  • 单体应用:将所有功能集成在一个应用中,耦合度高,难以维护和扩展。
  • SOA(面向服务架构):将应用拆分为多个服务,服务间通过网络通信,仍然依赖于大型企业级服务总线,耦合度较高。
  • 微服务架构:强调小型、独立的服务,服务之间通过轻量级的通信机制(如 HTTP/REST、消息队列)进行交互,支持快速开发和灵活扩展。

Spring Cloud Config 是什么?

Spring Cloud Config 是 Spring Cloud 提供的一个集中化配置管理工具,支持将配置存储在 Git、SVN 等版本控制系统中,提供 RESTful API 来读取和更新配置。它可以实现对多个微服务的统一管理,使得配置更新能够实时生效。

什么情况下需要使用分布式事务,有哪些方案?

需要使用分布式事务的场景包括:

  • 跨服务的数据一致性:多个服务需要在同一操作中更新数据,需要确保数据的一致性。
  • 复杂业务流程:如金融、电商等行业,涉及多个系统的协调。

常见的分布式事务方案包括:

  1. 两阶段提交(2PC):保证事务的原子性,但性能较低。
  2. 可靠消息服务(TCC、SAGA):通过将事务分解为多个小事务来实现,适合大多数业务场景。
  3. 基于补偿的事务:通过补偿操作来回滚之前的操作,适合网络延迟和失败的场景。

你们的服务是怎么做日志收集的?

服务日志收集通常使用以下几种方式:

  • 集中式日志管理:使用 ELK(Elasticsearch、Logstash、Kibana)或 EFK(Elasticsearch、Fluentd、Kibana)等栈进行日志收集和分析。
  • 分布式追踪:集成链路追踪工具(如 Zipkin、Jaeger)来收集和分析请求的执行路径。
  • 日志代理:使用日志代理(如 Fluentd、Filebeat)将日志从多个服务收集并发送到集中式存储。

说一下你对于 DDD 的了解?

领域驱动设计(DDD)是一种软件设计方法论,强调将软件设计与业务需求紧密结合。DDD 的核心概念包括:

  • 领域:业务所关心的核心概念。
  • 限界上下文:定义一个具体的模型和业务范围。
  • 实体:具有唯一标识的业务对象。
  • 值对象:无唯一标识的对象,用于表示属性或特征。
  • 聚合:一组相关的实体和值对象,围绕一个根实体进行管理。

什么是 Seata?

Seata 是一款开源的分布式事务解决方案,旨在为微服务架构提供事务支持。它通过各种模式(如 AT、TCC、SAGA)来实现分布式事务的一致性。

Seata 支持哪些模式的分布式事务?

Seata 支持以下分布式事务模式:

  1. AT(自动提交)模式:适合大多数业务场景,通过自动化的方式管理事务。
  2. TCC(Try-Confirm-Cancel)模式:适合对资源控制要求较高的场景,提供更大的灵活性。
  3. SAGA 模式:适合长时间运行的事务,通过编排或补偿方式来管理事务。

了解 Seata 的实现原理吗?

Seata 的实现原理主要包括以下几个部分:

  • 事务协调者:负责管理和协调各个参与者的事务。
  • 资源管理器:管理具体的资源(如数据库)事务,并与事务协调者进行通信。
  • 分支事务:参与者在执行业务逻辑时,向协调者报告事务状态,协调者根据状态决定事务的提交或回滚。

Seata 的事务回滚是怎么实现的?

Seata 的事务回滚主要通过以下步骤实现:

  • 当分支事务执行失败时,参与者将失败状态报告给事务协调者。

事务协调者通过补偿或回滚操作,将所有已提交的分支事务回滚到初始状态,确保数据一致性。

分布式和微服务有什么区别?

  • 分布式系统:是指在多个物理或虚拟计算机上运行的系统,通常包括多台服务器、网络等。可以是单体应用的分布式部署,也可以是微服务架构。
  • 微服务:是一种特定的分布式系统架构风格,强调将应用程序分解为小型、独立的服务。微服务具有更高的灵活性、可扩展性和可维护性。

Spring Cloud 有哪些注册中心?

Spring Cloud 支持以下注册中心:

  1. Eureka:Netflix 提供的服务注册与发现组件。
  2. Consul:HashiCorp 的服务发现与配置工具。
  3. Zookeeper:Apache 的分布式协调服务,广泛应用于注册和发现。

什么是 Eureka?

Eureka 是由 Netflix 开发的一个服务注册与发现组件,允许微服务在运行时注册自身并查询其他服务的地址。

Eureka 的实现原理说一下?

Eureka 的实现原理包括以下几个部分:

  • 服务注册:服务启动时向 Eureka 服务器注册自身信息,包括服务名称、IP 地址和端口号。
  • 服务发现:服务查询时向 Eureka 服务器请求已注册的服务列表,获取其他服务的地址。
  • 心跳机制:注册的服务定期向 Eureka 发送心跳,维护其在注册表中的有效性;如果长时间未发送心跳,Eureka 将移除该服务。

Spring Cloud 如何实现服务注册?

Spring Cloud 通过 Eureka 客户端库,使用注解(如 @EnableEurekaClient)和配置文件(如 application.yml)来实现服务注册。服务在启动时向 Eureka 服务器注册自身信息,并可以通过服务名称查询其他服务。

Consul 是什么?

Consul 是 HashiCorp 开发的一款开源工具,用于服务发现和配置管理,支持健康检查、负载均衡等功能。它提供了 HTTP API 和 DNS 接口,易于集成。

Eureka、Zookeeper、Nacos、Consul 的区别?

  • Eureka:主要用于服务注册与发现,提供丰富的集成和灵活的负载均衡,但没有强大的配置管理功能。
  • Zookeeper:用于分布式协调,支持服务注册与发现,但主要用于需要严格一致性和高可用性的场景。
  • Nacos:集成了服务发现和配置管理,支持动态配置和服务管理,使用更为简单。
  • Consul:支持服务发现、健康检查、负载均衡和配置管理,使用较为灵活,但相对复杂。

Nacos 中的 Namespace 是什么?

Nacos 中的 Namespace 用于将配置和服务进行隔离,允许在同一个 Nacos 实例中管理多个环境(如开发、测试、生产)的配置和服务。每个 Namespace 具有独立的配置和服务列表。

为什么需要负载均衡?

负载均衡的主要目的是:

  • 提高可用性:将请求分散到多个服务器,避免单点故障。
  • 提升性能:通过合理分配请求,降低单台服务器的负载,提高响应速度。
  • 弹性扩展:能够根据流量自动增加或减少服务器实例,灵活应对流量变化。

负载均衡的实现方式有哪些?

负载均衡的实现方式包括:

  1. 硬件负载均衡:使用专用设备(如 F5、阿里云 SLB)进行流量分发。
  2. 软件负载均衡:使用开源软件(如 Nginx、HAProxy)进行流量调度。
  3. DNS 负载均衡:通过 DNS 轮询将请求分发到不同的服务器。

负载均衡算法有哪些?

常见的负载均衡算法包括:

  1. 轮询:按照顺序将请求分发到每个服务器。
  2. 加权轮询:根据服务器的权重分配请求。
  3. 最少连接:将请求发送到当前连接数最少的服务器。
  4. IP 哈希:根据请求的 IP 地址进行哈希,确保相同用户的请求被发送到同一台服务器。

HTTP 与 RPC 之间的区别?

  • HTTP:一种无状态的请求-响应协议,适用于 Web 应用和 RESTful API,通常基于文本格式进行数据传输。
  • RPC(远程过程调用):允许在网络上调用远程计算机上的函数或过程,通常使用二进制协议进行数据传输,效率更高,支持更复杂的操作。

什么是 Feign?

Feign 是一个声明式的 Web 服务客户端,简化了服务间的调用,允许通过注解方式定义 HTTP 请求,自动实现请求的封装和调用。

Feign 是如何实现负载均衡的?

Feign 可以与 Ribbon 集成,通过 Ribbon 提供的负载均衡功能,实现服务调用时的负载均衡。Feign 客户端通过配置和注解定义调用的服务,Ribbon 会在请求时选择合适的服务实例。

为什么 Feign 第一次调用耗时很长?

Feign 第一次调用耗时长的原因通常包括:

  • 服务注册发现延迟:第一次调用时需要从注册中心查询服务实例,可能导致延迟。
  • 网络延迟:第一次网络请求可能面临 DNS 解析或网络连接的延迟。
  • 连接建立时间:TCP 连接建立和 SSL 握手也会增加初始调用的耗时。

Feign 和 OpenFeign 的区别?

  • Feign:是 Netflix 提供的一个声明式 HTTP 客户端库,支持与 Ribbon 的集成。
  • OpenFeign:是 Feign 的开源版本,增加了 Spring Cloud 的支持,可以与 Spring Boot 生态无缝集成,简化配置和使用。

Feign 和 Dubbo 的区别?

  • Feign:主要用于基于 HTTP 的 RESTful 服务调用,适用于微服务架构。
  • Dubbo:是 Alibaba 开发的 RPC 框架,支持高性能的远程调用,适用于需要高效、复杂的服务调用场景。

什么是熔断器?为什么需要熔断器?

熔断器是一种用于保护服务的设计模式,当某个服务出现故障时,熔断器会暂时阻止对该服务的调用,以避免连锁反应,保护系统的整体可用性。熔断器的主要目的是:

  • 防止服务雪崩:避免故障服务影响到正常服务。
  • 提高系统稳定性:快速返回错误信息,减少不必要的延迟。

什么是 Hystrix?

Hystrix 是由 Netflix 提供的一个熔断器库,帮助开发者控制服务的延迟和故障,提供熔断、降级、隔离等功能,增强系统的健壮性。

什么是服务雪崩?

服务雪崩是指某个服务故障导致大量依赖于该服务的其他服务也出现故障,从而引发连锁反应,最终导致整个系统崩溃的现象。

什么是服务降级?

服务降级是一种保护机制,当某个服务的性能下降或不可用时,系统可以自动转向其他服务或返回默认值,以保持系统的稳定性。

什么是服务熔断?

服务熔断是指在一定条件下(如超时、失败率过高)自动停止对某个服务的调用,避免对故障服务的持续调用,保护系统的整体可用性。

什么是服务限流?

服务限流是指限制服务的访问频率,以防止因过多请求导致服务崩溃。限流可以通过令牌桶、漏斗等算法实现。

什么是降级熔断?为什么需要熔断降级?

降级熔断是指在服务发生故障时,系统能够自动将请求转发到降级逻辑,返回友好的错误信息或默认值。需要熔断降级的原因包括:

  • 提高用户体验:即使在部分服务故障时,用户也能获得合理的反馈。
  • 保护系统稳定性:避免故障蔓延,确保其他正常服务不受影响。

熔断降级有哪些实现方案?

熔断降级的实现方案包括:

  1. Hystrix:提供熔断和降级功能,通过注解或 API 定义降级逻辑。
  2. Sentinel:通过规则配置实现熔断降级,支持复杂的流量控制和监控。
  3. 自定义熔断器:根据业务需求实现自定义的熔断器逻辑。

Hystrix 是怎么实现服务容错的?

Hystrix 通过以下方式实现服务容错:

  • 熔断机制:监控服务调用的成功率和响应时间,当超过设定阈值时,自动

开启熔断,防止对故障服务的持续调用。

  • 隔离策略:通过线程池和信号量隔离不同服务的调用,确保某个服务的故障不会影响到其他服务。
  • 降级策略:允许开发者定义当服务故障时的降级逻辑,返回友好的错误信息。

Sentinel 是怎么实现限流的?

Sentinel 通过配置限流规则(如 QPS、并发线程数)对请求进行限制。其核心组件包括:

  • 流量控制:根据设定规则动态限流。
  • 熔断降级:监控服务的运行状态,自动进行熔断和降级处理。
  • 集群限流:支持跨实例的流量控制,确保系统整体的稳定性。

Sentinel 与 Hystrix 的区别是什么?

  • 功能重点:Sentinel 强调流量控制、熔断降级和系统保护,而 Hystrix 更侧重于服务容错和隔离。
  • 实现方式:Sentinel 采用规则驱动的设计,支持动态调整;Hystrix 主要通过注解和配置实现。
  • 架构设计:Sentinel 设计更为灵活,支持复杂的流量控制场景,而 Hystrix 在高并发下可能面临性能瓶颈。

Sentinel 是怎么实现集群限流的?

Sentinel 通过共享控制面板(控制台)配置限流规则,所有实例通过网络同步限流状态,确保在集群中实现一致的限流策略。每个实例会根据规则动态调整请求处理能力。

什么是服务网格?

服务网格是一种基础设施层,提供服务间的通信管理,包括负载均衡、服务发现、熔断、监控等功能。服务网格允许开发者专注于业务逻辑,而将通用的服务通信问题交给网格处理。

什么是灰度发布、金丝雀部署以及蓝绿部署?

  • 灰度发布:逐步将新版本发布给一小部分用户,观察其表现后再逐步扩展。
  • 金丝雀部署:类似于灰度发布,但通常是将新版本部署到一小部分实例上,确保新版本在真实环境中的稳定性。
  • 蓝绿部署:维护两套相同环境(蓝、绿),在新版本上线时,切换流量到新的环境,确保无缝切换。

什么是微服务网关?为什么需要服务网关?

微服务网关是一个入口点,负责接收所有外部请求并将其路由到后端服务。服务网关的作用包括:

  • 请求路由:根据请求路径将请求转发到相应的微服务。
  • 负载均衡:实现对后端服务的负载均衡。
  • 安全性:提供认证和授权机制,保护后端服务。

Spring Cloud 可以选择哪些 API 网关?

Spring Cloud 支持以下 API 网关:

  1. Spring Cloud Zuul:提供动态路由、负载均衡和过滤器功能。
  2. Spring Cloud Gateway:基于 Spring 5 的反应式网关,支持更灵活的路由和过滤功能。

什么是 Spring Cloud Zuul?

Spring Cloud Zuul 是一个 API 网关服务,提供路由、负载均衡、监控等功能。Zuul 可以作为微服务架构的入口点,处理所有外部请求。

什么是 Spring Cloud Gateway?

Spring Cloud Gateway 是一种反应式 API 网关,基于 Spring 5 和 Project Reactor,提供路由、过滤、限流等功能,支持对微服务的高效管理。

说一下 Spring Cloud Gateway 的核心概念?

Spring Cloud Gateway 的核心概念包括:

  • 路由:通过定义路由规则,将请求转发到后端服务。
  • 过滤器:在请求到达目标服务之前或之后进行处理,可以用于请求修改、限流、监控等。
  • 负载均衡:支持对后端服务的负载均衡,提升系统的可靠性。

你项目里为什么选择 Gateway 作为网关?

选择 Spring Cloud Gateway 作为网关的原因可能包括:

  • 性能:基于反应式编程模型,处理高并发请求时性能优越。
  • 灵活性:支持动态路由和复杂的过滤逻辑,易于扩展。
  • 易集成性:与 Spring 生态系统的其他组件无缝集成,减少了开发成本。

Spring Cloud Gateway 与 Zuul 有什么区别?

  • 架构设计:Spring Cloud Gateway 是基于反应式架构,支持高并发和非阻塞请求,而 Zuul 是基于 Servlet API,性能上可能受到限制。
  • 功能扩展:Gateway 提供了更丰富的过滤器和路由功能,灵活性更高。
  • 易用性:Gateway 的配置和使用更为简洁,与 Spring Boot 的集成更为紧密。

说说什么是 API 网关?它有什么作用?

API 网关是微服务架构中的入口点,负责所有客户端请求的路由和管理。其作用包括:

  • 集中管理:将所有服务的调用集中在一个网关中,简化外部调用。
  • 安全性:提供统一的认证和授权机制,保护微服务。
  • 监控:可以对流量进行监控和分析,提供运行时指标和日志。

Dubbo 和 Spring Cloud Gateway 有什么区别?

  • 架构定位:Dubbo 是一个高性能的 RPC 框架,专注于服务间的调用,而 Spring Cloud Gateway 是 API 网关,负责请求的路由和管理。
  • 传输协议:Dubbo 支持多种协议(如 RPC),而 Gateway 主要处理 HTTP 请求。
  • 使用场景:Dubbo 适合高性能服务调用,Gateway 则适用于外部接口管理。

什么是令牌桶算法?工作原理是什么?使用它有哪些优点和注意事项?

令牌桶算法是一种流量控制算法,工作原理如下:

  • 令牌生成:以固定的速率向桶中添加令牌。
  • 请求处理:每次请求需要从桶中取出一个令牌,如果桶中没有令牌,请求被拒绝或延迟。
  • 控制流量:通过令牌的生成速率和桶的容量,控制请求的速率。

优点

  • 平滑流量:可以平滑控制请求速率,防止突发流量。
  • 灵活性:可以根据需求调整令牌生成速率和桶的容量。

注意事项

  • 桶的大小:设置合适的桶大小,以避免请求被过度拒绝。
  • 生成速率:根据业务需求,合理配置令牌生成速率。

MQ

说一下 RocketMQ 中关于事务消息的实现?

RocketMQ 中的事务消息支持在消息发送和处理的过程中保持消息的一致性。其实现过程包括三个步骤:

  1. 发送准备消息:事务消息首先发送一条准备消息到 Broker,状态为"待提交"。
  2. 执行本地事务:生产者随后执行本地事务,成功后提交本地事务,失败则回滚。
  3. 提交或回滚:在准备消息中,RocketMQ 会根据本地事务的执行结果,向 Broker 提交确认或回滚消息。通过事务状态检查的机制确保消息的最终一致性。

什么是消息队列?

消息队列是一种异步通信的方式,允许应用程序之间通过消息传递进行解耦。生产者将消息发送到队列中,消费者从队列中读取消息。消息队列通常用于处理高并发、异步任务和分布式系统中的数据传输。

为什么需要消息队列?

  1. 解耦:生产者和消费者之间不需要直接交互,提高系统的灵活性。
  2. 异步处理:可以在后台处理请求,提高系统的响应速度。
  3. 流量削峰:能够平滑处理高峰期的请求,避免系统过载。
  4. 可靠性:能够在消息持久化后即使系统故障也能恢复消息。

说一下消息队列的模型有哪些?

消息队列的模型主要有以下几种:

  1. 点对点模型(P2P):每条消息只能被一个消费者处理。
  2. 发布/订阅模型(Pub/Sub):每条消息可以被多个订阅者接收,适合广播场景。

简述下消息队列核心的一些术语?

  1. 消息:在消息队列中传递的数据单元。
  2. 队列:存储消息的地方,按照先进先出(FIFO)原则处理消息。
  3. 生产者:发送消息的应用程序。
  4. 消费者:接收并处理消息的应用程序。
  5. Broker:消息队列的服务器,负责消息的存储和传递。

如何保证消息不丢失?

  1. 持久化:将消息持久化存储到磁盘。
  2. 确认机制:消费者在处理完消息后发送确认,未确认的消息可以重新发送。
  3. 消息重试机制:对未成功处理的消息进行重试。
  4. 高可用性架构:通过集群和副本机制,避免单点故障。

如何处理重复消息?

  1. 去重机制:可以为每条消息分配唯一 ID,消费者在处理消息时检查是否已经处理过。
  2. 幂等性设计:确保多次处理相同消息的结果一致。

如何保证消息的有序性?

  1. 分区设计:将消息按某种规则(如用户 ID)分到同一个分区,以确保同一分区内的消息顺序。
  2. 顺序消费:限制消费者的数量,确保消息顺序处理。

如何处理消息堆积?

  1. 扩展消费者:增加消费者实例,提高消费速度。
  2. 优化消息处理逻辑:简化处理流程,减少处理时间。
  3. 流量控制:对生产者进行限流,避免过快地产生消息。

消息队列设计成推消息还是拉消息?推拉模式的优缺点?

  • 推模式
    • 优点:减少延迟,适合实时场景。
    • 缺点:可能导致网络拥堵,消费者处理能力不足时可能造成消息丢失。
  • 拉模式
    • 优点:消费者可控地请求消息,避免网络拥堵。
    • 缺点:可能引入延迟,需要定时轮询。

RocketMQ 的事务消息有什么缺点?你还了解过别的事务消息实现吗?

缺点:

  1. 复杂性:实现和管理事务消息的逻辑复杂。
  2. 性能损耗:由于需要检查和确认事务状态,可能引入额外的延迟。

其他实现:Apache Kafka 的事务消息实现,它使用一种基于两个阶段提交协议(2PC)的机制,确保消息的原子性。

说一下 Kafka 中关于事务消息的实现?

Kafka 的事务消息实现基于分区和消费者组的机制。其核心思想是使用事务 ID事务日志来管理消息的生产和消费。通过启用事务生产者,Kafka 允许生产者在一个事务中发送多条消息,然后在整个事务成功或失败时原子性地提交或回滚。

你了解 Kafka 中的时间轮实现吗?

Kafka 使用时间轮来处理延迟队列和超时消息。时间轮是一种高效的数据结构,能够在 O(1) 的时间复杂度内实现定时任务的调度。Kafka 利用时间轮来定期检查过期的消息并进行处理,避免了频繁的遍历操作。

Kafka的索引设计有什么亮点?

Kafka 的索引设计采用了稀疏索引机制。每个分区都有一个索引文件,其中记录了偏移量和对应的文件位置。通过稀疏索引,Kafka 只记录特定的偏移量,减少了索引的大小,提高了查找效率。

看过源码?那说说 Kafka 控制器事件处理全流程?

Kafka 控制器负责管理集群的元数据和分区的副本。其事件处理流程如下:

  1. 接收事件:控制器从 Zookeeper 接收分区状态变化事件。
  2. 更新元数据:根据事件更新内部元数据结构。
  3. 执行操作:在需要时,重新分配分区副本或迁移数据。
  4. 通知 Broker:将更新后的元数据广播给其他 Broker。

Kafka 中 Zookeeper 的作用?

Zookeeper 在 Kafka 中主要负责以下功能:

  1. 元数据管理:存储主题、分区、副本等元数据。
  2. 集群管理:管理 Broker 的注册和状态。
  3. 领导者选举:在分区副本中选举领导者 Broker。

Kafka为什么要抛弃 Zookeeper?

Kafka 计划抛弃 Zookeeper 是为了提高性能和简化架构。Zookeeper 的引入会增加系统复杂性,尤其是在处理高并发时可能成为性能瓶颈。因此,Kafka 正在开发自己的元数据管理方案,减少对 Zookeeper 的依赖。

看过源码?那说说 Kafka 处理请求的全流程?

Kafka 处理请求的全流程如下:

  1. 接收请求:Broker 接收到生产者或消费者的请求。
  2. 解析请求:根据请求类型解析请求参数。
  3. 执行操作:对于生产者,写入消息;对于消费者,读取消息。
  4. 返回结果:将处理结果返回给客户端。

RabbitMQ 中无法路由的消息会去到哪里?

RabbitMQ 中无法路由的消息会被发送到一个名为 死信交换机(Dead Letter Exchange, DLX) 的交换机,通常这些消息会被丢弃或者进行特定的处理。

RabbitMQ 中消息什么时候会进入死信交换机?

消息会进入死信交换机的情形包括:

  1. 消息被拒绝且未重新排队。
  2. 消息超时。
  3. 消息的 TTL(存活时间)到期。

说一下 AMQP 协议?

AMQP(Advanced Message Queuing Protocol)是一种开放标准的消息队列协议,提供消息的发送、接收、路由和确认等功能。AMQP 定义了消息的格式、传输过程以及各种消息队列服务的交互方式,旨在实现跨平台的消息中间件互操作性。

说一下 RabbitMQ 的事务机制?

RabbitMQ 支持事务机制,可以通过 tx.selecttx.commit 方法来管理事务。在事务模式下,消息在被确认之前可以被回滚。然而,使用事务机制会降低性能,通常推荐使用确认机制(acknowledgment)替代。

RabbitMQ 中主要有哪几个角色或者说概念?

RabbitMQ 的主要角色和概念包括:

  1. 生产者:发送消息的应用。
  2. 消费者:接收消息的应用。
  3. 队列:存储消息的缓冲区。
  4. 交换机:路由消息到一个或多个队列。

RabbitMQ 的 routing key 和 binding key 的最大长度是多少字节?

RabbitMQ 的 routing key 和 binding key 的最大长度为 255 字节。

RabbitMQ 中如何保证消息的顺序性?

RabbitMQ 保证消息顺序性的方式包括:

  1. 单个消费者:确保每个队列只有一个消费者,避免消息乱序。
  2. 使用优先级队列:根据优先级处理消息。

说说 RabbitMQ 的工作模式?

RabbitMQ 的工作模式包括:

  1. 发布/订阅模式:生产者将消息发送到交换机,消费者订阅特定的队列。
  2. 工作队列模式:多个生产者和消费者,平衡负载。

说一下 RabbitMQ 的缺点?

RabbitMQ 的缺点包括:

  1. 性能瓶颈:在高负载场景下可能出现性能瓶颈。
  2. 复杂的配置:对于初学者来说,配置和调优较为复杂。
  3. 消息持久性:持久化消息会引入一定的性能开销。

简单说一下 RabbitMQ 发送消息的过程?

RabbitMQ 发送消息的过程如下:

  1. 生产者连接到 RabbitMQ 服务器。
  2. 生产者发送消息到指定的交换机。
  3. 交换机根据 routing key 将消息路由到相应的队列。
  4. 消息被消费者消费。

RabbitMQ 如何避免消息的重复投递以及重复消费?

RabbitMQ 可以通过以下方式避免重复投递和消费:

  1. 唯一标识符:为每条消息生成唯一的 ID,消费者在处理前检查 ID。
  2. 消息确认:使用 ack 确认机制,未确认的消息将被重新投递。

RabbitMQ 中,如何保证消息的持久化?

RabbitMQ 保证消息持久化的方法:

  1. 将队列标记为持久化:创建队列时设置持久化选项。
  2. 将消息标记为持久化:发送消息时设置持久化属性。

RabbitMQ 中的 Channel 你有了解过吗?

RabbitMQ 中的 Channel 是与 Broker 之间进行通信的虚拟连接。一个连接可以有多个 Channel,每个 Channel 都可以独立处理消息、创建队列和交换机。

RabbitMQ 中,消息是如何进行路由的?

RabbitMQ 中消息的路由通过交换机和 routing key 实现。生产者将消息发送到交换机,交换机根据 routing key 和绑定关系决定将消息路由到哪个队列。

RabbitMQ 上一个 Queue 最多能存放多少条消息?

RabbitMQ 上一个队列理论上可以存放无限条消息,实际存放数量受限于服务器的内存和存储能力。

RabbitMQ 如何保证高可用?

RabbitMQ 通过以下方式确保高可用:

  1. 镜像队列:在多个节点之间复制队列,实现冗余。
  2. 集群:将多个 RabbitMQ 实例组成集群,增强故障容错能力。

RocketMQ 有什么优缺点?

优点:

  1. 高吞吐量:支持高并发消息处理。
  2. 事务支持:内置事务消息处理。
  3. 分布式特性:优秀的扩展性和负载均衡。

缺点:

  1. 学习曲线:相对复杂,需掌握较多概念。
  2. 生态较小:与其他成熟消息队列相比,社区支持和插件生态不够丰富。

为什么 RocketMQ 不使用 Zookeeper 作为注册中心呢?而选择自己实现 NameServer?

RocketMQ 选择自定义 NameServer 是为了降低对 Zookeeper 的依赖,减少系统复杂性并提高性能。自定义的 NameServer 旨在提供更快速的元数据访问和更新。

说一下 Kafka 为什么性能高?

Kafka 性能高的原因主要有:

  1. 顺序写入:采用顺序写入和文件系统的特性。
  2. 批量处理:支持批量消息的发送和接收,降低网络开销。
  3. 零拷贝技术:使用零拷贝减少数据复制,提高吞吐量。

说一下 Kafka 的应用场景?

Kafka 的应用场景包括:

  1. 实时数据处理:如流数据处理和 ETL 任务。
  2. 日志收集:集中管理和分析日志。
  3. 监控和指标收集:实时监控应用性能。

RabbitMQ 怎么实现延迟队列?

RabbitMQ 实现延迟队列的方式通常有:

  1. 使用 TTL:设置队列中消息的存活时间(TTL),超时后转入另一个队列。
  2. 利用插件:使用 RabbitMQ 延迟消息插件(rabbitmq-delayed-message-exchange)来实现。

Elasticsearch

1. 如何在 Elasticsearch 中设计和实现数据的多层次缓存机制?

在 Elasticsearch 中,可以通过以下几种方式设计和实现多层次缓存机制:

  • 查询缓存 :Elasticsearch 默认启用查询缓存,以提高相同查询的响应速度。可以通过设置 index.requests.cache.enable 来启用或禁用查询缓存。
  • 字段数据缓存(Fielddata) :当字段被用作聚合或排序时,会加载到内存中。可以通过设置 indices.fielddata.cache 来调整字段数据的缓存策略。
  • 结果缓存 :Elasticsearch 会缓存查询结果,尤其是对相同的聚合查询。可以通过设置 search.cache 来管理结果缓存。
  • 使用外部缓存:结合 Redis 或 Memcached 等外部缓存系统,缓存频繁访问的数据,进一步降低 Elasticsearch 的负载。

2. 如何通过 Elasticsearch 实现分布式事务?

Elasticsearch 本身不支持传统意义上的分布式事务,但可以通过以下方法模拟分布式事务:

  • 使用乐观锁:通过版本控制来避免并发写入的冲突。在文档更新时,指定文档的版本号,如果版本不匹配则重试。
  • 跨服务协调:使用分布式事务协调器(如 Saga 模式)来管理事务的状态,确保最终一致性。
  • 外部事务管理:在应用层管理数据的一致性和完整性,通过将相关操作放在同一个事务中进行处理。

3. 什么是 FST?在 Elasticsearch 中有哪些应用场景?

FST(Finite State Transducer)是一种高效的数据结构,主要用于存储和搜索字典中的字符串。它在 Elasticsearch 中的应用包括:

  • 词典压缩:FST 可以用于高效压缩词典,减少内存占用和磁盘空间。
  • 文本分析:在分词时,FST 可用于快速查找匹配的词。
  • 自动补全:FST 支持前缀查找,适用于实现自动补全功能。

4. Elasticsearch 中的 Fielddata 是什么?如何优化其性能?

Fielddata 是 Elasticsearch 为了在内存中加载字段数据而提供的一种机制。它通常用于排序、聚合和脚本。优化其性能的方法包括:

  • 限制 Fielddata 使用:避免对高基数字段使用 Fielddata,尤其是大量唯一值的字段。
  • 使用 Doc Values:为字段启用 Doc Values,以便在磁盘上存储,并在需要时加载到内存中。
  • 内存监控:定期监控 JVM 内存使用情况,避免内存溢出。

5. 如何实现 Elasticsearch 集群的滚动升级?

滚动升级是指在不中断服务的情况下逐步升级集群中的节点。具体步骤包括:

  1. 升级前准备:检查当前版本与目标版本之间的兼容性。
  2. 升级 Master 节点:首先升级 Master 节点,确保集群能正常运行。
  3. 逐个升级数据节点:在升级每个数据节点之前,先将其从集群中移除。升级后再将节点添加回集群。
  4. 监控集群状态:在每次升级后,监控集群的健康状态和性能。

6. 如何使用 Elasticsearch 实现机器学习模型的推理?

在 Elasticsearch 中实现机器学习模型的推理可通过以下方式:

  • 使用 Elasticsearch 的 Machine Learning 插件:该插件提供了内置的模型训练和推理功能,可以分析数据并生成预测。
  • 集成外部模型:将训练好的机器学习模型通过 REST API 接口与 Elasticsearch 集成,通过外部服务进行推理。

7. 什么是倒排表的 FOR 和 RBM 压缩算法?工作原理分别是什么?

  • FOR(Fast Object Retrieval):是一种针对倒排索引的压缩技术,主要通过压缩存储的文档 ID 列表来减少存储空间。通过使用变长编码和选择性压缩策略来提高压缩比。
  • RBM(Run Length Encoding with Bit Mapping):通过将相同的值连续存储为一段,从而减少重复数据的存储。适用于高度重复的文档 ID 列表。

8. 如何在确保数据一致性的前提下更新 Elasticsearch 的倒排索引?

在更新 Elasticsearch 的倒排索引时,可以采用以下策略:

  • 使用版本控制:通过文档版本号来确保更新的原子性。
  • 使用 Bulk API:将多个更新操作合并到一个请求中,减少因频繁更新而导致的一致性问题。
  • 使用 Refresh 操作:确保在查询之前执行 refresh 操作,使新数据可见。

9. 如何解决 Elasticsearch 集群中的双 Master 问题?

双 Master 问题通常是由于网络分区或配置错误导致的。解决方案包括:

  • 确保合适的集群设置 :设置合适的 discovery.zen.minimum_master_nodes,以确保集群在分区时不会产生多个 Master。
  • 监控和报警:监控集群状态,并在出现异常时进行报警,及时处理。

10. 什么是 Elasticsearch 的 Posting List 倒排列表?

Posting List 是倒排索引的核心组成部分,记录了每个词条在文档中的出现位置和相关信息。每个词条对应的 Posting List 包含文档 ID、位置和其他元数据。

11. 如何利用 Elasticsearch 实现大数据量(上亿量级)的聚合查询?

实现大数据量聚合查询的方法包括:

  • 使用合适的数据建模:对索引进行合理的设计,以支持高效的聚合。
  • 分片与副本:根据数据量设置合理的分片和副本数,提高并发处理能力。
  • 利用聚合管道:使用管道聚合将多个聚合结果合并,提高查询效率。

12. Elasticsearch 集群架构有哪些调优策略?

调优策略包括:

  • 节点角色分配:根据节点的角色(如主节点、数据节点、协调节点)进行合理分配。
  • 内存和 JVM 设置:调整 JVM 参数和内存使用策略,优化性能。
  • 监控和调整索引设置:根据查询和写入负载监控集群状态,动态调整索引设置。

13. 如何在 Lucene 中实现倒排索引?

在 Lucene 中,倒排索引的实现主要通过以下步骤:

  1. 文档解析:将文档内容解析为词项(Term)。
  2. 建立词典:记录每个词项及其出现的文档 ID。
  3. 构建 Posting List:为每个词项创建 Posting List,记录文档 ID 和位置信息。
  4. 索引写入:将构建的索引写入磁盘,形成可查询的倒排索引。

14. 如何优化 Elasticsearch 的 GC 来提升整体性能?

优化 Elasticsearch 的垃圾回收(GC)可以通过以下方式实现:

  • 选择合适的 GC 策略:根据使用场景选择合适的 GC 策略(如 G1 GC 或 CMS)。
  • 调整 JVM 内存参数:设置合适的堆内存大小,以减少 GC 的频率和停顿时间。
  • 监控 GC 行为:定期监控 GC 日志,调整参数以优化性能。

15. 如何优化 Elasticsearch 的写入性能以应对大数据量?

优化写入性能的方法包括:

  • 使用 Bulk API:批量写入数据,减少请求次数。
  • 禁用自动刷新:在大批量写入时,可以临时禁用索引的自动刷新,降低写入延迟。
  • 合理配置分片:根据数据量调整分片数量,避免单个分片负载过高。

16. Elasticsearch 集群什么情况下会出现脑裂?如何解决脑裂?

脑裂问题通常发生在网络分区导致的 Master 节点不同步,解决方案包括:

  • **设置 **discovery.zen.minimum_master_nodes:确保只有当大多数 Master 节点在线时才选举新 Master。
  • 使用 Zookeeper:使用 Zookeeper 作为集群的协调工具,增强集群的稳定性。

17. 如何对 Elasticsearch 的 JVM 进行调优以提升性能?

对 JVM 进行调优的策略包括:

  • 堆内存配置:合理配置堆内存,通常设置为物理内存的 50% 且不超过 32GB。
  • 选择合适的 GC:根据负载选择适合的垃圾回收器,调整参数以减少停顿时间。
  • 监控 JMX 性能指标:使用 JMX 监控 JVM 性能,动态调整参数。

18. Elasticsearch 底层是如何实现数据存储的?比如数据的存储流程和管理

Elasticsearch 使用 Lucene 库作为底层存储引擎,其数据存储流程如下:

  1. 文档接收:接收来自用户的文档请求。
  2. 索引过程:将文档解析为词项并构建倒排索引。
  3. 分片存储:将索引数据分布到不同的分片中,分片可以在不同的节点上。
  4. 数据持久化:使用事务日志和数据段文件将数据写入磁盘,确保数据的持久性。

19. Elasticsearch 在分布式环境下如何保证数据的最终一致性?

在分布式环境中,Elasticsearch 保证数据最终一致性的方法包括:

  • 副本机制:每个主分片都有多个副本,副本负责在主分片不可用时提供服务。
  • 版本控制:每个文档都有版本号,通过版本控制来确保更新操作的顺序。
  • 定期一致性检查:定期对集群状态进行一致性检查,确保数据的一致性。

20. 如何使用 Elasticsearch 实现高可用架构?

实现 Elasticsearch 的高可用架构可以采用以下策略:

  • 多节点部署:部署多个节点,确保即使部分节点故障,集群仍可正常运行。
  • 数据副本:为每个主分片配置副本,确保数据在节点故障时仍然可用。
  • 负载均衡:使用负载均衡器将请求分发到不同节点,提升系统的吞吐量和可用性。

计算机操作系统

什么是用户态和内核态?

用户态内核态是操作系统中两个不同的执行环境。

  • 用户态:在此模式下,应用程序运行时受到限制,不能直接访问硬件资源和系统内核的核心数据结构。用户态下的进程运行在受限环境中,保护系统安全和稳定性。若应用程序需要进行特权操作(如文件读写、网络通信),必须通过系统调用请求内核的服务。
  • 内核态:这是操作系统内核执行的模式,具有完全的访问权限。内核态下的代码可以直接访问硬件和系统资源,并且可以执行所有指令。内核态通常用于处理硬件中断、进程调度和管理内存等操作。

进程之间的通信方式有哪些?

进程间通信(IPC)是指不同进程之间交换数据的机制。常见的IPC方式包括:

  1. 管道(Pipe):提供单向通信,通常用于父子进程间。
  2. 命名管道(FIFO):类似于管道,但可以在无亲缘关系的进程之间使用。
  3. 消息队列:允许进程以消息的形式交换数据,消息可以是无结构的或有结构的。
  4. 共享内存:允许多个进程访问同一块内存区域,速度较快,但需要进行同步。
  5. 信号:用于通知进程某个事件发生。
  6. 套接字(Socket):常用于网络通信,也可以用于同一台计算机上的进程间通信。
  7. 信号量(Semaphore):用于控制多个进程对共享资源的访问,起到同步作用。

进程有哪几种状态?

进程的状态通常分为以下几种:

  1. 就绪(Ready):进程已准备好执行,但由于CPU资源未分配,正在等待调度。
  2. 运行(Running):进程正在CPU上执行。
  3. 阻塞(Blocked):进程因等待某些事件(如I/O操作完成)而暂时停止执行。
  4. 终止(Terminated):进程已经执行完毕或被强制终止,不再占用系统资源。

进程的调度算法你知道吗?

进程调度算法是操作系统用来决定进程何时运行的策略,常见的调度算法包括:

  1. 先来先服务(FCFS):按照进程到达的顺序进行调度。
  2. 最短作业优先(SJF):选择下一个最短执行时间的进程进行调度。
  3. 时间片轮转(RR):为每个进程分配一个时间片,轮流执行。
  4. 优先级调度:根据优先级高低选择进程执行,高优先级的进程先执行。
  5. 多级队列调度:将进程分为多个队列,每个队列采用不同的调度策略。

什么是软中断、什么是硬中断?

中断是硬件或软件向CPU发出的信号,请求处理某些事件。

  • 软中断(Software Interrupt):由程序通过特定指令主动触发的中断,例如系统调用时发出的中断。软中断用于实现用户程序与操作系统内核的交互。
  • 硬中断(Hardware Interrupt):由外部设备(如键盘、鼠标、网络适配器)生成的中断,CPU在执行过程中被外部事件打断,迫使其暂时停止当前操作,转而执行中断处理程序。

什么是分段、什么是分页?

**分段(Segmentation)分页(Paging)**是内存管理的两种方式。

  • 分段:将程序和数据逻辑上划分为不同的段(如代码段、数据段、堆栈段),每个段有一个段号和段基地址。分段允许更灵活的内存管理,支持共享和保护。
  • 分页:将内存分为固定大小的页面,程序逻辑空间也划分为同样大小的页。页表用于映射逻辑地址到物理地址。分页消除了外部碎片,但可能产生内部碎片。

说下你常用的 Linux 命令?

在Linux中,常用的命令包括:

  1. ls:列出目录内容。
  2. cd:改变当前工作目录。
  3. pwd:显示当前工作目录的完整路径。
  4. cp:复制文件或目录。
  5. mv:移动文件或目录,或重命名。
  6. rm:删除文件或目录。
  7. touch:创建空文件或更新文件的时间戳。
  8. chmod:更改文件或目录的权限。
  9. chown:更改文件或目录的所有者。
  10. grep:在文件中查找匹配的文本。
  11. find:查找文件。
  12. ps:查看当前运行的进程。
  13. top:动态显示系统中进程的资源使用情况。
  14. df:查看文件系统的磁盘空间使用情况。
  15. du:查看目录或文件的磁盘使用情况。

I/O到底是什么?

**I/O(输入/输出)**指的是计算机系统与外部环境(如用户、其他计算机、设备)之间的信息交换过程。I/O操作包括从外部设备读取数据(输入)和将数据发送到外部设备(输出)。I/O是计算机程序与外界交互的主要方式。

为什么网络 I/O 会被阻塞?

网络 I/O 被阻塞通常是因为:

  1. 等待数据:在进行网络读操作时,如果没有可用的数据,调用该操作的进程会被阻塞,直到数据到达。
  2. 缓冲区满:在进行网络写操作时,如果对方的接收缓冲区已满,进程会被阻塞,直到缓冲区有空间。
  3. 网络延迟:由于网络的传输延迟,数据未能及时到达,导致I/O操作被阻塞。

I/O模型有哪些?

I/O模型用于描述不同的输入/输出操作方式,主要包括:

  1. 阻塞I/O:进程在I/O操作时会被阻塞,直到操作完成。
  2. 非阻塞I/O:进程在I/O操作时不会被阻塞,如果操作无法立即完成,进程可以继续执行其他任务。
  3. 异步I/O:进程发起I/O操作后可以继续执行其他任务,I/O操作完成后通过回调或信号通知进程。
  4. 同步I/O:进程发起I/O操作并等待操作完成,然后再继续执行。

同步和异步的区别?

同步异步的主要区别在于任务的执行和等待方式:

  • 同步:任务发起后,调用者必须等待任务完成才能继续执行。适用于对结果顺序要求较高的场景。
  • 异步:任务发起后,调用者可以立即继续执行其他任务,无需等待任务完成,通常通过回调或事件处理机制来获取结果。

阻塞和非阻塞的区别?

阻塞非阻塞的区别在于对进程执行的影响:

  • 阻塞:在进行I/O操作时,进程会被挂起,直到操作完成,无法继续执行其他任务。
  • 非阻塞:在进行I/O操作时,进程不会被挂起,如果操作无法立即完成,进程可以继续执行其他任务。

同步、异步、阻塞、非阻塞的I/O的区别?

  • 同步阻塞I/O:进程在发起I/O请求时被挂起,等待I/O操作完成。
  • 同步非阻塞I/O:进程在发起I/O请求时不会被挂起,如果操作无法完成,进程会立即返回,继续执行其他任务。
  • 异步阻塞I/O:进程发起I/O请求后继续执行,但在需要结果时会被阻塞,直到结果可用。
  • 异步非阻塞I/O:进程发起I/O请求后立即返回,且不需要等待结果,通常通过回调函数来处理结果。

什么是 BIO、NIO、AIO?

  • BIO(Blocking I/O):传统的阻塞I/O模型,I/O操作是阻塞的,进程在等待I/O操作时被挂起。
  • NIO(Non-blocking I/O):非阻塞I/O模型,进程可以在发起I/O请求后继续执行其他任务,可以通过轮询或回调机制来检查I/O操作的完成状态。
  • **A

IO(Asynchronous I/O)**:异步I/O模型,进程发起I/O请求后可以立即返回,当I/O操作完成时,通过回调或信号通知进程。

什么是 Channel?

Channel 是 NIO 中的一个重要概念,代表一个可以进行 I/O 操作的通道。Channel 可以用来读写数据,具有类似于流(Stream)的特性,但支持异步和非阻塞 I/O。常用的 Channel 包括 FileChannel(文件通道)、SocketChannel(套接字通道)等。

什么是 Buffer?

Buffer 是 NIO 中的一个数据容器,用于在 Channel 读写数据时暂时存储数据。Buffer 有不同的数据类型(如 ByteBuffer、CharBuffer 等),并且在读写操作中需要管理位置(position)、限制(limit)和容量(capacity)等属性。

什么是 Selector?

Selector 是 NIO 中的一个组件,用于处理多个 Channel 的 I/O 操作。通过 Selector,单个线程可以监视多个 Channel 的状态,进行非阻塞 I/O 操作,适合高并发场景。它允许程序在没有数据可读或可写时继续处理其他任务。

到底什么是 Reactor?

Reactor 是一种事件驱动的设计模式,通常用于网络应用程序中。它通过使用 Selector 和多个 Handler 处理事件。Reactor 模式的核心思想是将 I/O 事件的处理与具体的业务逻辑解耦,当有 I/O 事件发生时,Reactor 会将事件分发给相应的处理器进行处理,从而实现高效的非阻塞 I/O。

Select、Poll、Epoll 之间有什么区别?

  • Select:早期的 I/O 多路复用机制,支持的文件描述符数量有限(通常为1024),需要遍历整个文件描述符集,性能较低。
  • Poll:类似于 Select,但没有文件描述符数量的限制,使用链表存储文件描述符,性能较 Select 有所提升,但在大量文件描述符时依然效率低下。
  • Epoll:Linux 特有的高效 I/O 多路复用机制,支持大量并发连接,使用事件驱动模型,只有当文件描述符有事件发生时才会返回,效率较高。

什么是物理地址,什么是逻辑地址?

  • 物理地址:实际内存单元的地址,表示数据在物理内存中的存储位置。它是硬件级别的地址,由内存管理单元(MMU)生成。
  • 逻辑地址:程序使用的地址,也称为虚拟地址。逻辑地址由程序生成,经过内存管理单元的转换后映射到物理地址。逻辑地址提供了对物理内存的抽象,使程序员无需关心实际物理内存的布局。

线程和进程有什么区别?

  • 进程:是操作系统分配资源的基本单位,每个进程有自己的内存空间和系统资源,进程之间相互独立。
  • 线程:是进程中的执行单元,同一进程内的线程共享内存和资源,可以提高程序的并发性和效率。线程的创建和销毁开销相对较小,切换速度也快于进程。

总体来说,线程和进程都是操作系统中的重要概念,但它们在资源管理和执行单元的独立性上存在显著区别。

计算机网络

常见的 HTTP 状态码有哪些?

HTTP 状态码用于指示服务器对客户端请求的处理结果。常见的 HTTP 状态码包括:

  • 200 OK:请求成功,服务器返回所请求的数据。
  • 201 Created:请求成功,并且服务器创建了新的资源。
  • 204 No Content:请求成功,但没有返回内容。
  • 301 Moved Permanently:请求的资源已被永久移动到新 URI。
  • 302 Found:请求的资源临时移动到新 URI。
  • 400 Bad Request:客户端请求的语法错误。
  • 401 Unauthorized:请求未授权,需提供身份验证。
  • 403 Forbidden:服务器拒绝请求,用户无权访问资源。
  • 404 Not Found:请求的资源未找到。
  • 500 Internal Server Error:服务器内部错误,无法完成请求。
  • 503 Service Unavailable:服务器暂时无法处理请求。

HTTP 请求包含哪些内容,请求头和请求体有哪些类型?

HTTP 请求由以下部分组成:

  1. 请求行:包括请求方法(如 GET、POST)、请求的 URI 和 HTTP 版本。
  2. 请求头 :包含客户端信息和请求的额外信息。常见的请求头有:
    • Host:请求的主机名。
    • User-Agent:客户端软件信息。
    • Accept:客户端可处理的媒体类型。
    • Content-Type:请求体内容类型(如 application/jsonapplication/x-www-form-urlencoded)。
  3. 请求体:通常用于 POST 或 PUT 请求,包含要发送的数据,数据类型可能是 JSON、XML、表单数据等。

除了四次挥手,还有什么方法断开连接?

除了四次挥手,TCP 连接可以通过以下方式断开:

  • 重置连接(RST):当一方检测到连接异常时,可以发送一个 RST 数据包来强制关闭连接,立即断开。
  • 应用层关闭:应用程序可以通过关闭套接字的方式通知操作系统关闭连接。

HTTP 1.0 和 2.0 有什么区别?

HTTP/1.0 和 HTTP/2.0 的主要区别包括:

  • 多路复用:HTTP/2.0 支持多路复用,可以在一个连接中并发处理多个请求和响应,HTTP/1.0 则需要为每个请求建立独立的连接。
  • 头部压缩:HTTP/2.0 使用 HPACK 算法对请求和响应头部进行压缩,减少网络带宽的使用。
  • 二进制分帧:HTTP/2.0 将数据转换为二进制格式,使用帧的方式传输,提高了效率和可扩展性。
  • 优先级:HTTP/2.0 支持请求的优先级处理,可以优化资源的获取顺序。

HTTP 2.0 和 3.0 有什么区别?

HTTP/2.0 和 HTTP/3.0 之间的主要区别包括:

  • 传输协议:HTTP/2.0 基于 TCP,而 HTTP/3.0 基于 QUIC(Quick UDP Internet Connections),QUIC 使用 UDP 以减少延迟和提高连接速度。
  • 连接管理:HTTP/3.0 的连接建立更快,支持快速恢复和迁移,减少了丢包的影响。
  • 内置加密:HTTP/3.0 默认使用加密(TLS),提供了更强的安全性。

到底什么是 TCP 连接?

TCP(传输控制协议)连接是通过三次握手过程建立的,保证了数据在网络中的可靠传输。TCP 连接具有以下特性:

  • 面向连接:在数据传输之前,必须先建立连接。
  • 可靠性:确保数据按顺序传输,并且在传输过程中不会丢失。
  • 流量控制:防止发送方发送数据过快而导致接收方缓冲区溢出。
  • 拥塞控制:避免网络拥堵,确保网络的高效利用。

HTTP 和 HTTPS 有什么区别?

HTTP(超文本传输协议)和 HTTPS(安全超文本传输协议)的主要区别在于:

  • 安全性:HTTPS 在 HTTP 的基础上通过 SSL/TLS 协议进行加密,确保数据在传输过程中的安全性,防止中间人攻击。
  • 端口:HTTP 通常使用端口 80,而 HTTPS 使用端口 443。
  • 性能:虽然 HTTPS 加密增加了一些开销,但现代优化使其在许多情况下比 HTTP 更快。

TCP 是用来解决什么问题?

TCP 主要用于解决以下问题:

  • 可靠性:通过确认和重传机制,确保数据包的可靠传输。
  • 顺序性:确保数据包按发送顺序到达接收方。
  • 流量控制:通过滑动窗口机制控制数据发送速度,防止接收方被淹没。
  • 拥塞控制:动态调整发送速率以应对网络拥塞。

TCP 和 UDP 有什么区别?

TCP 和 UDP 的主要区别包括:

  • 连接性:TCP 是面向连接的协议,而 UDP 是无连接的协议。
  • 可靠性:TCP 提供可靠的数据传输,而 UDP 不保证数据的可靠性。
  • 顺序性:TCP 确保数据按顺序到达,而 UDP 不保证顺序。
  • 开销:TCP 有更多的开销(如握手、确认等),而 UDP 开销较小,适合实时应用。

为什么要 TCP,IP 层实现控制不行么?

TCP 提供了许多 IP 层无法实现的功能,例如:

  • 可靠性:IP 协议仅提供数据包的传输,而 TCP 提供了确认、重传和错误检测等机制,确保数据的可靠性。
  • 流量控制和拥塞控制:TCP 可以动态调整数据流量,防止网络拥塞,而 IP 不具备这些功能。
  • 顺序传输:TCP 确保数据包按正确顺序到达,而 IP 只关注数据的传输,不关心顺序。

TCP 的粘包和拆包能说说吗?

粘包拆包是 TCP 通信中出现的问题,主要是由于 TCP 是流式传输,数据是以字节流的形式发送的:

  • 粘包:多个发送的数据包在接收端被合并为一个包,接收方无法判断边界。
  • 拆包:一个发送的数据包在接收端被拆分成多个包,接收方接收到的不是完整的数据。

解决这两个问题的方法包括使用自定义的协议头,标识数据包的长度和序号。

说说 TCP 的三次握手?

TCP 的三次握手过程用于建立连接,具体步骤如下:

  1. SYN:客户端发送一个 SYN 数据包(同步序列编号)到服务器,请求建立连接。
  2. SYN-ACK:服务器接收到 SYN 后,发送一个 SYN-ACK 数据包作为应答,确认接收到的请求。
  3. ACK:客户端收到 SYN-ACK 后,发送一个 ACK 数据包确认连接建立。

三次握手确保了双方都可以发送和接收数据。

TCP 初始序列号 ISN 怎么取值的?

TCP 初始序列号(ISN)通常是通过以下方式生成的:

  • 随机生成:ISN 应该是随机生成的,以防止序列号预测攻击。
  • 时间戳:可以使用系统时间或其他算法来确保序列号的唯一性。

TCP 三次握手时,发送 SYN 之后就宕机了会怎么样?

如果在发送 SYN 后客户端宕机:

  • 服务器在规定时间内没有收到 ACK,则会认为连接建立失败,并释放相关资源。
  • 客户端在重新启动后,可能会再次尝试建立连接。

什么是 SYN Flood 攻击?

SYN Flood 攻击是一种拒绝服务(DoS)攻击,攻击者发送大量 SYN 请求而不完成握手过程,导致目标服务器的连接队列耗尽,从而无法响应合法用户的请求。

说说 TCP 的四次挥手?

TCP 的四次挥手过程用于断开连接,具体步骤如下:

  1. FIN:主动关闭连接的一方发送 FIN 数据包,表示希望断开连接。
  2. ACK:接收方收到 FIN 后,发送 ACK 确认数据包。
  3. FIN:接收方发送自己的 FIN 数据包,表示也准备断开连接。
  4. ACK:主动关闭连接的一方发送 ACK 确认接收到的 FIN。

为什么 TCP 挥手需要有 TIME_WAIT 状态?

TIME_WAIT 状态用于确保:

  • 确认:确保最后的 ACK 数据包能够被接收方收到。如果接收方没有收到,可能会重新发送 FIN。
  • 旧连接的安全:防止由于网络延迟导致的旧数据

包混淆新连接。

TCP 超时重传机制是为了解决什么问题?

TCP 超时重传机制用于确保数据的可靠传输。当发送方发送数据包后,如果在指定时间内没有收到 ACK,发送方会重传该数据包,解决数据丢失或延迟的问题。

TCP 有超时重传为什么还需要快速重传机制?

快速重传机制用于提高数据传输的效率。即使数据包没有超时,发送方如果接收到三个重复的 ACK,说明数据包可能丢失,立即进行重传,而不必等待超时,减少延迟。

TCP 的 SACK 的引入是为了解决什么问题?

SACK(Selective Acknowledgment)用于解决 TCP 中的重复确认问题。它允许接收方告知发送方哪些数据包已经成功接收,哪些还未接收,从而提高重传的效率,避免不必要的数据重传。

TCP 滑动窗口的作用是什么?

TCP 滑动窗口机制用于流量控制。它允许接收方告知发送方可以接收的最大字节数,从而限制发送方的发送速率,确保接收方的缓冲区不会溢出。

说说 TCP 拥塞控制的步骤?

TCP 拥塞控制通常包括以下步骤:

  1. 慢启动:初始窗口大小较小,随着每次 ACK 的接收而指数增长。
  2. 拥塞避免:达到阈值后,窗口大小线性增长,以避免网络拥堵。
  3. 快速重传:接收到三个重复 ACK 时,立即重传丢失的数据包。
  4. 快速恢复:在快速重传后,重新调整阈值,继续传输。

ARP 和 RARP 分别是什么?有什么区别?

  • ARP(Address Resolution Protocol):用于将网络层的 IP 地址转换为链路层的 MAC 地址。
  • RARP(Reverse Address Resolution Protocol):用于将链路层的 MAC 地址转换为网络层的 IP 地址。

主要区别在于 ARP 是从 IP 到 MAC 的转换,而 RARP 是反向转换。

TCP/IP 四层模型是什么?

TCP/IP 四层模型包括:

  1. 应用层:为应用程序提供网络服务(如 HTTP、FTP)。
  2. 传输层:负责端到端的通信(如 TCP、UDP)。
  3. 网络层:负责数据包的转发(如 IP)。
  4. 链路层:处理直接相连的网络的传输(如 Ethernet)。

OSI 七层模型是什么?

OSI 七层模型包括:

  1. 物理层:传输原始比特流。
  2. 数据链路层:提供节点到节点的数据传输。
  3. 网络层:提供数据包转发。
  4. 传输层:提供端到端的通信。
  5. 会话层:管理会话和控制。
  6. 表示层:数据格式转换和加密。
  7. 应用层:为应用程序提供网络服务。

Cookie、Session、Token 之间有什么区别?

  • Cookie:由服务器发送到客户端的少量数据,存储在客户端浏览器中,用于识别用户状态。
  • Session:在服务器端存储用户信息,通过 Session ID 识别,通常与 Cookie 一起使用。
  • Token:一种自包含的令牌,通常用于身份验证,客户端携带,服务器根据 Token 验证用户身份。

JWT Token 能说说吗?

JWT(JSON Web Token)是一种用于身份验证和信息交换的开放标准。JWT 包含三部分:

  1. 头部:描述了 Token 的类型和所使用的加密算法。
  2. 有效载荷:存储用户的相关信息(如用户 ID、权限等)。
  3. 签名:用于验证信息未被篡改。

JWT 的优点包括可扩展性、无状态性和跨域支持。

简单谈谈你对 DNS 的理解?

DNS(域名系统)是将域名解析为 IP 地址的系统。用户输入域名时,DNS 服务器将其转换为相应的 IP 地址,从而帮助浏览器找到目标服务器。DNS 采用分布式结构,可以有效处理大量请求,确保域名的可用性和可靠性。

简单谈谈你对 CDN 的理解?

CDN(内容分发网络)是一个由多个分布在不同地理位置的服务器组成的网络,旨在加速用户访问网站和应用程序的速度。通过将静态资源缓存到离用户更近的边缘服务器上,CDN 减少了延迟和带宽消耗,提高了用户体验和网站性能。

从网络角度来看,用户从输入网址到网页显示,期间发生了什么?

用户输入网址后,发生的主要步骤包括:

  1. DNS 查询:浏览器通过 DNS 将域名解析为 IP 地址。
  2. TCP 连接:浏览器与服务器建立 TCP 连接,完成三次握手。
  3. HTTP 请求:浏览器向服务器发送 HTTP 请求,请求所需资源。
  4. 服务器响应:服务器处理请求并返回 HTTP 响应,包含所请求的资源。
  5. 数据传输:通过 TCP 传输数据,确保数据的可靠性和顺序。
  6. 网页渲染:浏览器接收到数据后,解析 HTML、CSS 和 JavaScript,并将网页渲染出来。
相关推荐
CoderJia程序员甲2 分钟前
重学SpringBoot3-Spring WebFlux之HttpHandler和HttpServer
java·spring boot·reactor·1024程序员节
chuk.10 分钟前
【JAVA】利用钉钉自定义机器人监控NACOS服务,实现实时下线通知
java·机器人·钉钉
weixi_kelaile52010 分钟前
ai智能语音电销机器人可以做哪些事情?
java·linux·服务器·人工智能·机器人·云计算·腾讯云
书鸢123618 分钟前
力扣每日一题合集
java·算法·leetcode
魔道不误砍柴功20 分钟前
Java 中 String str = new String(“hello“); 里面创建了几个对象?
java·开发语言·string·new
菜菜-plus1 小时前
微服务技术,SpringCloudAlibaba,Redis,RocketMQ,Docker,分库分表
java·spring boot·redis·spring cloud·docker·微服务·java-rocketmq
除了菜一无所有!2 小时前
基于SpringBoot技术的教务管理
java·spring boot·后端
lexusv8ls600h3 小时前
微服务设计模式 - 断路器模式 (Circuit Breaker Pattern)
java·微服务·设计模式
逸狼3 小时前
【JavaEE初阶】网络原理(2)
java·网络·java-ee
甲柒3 小时前
12-Docker发布微服务
java·docker·微服务