日常编程奇葩又常规问题总结
相信大家在日常编程中遇到过不少奇葩问题,第一反应就是不可能,怎么可能会出现这个问题呢?于是抓耳挠腮,带着充满疑惑的问题,四处寻找答案。其实遇到问题并不可怕,可怕的是我们缺少解决问题的信心,正所谓只要思想不滑坡,办法总比困难多。解决问题才是打工人的价值所在,也是个人价值展现的机会。
好了,话不多说,回归主题,本篇是我平时遇到的一些奇葩问题总结,包括同事遇到的问题,只要够奇葩,够古怪,够新颖,会持续收纳更新,建议各位小伙伴关注收藏,以后解决古怪问题、避免踩坑会有很大帮助,并且作为解决问题方法和经验的总结也是挺不错的。
- 问题1 路径正确,并且文件存在,为啥fopen打开失败 ?
文件打开失败,打印 strerror(errno),提示 No such file or directory,打开本地目录,文件明明存在,为啥提示文件不存在呢?
问ChatGPT也不好使,回答的都是常规解答的套话,经过一顿网络搜索,最后找到可能使用 chdir、chroot 函数改变了当前工作目录,于是乎整个工程中搜索通缉 “chdir”、"chroot",但遗憾的是没有找到,然后确认每个链接的库的源代码中进一步查找,最后在 miniunz.c 中找到(minizip是一个开源的解压/压缩库),解压开始时使用 chdir 函数设置当前工作目录,解压完之后再使用 chdir 还原,这个过程中如果刚好使用相对路径打开文件就会失败。另外一种打开失败的情况,可能是权限问题了,此时需要获取权限。
解决方法:打开文件改为使用绝对路径。
- 问题2 Socket 函数返回的描述符怎么是 0 ?
File Descriptor 0、1、2 分别为标准输入、标准输出、标准错误 用的描述符,3及以上则为常规描述符,返回 0 描述符,系统是不是有什么大病呀!
其实不是哈,通过仔细分析代码,后面找到问题原因:关闭 socket 时,将文件描述符赋值为0,再次关闭,就把标准输入文件描述符给关闭了,后面在调用 socket 函数,系统发现0是空闲的,于是就分配给了新的套接字。造成这个问题的本身其实是二次关闭问题,类似 double free。
解决方法:修改关闭逻辑,避免二次释放。
- 问题3 Tcp程序挂掉或重启后,端口为啥不生效?
这个问题是比较常见的,对于有点网络编程经验的同学应该都知道,tcp断开后,连接处于 Time Wait 状态,虽然关闭了fd(close的一端表示后面不再发送数据,还可以接收),但是连接并未完全释放,此时端口仍被占用。
PS:MSL为报文的最大生存时间,RFC 793 中规定MSL时间为 2min,为了保证关闭后消息能送达,TCP 的 Time Wait 状态设为 2MSL 等待时间。
解决方法:连接时使用 setsockopt 设置端口复用。
- 问题4 某源码返回错误,提示 Too many open files ?
在使用 ACL Redis 连接池时,程序运行一段时间后,从连接池获取连接时出错,提示 Too many open files.
这个问题也比较常规,在文件描述符泄露时,直到使用完,再打开文件就会报这个错,由于每次从连接池中取连接对象,用完没有放回池中,导致连接对象中包含的 socket 文件描述符泄露。问题根因其实对源码接口不熟,使用不当造成的。
如果没有fd泄露,仍然报这个错,那就是资源不足了,这个时候可以修改系统配置 vim /etc/sysctl.conf,通过修改 fs.file-max 、soft nofile、fs.nr_open 这三个参数的值来修改进程能打开的最大文件描述符数量,默认最大描述符一般为 1024,可以 ls -l /proc/pid/fd/ 查看当前进程正在使用的fd。
解决方法:从连接池对象中每次 peek 出连接对象,用完再 put 连接对象放回连接池中。
- 问题5 程序被OOM kill掉 ?
你的线上程序有没有在某个深夜突然被 kill 掉,然后接到电话前往公司救火,相信有不少小伙伴遇到过,这个问题非常常见,一般就是内存泄露,导致内存用完,或者申请大内存,系统资源不足,表现出的现象就是内存不够,被系统 Out of memory 机制 kill 了。这两种原因在我这几年中的开发中都遇到过,第一种情况是写文件没有正常关闭,系统缓存中存在大量待写入文件的内存数据,久而久之内存被榨干了;另外一种情况是在 new 一个 kafka 对象时没有申请到大内存失败。
解决方法:避免内存泄露,减少内存碎片,防止申请大内存失败,当然也可以增加内存条。
- 问题6 程序启动时加载动态库报错 file too short ?
问题原因是动态库文件损坏,一般程序在运行过程中突然掉电,或者从压缩包中提取文件、拷贝文件时。
解决方法:动态库损坏的话想办法更新动态库(从其它地方复制过来、系统还原等),软链接问题的话,删除软连接,重新链接。
- 总结:以下是根据个人工作以来总结的一套排查问题的方法,可以结合自己解决问题的思路,取其精华,去其糟粕
- Understand 理解问题。一般问题由客户或者测试提出,为避免问题延伸和理解上不一致,尽量让提问者对问题进行客观描述,避免双方猜测脑补,干扰问题后续排查;
- Check 检查环境。包括硬件环境、程序版本、程序配置,启动方式等,有时一些简单的问题从这一步就能排查出来;
- Analysis 分析问题。通过程序运行时留下的一些蛛丝马迹,比如日志、抓包或者自己加些调试信息来分析程序的执行流程,找到问题原因。对于必现问题,业务流程熟悉的话,看下代码基本就清楚,不熟悉的可话以通过日志或者调试跟踪程序处理流程;对于偶现问题,首先尽可能去复现,然后再根据必现问题的思路来排查;
- Solution 解决方案。查出问题后一般是比较容易解决的,不好解决的话,即时反馈,是规避问题、调整架构、还是引入资源等,讨论出合理的解决方案;
- Execute 根据解决方案指引进行实施,实施完成后务必进行自测验证,很多程序员有时觉得问题简单,改完也不自测就直接上传代码,出现问题后,引起后面一连串的重复工作。问题早发现早解决,避免向下排污。
最后,也希望大家能提出一些类似宝贵问题,我们一起讨论、学习、成长。
本文作者:博客园博主 KeepHopes,对大数据、人工智能领域颇感兴趣,请多多赐教!
原文链接:https://www.cnblogs.com/yuwanxian/p/17717768.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处,谢谢!