go 内存泄漏排查

发现问题

通过k8s容器查看到内存使用率不断攀升
alt text

查找问题

  1. 在 服务启动的main函数中加入 pprof

alt text

  1. dockerfile 中安装检查所需工具 curl 以及 ss 命令报包 iproute2 等
  1. 获取 pprof 内存图,

go tool pprof -seconds=10 -http=:9999 http://localhost:6060/debug/pprof/heap

存在网络隔离问题,不能直接从开发机访问测试机、线上机器,或者测试机、线上机器没有安装go,那也可以先在容器中安装 curl 工具,然后将信息下载到本地查看

例如

1
2
3
4
// 该命令主要查看内存信息,可查看具体哪些地方使用内存过高
curl http://localhost:6060/debug/pprof/heap?seconds=600 > heap.out
<!-- 该命令主要查看 goroutine 信息 go 中内存泄漏大概率由 goroutine 未释放未被垃圾回收引起。首先应该查看 goroutine 个数是否异常 -->
curl http://localhost:6060/debug/pprof/goroutine?debug=1 > goroutine.out

将 pprof 信息输出到文件 heap.out 然后将文件下载到本地执行

1
2
3
4
go tool pprof -http=':8081'           \
-diff_base xxx.out \ [对照的文件,非必需,可多次进行对比查看具体问题]
heap.out [查看的文件]

分析问题

  1. 通过图形alt text分析发现可能跟 es 客户端有关

  2. 进入实例中通过命令查看当前连接数

    1
    time netstat -antlp | grep EST | wc -l

    发现有大量连接

  3. 通过 ss -s 命令查看具体是哪些连接发现全是 estab 占用

查看代码问题,发现原来是 es 客户端忘记对 resp.Body.Close()

其他方式

在通过 pprof 图发现 es 客户端可能出现问题时,使用 cursor 将使用到 es 客户端的文件加入 compose。直接询问 api 该文件中的 es 客户端使用哪里有问题让 ai 帮忙查找。

kubectl

kubectl 相关操作
当k8s中有进程挂了,通过 docker logs 查看不到具体原因,
可通过
kubectl get pod -n <<namespace>>
命令查看当前 pod 状态
是否和镜像有关
如需重启可通过
kubectl rollout restart deployment pod_name -n holdcloud
命令重启,或通过客户端
$sed -i "s/:dev/:$COMMIT/g" k8s.yaml$ ./kubectl --server=10.0.1.1:8080 apply -f k8s.yaml

k8s_del_pod

1、先删除pod2、再删除对应的deployment否则只是删除pod是不管用的,还会看到pod,因为deployment.yaml文件中定义了副本数量

实例如下:

删除pod

[root@test2 ~]# kubectl get pod -n <>
NAME READY STATUS RESTARTS AGE
jenkins2-8698b5449c-grbdm 1/1 Running 0 8s
[root@test2 ~]# kubectl delete pod jenkins2-8698b5449c-grbdm -n jenkins
pod “jenkins2-8698b5449c-grbdm” deleted

查看pod仍然存储

[root@test2 ~]# kubectl get pod -n <>
NAME READY STATUS RESTARTS AGE
jenkins2-8698b5449c-dbqqb 1/1 Running 0 8s
[root@test2 ~]#

删除deployment

[root@test2 ~]# kubectl get deployment -n <>
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
jenkins2 1 1 1 1 17h
[root@test2 ~]# kubectl delete deployment <> -n <>

再次查看pod消失

deployment.extensions “jenkins2” deleted
[root@test2 ~]# kubectl get deployment -n jenkins
No resources found.
[root@test2 ~]#
[root@test2 ~]# kubectl get pod -n jenkins
No resources found.

openssl

mac 中 ln -s /usr/xxx/openssl /usr/bin/openssl 提示无权限
可使用
ln -s /usr/xxx/openssl /usr/bin/local/openssl

max_user_watches

使用npm 或者 nodemon 启动项目发现 报错 System limit for number of file watchers reached
使用node不会报错

经常会报这个错误,出错原因大致意思是文件监控数量超过了系统限制。其实就是打开的文件过多导致的,不管是什么文件,只要有进程在,就是一个file watchers,临时解决办法就是关掉几个进程,再运行npm start,就好了,但是等到系统开启的进程一多起来,再次运行又有可能出现同样的错误,为了永久解决这个问题,必须修改系统参数。
系统默认的参数可以在/proc/sys/fs/inotify/max_user_watches变量中看到,默认是8192。

修改/etc/sysctl.conf文件,在末尾增加一行记录:
1
fs.inotify.max_user_watches=524288

sudo sysctl -p

线上数据库更改结构工具

#!/bin/bash

1 首先安装 percona-toolkit_3.3.1

— wget https://downloads.percona.com/downloads/percona-toolkit/3.3.1/binary/debian/xenial/x86_64/percona-toolkit_3.3.1-1.xenial_amd64.deb
解压工具包 dpkg -X ./percona-toolkit_3.3.1-1.xenial_amd64.deb percona
工具使用位置为 /percona/usr/bin/pt-online-schema-change

2 按照文档提示使用工具会提示缺少依赖包

安装依赖包
sudo apt-get install perl-DBD-MySQL
E: dpkg 被中断,您必须手工运行 ‘sudo dpkg –configure -a’ 解决此问题。

执行脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 数据库配置
table=bucket_
cnn_host='10.0.0.1'
cnn_user='root'
cnn_pwd='xxx'
cnn_db='mydb'
# 工具地址配置
pttoolbash=/usr/yupoo/app/percona/usr/bin/pt-online-schema-change
<!-- 例子 向 bucket_ 表中插入account_id以及自增id -->
for conment in "ADD COLUMN id bigint(20) NOT NULL unique key AUTO_INCREMENT" "ADD COLUMN account_id bigint(20) NOT NULL DEFAULT '0' COMMENT '用户id'" "ADD INDEX bucket_account_id_IDX(account_id,bucket_id)"
do
alter_conment=${conment}
echo 开始处理表 "$table" 执行脚本 "$alter_conment"
$pttoolbash --charset=utf8 --no-version-check --user=${cnn_user} --password=${cnn_pwd} --host=${cnn_host} --port=3306 D=${cnn_db},t=$table --alter "${alter_conment}" --execute
echo ${var}
done

get请求中的url参数特殊符号

在http请求中使用get传参需要注意 ,url参数中有+、空格、=、%、&、#等特殊符号可能在服务器端无法获得正确的参数值。
原因是 Url 的编码格式采用的是ASCII码,而不是Unicode,会将特殊符号进行转码,+ url中代表空格,故而,如果url传入+,则会自动转成空格。

使用get传参,不要使用此列特殊符号。 如必须使用则需要转换。

将这些字符转化成服务器可以识别的字符,对应关系如下:

符号 描述 替代
+ URL 中+号表示空格 %2B
空格 URL中的空格可以用+号或者编码 %20
/ 分隔目录和子目录 %2F
? 分隔实际的URL和参数 %3F
% 指定特殊字符 %25
# 表示书签 %23
& URL 中指定的参数间的分隔符 %26
= URL 中指定参数的值 %3D