面试题

1.一:阅读下面代码,并尽可能找出存在的所有bug,并修复。

def find_max(nums):
    max = 0  
    for num in nums:
        if num > max:
            max = num
return max  
def find_max(nums):
    if not nums:  # 处理空列表情况
        return None
    maximum = nums[0]  # 将初始值设为列表的第一个元素
    for num in nums:
        if num > maximum:
            maximum = num
    return maximum  # 修正缩进,确保在函数体内

二:实现一个小工具(Java或者Python),从一个日志文件中统计给定的关键字的出现次数(时间精确到秒,有可能同一时间关键字会出现多次),并按照时间倒序输出。

1、文件内容格式:"YYYY-MM-DD HH:MM:SS <LOG_LEVEL> <MESSAGE>"。

2、举例,例如文件内容为:

2021-12-14 12:05:00 LV5 ERROR

2021-12-14 12:05:00 LV5 ERROR

2021-12-14 12:05:01 LV1 Info

2021-12-14 12:05:02 LV1 Info

2021-12-14 12:05:03 LV1 Info

2021-12-14 12:05:05 LV5 ERROR

3、输出如下:

2021-12-14 12:05:05 ERROR 1

2021-12-14 12:05:00 ERROR 2

import sys
from collections import defaultdict
#from typing import Dict, DefaultDict, List, Tuple, Optional


def count_keywords(log_file: str, level: str) -> defaultdict[str, defaultdict[str, int]]:
    """
    统计日志文件中每个时间戳下特定级别的出现次数

    参数:
        log_file: 日志文件路径
        level: 需要统计的日志级别

    返回:
        嵌套字典,格式为 {时间戳: {关键字: 次数}}
    """
    time_keyword_counts: defaultdict[str, defaultdict[str, int]] = defaultdict(lambda: defaultdict(int))

    with open(log_file, 'r') as f:
        for line in f:
            parts = line.strip().split()
            if len(parts) < 4:
                continue  # 跳过格式不正确的行

            timestamp = ''.join(parts[:2])
            keyword = parts[3]  # 假设关键字是第4列

            # 对应时间戳的关键字计数加1
            time_keyword_counts[timestamp][keyword] += 1

    return time_keyword_counts


def main() -> None:
    log_file: str = 'F:/Users/Administrator/PycharmProjects/PythonProject/your_log_file.txt'
    level: str = 'Info'

    # 统计所有关键字出现次数
    counts: defaultdict[str, defaultdict[str, int]] = count_keywords(log_file, level)

    # 按时间倒序输出结果
    for timestamp in sorted(counts.keys(), reverse=True):
        for keyword, count in counts[timestamp].items():
            if keyword == level:
                print(f"{timestamp}  {keyword}   {count}")


if __name__ == "__main__":
    main()

三:请试着回答以下问题:

1.解释吞吐量、tps、rps。


在计算机系统、性能测试和网络领域中,**吞吐量(Throughput)、TPS(Transactions Per Second)、RPS(Requests Per Second)** 是常用的性能指标,用于衡量系统的处理能力和效率。以下是它们的详细解释:


### **一、吞吐量(Throughput)**
**定义**:  
吞吐量是指系统在**单位时间内处理的任务或数据量**,通常用于衡量系统的整体处理能力。它可以表示为:  
- 单位时间内处理的请求数、任务数、数据量(如字节、数据包等)。  
- 例如:Web 服务器每秒处理的 HTTP 请求数、数据库每秒执行的事务数、网络链路每秒传输的数据量(Mbps)。

**特点**:  
1. **范围广泛**:吞吐量是一个笼统的指标,需结合具体场景定义单位(如请求数、数据量等)。  
2. **受资源限制**:受 CPU、内存、磁盘 I/O、网络带宽等硬件资源或软件瓶颈的影响。  
3. **动态变化**:系统负载不同时,吞吐量可能波动(如峰值流量下吞吐量可能下降)。

**应用场景**:  
- 衡量网络带宽:如“某链路吞吐量为 100 Mbps”。  
- 评估服务器性能:如“某 API 服务的最大吞吐量为 5000 请求/秒”。


### **二、TPS(Transactions Per Second,每秒事务数)**
**定义**:  
TPS 是指系统在**每秒内完成的事务数**。这里的“事务”是一个**逻辑概念**,通常指一组相关操作的集合(如数据库事务、用户业务操作等)。  
- 例如:  
  - 数据库事务:一条 SQL 插入语句或包含多个步骤的事务(如转账操作:扣减余额 + 增加对方余额)。  
  - 业务事务:用户下单(包含查询库存、生成订单、扣减库存等多个子操作)。

**特点**:  
1. **业务相关性**:依赖于具体业务逻辑,不同事务的复杂度可能差异很大(如简单查询 vs. 复杂事务)。  
2. **原子性**:事务通常要求“要么全部成功,要么全部失败”,因此 TPS 仅统计**成功完成的事务数**。  
3. **与响应时间关联**:高 TPS 可能伴随较长的响应时间(因系统负载高),需平衡两者。

**应用场景**:  
- 数据库性能测试:如“MySQL 集群的 TPS 峰值为 2000”。  
- 业务系统压测:如“电商平台每秒完成的订单事务数”。


### **三、RPS(Requests Per Second,每秒请求数)**
**定义**:  
RPS 是指系统在**每秒内处理的请求数**,这里的“请求”通常指**单次独立的操作**,如客户端向服务器发送的一个 HTTP 请求、一次 API 调用等。  
- 例如:  
  - 浏览器向服务器发送一个 GET 请求获取网页。  
  - 客户端调用一个微服务接口获取数据。

**特点**:  
1. **细粒度**:RPS 衡量单个请求的处理效率,不涉及事务的“原子性”或“完整性”,仅统计请求的处理次数(成功或失败)。  
2. **无状态性**:每个请求通常是独立的,不依赖其他请求的上下文(如 RESTful API 请求)。  
3. **容易统计**:在性能测试工具(如 JMeter、Postman)中可直接监控 RPS。

**应用场景**:  
- Web 服务性能测试:如“某 API 的 RPS 极限为 10,000”。  
- 接口压测:评估单个接口在高并发下的处理能力。


### **四、三者的区别与联系**
| **指标**       | **单位**              | **粒度**       | **是否关注业务逻辑** | **统计范围**               |
|----------------|-----------------------|----------------|----------------------|----------------------------|
| **吞吐量**     | 自定义(如请求数、字节数) | 宏观           | 否(通用指标)       | 系统整体处理能力           |
| **TPS**        | 事务数/秒             | 中观(业务级) | 是(依赖事务定义)   | 成功完成的事务数           |
| **RPS**        | 请求数/秒             | 微观(请求级) | 否(仅统计请求次数) | 处理的请求数(成功/失败)   |

**联系**:  
- TPS 和 RPS 是吞吐量的具体表现形式,吞吐量可通过 TPS 或 RPS 等指标量化。  
- 一般来说,**RPS ≥ TPS**(一个事务可能包含多个请求)。例如,一个下单事务可能包含 3 次 API 请求(查询库存、生成订单、扣减库存),则 TPS=1 时,RPS=3。


### **五、实际应用建议**
1. **选择指标的依据**:  
   - 若关注**业务完整性**(如数据库事务),用 **TPS**。  
   - 若关注**接口并发能力**(如单个 API),用 **RPS**。  
   - 若需宏观评估系统性能(如数据传输效率),用 **吞吐量**。  

2. **性能优化方向**:  
   - 提升 TPS/RPS:优化代码逻辑、增加硬件资源(如扩容服务器)、引入缓存或异步处理。  
   - 降低响应时间:减少请求处理耗时(如优化 SQL、减少网络调用)。  

3. **工具支持**:  
   - 吞吐量监控:常用工具包括 Prometheus、Grafana、Wireshark。  
   - TPS/RPS 压测:JMeter、Apache Benchmark(AB)、LoadRunner。  

通过合理运用这些指标,可以更精准地评估系统性能、定位瓶颈并优化架构。

2.tps上不去,可能的原因是什么?

TPS(Transactions Per Second)上不去通常是系统性能瓶颈的表现,可能涉及硬件资源、软件架构、数据库、网络或代码逻辑等多个层面。以下是常见的原因及排查方向:


### **一、硬件资源瓶颈**
1. **CPU 利用率过高**  
   - **表现**:CPU 使用率长期超过 80%,导致线程等待 CPU 时间片,事务处理变慢。  
   - **可能原因**:  
     - 复杂计算逻辑(如加密、压缩)。  
     - 死循环或无限递归。  
     - 线程数过多导致上下文切换频繁。  
   - **排查工具**:`top`、`htop`、`vmstat`、JVM 线程分析(如 VisualVM)。

2. **内存不足**  
   - **表现**:频繁触发 GC(垃圾回收)或出现 OOM(内存溢出),系统卡顿。  
   - **可能原因**:  
     - 内存泄漏(如缓存未释放、长生命周期对象持有引用)。  
     - 堆内存分配过小(如 JVM 参数 `-Xmx` 设置不合理)。  
     - 大量数据加载到内存(如全量查询数据库)。  
   - **排查工具**:`free -h`、`jstat`、内存分析工具(如 MAT)。

3. **磁盘 I/O 瓶颈**  
   - **表现**:磁盘读写耗时高(如平均 I/O 等待时间超过 10ms)。  
   - **可能原因**:  
     - 频繁的磁盘读写(如日志写入、文件上传)。  
     - 磁盘顺序读写变为随机读写(如索引失效导致全表扫描)。  
     - 机械硬盘性能不足(建议升级 SSD)。  
   - **排查工具**:`iostat`、`iotop`、`sar`。

4. **网络带宽不足**  
   - **表现**:网络延迟高、丢包率高,跨节点调用耗时增加。  
   - **可能原因**:  
     - 网络带宽被占满(如大量文件下载)。  
     - 网络拓扑不合理(如单点带宽限制)。  
     - 防火墙或代理服务器配置导致请求阻塞。  
   - **排查工具**:`iftop`、`netstat`、`ping`、`traceroute`。


### **二、数据库性能问题**
1. **SQL 语句低效**  
   - **表现**:单条 SQL 执行时间过长,导致事务阻塞。  
   - **可能原因**:  
     - 缺少必要索引(如 WHERE 条件字段未建索引)。  
     - 全表扫描或全索引扫描。  
     - 复杂查询(如多表 JOIN 未优化)。  
   - **排查工具**:数据库慢查询日志、EXPLAIN 分析执行计划。

2. **数据库连接池配置不合理**  
   - **表现**:连接池耗尽,新事务等待连接。  
   - **可能原因**:  
     - 最大连接数设置过小。  
     - 连接泄漏(如未及时释放连接)。  
     - 长事务占用连接时间过长。  
   - **排查工具**:数据库连接监控、应用日志。

3. **事务设计不合理**  
   - **表现**:事务持有锁时间过长,导致其他事务阻塞。  
   - **可能原因**:  
     - 事务范围过大(如包含网络调用、文件操作)。  
     - 事务隔离级别过高(如 SERIALIZABLE)。  
     - 死锁(多个事务循环等待锁)。  
   - **排查工具**:数据库死锁日志、事务监控。


### **三、应用架构与代码问题**
1. **同步阻塞调用过多**  
   - **表现**:线程池被占满,新请求排队等待。  
   - **可能原因**:  
     - 大量同步 I/O 操作(如文件读写、网络请求)。  
     - 未使用异步处理(如 CompletableFuture、消息队列)。  
   - **优化方向**:引入异步框架(如 Reactor、Netty)或消息队列(如 Kafka)。

2. **锁竞争激烈**  
   - **表现**:线程频繁等待锁释放,CPU 使用率高但吞吐量低。  
   - **可能原因**:  
     - 全局锁(如 `synchronized` 块范围过大)。  
     - 锁粒度粗(如对整个对象加锁而非特定资源)。  
   - **优化方向**:使用细粒度锁(如 ReentrantLock)、无锁数据结构(如 ConcurrentHashMap)。

3. **缓存未生效**  
   - **表现**:重复查询相同数据,数据库压力大。  
   - **可能原因**:  
     - 缓存命中率低(如缓存过期策略不合理)。  
     - 未使用缓存(如频繁查询热点数据)。  
   - **优化方向**:引入 Redis 等缓存中间件,设置合理的缓存过期时间。


### **四、中间件与配置问题**
1. **线程池配置不合理**  
   - **表现**:线程池拒绝策略触发,请求被丢弃。  
   - **可能原因**:  
     - 核心线程数/最大线程数设置过小。  
     - 任务队列长度不合理(如无界队列导致 OOM)。  
   - **优化方向**:根据业务特性调整线程池参数(如 CPU 密集型 vs. I/O 密集型)。

2. **容器/框架性能参数未调优**  
   - **表现**:应用服务器(如 Tomcat、Nginx)无法处理高并发。  
   - **可能原因**:  
     - Tomcat 的 maxThreads、acceptCount 参数过低。  
     - Nginx 的 worker_processes、worker_connections 设置不合理。  
   - **优化方向**:根据服务器硬件资源调整参数(如 Tomcat 的 maxThreads 设为 CPU 核心数×2)。


### **五、外部依赖问题**
1. **第三方服务响应慢**  
   - **表现**:调用外部 API 耗时过长,导致事务阻塞。  
   - **可能原因**:  
     - 第三方服务自身性能问题。  
     - 网络延迟高(如跨区域调用)。  
   - **优化方向**:添加熔断、降级机制(如 Hystrix、Sentinel),缓存常用结果。

2. **分布式系统协调开销大**  
   - **表现**:微服务间调用链路长,依赖服务过多。  
   - **可能原因**:  
     - 服务拆分过细,导致 RPC 调用频繁。  
     - 分布式事务一致性开销(如两阶段提交)。  
   - **优化方向**:合理设计服务边界,减少不必要的服务间调用。


### **六、排查思路建议**
1. **监控工具先行**:  
   - 查看系统资源监控(CPU、内存、磁盘、网络)。  
   - 分析应用日志(如慢请求日志、异常堆栈)。  
   - 使用 APM 工具(如 Skywalking、Pinpoint)追踪请求链路。

2. **逐步定位瓶颈**:  
   - 从最外层(网络、负载均衡)向内层(应用、数据库)排查。  
   - 对比不同负载下的性能表现(如低负载 vs. 高负载)。

3. **压测验证**:  
   - 使用 JMeter、Gatling 等工具复现问题,观察 TPS、响应时间、错误率的变化趋势。


通过以上分析,结合具体业务场景和系统架构,通常可以定位并解决 TPS 上不去的问题。

3.我有一个jmeter脚本,我期望,某个时间点开始运行,运行一段时间之后,暂停,然后再过一段时间又运行?怎么设计?

我理解你需要使用 JMeter 设计一个具有定时启动、暂停和恢复功能的测试计划。以下是几种实现方案:


### **方案一:使用 JMeter 内置定时器和线程组控制**
JMeter 的 **线程组** 和 **定时器** 可以组合实现定时启停逻辑:

1. **设置启动延迟**:在线程组中设置 `延迟启动时间`(Delay Thread Creation Until Needed),让测试在指定时间点开始。
2. **控制运行时长**:使用 `持续时间(秒)`(Duration)限制测试运行时间。
3. **多次循环执行**:通过设置多个线程组,并配合 `固定定时器`(Constant Timer)或 `BeanShell 定时器` 实现暂停后再次启动。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.5">
  <hashTree>
    <!-- 线程组1:09:00 启动,运行 30 分钟 -->
    <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="线程组1 - 09:00-09:30" enabled="true">
      <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
      <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
        <boolProp name="LoopController.continue_forever">false</boolProp>
        <stringProp name="LoopController.loops">-1</stringProp>
      </elementProp>
      <stringProp name="ThreadGroup.num_threads">100</stringProp>
      <stringProp name="ThreadGroup.ramp_time">10</stringProp>
      <boolProp name="ThreadGroup.scheduler">true</boolProp>
      <stringProp name="ThreadGroup.duration">1800</stringProp> <!-- 30分钟 -->
      <stringProp name="ThreadGroup.delay">21600</stringProp> <!-- 6小时(09:00相对于00:00的秒数) -->
      <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
      <stringProp name="ThreadGroup.num_threads">100</stringProp>
      <hashTree/>
    </ThreadGroup>
    
    <!-- 线程组2:10:30 启动,运行 20 分钟 -->
    <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="线程组2 - 10:30-10:50" enabled="true">
      <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
      <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
        <boolProp name="LoopController.continue_forever">false</boolProp>
        <stringProp name="LoopController.loops">-1</stringProp>
      </elementProp>
      <stringProp name="ThreadGroup.num_threads">150</stringProp>
      <stringProp name="ThreadGroup.ramp_time">10</stringProp>
      <boolProp name="ThreadGroup.scheduler">true</boolProp>
      <stringProp name="ThreadGroup.duration">1200</stringProp> <!-- 20分钟 -->
      <stringProp name="ThreadGroup.delay">37800</stringProp> <!-- 10小时30分钟相对于00:00的秒数 -->
      <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
      <hashTree/>
    </ThreadGroup>
    
    <!-- 添加你的 HTTP 请求、监听器等元素 -->
    <hashTree/>
  </hashTree>
</jmeterTestPlan>
```


### **方案二:使用外部脚本控制 JMeter 进程**
通过编写脚本调用 JMeter 的命令行接口(CLI),结合系统定时任务实现更灵活的控制:

1. **编写 Shell 脚本**(适用于 Linux/macOS):
```bash
#!/bin/bash

# 定义测试时间点(24小时制)
START_TIME_1="09:00"
END_TIME_1="09:30"
START_TIME_2="10:30"
END_TIME_2="10:50"

# JMeter 路径和测试脚本
JMETER_PATH="/path/to/jmeter/bin/jmeter"
TEST_PLAN="/path/to/your/test.jmx"
LOG_FILE="/path/to/results/$(date +%Y%m%d)_jmeter.log"

# 计算时间间隔(秒)
function get_seconds_until() {
    target_time=$1
    current_time=$(date +%H:%M)
    target_seconds=$(date -d "$target_time" +%s)
    current_seconds=$(date -d "$current_time" +%s)
    
    if [ $target_seconds -lt $current_seconds ]; then
        target_seconds=$((target_seconds + 86400))  # 加一天
    fi
    
    echo $((target_seconds - current_seconds))
}

# 等待到指定时间
function wait_until() {
    target_time=$1
    seconds=$(get_seconds_until "$target_time")
    echo "等待 $seconds 秒直到 $target_time..."
    sleep $seconds
}

# 运行 JMeter 测试
function run_test() {
    start_time=$1
    end_time=$2
    duration=$(( $(date -d "$end_time" +%s) - $(date -d "$start_time" +%s) ))
    
    echo "[$(date)] 开始测试: $start_time 到 $end_time (持续 $duration 秒)"
    $JMETER_PATH -n -t $TEST_PLAN -l $LOG_FILE -e -o /path/to/report -Jduration=$duration &
    
    # 等待测试结束
    sleep $duration
    echo "[$(date)] 测试结束"
}

# 主流程
wait_until "$START_TIME_1"
run_test "$START_TIME_1" "$END_TIME_1"

wait_until "$START_TIME_2"
run_test "$START_TIME_2" "$END_TIME_2"
```

2. **添加系统定时任务**:
```bash
# 使用 cron 调度脚本每天执行
0 8 * * * /path/to/your/script.sh > /path/to/script.log 2>&1
```


### **方案三:使用 BeanShell 或 Groovy 脚本动态控制**
在 JMeter 中添加 **BeanShell 前置处理器** 或 **JSR223 采样器**,通过脚本实现复杂的时间控制逻辑:

```java
import java.util.Calendar;
import java.util.Date;

// 定义时间点(小时和分钟)
int startTime1Hour = 9;
int startTime1Minute = 0;
int endTime1Hour = 9;
int endTime1Minute = 30;
int startTime2Hour = 10;
int startTime2Minute = 30;
int endTime2Hour = 10;
int endTime2Minute = 50;

// 获取当前时间
Calendar now = Calendar.getInstance();
int currentHour = now.get(Calendar.HOUR_OF_DAY);
int currentMinute = now.get(Calendar.MINUTE);

// 计算当前分钟数(从00:00开始)
int currentMinutes = currentHour * 60 + currentMinute;
int start1Minutes = startTime1Hour * 60 + startTime1Minute;
int end1Minutes = endTime1Hour * 60 + endTime1Minute;
int start2Minutes = startTime2Hour * 60 + startTime2Minute;
int end2Minutes = endTime2Hour * 60 + endTime2Minute;

// 判断是否在测试时间段内
boolean isInTestWindow = (currentMinutes >= start1Minutes && currentMinutes < end1Minutes) || 
                        (currentMinutes >= start2Minutes && currentMinutes < end2Minutes);

// 如果不在测试窗口内,暂停执行
if (!isInTestWindow) {
    // 计算下一个测试窗口的等待时间
    long waitMillis = 0;
    if (currentMinutes < start1Minutes) {
        waitMillis = (start1Minutes - currentMinutes) * 60 * 1000;
    } else if (currentMinutes < end1Minutes) {
        waitMillis = 0; // 正在第一个窗口内
    } else if (currentMinutes < start2Minutes) {
        waitMillis = (start2Minutes - currentMinutes) * 60 * 1000;
    } else {
        // 今天的测试窗口已过,等待明天
        waitMillis = (24 * 60 - currentMinutes + start1Minutes) * 60 * 1000;
    }
    
    // 暂停线程
    if (waitMillis > 0) {
        System.out.println("当前时间: " + currentHour + ":" + currentMinute);
        System.out.println("等待 " + (waitMillis / 1000 / 60) + " 分钟进入下一个测试窗口");
        Thread.sleep(waitMillis);
    }
}
```


### **方案四:使用 JMeter 的插件(如 Ultimate Thread Group)**
安装 **JMeter Plugins**,使用 **Ultimate Thread Group** 图形化配置复杂的线程调度:

1. **安装插件**:  
   - 下载 [JMeter Plugins Manager](https://jmeter-plugins.org/wiki/PluginsManager/),并放入 JMeter 的 `lib/ext` 目录。
   - 启动 JMeter,通过菜单 `Options → Plugins Manager` 安装 `jpgc-casutg`。

2. **配置 Ultimate Thread Group**:  
   - 添加 `jp@gc - Ultimate Thread Group` 元件。
   - 使用图形界面设置多个线程启动/停止时间点,精确控制吞吐量随时间的变化。


### **推荐方案**
- **简单场景**(固定时间点,无需动态调整):优先使用 **方案一**,通过线程组的调度器实现。
- **复杂场景**(动态时间逻辑或需要外部干预):使用 **方案二** 或 **方案三**,结合脚本实现灵活控制。
- **需要图形化配置**:使用 **方案四** 的 Ultimate Thread Group 插件。

通过以上方法,你可以实现 JMeter 测试在指定时间点自动启动、暂停和恢复,满足复杂的性能测试需求。

4.常用的linux性能分析命令有哪些?

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务