服务出错排错方法(持续更新)

2022-12-28 12:12:17 浏览数 (1)

撸代码这么久,从之前简单的脚本,到单体应用,到最后的微服务,我们的应用总会因为各种奇奇怪怪的原因罢工,有些错误显而易见,而有些错误也会让人一时摸不到头脑。究其原因,还是需要加强自己的修养,多多总结,就能做到防患于未然。

下面老高会总结一些平时遇到的问题,以及对应的解决思路和方法,同事也欢迎大家补充!

环境类问题

环境问题是一个比较宽泛的概念,如果把一个应用比作一个人,程序的运行就比作去工作,对应人类的办公室。

最常见的办公室就是你的开发机了,可以理解为应用在在家办公

有钱的公司会给自己的所有应用租一栋大楼,然后把应用合理规划到大楼的各个办公室,而像老高这种码农,也就租的起一个路边摊了。。。

这二者的差别在哪儿呢?打个比方,如果大楼失火了,如果是大公司,有自己的灭火团队,可能作为员工的"应用",感知到的是个别办公室暂时无法使用,被分配到别的场地办公,等火灭了,就自动回迁。如果是老高的路边摊出了问题,那我的网站你都打不开了(不会自动恢复)。

系统

系统决定了你的应用的办公舒适度,他可以为应用提供各种支持,比如大仓库(大硬盘),24小时监控、保安巡逻(监控告警) 等等。

硬盘

如果服务突然出现了应用卡顿,首先应该排查应用使用的磁盘空间是否已经所剩无几。

原因有:

  1. 应用都会写本地日志,如果磁盘满的情况,可能会因为所用的日志库不够健壮,导致很多失败,从而影响应用的稳定
  2. mysql磁盘满了,数据写不进去了,更新操作被挂起,导致服务报错
  3. redis配置了持久化,当无写入空间时,redis就无法对外提供写服务了
  4. inode如果超过配额,会导致一种特殊情况,磁盘没有满但无法写入

解决方案:

  • df -h查看磁盘使用
  • df -i查看inode使用情况
  • 关注系统中的大文件
代码语言:javascript复制
# 寻找当前目录下大于1G的文件
find . -type f -size  1G
# 寻找当前目录下大于1G的文件并排序
find . -type f -size  1G  -print0 | xargs -0 du -h | sort -nr
# 查看最大深度为2的文件夹大小
du -h --max-depth=2
  • 为应用预留更大的空间,并且当磁盘空间使用率达到80%需要告警
  • 如果你的应用跑在docker中,那么一定要为容器配置日志限制,否则该容器可能把磁盘用日志打满,另外建议给docker服务手动配置最大日志,方法请自行google。
代码语言:javascript复制
  logging: 
    driver: “json-file” 
    options: 
      max-size: “3m” 
  • 为你的应用选择合适的硬盘,如果你使用了云服务器,一般挂盘会让你选择普通型还是高性能型,这里的衡量标准是啥?如果你的请求中80% 都是读,那么可以使用普通盘,大于20%的业务请求都是在写入,请使用高性能。
内存

说到内存,老高第一个想到的就是OOM了。。。但是想把OOM讲清楚不是本文的目的。这里就像说一个点,在编程的时候,一定要尽量节省内存,Linux虽然是无私的(Memory Overcommit),你申请的内存的时候"满口答应",但真的等到系统内存不够用的时候,别忘了OMM Killer会来嘎嘎乱杀。

举个golang的demo

代码语言:javascript复制
# snippet 1
response, err = ioutil.ReadAll(resp.Body)

# snippet 2
response := bytes.NewBuffer(make([]byte, 4096))
io.Copy(response, resp.Body)

不知道大家看出来代码1和2的区别没,如果resp.Body投毒,返回会来一个10G的文件,那么代码1会让你的内存瞬间爆掉,而代码二会更加柔性(这种情况在下载文件的时候十分明显)。

内存对齐

平台

k8s/tke
  • 调度超时
  • 健康检查
  • 快速启动
  • 不要用supervisor
  • 超卖问题
  • prestop
  • 内核文件

服务治理

编码类问题

配置错误

配置项本身有问题

老高的业务中不同的环境有不同配置文件,有时会出现某项配置在开发环境,但是测试环境中丢失的问题。

配置编码

业务中有时候会填写DSN(数据源名称),比如:

代码语言:javascript复制
mysql:
dsn://user:password@tcp(localhost:3306)/your_db?charset=xxx
redis://password@127.0.0.1:6379/0

但是密码中可能会出现 =?:等特殊字符,这些字符可能会导致DSN无法解析,比如dsn://user:localhost:3306@tcp(localhost:3306)/your_db?charset=xxx这种,就会比较难解析。

此处就很容易发生错误。

迁移

0 人点赞