---
url: /notes/面试/场景/index.md
---
\[TOC]

## 订单在取消的那一刻用户刚好付款

[一笔订单，在取消的那一刻用户刚好付款了，怎么办？ - 后端场景面试题 - 面试鸭 - 程序员求职面试刷题神器](https://www.mianshiya.com/bank/1795650132375805954/question/1797465845035827202#heading-0)

可能出现两种情况

（1）用户支付成功，支付回调时支付单还没结束，等回调结束，取消支付单的事务提交，支付单取消，此时用户扣款了，但是对应的权益或资产没了

（2）用户支付成功，支付回调时支付单已取消。但此时用户已经扣款，东西没了

两种情况下的状态

（1）待支付 -> 支付中 -> 支付成功

（2）待支付 -> 支付中 -> 已取消

```sql
# 支付成功
update pay_info set status = 'paySuccess' where orderNo = '1' and status = 'paying';

# 取消
update pay_info set status = 'cancel' where orderNo = '1' and status = 'paying';
```

根据状态判断，保证只有一种情况成功，另一个一定失败

（1）假设情况1成功，此时用户已经成功付款，stats变为paySuccess，取消订单的sql一定失败

（2）假设情况2成功，此时订单已被取消，status已经变为cancel，支付成功的sql一定失败，这是需要给用户退款

**业务优化**

针对超时订单，可以在页面上设置取消订单的倒计时比后端实际的倒计时延迟一定的时间，如前端30分钟，后端31分钟

**Redis分布式锁实现**

每次进行对订单的取消或付款时，使用分布式锁锁住订单

**订单取消流程**

**订单付款流程**

## 避免用户重复下单（多次下单未支付，占用库存）

[如何避免用户重复下单（多次下单未支付，占用库存） - 后端场景面试题 - 面试鸭 - 程序员求职面试刷题神器](https://www.mianshiya.com/bank/1795650132375805954/question/1856228340908228610)

1. 前端按钮控制

2. 每次下单请求中生成一个唯一的requestId或token。每次进入订单页面前生成

3. 分布式锁 + 判断 + 下单

   以用户维度加锁，如xxxxx+userId，同一个用户的操作会被锁定

   判断用户是否有在流程中未支付的订单

   如果没有则正常下单

   如果有则直接返回，提醒还有未支付的订单

## 线上排查Redis机器爆了，怎么优化

[线上发现 Redis 机器爆了，如何优化？ - 后端场景面试题 - 面试鸭 - 程序员求职面试刷题神器](https://www.mianshiya.com/bank/1795650132375805954/question/1795660206586503170#heading-2)

[如果发现 Redis 内存溢出了？你会怎么做？请给出排查思路和解决方案 - 后端场景面试题 - 面试鸭 - 程序员求职面试刷题神器](https://www.mianshiya.com/bank/1795650132375805954/question/1823991791071256577)

排查CPU，内存、带宽

**内存**

部分数据是否不用存储到Redis，数据的过期时间是否过长

临时垂直扩展（增加redis内存），水平扩展（增加redis实例）

**CPU**

可能是大量读写请求，且有复杂的操作命令，如聚合、排序

大key拆分，复杂操作放在后端

**带宽**

传输的数据量过大，优化大key

## 百万excel导入/导出

[项目上有个导出 excel 场景发现很慢，怎么优化？ - 后端场景面试题 - 面试鸭 - 程序员求职面试刷题神器](https://www.mianshiya.com/bank/1795650132375805954/question/1795715838014431233)

**导出**

业务逻辑慢，尽量优化减少时间复杂度、多线程优化

数据库查询慢，通过执行计划查看sql是否命中索引或深分页

excel生成慢，使用批量写入数据，避免一行一行写入

Apache poi等生成excel框架非常消耗内存，将整个文件加载到内存

easy excel基于Simple api for xml解析excel文件，逐行读取

**导入**

内存，不要一次性加载过多数据到内存，分配处理

时间，尽量使用异步，大量数据插入需要时间

异常，可能出现数据格式错误

## 数据库连接池爆满问题排查

[线上数据库连接池爆满问题排查 - 后端场景面试题 - 面试鸭 - 程序员求职面试刷题神器](https://www.mianshiya.com/bank/1795650132375805954/question/1797943801076121602)

重启大法

长事务，执行慢，导致长时间占用连接

短事务，执行快，并发过高

**数据库查询性能优化**

* 慢sql日志
* 优化查询
* 数据库锁竞争

**突发流量的应对措施**

* 限流
* 请求排队
* 服务降级

## 线上CPU飙高排查

[线上 CPU 飙高如何排查？ - 后端场景面试题 - 面试鸭 - 程序员求职面试刷题神器](https://www.mianshiya.com/bank/1795650132375805954/question/1807672527650004993)

（1）top确认哪个进程占用cpu高

（2）`top -Hp 进程号`查询具体的线程id

（3）`printf "%x\n" 线程id` 转换为16进制

（4）通过jstack 进程号 | grep 线程id的16进制 -A 100查看具体线程

（5）根据堆栈信息定位代码

## 分析JVM内存占用情况，OOM分析

[怎么分析 JVM 当前的内存占用情况？OOM 后怎么分析？ - 后端场景面试题 - 面试鸭 - 程序员求职面试刷题神器](https://www.mianshiya.com/bank/1795650132375805954/question/1818990174270726145)

```shell
jstat -gc <pid> 1000 10
```

-gc：显示垃圾回收信息

pid：进程id

1000：每1000毫秒采样一次

10：采样10次

```sh
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC       MU       CCSC    CCSU     YGC     YGCT     FGC    FGCT     GCT
1536.0 1536.0  0.0    0.0    30720.0   1024.0  708608.0    2048.0   44800.0  43712.6   4864.0  4096.0      4    0.072   1      0.015    0.087
1536.0 1536.0  0.0    0.0    30720.0   2048.0  708608.0    2048.0   44800.0  43712.6   4864.0  4096.0      4    0.072   1      0.015    0.087
1536.0 1536.0  0.0    0.0    30720.0   3072.0  708608.0    2048.0   44800.0  43712.6   4864.0  4096.0      4    0.072   1      0.015    0.087
```

> FGCL：full GC的次数
>
> 如果变化频率很高，说明系统性能和吞吐量将下降，可能出现内存溢出

jmap：生成堆转储文件

> 该命令会导致虚拟机暂停工作1-3s

```sh
jmap -heap <pid>
```

```sh
Attaching to process ID 1234, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11

using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 1048576000 (1000.0MB)
   NewSize                  = 1310720 (1.25MB)
   MaxNewSize               = 17592186044415 MB
   OldSize                  = 8388608 (8.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 46989312 (44.8125MB)
   used     = 14364528 (13.697036743164062MB)
   free     = 32624784 (31.115463256835938MB)
   30.57471507400737% used
Eden Space:
   capacity = 41943040 (40.0MB)
   used     = 12058624 (11.5MB)
   free     = 29884416 (28.5MB)
   28.769444942474365% used
From Space:
   capacity = 5036288 (4.8046875MB)
   used     = 2305904 (2.1997528076171875MB)
   free     = 2730384 (2.6049346923828125MB)
   45.8012652387619% used
To Space:
   capacity = 5036288 (4.8046875MB)
   used     = 0 (0.0MB)
   free     = 5036288 (4.8046875MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 100663296 (96.0MB)
   used     = 1433600 (1.3671875MB)
   free     = 99229696 (94.6328125MB)
   1.4241612307230632% used

10764 interned Strings occupying 826944 bytes.
```

### OOM

```SH
jmap -dump:format=b,file=heap_dump.hprof <pid>
```

可增加JVM参数，在发生OOM时自动生成dump文件

```sh
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof
```

使用工具打开heapdump.hprof文件分析

* Eclipse MAT（Memory Anzlyzer Tool）

* VisualIVM

* [Universal JVM GC analyzer - Java Garbage collection log analysis made easy](https://gceasy.io/)
