bug story

主要记录自己在项目中比较记忆犹新的各种bug

####IP 配置
描述
127.0.0.1与eth1的ip弄错。在stage环境上,没有做网络的限制,通过127.0.0.1可以访问到swarm的服务,在线上环境,有网络的限制,还能通过eth1的ip访问到swarm的服务,在数据插入的时候,没有留意,开始以为一直是swarm的问题,后来发现,原来是数据库ip配制的问题。

表面原因,ip配制错误

深层原因,连接信息应该通过环境变量传入进来,比如像数据库连接信息,swarm client 以及 etcd client 这种信息,这个就是代买编写的规范性方面所遇到的问题,连接信息一定要通过环境变量加载进来,或者配置文件,写成配置文件的话,就相当于是启动的时候传入了几个参数。

缺乏容器里外的概念,应用都是在容器里面启动的,127.0.0.1怎么可能访问到容器外面的网络呢,除非都是用net=host的模式。

在stage环境上,竟然加上了net=host参数,但是在线上环境,可能没有加上,还是因为线上环境和stage环境的配置不一致所导致的。

环境变量配置

描述

给原来的老项目中添加一个报警功能,通过docker compose文件的方式来启动,因为要在里面添加一些新的环境变量,修改的时候不够小心,把一个关键的环境变量(原来是true)设置成了truei导致程序启动的时候,每次api返回一个错误。

表面原因,做工作不够细致。深层次原因,程序对于环境变量的检测不到位,没有进行input参数的检测,比如输入的参数如果不是false或者true会怎样,自己输出的日志信息也不够详细,导致出了问题难定位。即使给api返回了错误的信息,也应该在本程序的日志这里留一个对应的记录才行。

之前的程序在给api返回的信息中,指明了环境表变量的问题,但是本身没有log输出,这样就导致了在出现问题之后,很难进行排查。虽然给api也返回了信息,但是显然环境变量这边的信息不是api传过来的,是程序启动时候设置进去的,不管api怎么样,这个参数都是要设置的,这样在程序启动这边,就应该打印有对应的log信息。

json解析的问题

在使用Golang进行json解析的时候,想当然地把结构体中的字段的首字母定义成了小写的形式。老员工仔细看一眼就能看出来,一提醒我我也能知道,但是自己在主动些的时候就是有异常然后json 解析不成功,由于在一个大的已有项目中进行更改很难去把问题限制在一个比较小的范围因此出了问题常常不确定是哪部分导致的,这种字段大小写的问题实在是不应该犯的。

listkeys的问题

在我们的项目中有一个接口是通过输入的volumename查找对应的volumeid,具体实现的逻辑如下,函数的输入参数是searchName,函数逻辑是,先列出当前所有的volume信息,之后对这些volume信息遍历,如果遍历的时候发现volumename==searchName,count+1,如果最后count值==0或者>1就会报错。这样的逻辑其实默认假设了list时候返回的信息是没有重复的,或者说返回的是一个set或是map。然而实际情况是list所有的volume信息的时候,返回的数据是一个list,这个list中出现了好多重复的元素比如[volumeida:volumenamea,volumeida:volumenamea]这样如果searchName是volumeName的话,计数值就为2,然而实际是仅有一个volume的。这就是考虑输入参数不周全的问题。因为涉及多层的调用,所以在调用之前最好是假设对方的接口是不牢靠的,处理之前一定要考虑到各种情况,即使没有办法规避也要留有debug的日志信息。比如这个问题是重新添加了list的打印,然后build代码,放在线上运行才发现原来接口返回的信息本身就有问题(如果接口定义的时候返回一个map或者set也就没有这种问题了),整个过程浪费了好多时间和心力。

==写成了=的问题

这种问题虽然是很基本,但是常常跌倒在这里,有时候感叹,我靠,怎么会是这样,这不科学啊,回过头来再仔细一看原来是==写成了=。对于这种问题,还是老老实实地通过单元测试来解决比较好,不要心存侥幸,觉得自己的程序就没有问题,一定要用测试说话,求是求是,用测试来证明自己的函数没问题,并不是自己拍胸脯随便说说。

c中的segmentation fault的问题

一次是malloc()后面的数字写错了,本来应该是写成 malloc(rindex-lindex)结果写成了malloc(sizeof(rindex-lindex))
一次是空间定义的小了

一个tips就是看上下文,也就是看输入和输出

实在不行就是用笨办法,大致定位到出错的函数,然后打点往下走,看在哪一步的时候程序有报错,这个方法虽然慢一些,但最后往往都能找到出错的地方。

主要是代码常常写的不完整,没有检测函数的返回值,导致即使malloc没有成功也不知道是由于什么原因导致的,直接在malloc的过程中就给报错了。

对malloc这种裸的内存操作一定要对输入参数考虑充分,边界条件考虑清楚。一个是习惯问题,一个是经验问题。

使用多了golang的编程模型就觉得其他的语言各种不严谨与随意,因为golang就是在代码里强制地返回error然后程序必须处理这个error,虽然有时候看起来繁琐,但是可以让所有的可能的问题最准确的定位出来,代码中bug出现的概率首先就小了很多,即使是有错误也能很快定位了。

安装nvidia driver

之前帮同学安装nvidia driver 开始是双系统,每次装好都说有个脚本不能运行然后安装失败,smi无法于nvidia通信, 后来把windows卸载了,只装ubuntu14.04之后又参考了这个教程 https://gist.github.com/wangruohui/df039f0dc434d6486f5d4d098aa52d07 才弄好,主要是在bios设置中有一个secure boot option没有修改, 导致有些内核模块没法写入到系统, 总之driver的问题不仅仅是软件的问题,应该把软件和硬件看成一个整体然后全方位的考虑,暂时先写在这里,万一以后自己也要装driver就省去好多事了,从这个角度看双系统还是有风险的,也可能是driver相互冲突,还是单系统加虚拟机的方式比较好用。