前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深圳某小厂面试,也没扛住。。。

深圳某小厂面试,也没扛住。。。

作者头像
小林coding
发布2024-05-17 18:59:28
1020
发布2024-05-17 18:59:28
举报
文章被收录于专栏:小林coding小林coding

图解学习网站:https://xiaolincoding.com

大家好,我是小林。

之前有很多读者咨询我,现在搞后端开发,校招毕业能拿到多少薪资?

其实拿到多少薪资,跟进到什么规模的公司关系比较大,能进大厂的人还是少数人。

  • 互联网一线大厂:35w+ 年薪
  • 互联网二线厂:25-30w 年薪
  • 中厂:15w-25w年薪
  • 小厂:10w 左右

不同规模的公司,薪资差距也是比较大,对应的面试难度也会有所区别。

后端面经」系列已经分享了非常多的互联网大厂的面经,这次我们来看不一样的,来看看深圳某小厂后端面经。

无算法,问的问题偏基础和简单,会偏应用多一些没有深挖太多的八股内容。

主要考察了Java 基础+JVM+MySQL+Spring+微服务+消息队列+Redis+设计模式这些内容。

说一下Java的特点

主要有以下的特点:

  • 平台无关性:Java的“编写一次,运行无处不在”哲学是其最大的特点之一。Java编译器将源代码编译成字节码(bytecode),该字节码可以在任何安装了Java虚拟机(JVM)的系统上运行。
  • 面向对象:Java是一门严格的面向对象编程语言,几乎一切都是对象。面向对象编程(OOP)特性使得代码更易于维护和重用,包括类(class)、对象(object)、继承(inheritance)、多态(polymorphism)、抽象(abstraction)和封装(encapsulation)。
  • 内存管理:Java有自己的垃圾回收机制,自动管理内存和回收不再使用的对象。这样,开发者不需要手动管理内存,从而减少内存泄漏和其他内存相关的问题。

为什么Java解释和编译都有?

首先在Java经过编译之后生成字节码文件,接下来进入JVM中,就有两个步骤编译和解释。如下图:

编译性

  • Java源代码首先被编译成字节码,JIT 会把编译过的机器码保存起来,以备下次使用。

解释性:

  • JVM中一个方法调用计数器,当累计计数大于一定值的时候,就使用JIT进行编译生成机器码文件。否则就是用解释器进行解释执行,然后字节码也是经过解释器进行解释运行的。

所以Java既是编译型也是解释性语言,默认采用的是解释器和编译器混合的模式。

jvm是什么?

JVM是 java 虚拟机,主要工作是解释自己的指令集(即字节码)并映射到本地的CPU指令集和OS的系统调用。JVM屏蔽了与操作系统平台相关的信息,使得Java程序只需要生成在Java虚拟机上运行的目标代码(字节码),就可在多种平台上不加修改的运行,这也是Java能够“一次编译,到处运行的”原因。

说一下jvm的垃圾回收机制?

垃圾回收算法:

  • 标记-清除算法:标记-清除算法分为“标记”和“清除”两个阶段,首先通过可达性分析,标记出所有需要回收的对象,然后统一回收所有被标记的对象。标记-清除算法有两个缺陷,一个是效率问题,标记和清除的过程效率都不高,另外一个就是,清除结束后会造成大量的碎片空间。有可能会造成在申请大块内存的时候因为没有足够的连续空间导致再次 GC。
  • 复制算法:为了解决碎片空间的问题,出现了“复制算法”。复制算法的原理是,将内存分成两块,每次申请内存时都使用其中的一块,当内存不够时,将这一块内存中所有存活的复制到另一块上。然后将然后再把已使用的内存整个清理掉。复制算法解决了空间碎片的问题。但是也带来了新的问题。因为每次在申请内存时,都只能使用一半的内存空间。内存利用率严重不足。
  • 标记-整理算法:复制算法在 GC 之后存活对象较少的情况下效率比较高,但如果存活对象比较多时,会执行较多的复制操作,效率就会下降。而老年代的对象在 GC 之后的存活率就比较高,所以就有人提出了“标记-整理算法”。标记-整理算法的“标记”过程与“标记-清除算法”的标记过程一致,但标记之后不会直接清理。而是将所有存活对象都移动到内存的一端。移动结束后直接清理掉剩余部分。
  • 分代回收算法:分代收集是将内存划分成了新生代和老年代。分配的依据是对象的生存周期,或者说经历过的 GC 次数。对象创建时,一般在新生代申请内存,当经历一次 GC 之后如果对还存活,那么对象的年龄 +1。当年龄超过一定值(默认是 15,可以通过参数 -XX:MaxTenuringThreshold 来设定)后,如果对象还存活,那么该对象会进入老年代。

垃圾回收器:

  • Serial 收集器,串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。
  • ParNew 收集器,ParNew 收集器其实就是 Serial 收集器的多线程版本。
  • Parallel 收集器,Parallel Scavenge 收集器类似 ParNew 收集器,Parallel 收集器更关注系统的吞吐量。
  • Parallel Old 收集器,Parallel Old 是 Parallel Scavenge 收集器的老年代版本,使用多线程和“标记-整理”算法
  • CMS 收集器,CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
  • G1 收集器,G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征

类加载过程介绍一下

类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括以下 7 个阶段:

  • 加载
  • 验证
  • 准备
  • 解析
  • 初始化
  • 使用
  • 卸载

验证、准备、解析 3 个阶段统称为连接。

JVM 中类的装载是由类加载器,也就是ClassLoader,和它的子类来实现的,Java 中的类加载器是一个重要的 Java 运行时系统组件,它负责在运行时查找和装入类文件中的类。

由于 Java 的跨平台性, 经过编译的 Java 源程序并不是一个可执行程序, 而是一个或多个类文件。当 Java 程序需要使用某个类时,JVM 会确保这个类已经被加载、连接( 验证、 准备和解析)和初始化。

类的加载是指把类的.class 文件中的数据读入到内存中,通常是创建一个字节数组读入.class 文件,然后产生与所加载类对应的 Class 对象。加载完成后, Class 对象还不完整, 所以此时的类还不可用。当类被加载后就进入连接阶段, 这一阶段包括验证、准备( 为静态变量分配内存并设置默认的初始值) 和解析( 将符号引用替换为直接引用) 三个步骤。

最后 JVM 对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;2)如果类中存在初始化语句, 就依次执行这些初始化语句。

八种基本的数据类型

Java支持数据类型分为两类:基本数据类型和引用数据类型。基本数据类型共有8种,可以分为三类:

  • 数值型:整数类型(byte、short、int、long)和浮点类型(float、double)
  • 字符型:char
  • 布尔型:boolean

8种基本数据类型的默认值、位数、取值范围,如下表所示:

Float和Double的最小值和最大值都是以科学记数法的形式输出的,结尾的“E+数字”表示E之前的数字要乘以10的多少倍。比如3.14E3就是3.14×1000=3140,3.14E-3就是3.14/1000=0.00314。注意一下几点:

  • java八种基本数据类型的字节数:1字节(byte、boolean)、 2字节(short、char)、4字节(int、float)、8字节(long、double)
  • 浮点数的默认类型为double(如果需要声明一个常量为float型,则必须要在末尾加上f或F)
  • 整数的默认类型为int(声明Long型在末尾加上l或者L)
  • 八种基本数据类型的包装类:除了char的是Character、int类型的是Integer,其他都是首字母大写
  • char类型是无符号的,不能为负,所以是0开始的

数据库的联表查询

数据库有以下几种联表查询类型:

  1. 内连接 (INNER JOIN)
  2. 左外连接 (LEFT JOIN)
  3. 右外连接 (RIGHT JOIN)
  4. 全外连接 (FULL JOIN)

1. 内连接 (INNER JOIN)

内连接返回两个表中有匹配关系的行。示例:

代码语言:javascript
复制
SELECT employees.name, departments.name
FROM employees
INNER JOIN departments
ON employees.department_id = departments.id;

这个查询返回每个员工及其所在的部门名称。

2. 左外连接 (LEFT JOIN)

左外连接返回左表中的所有行,即使在右表中没有匹配的行。未匹配的右表列会包含NULL。示例:

代码语言:javascript
复制
SELECT employees.name, departments.name
FROM employees
LEFT JOIN departments
ON employees.department_id = departments.id;

这个查询返回所有员工及其部门名称,包括那些没有分配部门的员工。

3. 右外连接 (RIGHT JOIN)

右外连接返回右表中的所有行,即使左表中没有匹配的行。未匹配的左表列会包含NULL。示例:

代码语言:javascript
复制
SELECT employees.name, departments.name
FROM employees
RIGHT JOIN departments
ON employees.department_id = departments.id;

这个查询返回所有部门及其员工,包括那些没有分配员工的部门。

4. 全外连接 (FULL JOIN)

全外连接返回两个表中所有行,包括非匹配行,在MySQL中,FULL JOIN 需要使用 UNION 来实现,因为 MySQL 不直接支持 FULL JOIN。示例:

代码语言:javascript
复制
SELECT employees.name, departments.name
FROM employees
LEFT JOIN departments
ON employees.department_id = departments.id

UNION

SELECT employees.name, departments.name
FROM employees
RIGHT JOIN departments
ON employees.department_id = departments.id;

这个查询返回所有员工和所有部门,包括没有匹配行的记录。

mysql中的一些基本函数,你知道哪些?

一、字符串函数

  1. CONCAT(str1, str2, ...)
    • 连接多个字符串,返回一个合并后的字符串。
代码语言:javascript
复制
SELECT CONCAT('Hello', ' ', 'World') AS Greeting;
  1. LENGTH(str)
    • 返回字符串的长度(字符数)。
代码语言:javascript
复制
SELECT LENGTH('Hello') AS StringLength;
  1. SUBSTRING(str, pos, len)
    • 从指定位置开始,截取指定长度的子字符串。
代码语言:javascript
复制
SELECT SUBSTRING('Hello World', 1, 5) AS SubStr;
  1. REPLACE(str, from_str, to_str)
    • 将字符串中的某部分替换为另一个字符串。
代码语言:javascript
复制
SELECT REPLACE('Hello World', 'World', 'MySQL') AS ReplacedStr;

二、数值函数

代码语言:javascript
复制
SELECT FLOOR(123.456) AS FloorValue;
  1. ABS(num)
    • 返回数字的绝对值。
代码语言:javascript
复制
SELECT ABS(-10) AS AbsoluteValue;
  1. POWER(num, exponent)
    • 返回指定数字的指定幂次方。
代码语言:javascript
复制
SELECT POWER(2, 3) AS PowerValue;

三、日期和时间函数

  1. NOW()
    • 返回当前日期和时间。
代码语言:javascript
复制
SELECT NOW() AS CurrentDateTime;
  1. CURDATE()
    • 返回当前日期。
代码语言:javascript
复制
SELECT CURDATE() AS CurrentDate;

四、聚合函数

  1. COUNT(column)
    • 计算指定列中的非NULL值的个数。
代码语言:javascript
复制
SELECT COUNT(*) AS RowCount FROM my_table;
  1. SUM(column)
    • 计算指定列的总和。
代码语言:javascript
复制
SELECT SUM(price) AS TotalPrice FROM orders;
  1. AVG(column)
    • 计算指定列的平均值。
代码语言:javascript
复制
SELECT AVG(price) AS AveragePrice FROM orders;
  1. MAX(column)
    • 返回指定列的最大值。
代码语言:javascript
复制
SELECT MAX(price) AS MaxPrice FROM orders;
  1. MIN(column)
    • 返回指定列的最小值。
代码语言:javascript
复制
SELECT MIN(price) AS MinPrice FROM orders;

如果项目中要用到原生的mybatis去查询,该怎样写?

步骤概述:

  1. 配置MyBatis: 在项目中配置MyBatis的数据源、SQL映射文件等。
  2. 创建实体类: 创建用于映射数据库表的实体类。
  3. 编写SQL映射文件: 创建XML文件,定义SQL语句和映射关系。
  4. 编写DAO接口: 创建DAO接口,定义数据库操作的方法。
  5. 编写具体的SQL查询语句: 在DAO接口中定义查询方法,并在XML文件中编写对应的SQL语句。
  6. 调用查询方法: 在服务层或控制层调用DAO接口中的方法进行查询。

详细步骤:

  1. 配置MyBatis: 在配置文件中配置数据源、MyBatis的Mapper文件位置等信息。
  2. 创建实体类: 创建与数据库表对应的实体类,字段名和类型需与数据库表保持一致。
代码语言:javascript
复制
public class User {
    private Long id;
    private String username;
    private String email;
    // Getters and setters
}
  1. 编写SQL映射文件: 在resources目录下创建XML文件,定义SQL语句和映射关系。
代码语言:javascript
复制
<!-- userMapper.xml -->
<mapper namespace="com.example.dao.UserMapper">
    <select id="selectUserById" resultType="com.example.model.User">
        SELECT * FROM users WHERE id = #{id}
    </select>
</mapper>
  1. 编写DAO接口: 创建DAO接口,定义查询方法。
代码语言:javascript
复制
public interface UserMapper {
    User selectUserById(Long id);
}
  1. 编写具体的SQL查询语句: 在XML文件中编写对应的SQL语句。
  2. 调用查询方法: 在服务层或控制层中调用DAO接口中的方法进行查询。
代码语言:javascript
复制
// 在Service层中调用
User user = userMapper.selectUserById(1);

通过以上步骤,你可以利用原生的MyBatis框架来进行数据库查询操作。请确保配置正确、SQL语句准确并与数据库字段匹配,以确保查询的准确性和高效性。

让我讲一下红黑树

红黑树是一种自平衡的二叉查找树,

具有以下特点:

  1. 每个节点要么是红色,要么是黑色。
  2. 根节点是黑色。
  3. 每个叶子节点(NIL节点)是黑色。
  4. 如果一个节点是红色,则其子节点必须是黑色。
  5. 从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点。

红黑树的自平衡性质可以保证在进行插入、删除等操作后,树的高度保持在O(log n)内,从而保持了较高的查找、插入和删除效率。下面是红黑树插入节点的过程,这左旋右旋的操作,就是为了自平衡。

讲一下spring ioc是什么

Spring框架中的IoC(Inverse of Control,控制反转)是一种设计原则,它的基本思想是将程序的控制权交给框架,由框架负责控制对象的创建和管理,而不是由程序员手动管理对象之间的依赖关系。IoC容器是实现IoC的核心,Spring的IoC容器负责创建对象、注入对象之间的依赖关系,以及管理对象的生命周期。

IoC容器的作用:

  1. 对象的创建和管理: IoC容器负责创建对象,并管理它们的生命周期。
  2. 依赖注入: IoC容器负责将依赖关系注入到对象中,消除了硬编码的依赖。
  3. 解耦: 通过IoC容器,对象之间的耦合性降低,提高了代码的可维护性和灵活性。

Spring提供了两种主要的IoC容器实现:

  1. BeanFactory: 是Spring IoC容器的基本实现,它是一个工厂模式的实现,延迟加载对象。
  2. ApplicationContext: 是BeanFactory的扩展,提供了更多的功能,如国际化处理、事件传递、应用程序层特定上下文的配置等。

Spring IoC的工作流程:

  1. 配置: 通过XML配置文件、注解或Java配置类配置Bean的信息和依赖关系。
  2. 实例化: IoC容器根据配置文件中定义的信息实例化Bean。
  3. 注入: IoC容器将Bean之间的依赖关系通过构造函数注入或Setter注入的方式进行赋值。
  4. 管理: IoC容器管理Bean的生命周期,包括初始化、使用和销毁。

通过IoC,Spring框架实现了松耦合、灵活性强、易于测试和维护的特性,使得开发者可以更专注于业务逻辑的实现,而无需关注对象之间的依赖关系和对象的生命周期管理。

spring框架中都用到了哪些设计模式

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

说一下对于redis的认识

Redis是一个开源的内存数据库,也被称为数据结构服务器,它提供了高性能的键值存储,支持多种数据结构(如字符串、列表、集合、哈希表、有序集合),Redis的数据通常存储在内存中,因此读写速度非常快,并且对数据类型的操作都是原子性的,因为执行命令由单线程负责的,不存在并发竞争的问题。

Redis主要应用场景:

  1. 缓存:作为缓存存储,提升读取速度,减轻后端数据库压力。
  2. 会话存储:存储用户会话信息,提供快速访问。
  3. 消息队列:通过Redis的发布/订阅功能搭建消息队列,实现异步通信。
  4. 计数器:用于实现各种计数功能,如网站访问量统计等。
  5. 分布式锁:实现分布式环境下的锁机制,避免资源竞争问题。

分布式登陆怎样做

分布式系统中的登录机制需要解决多个服务器节点共享用户认证状态的问题。以下是常见的解决方法及关键概念:

  1. 基于Session的分布式登录

1.1 共享Session

  • Session复制:将用户的session在多个服务器之间进行复制。这种方法容易造成性能瓶颈,因为每次用户登录或状态改变都需要在所有服务器之间同步session数据。

1.2 中央Session存储

  • Session存储在集中式数据库:使用如Redis、Memcached等分布式缓存作为Session存储,这种方式可以快速访问和更新Session。
  • 使用Spring Session:Spring Session提供了一套解决分布式Session管理的方案,可以与Redis、Hazelcast等集成。

示例:Spring Session与Redis集成

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
代码语言:javascript
复制
spring:
  session:
    store-type: redis
  redis:
    host: localhost
    port: 6379

  1. 基于Token的分布式登录(推荐)

2.1 JWT(JSON Web Token)

  • JWT工作原理
    1. 用户使用用户名和密码登录,服务器验证成功后生成JWT。
    2. JWT包含用户信息和签名,返回给客户端。
    3. 客户端存储JWT并在每次请求中携带,服务器使用密钥验证JWT的合法性,无需服务器存储用户状态。
  • JWT示例:
    • 生成JWT
代码语言:javascript
复制
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

String jwt = Jwts.builder()
    .setSubject("user")
    .signWith(SignatureAlgorithm.HS256, "secretKey")
    .compact();
  • 验证JWT
代码语言:javascript
复制
Jwts.parser()
    .setSigningKey("secretKey")
    .parseClaimsJws(jwt);

2.2 OAuth 2.0

  • OAuth 2.0是一个开放授权框架,用于第三方应用访问资源所有者资源。
  • 授权码模式是最常用的模式,特别适合分布式系统。

OAuth 2.0工作流程:

  1. 用户认证请求:客户端请求授权服务器。
  2. 授权码返回:授权服务器验证用户后返回授权码。
  3. 获取Access Token:客户端使用授权码请求授权服务器获取Access Token。
  4. 访问资源:客户端使用Access Token访问资源服务器。

总结

选择分布式登录方案需要根据具体的业务需求和系统架构来决定。以下是一些推荐和注意事项:

  • 小型、简单系统可以使用中央Session存储解决方案,如Spring Session + Redis。
  • 对于大型系统,特别是需要与第三方系统集成的,推荐使用基于JWT的分布式登录或OAuth 2.0。
  • 借助现代化单点登录协议(如OAuth 2.0, OpenID Connect)实现更复杂的认证和授权需求。
  • 安全是关键:确保Token的安全传输和存储,使用HTTPS,且对重要信息进行加密处理。

项目中哪些地方使用到了消息队列?

主要是利用了消息队列的异步的作用,将某个任务比较耗时,如发邮件、生成报告、数据处理等,可以使用消息队列实现异步处理,提升系统响应速度。

消息队列三大作用:

  • 解耦:可以在多个系统之间进行解耦,将原本通过网络之间的调用的方式改为使用MQ进行消息的异步通讯,只要该操作不是需要同步的,就可以改为使用MQ进行不同系统之间的联系,这样项目之间不会存在耦合,系统之间不会产生太大的影响,就算一个系统挂了,也只是消息挤压在MQ里面没人进行消费而已,不会对其他的系统产生影响。
  • 异步:加入一个操作设计到好几个步骤,这些步骤之间不需要同步完成,比如客户去创建了一个订单,还要去客户轨迹系统添加一条轨迹、去库存系统更新库存、去客户系统修改客户的状态等等。这样如果这个系统都直接进行调用,那么将会产生大量的时间,这样对于客户是无法接收的;并且像添加客户轨迹这种操作是不需要去同步操作的,如果使用MQ将客户创建订单时,将后面的轨迹、库存、状态等信息的更新全都放到MQ里面然后去异步操作,这样就可加快系统的访问速度,提供更好的客户体验。
  • 削峰:一个系统访问流量有高峰时期,也有低峰时期,比如说,中午整点有一个抢购活动等等。比如系统平时流量并不高,一秒钟只有100多个并发请求,系统处理没有任何压力,一切风平浪静,到了某个抢购活动时间,系统并发访问了剧增,比如达到了每秒5000个并发请求,而我们的系统每秒只能处理2000个请求,那么由于流量太大,我们的系统、数据库可能就会崩溃。这时如果使用MQ进行流量削峰,将用户的大量消息直接放到MQ里面,然后我们的系统去按自己的最大消费能力去消费这些消息,就可以保证系统的稳定,只是可能要跟进业务逻辑,给用户返回特定页面或者稍后通过其他方式通知其结果。

为什么要用rabbitmq? 其他消息队列有什么特点?

Kafka、ActiveMQ、RabbitMQ、RocketMQ来进行不同维度对比。

特性

ActiveMQ

RabbitMQ

RocketMQ

Kafka

单机吞吐量

万级

万级

10 万级

10 万级

时效性

毫秒级

微秒级

毫秒级

毫秒级

可用性

高(主从)

高(主从)

非常高(分布式)

非常高(分布式)

消息重复

至少一次

至少一次

至少一次 最多一次

至少一次最多一次

消息顺序性

有序

有序

有序

分区有序

支持主题数

千级

百万级

千级

百级,多了性能严重下滑

消息回溯

不支持

不支持

支持(按时间回溯)

支持(按offset回溯)

管理界面

普通

普通

完善

普通

选型的时候,我们需要根据业务场景,结合上述特性来进行选型。

比如你要支持天猫双十一类超大型的秒杀活动,这种一锤子买卖,那管理界面、消息回溯啥的不重要。我们需要看什么?看吞吐量!

所以优先选Kafka和RocketMQ这种更高吞吐的。

比如做一个公司的中台,对外提供能力,那可能会有很多主题接入,这时候主题个数又是很重要的考量,像Kafka这样百级的,就不太符合要求,可以根据情况考虑千级的RocketMQ,甚至百万级的RabbitMQ。

又比如是一个金融类业务,那么重点考虑的就是稳定性、安全性,分布式部署的Kafka和Rocket就更有优势。

特别说一下时效性,RabbitMQ以微秒的时效作为招牌,但实际上毫秒和微秒,在绝大多数情况下,都没有感知的区别,加上网络带来的波动,这一点在生产过程中,反而不会作为重要的考量。

其它的特性,如消息确认、消息回溯,也经常作为考量的场景,管理界面的话试公司而定了,反正我呆过的地方,都不看重这个,毕竟都有自己的运维体系。

用过哪些微服务组件?

微服务常用的组件:

  • 注册中心:注册中心是微服务架构最核心的组件。它起到的作用是对新节点的注册与状态维护,解决了「如何发现新节点以及检查各节点的运行状态的问题」。微服务节点在启动时会将自己的服务名称、IP、端口等信息在注册中心登记,注册中心会定时检查该节点的运行状态。注册中心通常会采用心跳机制最大程度保证已登记过的服务节点都是可用的。
  • 负载均衡:负载均衡解决了「如何发现服务及负载均衡如何实现的问题」,通常微服务在互相调用时,并不是直接通过IP、端口进行访问调用。而是先通过服务名在注册中心查询该服务拥有哪些节点,注册中心将该服务可用节点列表返回给服务调用者,这个过程叫服务发现,因服务高可用的要求,服务调用者会接收到多个节点,必须要从中进行选择。因此服务调用者一端必须内置负载均衡器,通过负载均衡策略选择合适的节点发起实质性的通信请求。
  • 服务通信:服务通信组件解决了「服务间如何进行消息通信的问题」,服务间通信采用轻量级协议,通常是HTTP RESTful风格。但因为RESTful风格过于灵活,必须加以约束,通常应用时对其封装。例如在SpringCloud中就提供了Feign和RestTemplate两种技术屏蔽底层的实现细节,所有开发者都是基于封装后统一的SDK进行开发,有利于团队间的相互合作。
  • 配置中心:配置中心主要解决了「如何集中管理各节点配置文件的问题」,在微服务架构下,所有的微服务节点都包含自己的各种配置文件,如jdbc配置、自定义配置、环境配置、运行参数配置等。要知道有的微服务可能可能有几十个节点,如果将这些配置文件分散存储在节点上,发生配置更改就需要逐个节点调整,将给运维人员带来巨大的压力。配置中心便由此而生,通过部署配置中心服务器,将各节点配置文件从服务中剥离,集中转存到配置中心。一般配置中心都有UI界面,方便实现大规模集群配置调整。
  • 集中式日志管理:集中式日志主要是解决了「如何收集各节点日志并统一管理的问题」。微服务架构默认将应用日志分别保存在部署节点上,当需要对日志数据和操作数据进行数据分析和数据统计时,必须收集所有节点的日志数据。那么怎么高效收集所有节点的日志数据呢?业内常见的方案有ELK、EFK。通过搭建独立的日志收集系统,定时抓取各节点增量日志形成有效的统计报表,为统计和分析提供数据支撑。
  • 分布式链路追踪:分布式链路追踪解决了「如何直观的了解各节点间的调用链路的问题」。系统中一个复杂的业务流程,可能会出现连续调用多个微服务,我们需要了解完整的业务逻辑涉及的每个微服务的运行状态,通过可视化链路图展现,可以帮助开发人员快速分析系统瓶颈及出错的服务。
  • 服务保护:服务保护主要是解决了「如何对系统进行链路保护,避免服务雪崩的问题」。在业务运行时,微服务间互相调用支撑,如果某个微服务出现高延迟导致线程池满载,或是业务处理失败。这里就需要引入服务保护组件来实现高延迟服务的快速降级,避免系统崩溃。

SpringCloud Alibaba实现的微服务架构:

  • 注册中心:SpringCloud Alibaba中使用Alibaba Nacos组件实现注册中心,Nacos提供了一组简单易用的特性集,可快速实现动态服务发现、服务配置、服务元数据及流量管理。
  • 负载均衡:SpringCloud Alibaba 使用Nacos服务端均衡实现负载均衡,与Ribbon在调用端负载不同,Nacos是在服务发现的同时利用负载均衡返回服务节点数据。
  • 服务通信:SpringCloud Alibaba 使用Netflix FeignAlibaba Dubbo组件来实现服务通行,前者与SpringCloud采用了相同的方案,后者则是对自家的RPC 框架Dubbo也给予支持,为服务间通信提供另一种选择。
  • API服务网关:SpringCloud Alibaba 在API服务网关组件中,使用与SpringCloud相同的组件,即:SpringCloud Gateway
  • 配置中心:SpringCloud Alibaba在配置中心组件中使用Nacos内置配置中心,Nacos内置的配置中心,可将配置信息存储保存在指定数据库
  • 集中式日志管理:SpringCloud Alibaba在原有的ELK方案外,还可以使用阿里云日志服务(LOG)实现日志集中式管理。
  • 分布式链路追踪:SpringCloud Alibaba在分布式链路组件中采用与SpringCloud相同的方案,即:Sleuth/Zipkin Server
  • 服务保护:SpringCloud Alibaba使用Alibaba Sentinel实现系统保护,Sentinel不仅功能更强大,实现系统保护比Hystrix更优雅,而且还拥有更好的UI界面。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小林coding 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 说一下Java的特点
  • 为什么Java解释和编译都有?
  • jvm是什么?
  • 说一下jvm的垃圾回收机制?
  • 类加载过程介绍一下
  • 八种基本的数据类型
  • 数据库的联表查询
  • mysql中的一些基本函数,你知道哪些?
  • 如果项目中要用到原生的mybatis去查询,该怎样写?
  • 让我讲一下红黑树
  • 讲一下spring ioc是什么
  • spring框架中都用到了哪些设计模式
  • 分布式登陆怎样做
  • 项目中哪些地方使用到了消息队列?
  • 为什么要用rabbitmq? 其他消息队列有什么特点?
  • 用过哪些微服务组件?
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档