当前位置: 首页 > article >正文

一些面试问题的深入与思考

Bug排查

原问题:多个服务的bug你是怎么排查的。如果是内存泄漏这种情况看日志看不了怎么办。
题解:内存泄漏的问题往往不会直接从日志中体现,需要用更多手段来定位解决。如下:

1、使用 Go 自带的性能分析工具

(1) pprof 工具(性能剖析)

pprof 是 Go 内置的性能分析工具,能分析内存、CPU 和 goroutine 使用等。如:heap:内存分配情况;goroutine:当前 goroutine 使用情况;cpu:CPU 使用情况
启动服务后,访问 http://localhost:6060/debug/pprof/ 即可查看不同类型的剖析数据,

import (
    _ "net/http/pprof" // 引入 pprof 包
    "net/http"
    "log"
)

func main() {
    // 在 6060 端口暴露 pprof 信息
    go func() {
        log.Println(http.ListenAndServe("localhost:6060", nil))
    }()

    // 其他业务逻辑代码
}

获取内存信息:用以下命令收集内存堆信息:这将打开一个交互式界面,显示内存使用情况。可以用 top 命令查看哪些函数占用了最多内存,或者用 list <func_name> 查看某个函数的详细内存分配情况。

go tool pprof http://localhost:6060/debug/pprof/heap

分析 goroutine 堆栈:如果怀疑程序中存在 goroutine 泄漏,可以用以下命令查看 goroutine 的堆栈:查看是否有不必要的 goroutine 一直存在,未能及时退出,导致内存泄漏。

go tool pprof http://localhost:6060/debug/pprof/goroutine

(2) Go Trace(跟踪)

go tool trace 提供了更深入的跟踪功能,帮助观察程序的调度情况、goroutine 的执行轨迹等。识别是否有 goroutine 持续占用内存,或者是否存在调度瓶颈等问题。
启用 pprof 后,访问 http://localhost:6060/debug/pprof/trace 来获取追踪数据。

go tool trace http://localhost:6060/debug/pprof/trace?seconds=30 # 收集 30 秒的追踪数据
2. 监控和日志结合

对于内存泄漏问题,日志本身可能不提供明确的异常信息,但可结合内存监控和日志来看。

(1) 使用 Prometheus + Grafana 监控内存使用情况

集成 Prometheus 客户端,定期暴露内存使用情况,用 Grafana 可视化展示。实时监控服务的内存消耗变化,及时发现内存泄漏。

暴露内存指标:在 Go 程序中使用 runtime.ReadMemStats 获取内存统计数据,并通过 Prometheus 暴露这些指标:如果内存使用不断增长而没有释放,就可能意味着存在内存泄漏。

import (
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "net/http"
    "runtime"
    "log"
)

var (
    memoryStats = prometheus.NewGaugeVec(
        prometheus.GaugeOpts{
            Name: "go_memory_stats",
            Help: "Go memory statistics",
        },
        []string{"stat"},
    )
)

func init() {
    prometheus.MustRegister(memoryStats)
}

func recordMemoryStats() {
    var m runtime.MemStats
    runtime.ReadMemStats(&m)
    memoryStats.WithLabelValues("heap_alloc").Set(float64(m.HeapAlloc))
    memoryStats.WithLabelValues("heap_sys").Set(float64(m.HeapSys))
    memoryStats.WithLabelValues("heap_idle").Set(float64(m.HeapIdle))
    memoryStats.WithLabelValues("heap_inuse").Set(float64(m.HeapInuse))
}

func main() {
    go func() {
        for {
            recordMemoryStats()
            time.Sleep(10 * time.Second)
        }
    }()

    http.Handle("/metrics", promhttp.Handler())
    log.Fatal(http.ListenAndServe(":8080", nil))
}

(2) 定期记录内存使用信息

如果不使用 Prometheus,也可以定期记录程序的内存使用信息,并通过日志查看内存变化。例如:通过日志定期记录内存使用情况,可检测内存是否存在异常增长,尤其是在特定的负载下。

import (
    "log"
    "runtime"
)

func logMemoryUsage() {
    var m runtime.MemStats
    runtime.ReadMemStats(&m)
    log.Printf("Alloc = %v MiB", bToMb(m.Alloc))
    log.Printf("TotalAlloc = %v MiB", bToMb(m.TotalAlloc))
    log.Printf("Sys = %v MiB", bToMb(m.Sys))
    log.Printf("NumGC = %v", m.NumGC)
}

func bToMb(b uint64) uint64 {
    return b / 1024 / 1024
}
3、代码审查和手动检查

检查不必要的引用:确保没有无意中持有不再需要的引用,尤其是大对象(如 map、slice 等)。
检查 goroutine 的生命周期:确保所有启动的 goroutine 在任务完成后能够正确退出,避免因 goroutine 泄漏导致内存问题。
用 defer 确保资源释放:在会发生内存泄漏的地方,确保通过 defer 释放资源(例如关闭文件、数据库连接等)。

4、压力测试和负载测试

通过模拟实际业务场景的高并发或长时间运行,来进行压力测试。可以使用如 wrk、hey 等工具进行负载测试,观察在高负载下服务的内存使用情况,看看是否存在内存泄漏。

压测

1、hey
一个轻量级、易用的 HTTP 性能测试工具,适合对中小规模应用进行负载测试。配置简单,适合快速进行简单的压力测试。不支持脚本。
举例:

hey -n 1000 -c 100 http://example.com
#-n 1000:发送 1000 个请求
#-c 100:使用 100 个并发连接

输出:

Summary:
  Total:	2.1234 secs
  Slowest:	0.2890 secs
  Fastest:	0.0123 secs
  Average:	0.0456 secs
  Requests/sec:	470.31
  Total data:	113.8 MB
  Response time histogram:
  0.012 [1]	|
  0.045 [934]	|
  0.100 [65]	|
  0.150 [0]	|

2、wrk
适用于大规模、高并发的性能测试。通过多线程和 Lua 脚本提供更高的灵活性和定制能力,适合需要进行详细性能分析的复杂场景。

压测效果影响因素:1、硬件资源:服务器的CPU、内存和网络带宽;2、并发量;3、请求类型;4、代码质量,数据库性能,缓存机制; 5、网络延迟

举例与输出:

wrk -t12 -c400 -d30s http://example.com
#-t12:使用 12 个线程进行测试
#-c400:使用 400 个连接
#-d30s:进行 30 秒的测试
Running 30s test @ http://example.com
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     31.77ms   22.45ms  98.56ms   84.55%
    Req/Sec    1405.72     65.85   1552.00    83.43%
  506837 requests in 30.08s, 63.25MB read
Requests/sec: 16807.51
Transfer/sec:    2.10MB

性能优化方向 思考

1、 缓存
l1、l2、l3 级 cache、浏览器缓存、Redia、

缓存相关的问题:雪崩、穿透、击穿、热点 key监控再分散、缓存淘汰、数据一致性三类方法、

2、 并行化处理
后来的Redis 多线程、主从数据库

3、 批量化处理
AOF 缓冲区、Redis的pipeline 、

4、 数据压缩处理
AOF 文件对同一key的多次写、pb、

5、 无锁化
sync.Map、GM到GMP、mvcc 、消息队列

6、 分片化
Redis集群、

7、 避免请求
bufferpool 、

8、 池化
对象池:sync.pool
协程池:gopool
数据库连接池

9、 异步处理
回调函数实现、bgsave、Redis用unlink 异步删除key、

10、顺序写
MySQL 自增主键、写undolog 和 binlog 日志、

总结:做服务性能优化,要从自身服务架构出发,分析服务调用链耗时分布跟 CPU 消耗,优化有问题的 RPC 调用和函数。
多学中间件,上面几种方法很多在常用中间件中有体现。具体学“如何用;底层优秀的设计思想;理解为什么要这样设计;这种设计有什么好处;”

性能瓶颈测试

原题:性能瓶颈是在磁盘,网络还是哪里,怎么设计测试用例验证

1、确定瓶颈的位置

(1)网络带宽测试:
用工具如 iperf 或 netperf 测 A 到 B 的网络带宽。
在传输过程中监控网络带宽和延迟:用 nload、iftop 或 netstat 来监控网络带宽的使用情况。

(2)磁盘性能测试:
fio 或 iostat 测试源服务器 A 和目标服务器 B 的磁盘读写性能。
测试读写吞吐量(MB/s);磁盘 IOPS(每秒输入输出操作数);测试磁盘延迟。
再有,就是测不同磁盘(SSD vs HDD)的性能差异。

(3)CPU 和内存性能:
top 或 htop 工具监控 CPU 和内存的利用率,检查是否有高 CPU 使用率或内存瓶颈。
使用 stress 或 sysbench 对系统进行压力测试,观察负载和性能变化。

2、测试用例设计

(1)网络带宽测试用例:
目标:测量网络带宽和延迟
在 A 和 B 上分别运行 iperf,测试不同的带宽条件。
比较局域网(LAN)与广域网(WAN)的带宽差异。
测量 A 和 B 之间的延迟,使用 ping 或 traceroute 进行网络延迟分析。

预期结果:确保网络带宽充足,延迟较低。

(2)磁盘性能测试用例:
目标:测量磁盘读写性能
在 A 上使用 fio 执行大文件的顺序读取(sequential read)和顺序写入(sequential write)测试。
在 B 上执行相同的磁盘性能测试。

预期结果:磁盘的读取和写入性能足够高,不会成为瓶颈。

(3)传输工具性能测试用例:
目标:测试不同工具和协议的传输效率
使用 scp、rsync、ftp、sftp 和 Rclone 进行同样文件的传输,记录传输时间。
测不同的传输模式(压缩、不压缩)对性能的影响。

预期结果:选择最佳传输工具和配置(如:启用压缩)。

(4)并发传输测试用例:
目标:测 多线程或多连接传输对性能的影响
使用工具支持并行传输(如 rsync并行、多线程工具 aria2 等)。
对比单线程与多线程的传输性能。

预期结果:并行传输显著提升文件传输速度。


http://www.kler.cn/a/419391.html

相关文章:

  • 相交链表和环形链表
  • LeetCode题解:34.在排序数组中查找元素的第一个和最后一个位置【Python题解超详细,二分查找法、index法】,知识拓展:index方法详解
  • 一体化数据安全平台uDSP 入选【年度创新安全产品 TOP10】榜单
  • 349. 两个数组的交集:
  • 使用 Spring Boot 和 GraalVM 的原生镜像
  • C#使用ExcelDataReader读取Xlsx文件为DataTable对象
  • 国际网络安全趋势
  • git push使用
  • 探索Linux的目录结构:深入理解文件系统的组织
  • mongodb配置ssl连接
  • 详解Qt PDF 之 QPdfDocument与 QPdfView 打开与显示pdf
  • 如何在 Debian 7 上设置 Apache 虚拟主机
  • 时频转换 | Matlab基于S变换S-transform一维数据转二维图像方法
  • node == RabbitMQ入门教程
  • 手机控制载货汽车一键启动无钥匙进入广泛应用
  • 综合实验——用户远程登陆并更改文件
  • 网络七层杀伤链
  • 网络安全-夜神模拟器如何通过虚拟机的Burp Suite代理应用程序接口
  • python学习笔记9-零散知识点
  • vue3 路由跳转携带参数以及其他页面接收参数
  • 数据库学习记录03
  • 鸿蒙开发:自定义一个任意位置弹出的Dialog
  • React第十节组件之间传值之context
  • 扩散模型赋能3D 视觉的综述报告
  • 通信原理实验:PCM编译码
  • CEF127 编译指南 Linux篇 - 安装Git和Python(三)