预见猿份
主题
首页面试题在线工具关于我们老苗一对一私教学员评价
实战项目
项目前置基础创新WMS项目Java微服务框架与实战云岚到家项目闪聚支付项目学成在线项目青橙电商项目JVM原理与实战调优分布式事务专题Java高频面试题MySQL从入门到精通Java数据结构与算法老苗一对一私教学员评价blog
blog
  • Java工程师高频面试题

    • 课程介绍
    • Java基础常见面试题
    • Java并发编程面试题
    • 数据库常见面试题
    • Redis 常见面试题
    • Java 框架常见面试题
    • Linux NG ES MQ SEATA 常见面试题
    • Java常见算法面试题
    • Java AI相关面试题
    • Java 工程师面试最常考的 80 道高频题
    • Java面试实录







----- 到底线了 -----

×

欢迎来到预见猿份,本站项目均为站长原创,学习中有问题可直接提交给站长老苗解决(微信:mrt_0607)。

苗润土老师,20余年一线项目经验,2014年加入黑马,星辰wms、云岚到家、学成在线项目作者,历任高级讲师、教学主管及课程研究员。 b站老苗

Linux NG ES MQ SEATA 常见面试题 ​

本章涉及Linux、NG、Elasticsearch、RabbitMQ、SEATA常见面试题,需要系统学习各技术的参见下边的教程:

Elasticsearch:https://yjoffer.com/springcloud/chapter6/chapter6.html

RabbitMQ: https://yjoffer.com/springcloud/chapter4/chapter4.html

SEATA: https://yjoffer.com/springcloud/chapter2/chapter2.html

Linux: https://yjoffer.com/project_preposition/linux/linux.html

1.Linux篇 ​

linux常用命令 ​

Linux命令速查:https://yjoffer.com/tools/linux-cheatsheet.html

几乎必问的题目,考察你到底有没有操作过linux,这里只说我们作为开发常用的一些命令

❗ 看日志:tail或者less,tail -f可以动态看日志变化

搜索日志里的内容:grep -n可以搜索文件里的内容并显示行号,配合|管道符可以在上面tail的结果里搜索,也可以使用less命令然后输入/搜索,类似vim。注意不要使用vim命令查看日志,因为日志比较大,vim会将文件内容加载到内存中

查看端口是否被占用,netstat -ant | grep 8080 8080就是被占用的端口号,然后会显示出对应的进程ID,再通过kill -9 1111杀死对应的进程,1111就是进程ID

后台启动:nohup java -jar app.jar &,nohup不挂起启动,否则直接java -jar关闭窗口后,进程也没了。注意nohup 后也可以跟其他命令,比如nohup ./elasticsearch就是后台启动es

修改文件:vim,vim进去之后,有三种模式,i、a、o进入编辑模式,:wq保存退出,:q!不保存退出,G跳转到最后一行,dd删除当前行,/?可以进行搜索

查看进程是否存在:ps -ef | grep java java就是你要搜索的进程信息

查看目前机器负载信息:top可以看到cpu,内存占比比较高的进程

搜索文件:find -name "*.java"搜索当前目录.java结尾的文件

复制、删除、剪切:cp、mv、rm

docker常用命令 ​

Docker命令速查:https://yjoffer.com/tools/docker-cheatsheet.html

切记不要和linux命令搞混

❗ 拉取镜像:docker pull

查看容器日志:docker logs

查看容器:docker ps

启动、停止、重启容器:docker start、docker stop、docker restartdocker compose的作用:定义和运行多容器Docker应用程序的工具。它使用一个YAML文件(docker-compose.yml)来配置应用程序的服务,通过一个单一的命令来启动、停止和管理整个应用程序的所有服务。 Dockerfile常用指令:

FROM:指定基础镜像

ENV:设置环境变量

COPY:复制本地文件到镜像指定目录

RUN:执行Linux的shell命令

EXPOSE:指定容器运行时的监听端口

ENTRYPOINT:指定镜像中应用的启动命令

git常用命令 ​

开发中几乎每天都会用到,这里整理最常用的Git命令,配合面试场景记忆

克隆仓库:git clone 仓库地址,把远程代码拉到本地

拉取最新代码:git pull,相当于git fetch加git merge两步

查看状态:git status,看哪些文件被修改、新增

查看差异:git diff 查看工作区改动,git diff --cached 查看已暂存的改动

添加暂存区:git add . 添加所有改动,或 git add 文件名 只添加指定文件

提交:git commit -m "提交说明",先add再commit

推送:git push,把本地提交推送到远程仓库

分支操作:git branch 查看分支,git checkout -b 分支名 创建并切换分支,git branch -d 分支名 删除分支

切换分支:git checkout 分支名,新版本也可以用 git switch 分支名

合并分支:git merge 分支名,把指定分支合并到当前分支

查看提交历史:git log,git log --oneline 一行一条简略显示

撤销修改:git reset --hard 版本号 回退到指定版本,git revert 回滚某次提交,git checkout -- 文件名 丢弃工作区未提交的修改

临时暂存:git stash 把当前改动暂存起来,git stash pop 恢复,切分支前常用

查看远程仓库:git remote -v 查看远程仓库地址

解决冲突:先git pull拉最新代码,有冲突时手动修改冲突文件,改完再git add、git commit、git push

2.MQ篇 ​

MQ的使用场景 ​

常见的MQ有:RabbitMQ、Kafka、RocketMQ,Kafka是分布式的,所以能应对比较大的数据量和并发量。一般情况下RabbitMQ足够

❗ 解耦:服务和服务之间调用

异步:直接通过发送mq消息,使调用流程变成异步

削峰:通过MQ把流量削峰

IOT:物联网设备信息上报

RabbitMQ怎么保证MQ的消息可靠性 ​

❗ 1. 做持久化,其中包括:

  • 交换机持久化:exchange设置成durable
  • 队列持久化:queue设置成durable
  • 消息持久化
  1. 生产者确认机制
  2. 消费者确认机制:当消费者处理消息结束后,应该向RabbitMQ发送一个回执,告知RabbitMQ自己消息处理状态。回执ACK

RabbitMQ的交换机类型 ​

❗ - Fanout:广播,将消息交给所有绑定到交换机的队列。我们最早在控制台使用的正是Fanout交换机

  • Direct:订阅,基于RoutingKey(路由key)发送给订阅了消息的队列
  • Topic:通配符订阅,与Direct类似,只不过RoutingKey可以使用通配符
  • Headers:头匹配,基于MQ的消息头匹配,用的较少。

RabbitMQ实现延迟消息 ​

常用于订单超时未支付、或者预约(电影院、自习室等)锁定后未未付款

❗ 实现延迟消息有两种方式:

  1. 死信交换机+TTL死信: 当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter)简单来说就是消费不了或者失败的消息:
  • 消费者使用basic.reject或 basic.nack声明消费失败,并且消息的requeue参数设置为false
  • 消息是一个过期消息,超时无人消费
  • 要投递的队列消息满了,无法投递 所以只要我们这个队列不设置消费者,同时设置TTL(有效期),就可以实现延迟消息的效果 但是:如果队列消息堆积没来得及消费,消息也会进到死信队列,所以这个TTL时间要根据具体情况分析
  1. 延迟消息插件 DelayExchange插件,RabbitMQ官方提供。安装好之后,代码中指定延迟交换机(delayed=true),发送的时候指定延迟时间即可

MQTT是什么了解过吗 ​

❗ MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是一种轻量级、基于发布/订阅模式的网络协议,用于连接设备到服务器、服务器到服务器或设备到设备的消息通信。它被设计为开放、简单、易于实现,同时保持了灵活性和可靠性。 应用场景:

  • 物联网(IoT):MQTT广泛用于物联网设备的消息通信,如智能家居、工业自动化等。
  • 移动应用:移动设备可以使用MQTT与服务器进行消息交换,实现推送通知等功能。
  • 车载系统:车辆可以通过MQTT与服务器通信,发送状态更新或接收指令。
  • 远程监控:MQTT可以用于远程监控系统,实时传输设备状态和传感器数据。
  • 事件驱动架构:在事件驱动的系统中,MQTT可以作为事件的传输机制

如何解决消息积压 ​

❗ 1. 快速应急

  • 增加消费者:水平扩容实例,并调大 prefetch 预取值。
  • 启用惰性队列:消息落盘,用磁盘换内存安全(适合百万级积压)。
  1. 根治手段
  • 消费者提速:改用多线程消费,或将同步调用改为异步批量处理。
  • 上游限流:在生产者端限速,防止瞬间流量冲击。
  1. 终极兜底
  • 临时转储:将积压消息直接转存至数据库或Redis,错峰慢慢消费,让MQ先恢复。

Kafka有没有了解过,为什么用RabbitMQ ​

❗ 推荐回答: Kafka 我有一定的了解。Kafka是一种吞吐量比较高的分布式消息队列。 使用RabbitMQ基于以下几个原因吧:

  1. 我们的吞吐量并没有那么大,并且RabbitMQ的消息确认机制比较好
  2. 用起来RabbitMQ的管理页面也比较方便还有一些生态插件
  3. 不过在我看来kafka和Rabbitmq没有本质区别,对我们程序员来说都是消息队列都是辅助的手段而已

3.ElasticSearch篇 ​

ES的底层原理以及为什么使用ES ​

❗ 概念:ES是基于Apache Lucene的一个全文检索数据库 底层原理:倒排索引

倒排索引:倒排索引是一种数据结构,它将文档中的分词作为索引项,记录每个分词在哪些文档中出现以及出现的位置或对应的ID,以便快速进行关键词检索。

为什么用:可以进行全文检索,速度快,适合存储海量数据,但是数据是加载到内存中再去查询,所以对服务器的配置要求较高

ES数据怎么和Mysql同步 ​

❗ 1. 同步双写,也就是往mysql增删改的时候,同步也去处理一下ES的数据

优点:实现简单

缺点:对业务侵入较大,无法复用

  1. MQ消息,不同步写了,而是增删改的时候通过发送MQ消息来处理ES的数据 优点:实现也很简单,解耦 缺点:ES如果失败不太好处理,依赖MQ的可用性

  2. Canal中间件,通过canal监听mysql的binlog实现同步,实际开发可能也需要依赖MQ 优点:代码无入侵,实时性较好 缺点:实现相对复杂一些,依赖canal可用性 总结:同步双写最简单,但也最难维护,Canal看似简单,但实际又引入了新的中间件,增加了不稳定性,如果你们是小型项目,并且ES里就一个索引(一张表),那就直接同步双写就行了,省事

4.Seata篇 ​

什么是Seata和分布式事务 ​

❗ Seata是什么?处理分布式事务 什么是分布式事务? 平时我们的事务都是用Spring提供的事务管理器来控制的,但是这种只能控制在代码层面 如果我们是微服务的场景,其中涉及到了远程调用,比如我们的下单功能得先修改订单状态,然后调用业务模块(例如购买课程),因为中间通过HTTP调用,所以Spring的事务管理器就没法管理。 或者是涉及到调用第三方的接口,这种情况使用Seata也无法处理,因为Seata只能管理我们自己项目中夸服务的调用。

Seata的原理和解决方案 ​

❗ 在Seata的事务管理中有三个重要的角色:

  • TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
  • TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
  • RM (Resource Manager) - 资源管理器:管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。 其中Seata支持四种不同的分布式事务解决方案:
  • XA
  • TCC
  • AT(常用)
  • SAGA

XA和AT模式 ​

❗ XA规范 是X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准,XA规范 描述了全局的TM与局部的RM之间的接口,几乎所有主流的数据库都对 XA 规范 提供了支持。 一阶段:

  • 事务协调者通知每个事物参与者执行本地事务
  • 本地事务执行完成后报告事务执行状态给事务协调者,此时事务不提交,继续持有数据库锁 二阶段:
  • 事务协调者基于一阶段的报告来判断下一步操作
  • 如果一阶段都成功,则通知所有事务参与者,提交事务
  • 如果一阶段任意一个参与者失败,则通知所有事务参与者回滚事务 优点是什么?
  • 事务的强一致性,满足ACID原则
  • 常用数据库都支持,实现简单,并且没有代码侵入 缺点是什么?
  • 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
  • 依赖关系型数据库实现事务

❗ AT模式同样是分阶段提交的事务模型,不过缺弥补了XA模型中资源锁定周期过长的缺陷 阶段一RM的工作:

  • 注册分支事务
  • 记录undo-log(数据快照)
  • 执行业务sql并提交
  • 报告事务状态 阶段二提交时RM的工作:
  • 删除undo-log即可 阶段二回滚时RM的工作:
  • 根据undo-log恢复数据到更新前

AT与XA的区别 ​

❗ - XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。

  • XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
  • XA模式强一致;AT模式最终一致 可见,AT模式使用起来更加简单,无业务侵入,性能更好。因此企业90%的分布式事务都可以用AT模式来解决。但是AT模式也有问题,就是如果在undolog还未提交的时候,数据又被其他修改,会导致无法undolog无法处理,无限重试,新版本Seata已经解决这个问题(说出以上内容显得更加真实)

TCC模式 ​

❗ TCC模式与AT模式非常相似,每阶段都是独立事务,不同的是TCC通过人工编码来实现数据恢复。需要实现三个方法:

  • try:资源的检测和预留;
  • confirm:完成资源操作业务;要求 try 成功 confirm 一定要能成功。
  • cancel:预留资源释放,可以理解为try的反向操作。 TCC模式的每个阶段是做什么的?
  • Try:资源检查和预留
  • Confirm:业务执行和提交
  • Cancel:预留资源的释放 TCC的优点是什么?
  • 一阶段完成直接提交事务,释放数据库资源,性能好
  • 相比AT模型,无需生成快照,无需使用全局锁,性能最强
  • 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库 TCC的缺点是什么?
  • 有代码侵入,需要人为编写try、Confirm和Cancel接口,太麻烦
  • 软状态,事务是最终一致
  • 需要考虑Confirm和Cancel的失败情况,做好幂等处理、事务悬挂和空回滚处理

5.Nginx篇 ​

Nginx你们用来做什么? ​

前端服务器 ​

直接把前端代码放到html文件夹下,就可以当作前端服务器来使用

反向代理 ​

配置server块,关键是里面的proxy_pass,后面跟的就是要转发到的地址

Nginx
http {
    server {
        listen 80;  # 监听的端口
        server_name your_domain.com;  # 你的域名或 IP 地址

        location / {
            proxy_pass http://backend_server_ip:backend_port;  # 后端服务器的 IP 地址和端口
        }
    }
}
1
2
3
4
5
6
7
8
9
10

负载均衡 ​

配置类似反向代理,关键就在于upstream 里配置了多个ip和地址,而proxy_pass 里则变成了upstream 后面的名字。默认是轮询,也可以在upstream配置负载策略:轮询、加权轮询、最少链接、ip哈希

Nginx
http {
    upstream backend_servers {
        server backend_server1_ip:backend_port1;
        server backend_server2_ip:backend_port2;
        server backend_server3_ip:backend_port3;
    }

    server {
        listen 80;
        server_name your_domain.com;

        location / {
            proxy_pass http://backend_servers;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

限流 ​

基于IP限流 ​

基于IP限流可以限制特定IP地址在单位时间内的请求频率。这有助于防止单个IP地址对服务器发起过多的请求,导致服务器过载。

配置项说明
limit_req_zone用于定义限流区域和相关参数。这个区域用于存储客户端IP地址的请求计数信息,并根据定义的速率限制来处理请求。
例如,limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; 这里,$binary_remote_addr是客户端的IP地址(二进制格式),mylimit是区域名称,10m是分配给该区域的共享内存大小,1r/s表示每秒只允许一个请求。
limit_req在需要限流的 nginx.conf中的http中的location 中使用,引用之前定义的限流区域。当客户端的请求频率超过指定的限制时,Nginx会采取相应的措施,如延迟请求或拒绝请求。
例如,limit_req zone=mylimit burst=5 nodelay; 这里,mylimit是之前定义的限流区域名称,burst=5表示在超过速率限制时,还可以处理额外的5个请求,而nodelay表示立即拒绝超出限制的请求,而不是将它们放入队列中等待处理。

示例:如果限制每个IP地址每秒只能发送一个请求到/api路径的话;可以如下配置:

Nginx
http {  
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;  
  
    server {  
        listen 80;  
  
        location /api {  
            limit_req zone=mylimit burst=5 nodelay;  
            # 其他配置...  
        }  
    }  
}
1
2
3
4
5
6
7
8
9
10
11
12

说明:如果某个IP地址在1秒内发送了超过一个请求到/api路径,Nginx将根据burst参数的值来决定如何处理这些额外的请求。上面的示例中,由于设置了burst=5,所以Nginx会允许额外的5个请求,但会立即拒绝超出这个限制的请求(由于nodelay参数的存在)。

基于连接数限流 ​

连接数限流可以限制单个IP地址或特定key的并发连接数。这有助于防止单个IP地址或客户端建立过多的连接,耗尽服务器资源。

连接数限流架构图

配置项说明
limit_conn_zone用于定义一个共享内存区域,这个区域用于存储每个客户端的连接数信息。
例如,limit_conn_zone $binary_remote_addr zone=addr:10m; 这行代码定义了一个名为addr、大小为10MB的共享内存区域,用于根据客户端的IP地址($binary_remote_addr)来限制连接数。
limit_conn用于在指定的位置限制客户端的连接数。它引用之前通过limit_conn_zone定义的共享内存区域和key,当连接数达到限制时,新的连接将被拒绝。
例如,location / { limit_conn addr 10; } 这行代码表示,对于IP地址为key的连接,最大并发连接数为10。如果某个IP地址的并发连接数超过了这个限制,新的连接请求将被Nginx拒绝。

示例:

Nginx
http {  
    limit_conn_zone $binary_remote_addr zone=addr:10m;  
  
    server {  
        listen 80;  
        server_name example.com;  
  
        location / {  
            limit_conn addr 10;  
            # 其他配置...  
        }  
    }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13

说明:在上述示例中,limit_conn_zone定义了一个名为addr的连接数限流区域,该区域使用IP地址作为key,并设置了10MB的共享内存区域来存储状态信息。在location块中,limit_conn指令引用了该连接数限流区域,并设置了10作为单个IP地址的最大并发连接数。如果某个IP地址的并发连接数超过了这个限制,Nginx将拒绝新的连接请求。

3)区别 ​

一个连接中可以发起多个请求。这就是最核心的区别。

  • 关注点不同:IP限流关注的是请求的频率,而连接数限流关注的是同时建立的连接数量。
  • 应用场景不同:IP限流更适用于防止密码暴力破解等场景,因为它关注的是请求的频率;而连接数限流更适用于防止资源耗尽的场景,因为它关注的是连接的数量。
  • 效果不同:IP限流可能会允许某个IP地址在短时间内建立多个连接,但会限制它的请求频率;而连接数限流则会限制某个IP地址同时建立的连接数量,不论请求频率如何。

6.场景篇 ​

MQ的消息太多消费不完怎么办 ​

❗ 消息堆积问题处理方案是类似的

  1. 增加更多消费者提高消费速度
  2. 消费者本身使用多线程方式提高消费速度
  3. 提高队列容积,提高堆积上限 RabbitMQ还可以开启惰性队列(LazyQueue)来支撑大量的消息存储

MQ消息丢了怎么办 ​

❗ 参考RabbitMQ的消息确认和持久化机制

MQ消息重复消费怎么办 ​

❗ 1. 消息幂等:消费者处理逻辑做幂等性处理 2. 消息去重:使用消息去重机制来检查已经处理过的消息 3. 消息确认:开启消息确认机制,减少消息的重复传递 【追问】:如何做幂等性处理: 首先要明白的是,这里处理消息应该都是做的增删改的操作,查询本身就是幂等并且消费者做查询操作也没有意义

  1. 使用数据库的唯一主键或者唯一索引来控制重复新增操作
  2. 根据消息体内容生成一个唯一ID或者令牌,消费之前先把ID存储到数据库或者redis,只有存储成功才能继续消费,确保消息的唯一性
  3. 使用乐观锁或者悲观锁,在更新数据时保证数据一致性,乐观锁可以通过时间戳的方式实现(sql语句),但是有可能出现ABA问题
  4. 利用业务本身的一些特点实现幂等,比如签到利用了redis的bitmap,本身就不可重复
  5. 状态机,例如订单已经被修改为已支付状态,就不能再被修改回未支付状态

你们系统的日志怎么收集的 ​

❗ 收集日志在实际工作中尤其是微服务系统,其实是个比较麻烦的功能 这里提供三种答案供大家参考,结合你们业务的实际情况

  1. 每个服务记录自己的日志,打日志的地方加上链路ID(请求ID),这个ID通常由网关生成,一路往下传递,各微服务打日志的时候都要打印出该ID用于定位同一个请求
  2. 使用ELK架构,也就是ElasticSearch+Logstash+Kibana
  • ES大家很熟悉是一个分布式的全文检索数据库
  • Logstash是一个日志收集工具,大家可以理解成日志和ES之间的管道,当然这中间还可以加入Kafka做为日志不丢失的一层保障
  • Kibana就是ES的控制台,用于我们去查看日志,这些日志在索引库中都会带着服务的名称,所以很方便的可以区分日志内容,并且可以做全文检索,
  1. 使用阿里云的日志收集服务SLS,花钱但是比较好用,查看日志直接去阿里云平台上查看,但是对应的你们的服务器最好也在阿里云上

生产问题怎么排查 ​

❗ 这里面试官可能会问两种问题 第一种就是让你说一个真实排查的经历,这种情况还是建议同学们上网搜索一个别人的真实经历,消化吸收 第二种是让你说一下整体排查思路,我们这里针对第二种做一个解答 遇到问题后,我们其实大概能猜到问题是出在哪里

  1. 所以第一时间看看日志,确认一下思路(看日志的方式配合上面日志收集的思路说,别说漏了,如果是ELK就去Kibana查,如果是直接收集的就去生产服务器查日志)
  2. 如果看日志看不出来,那就先尝试复现问题,尽量是在本地
  3. 如果日志输出内容符合情况那大概就知道如何去解决,如果不知道怎么解决还是通过本地复现然后debug的方式来排查问题
  4. 如果不能复现,说明可能本地数据库的数据和生产不一致,那应该想办法做数据同步,不用全量同步,把关键的数据同步过来即可
  5. 如果还是不能复现但是生产会出现,那就用Arthas的探针进去深入排查(具体用法同学们自行搜索,这里无法完整展现)

你们系统怎么部署的?部署了几台机器 ​

❗ 这个具体多少台服务器取决于你们的项目,这里只是举例子,同学们切勿照着念,一定要自己提前准备好 例如XX学堂中一共10个微服务:鉴权、交易、支付、学习、媒资、网关、课程、优惠券、用户、点赞 这些微服务中,网关单独部署集群(两台2核2G足够) 高频业务放到一个高配机器中例如:交易、优惠券、点赞(两台4核8G) 其余的用一般配置放一起即可(两台2核4G或者2核8G) 为什么都要用两台,原因是为了做高可用,不能出现单点故障,但是碍于成本所以不部署更多,后期如果点赞、优惠券服务压力过大,还可以再单独拎出来部署,但是目前碍于成本先部署在一起

如何实现单点登录(SSO) ​

❗ ##### 什么是单点登录? 单点登录是一种身份认证的机制,允许用户在访问多个相关但独立的软件系统时,只需一次登录,便可无缝访问所有系统。这大大提高了用户体验,并简化了管理和维护的复杂性。

单点登录的工作原理 ​

令牌(Token)机制:后续切换系统时只需要携带有效令牌即可通过校验 身份验证的协议:常见的就是OAuth2和OpenIDConnect

实现单点登录 ​

详细的需要大家自己写代码去理解,这里只说最简单的回答 使用Spring Security OAuth2框架实现

对接过其他第三方平台接口吗 ​

❗ 只对结果云服务平台的一些接口,例如阿里云的OSS、短信发送、微信的登录、支付、高德地图的位置查询、路线查询 具体实现,还得同学们自行查阅,不要偷懒,说到这些面试官90%会接着问:那你说下高德地图的路线规划吧

写过前端代码吗 ​

❗ 写过,但是我们一般就是写一些管理端的增删改查页面 使用的是Vue3+ElementPlus(ElementUI是vue2版本)做的,流程就是把官网的组件代码先复制下来,然后再改成自己需要的形式,整体的前端代码架子是前端人员帮我们搭建好了,我们只需要写对应的vue模块就行 Vue常用指令标签:

  • v-bind:动态地绑定一个或多个属性。
  • v-model:在表单元素上创建双向数据绑定。
  • v-on:用于监听DOM事件。
  • v-if、v-else-if、v-else:条件性地渲染元素。
  • v-for:用于基于源数据多次渲染元素。 Vue的生命周期:生命周期有很多,平时我们用的最多的就是mounted,挂载完成后,通常用于执行一些页面加载完成后直接执行的一些逻辑,比如数据加载 ElementPlus常用标签:
  • Button:按钮
  • Table:表格
  • Form:表单
  • Pagination:分页

最近在看什么新技术吗? ​

❗ 这个就说去B站上看一些黑马的视频,比如面试专题之类的,这个不能胡说,因为面试官很可能会接着问你里面的具体内容,所以务必是看过的视频

你们系统用户量有多少?QPS/TPS有多少 ​

❗ 思路:我们的系统都是to C的系统,所以用户量最好提前想好 你们项目上线多久?几个月,计算总共的用户量(下载量)假设10万用户 月活大概多少:1万左右,日活:1000左右 TPS:说的是高频接口的峰值:可能就几百 虽然用户量少,但是我们自己要求高,我自己要求能抗住2000线并发 模拟回答:我们的系统刚上线没多久,期间搞过几次营销活动和宣传拉新,但是效果一般,总用户量还行,突破十万了,但是留存下来的不多,月活也就1000左右浮动,而对于我们的一些高频接口,如抢券、抢红包(类似薅羊毛的接口),峰值还可以,TPS大概能有几百,其他的基本没什么并发量。 或者:我们系统还没上线,我们项目经理对于我们的一些高频接口,都是做了压力测试,统一2000线去压测,然后看接口RT时间有没有超的,我们要求最多不能超过2秒

你们项目的部署上线流程是什么 ​

❗ 部署上线分两种:手动、自动 先说手动:就是我们开发完、测试完之后,整体没什么bug了,可以正式进入上线流程。那我们开发要准备几个东西给运维(或者没有运维)

  • 项目包:就是我们的Jar包,微服务的话可能涉及到多个
  • 数据库脚本:如果这次涉及到了数据库的改动,如加字段、建表等
  • 定时任务:如果本次新增了定时任务,要做出新增说明 把这些东西给运维之后,然后运维会去发版部署。 自动:使用的阿里云的云效平台(建议自己百度体验一下,免费的)

JWT相关的问题 ​

❗ ##### JWT的组成 头(header)、载荷(payload)、签名(signature)。其中头和载荷是明文,直接用base64编码,签名是用头和载荷通过密钥经过加密的得到的一个结果,就是用签名来判断这个JWT是否合法是否被篡改过

校验过程 ​

我们收到JWT之后,首先拿到这三部分,然后使用我们自己的密钥对头和载荷进行加密,然后对比

具体签名的加密算法 ​

如果需要保证JWT的机密性,可以使用对称加密算法(如AES)对负载进行加密;如果只需要验证JWT的完整性和认证,可以使用HS256等签名算法。对于非对称加密,可以使用RSA或ECDSA算法。 这里我们通常使用RSA或HS256即可

微信支付相关 ​

微信扫码支付业务流程

❗ ##### 下单流程

  1. 用户下单生成本地商户订单
  2. 调用微信统一下单接口生成预支付订单
  3. 微信收到请求后,生成预支付订单,返回订单标识(prepayid,code_url)
  4. 我们的商户系统接收到订单标识之后,返回数据到客户端,客户端根据数据生成二维码或者唤起小程序
  5. 用户可以扫码支付或者点击小程序支付,输入密码提交支付请求到微信
  6. 微信服务器将进行权限校验,通过就进行扣款,成功就支付成功。
微信支付结果通知 ​
  1. 支付成功之后,微信会返回给用户支付结果
  2. 支付成功之后,微信会给我们下单的时候设置的notify_url地址发送请求,也就是我们接受结果的回调地址
  3. 在网络不稳定或者设备接口故障的情况下,我们还可以通过调用微信查询订单接口,主动查询订单支付状态
相关问题 ​
  1. 如何避免假通知?
  1. 接收到微信的回调请求后先进行签名校验
  2. 在回调接口中调用微信查询订单的接口进行二次判断
  3. 如何避免通知丢失?两种方式:
  1. 创建商户订单的时候,发送一个1分钟(时间可以变化)的延迟消息,5分钟之后再去微信查询订单状态,如果是已支付,就调整为已支付即可
  2. 定时任务,每隔一分钟就查询一下系统中未支付的订单状态,去微信查询这些订单的实际支付状态,如果是已支付就改成已支付即可
  3. 如何避免重复通知
  1. 接收到通知之后,首先判断订单状态,如果已支付的话,直接返回SUCCESS即可
  2. 如何退款?
  1. 调用微信的退款接口
  2. 如果商户系统订单已经关闭的情况下,用户再次支付会怎么样?
  1. 我们在关闭取消订单的时候,首先会调用微信支付的关闭订单接口,然后再关闭我们自己的系统订单
  2. 项目如何实现微信支付和支付宝支付?
  1. 我们项目对微信支付和支付宝支付进行封装,配合SpringBoot自动装配的特性,只需要在配置文件中配置相关信息即可直接使用,根据前端参数决定调用什么API
← Java 框架常见面试题Java常见算法面试题 →








如果发现文档内容有错误或排版错乱,请及时联系站长老苗修改,不胜感激。联系方式
关于我们 | 隐私政策 | 豫ICP备2026003386号-4 | 豫公网安备41010202004008号
目录

本页无章节