写点什么

系统实战 - 逻辑多租服务的高并发调优

作者:三叶草
  • 2022 年 9 月 13 日
    贵州
  • 本文字数:1966 字

    阅读完需:约 6 分钟

性能优化是没有上限的,当系统能满足用户业务诉求,且系统成本可接受情况下,就可以点到为止了!由于系统开发语言是 Go,所以本文的相关例子均使用 Go 相关的内容了。

一、工具准备

高并发调优,实际上就是使用熟练的使用工具,压测出来具体的瓶颈点,然后针对性的优化;当然,熟悉业务的情况下,能更好的从系统架构层面优化。go 程序中常用的性能优化工具如下:

  • go pprof

黑盒形式:通过 pprof 抓取到系统的瓶颈分布点

  • benchmark

白盒形式:感知到系统瓶颈后,针对改造后的方法,可以快速使用 benchmark 来本地测试,修改后的代码是否符合预期,避免频繁的发布上线来测试

二、方法

优化的最底层实际上是优化计算资源性能、网络资源性能、存储资源性能,对应的是 cpu、内存、网络带宽、http 连接、磁盘 I/O


对应的业务层可以做的事情:

  • 端到端调用链路分析,解决依赖服务和系统自身瓶颈,任何一个组件都有瓶颈问题

  • 扩 cpu、内存资源

  • 扩连接数资源

  • 扩网络带宽资源

  • 扩 ssd 磁盘性能

  • 重复数据,本地缓存化

  • redis、etcd、数据库等元数据,可以本地缓存化,减少网络 I/O

  • token 认证、鉴权、签名生成,可以本地缓存化,定时刷新本地 token

  • 参数类校验,涉及正则匹配等吃 cpu 的操作,本地缓存化

  • 善用 sync.Pool,将重复使用的对象缓存下来,减少对象生成次数,GC 次数,例

  • json.unmarshal 时,反序列化对象使用 sync.Pool 进行改造

  • ioutil.ReadAll 改造成 bytes.NewBuffer 结合 sync.Pool 进行改造

  • 减少共享资源的竞争

  • 读远大于写的,尽量使用读写锁

  • 写远大于读的,考虑优化架构(不使用全局锁、锁粒度尽量小、转换成异步操作,非必要不在高并发场景走该逻辑),尽量不要出现该场景

  • 能做到租户之间的资源隔离,甚至是更小力度的隔离,非必要不使用全局的控制变量

  • 注意共享 channel 的使用

  • 减少阻塞性操作

  • 全局性的变量做流量控制时,避免单租户给阻塞,做到异常场景下的租户隔离

  • 统计指标、审计日志、健康检查等任务,使用异步任务,非阻塞式的去执行

  • 注意共享 channel 的使用

  • 池化,将资源做到可控

  • http 连接的池化,防止连接数量不够,爆掉了;另外复用连接,防止频繁新建,提升性能

  • 请求内容的池化,防止请求 body 过大,将内存爆掉了

  • 减少日志打印

  • 只打印最关键的日志,另外日志中字符串拼接选用高性能的 api(例 buffer)

  • 减少重复代码执行逻辑,提前返回

三、实践

1、工具的用法

1)go pprof 观测系统火焰图

  • 在待优化的程序的 main 函数中,引入 pprof 包,开启 http 服务,监听系统资源的变化

import(  "net/http"  _ "net/http/pprof"  )go func(){    err := http.ListenAndServe("0.0.0.0:8888", nil)    if err !=nil {        fmt.Println("init pprof failed")    }}()
复制代码


  • 使用 Jmeter 直接对核心接口进行压测,其中 Jmeter 里面的参数配置勾选上“Same user on each iteration”,确保复用线程,避免 Jmeter 频繁新建线程,引起不必要的开销

  • 在本地电脑的 cmd 窗口界面,输入一下命令进行获取远程数据面的性能数据,加上-http 后,可以直接弹出浏览器页面,在浏览器页面上可以看到性能引用图,以及火焰图,以及 top 数据,根据图像数据定位具体的 cpu 消耗点,以及内存泄露点

  • 获取 cpu 的数据

go tool pprof -http=:8888 http://123.123.123.123:8888/debug/pprof/profile

  • 获取内存数据

go tool pprof -http=:8888 http://123.123.123.123:8888/debug/pprof/heap

  • 获取 goroutine 数据

其中,debug=1 时可以查看泄露的协程总数,debug=2 可以查看具体协程阻塞多久

http://123.123.123.123:8888/debug/pprof/goroutine?debug=1

  • 也可已在控制台直接查看 pprof 的信息

在控制台输入:

go tool pprof http://123.123.123.123:8888/debug/pprof/goroutine?debug=1

使用 traces,展示函数的调用链


2)关键指标的观测,配合火焰图,定位问题

  • 系统时延

  • 关键的组件端到端调度时延,一定要有业务日志记录

  • 查看进程 cpu 和内存消耗

  • top

  • 查看容器的监控指标

  • docker stats {containerId}

  • 查看当前某个端口连接数

 netstat –ano|grep 31220 |wc -l

  • 查看当前句柄数目最多的进程

  • lsof -n|awk '{print $2}'| sort | uniq -c | sort -nr | head


2)代码改造实战

  • http 连接调优

  • 使用 http2 的连接池特性,自建长连接池,复用连接,避免新连接导致的性能开销

  • fasthttp 替换 net/http,使用更高性能的开源组件

  • 本地缓存

  • redis+本地 gcache,存储数据库中的元数据,加速元数据访问

  • token、签名本地缓存,支持定时刷新

  • sync.Pool 缓存重复重建的对象,减少 gc 频率

  • 锁力度优化

  • 优化阻塞性的全局锁,改造业务逻辑,避免出现全局锁竞争问题

  • 非关键流程,同步阻塞改造成异步阻塞

  • 读多写少的场景,将互斥锁全部改造成读写锁


推荐参考:

go 的高性能编程 Go 语言高性能编程 | 极客兔兔 (geektutu.com)

sync.Pool 优化实战 Golang 内存分配优化 – 萌叔 (vearne.cc)

go pprof 的可参考 Golang 大杀器之性能剖析 PProf - SegmentFault 思否

fasthttp 和 net/http 的区别 net/http与fasthttp区别 - 简书 (jianshu.com)

用户头像

三叶草

关注

还未添加个人签名 2019.11.17 加入

还未添加个人简介

评论

发布
暂无评论
系统实战-逻辑多租服务的高并发调优_性能优化_三叶草_InfoQ写作社区