
欢迎来到预见猿份,本站项目均为站长原创,学习中有问题可直接提交给站长老苗解决(微信: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 - 消息持久化
- 生产者确认机制
- 消费者确认机制:当消费者处理消息结束后,应该向
RabbitMQ发送一个回执,告知RabbitMQ自己消息处理状态。回执ACK
RabbitMQ的交换机类型
❗ - Fanout:广播,将消息交给所有绑定到交换机的队列。我们最早在控制台使用的正是Fanout交换机
- Direct:订阅,基于RoutingKey(路由key)发送给订阅了消息的队列
- Topic:通配符订阅,与Direct类似,只不过RoutingKey可以使用通配符
- Headers:头匹配,基于MQ的消息头匹配,用的较少。
RabbitMQ实现延迟消息
常用于订单超时未支付、或者预约(电影院、自习室等)锁定后未未付款
❗ 实现延迟消息有两种方式:
- 死信交换机+TTL死信: 当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter)简单来说就是消费不了或者失败的消息:
- 消费者使用
basic.reject或basic.nack声明消费失败,并且消息的requeue参数设置为false - 消息是一个过期消息,超时无人消费
- 要投递的队列消息满了,无法投递 所以只要我们这个队列不设置消费者,同时设置TTL(有效期),就可以实现延迟消息的效果 但是:如果队列消息堆积没来得及消费,消息也会进到死信队列,所以这个TTL时间要根据具体情况分析
- 延迟消息插件 DelayExchange插件,RabbitMQ官方提供。安装好之后,代码中指定延迟交换机(delayed=true),发送的时候指定延迟时间即可
MQTT是什么了解过吗
❗ MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是一种轻量级、基于发布/订阅模式的网络协议,用于连接设备到服务器、服务器到服务器或设备到设备的消息通信。它被设计为开放、简单、易于实现,同时保持了灵活性和可靠性。 应用场景:
- 物联网(IoT):MQTT广泛用于物联网设备的消息通信,如智能家居、工业自动化等。
- 移动应用:移动设备可以使用MQTT与服务器进行消息交换,实现推送通知等功能。
- 车载系统:车辆可以通过MQTT与服务器通信,发送状态更新或接收指令。
- 远程监控:MQTT可以用于远程监控系统,实时传输设备状态和传感器数据。
- 事件驱动架构:在事件驱动的系统中,MQTT可以作为事件的传输机制
如何解决消息积压
❗ 1. 快速应急
- 增加消费者:水平扩容实例,并调大
prefetch预取值。 - 启用惰性队列:消息落盘,用磁盘换内存安全(适合百万级积压)。
- 根治手段
- 消费者提速:改用多线程消费,或将同步调用改为异步批量处理。
- 上游限流:在生产者端限速,防止瞬间流量冲击。
- 终极兜底
- 临时转储:将积压消息直接转存至数据库或Redis,错峰慢慢消费,让MQ先恢复。
Kafka有没有了解过,为什么用RabbitMQ
❗ 推荐回答: Kafka 我有一定的了解。Kafka是一种吞吐量比较高的分布式消息队列。 使用RabbitMQ基于以下几个原因吧:
- 我们的吞吐量并没有那么大,并且
RabbitMQ的消息确认机制比较好 - 用起来
RabbitMQ的管理页面也比较方便还有一些生态插件 - 不过在我看来
kafka和Rabbitmq没有本质区别,对我们程序员来说都是消息队列都是辅助的手段而已
3.ElasticSearch篇
ES的底层原理以及为什么使用ES
❗ 概念:ES是基于Apache Lucene的一个全文检索数据库 底层原理:倒排索引
倒排索引:倒排索引是一种数据结构,它将文档中的分词作为索引项,记录每个分词在哪些文档中出现以及出现的位置或对应的ID,以便快速进行关键词检索。
为什么用:可以进行全文检索,速度快,适合存储海量数据,但是数据是加载到内存中再去查询,所以对服务器的配置要求较高
ES数据怎么和Mysql同步
❗ 1. 同步双写,也就是往mysql增删改的时候,同步也去处理一下ES的数据
优点:实现简单
缺点:对业务侵入较大,无法复用
MQ消息,不同步写了,而是增删改的时候通过发送MQ消息来处理ES的数据 优点:实现也很简单,解耦 缺点:ES如果失败不太好处理,依赖MQ的可用性
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,后面跟的就是要转发到的地址
http {
server {
listen 80; # 监听的端口
server_name your_domain.com; # 你的域名或 IP 地址
location / {
proxy_pass http://backend_server_ip:backend_port; # 后端服务器的 IP 地址和端口
}
}
}负载均衡
配置类似反向代理,关键就在于upstream 里配置了多个ip和地址,而proxy_pass 里则变成了upstream 后面的名字。默认是轮询,也可以在upstream配置负载策略:轮询、加权轮询、最少链接、ip哈希
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;
}
}
}限流
基于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路径的话;可以如下配置:
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;
# 其他配置...
}
}
}说明:如果某个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拒绝。 |
示例:
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
listen 80;
server_name example.com;
location / {
limit_conn addr 10;
# 其他配置...
}
}
}说明:在上述示例中,limit_conn_zone定义了一个名为addr的连接数限流区域,该区域使用IP地址作为key,并设置了10MB的共享内存区域来存储状态信息。在location块中,limit_conn指令引用了该连接数限流区域,并设置了10作为单个IP地址的最大并发连接数。如果某个IP地址的并发连接数超过了这个限制,Nginx将拒绝新的连接请求。
3)区别
一个连接中可以发起多个请求。这就是最核心的区别。
- 关注点不同:IP限流关注的是请求的频率,而连接数限流关注的是同时建立的连接数量。
- 应用场景不同:IP限流更适用于防止密码暴力破解等场景,因为它关注的是请求的频率;而连接数限流更适用于防止资源耗尽的场景,因为它关注的是连接的数量。
- 效果不同:IP限流可能会允许某个IP地址在短时间内建立多个连接,但会限制它的请求频率;而连接数限流则会限制某个IP地址同时建立的连接数量,不论请求频率如何。
6.场景篇
MQ的消息太多消费不完怎么办
❗ 消息堆积问题处理方案是类似的
- 增加更多消费者提高消费速度
- 消费者本身使用多线程方式提高消费速度
- 提高队列容积,提高堆积上限
RabbitMQ还可以开启惰性队列(LazyQueue)来支撑大量的消息存储
MQ消息丢了怎么办
❗ 参考RabbitMQ的消息确认和持久化机制
MQ消息重复消费怎么办
❗ 1. 消息幂等:消费者处理逻辑做幂等性处理 2. 消息去重:使用消息去重机制来检查已经处理过的消息 3. 消息确认:开启消息确认机制,减少消息的重复传递 【追问】:如何做幂等性处理: 首先要明白的是,这里处理消息应该都是做的增删改的操作,查询本身就是幂等并且消费者做查询操作也没有意义
- 使用数据库的唯一主键或者唯一索引来控制重复新增操作
- 根据消息体内容生成一个唯一ID或者令牌,消费之前先把ID存储到数据库或者redis,只有存储成功才能继续消费,确保消息的唯一性
- 使用乐观锁或者悲观锁,在更新数据时保证数据一致性,乐观锁可以通过时间戳的方式实现(sql语句),但是有可能出现ABA问题
- 利用业务本身的一些特点实现幂等,比如签到利用了redis的bitmap,本身就不可重复
- 状态机,例如订单已经被修改为已支付状态,就不能再被修改回未支付状态
你们系统的日志怎么收集的
❗ 收集日志在实际工作中尤其是微服务系统,其实是个比较麻烦的功能 这里提供三种答案供大家参考,结合你们业务的实际情况
- 每个服务记录自己的日志,打日志的地方加上链路ID(请求ID),这个ID通常由网关生成,一路往下传递,各微服务打日志的时候都要打印出该ID用于定位同一个请求
- 使用ELK架构,也就是ElasticSearch+Logstash+Kibana
ES大家很熟悉是一个分布式的全文检索数据库Logstash是一个日志收集工具,大家可以理解成日志和ES之间的管道,当然这中间还可以加入Kafka做为日志不丢失的一层保障Kibana就是ES的控制台,用于我们去查看日志,这些日志在索引库中都会带着服务的名称,所以很方便的可以区分日志内容,并且可以做全文检索,
- 使用阿里云的日志收集服务SLS,花钱但是比较好用,查看日志直接去阿里云平台上查看,但是对应的你们的服务器最好也在阿里云上
生产问题怎么排查
❗ 这里面试官可能会问两种问题 第一种就是让你说一个真实排查的经历,这种情况还是建议同学们上网搜索一个别人的真实经历,消化吸收 第二种是让你说一下整体排查思路,我们这里针对第二种做一个解答 遇到问题后,我们其实大概能猜到问题是出在哪里
- 所以第一时间看看日志,确认一下思路(看日志的方式配合上面日志收集的思路说,别说漏了,如果是ELK就去Kibana查,如果是直接收集的就去生产服务器查日志)
- 如果看日志看不出来,那就先尝试复现问题,尽量是在本地
- 如果日志输出内容符合情况那大概就知道如何去解决,如果不知道怎么解决还是通过本地复现然后debug的方式来排查问题
- 如果不能复现,说明可能本地数据库的数据和生产不一致,那应该想办法做数据同步,不用全量同步,把关键的数据同步过来即可
- 如果还是不能复现但是生产会出现,那就用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即可
微信支付相关

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