前两篇文章我们分别从软件、硬件角度讲述了模块重启的原因和解决方法。本文作为该系列的终篇,将详细说一下如何应对,让重启损失减到最低。
鲁棒性
提高鲁棒性才是最根本目标。为了达到这一点,应对代码进行反复测试,才能把大多数隐患解决掉(某哲人说过,当你发现一个bug,那么还有10个隐含bug未被发现)。只有通过各种极端环境下的测试,才能确保上线无忧。
发个GPRS DTU的测试表,大家体会一下:
项目 | 测试目的 | 测试方法 | 评测标准 | 结果判断标准 |
在线空闲测试 | 测试GPRS DTU维持已建链路的能力。GPRS DTU通过心跳保持连接 | 连上数据中心后不发任何数据,观察它能维持链路多久 | 应至少能维持平均1小时以上的链路持续时间,不发生断线重连 | 如果DTU或数据中心任何一方无法收到对方的数据包,则为不合格 |
数据中心关闭后恢复测试 | 测试GPRS DTU在数据中心中断服务并恢复后的快速响应、恢复能力 | 数据中心短时间关闭(如1分钟);数据中心长短时间关闭(如1小时); | DTU是否能快速连接上来,恢复时间应该在5分钟内,越快越好,(重复多次该项测试) | DTU必须能100%恢复连接,否则为不合格 |
频繁双向小数据量测试 | 测试GPRS DTU频繁收发小数据包的能力 | 在数据中心和DTU端,每10秒向对方发送一个100字节左右的数据包,持续10分钟 | 没有发生断线重连,也没有丢失任何数据包 | 如果出现DTU断线后再也不上线,或上线后无法继续双向收发数据,出现丢包,内容错误,即为不合格; |
双向大数据压力测试 | 测试GPRS DTU频繁收发大数据包的能力 | 在数据中心和DTU端,每2秒都向对方发送一个1000字节左右的数据包,持续30分钟 | 没有发生断线重连,也没有丢失任何数据包 | 如果出现DTU断线后再也不上线,或上线后无法继续双向收发数据,出现丢包,内容错误,传输过慢,即为不合格; |
重复上电测试 | 某些时候,现场会出现临时断电然后恢复的情况,GPRS DTU应能保证可靠的登录数据中心 | 上电,然后等待GPRS DTU连接上数据中心,每次DTU都能在2分钟内登录到数据中心 | 重复进行20次测试 | 一旦发现有一次DTU始终无法连接到数据中心,则为不合格 |
拨号及短信干扰测试 | DTU登录或在线运行过程中,可能会收到一些不明短信或电话呼叫, GPRS DTU应能保证这些情况不影响其正常工作 | 将DTU上电,然后等待10秒左右,开始向DTU发送2条短信,以及2次呼叫, | DTU应能正确的连接上数据中心,重复进行20次测试 | 一旦发现有一次DTU始终无法连接到数据中心,则为不合格 |
看门狗测试 | 有良好看门狗机制的产品,在DTU死机时,能使其CPU复位 | 瞬间短路几个管脚,让其程序跑飞,或者RAM数据错乱,使看门狗介入工作,复位CPU | 重复多次测试该项,DTU必须能100%复位 | 如果不能复位则不合格 |
去卡测试 | SIM卡短时接触不良,GPRS DTU应能自动恢复 | 在GPRS DTU连接数据中心时,短时、长时取卡,然后再插卡,看GPRS DTU是否会掉线及正常收发数据 | 应可连接到数据中心,正常收发数据 | 如果不能连接到数据中心,或者收发数据,则不合格 |
电源波动测试 | 可能出现较大范围的电源波动,GPRS DTU应能适应这种电源波动 | 模拟允许值范围内的电压波动,和低压情况 | GPRS DTU是否会出现再也无法连接数据中心的情况 | 如果不能连接到数据中心,或者收发数据,则不合格 |
欠费测试 | 常年运行过程中,很可能会出现因SIM卡欠费,导致无法使用GPRS业务,在进行充值后,GPRS DTU应自动恢复与中心的连接 | 找一张欠费的SIM卡插入GPRS DTU,等待10分钟,给SIM卡充值,看DTU是否能自动连接到数据中心 | 如果DTU始终无法自行连接数据中心,并且必须要人工复位一次才能恢复连接到数据中心,则视为不合格 | |
域名解析测试 | 由于域名解析服务存在临时失效的情况,因此在使用域名解析时,需要加测这个项目 | 域名失效模拟,恢复域名的指向,然后观察DTU是否能自动连接到数据中心 | 恢复时间越短越好 | 如果DTU始终无法自动连接数据中心,则为不合格 |
去天线测试 | 常年运行过程中,很可能会因信号问题(基站或天线)导致无法使用GPRS业务,在信号恢复后,GPRS DTU应自动恢复与中心的连接 | 去掉天线,模拟信号丢失情况。等待10分钟,重新插入天线,看DTU是否能自动连接到数据中心 | 如果DTU始终无法自行连接数据中心,并且必须要人工复位一次才能恢复连接到数据中心,则视为不合格 |
一个 GPRS DTU 的测试尚且如此,更复杂的项目,需要测试的内容也更多。只有通过了测试,代码稳定运行不出错,才能顺利上线。
关于这方面呢,开发者可以阅读一下《Unix编程艺术》、《人月神话》、《黑客与画家》、《程序员修炼之道》、《软件随想录》等书籍。
LED
毕竟,有些时候的测试环境还是偏于理想化,而实际场景千差万别。会有很多意想不到的bug出现,而现场往往是没有调试的机会,甚至只能“盲·Debug”,这种情况下怎么办呢?
开发者可以在写代码时,定制LED闪烁规则,使用GPIO控制LED闪烁。如此一来即便是完全不懂的人,通过观察LED情况,查表也能知晓当前设备的状态了。譬如:
绿灯频闪——未附着;
绿灯慢闪——正在附着;
绿灯爆闪——系统错误;
绿灯常亮——附着成功,可以正常通信;
绿灯熄灭——无卡;
绿灯呼吸——正在通信;
实际上,通过控制电压域,甚至还可以实现不同亮度。
根据LED闪烁情况和现场实际环境,开发者大致可以锁定问题所在,后续使用OTA升级修复bug。
不得不重启
某些极为特殊的情况下,模块“不得不重启”(比如人工断电),那么如何记录运行状态,并保证启动继续运行,就成了研究的重点。
如果有电池,切换到电池供电的情况下,立即上报工作状态到云端。等待再次开机后,从云端获取工作状态并继续。如果没有电池,那么定期保存工作状态到配置文件似乎成了唯一的选项(请参考nvm demo)。
工作时,定时保存工作状态到模块内(10w次擦写+均衡磨损技术,不需要担心寿命问题),意外掉电时,至多损失某定时保存前的数据;模块上电开机后,首先读取配置文件,恢复工作状态,不会影响模块继续运行。
不过这里还有几个坑:
1、读写中,意外掉电导致的文件损坏;
2、计时器的时间戳变动;
3、待处理的数据。
关于“坑1”,nvm.lua 已经最大限度规避了。大致思路如下:
更新参数时:
1.新建一个param.temp的文件,将nvm_para.lua的文件内容与更新的内容合并好,写入param.temp
2.删除nvm_para.lua
3.将param.temp更名为nvm_para.lua
开机时的处理:
1.如果nvm_para.lua存在,而param.temp不存在,不用做特殊处理;
2.如果nvm_para.lua存在,而param.temp也存在,删除param.temp;
3.如果nvm_para.lua不存在, 而param.temp存在,将param.temp更名为nvm_para.lua;
4.如果两者都不存在,恢复默认值;
感兴趣的童鞋可以去阅读nvm.lua的代码。
关于“坑2”,此计时器是指“基于时间戳的延迟N秒开启关闭某业务”。必须由配置文件的3个参数进行控制,即开始时间、持续时间、关闭时间、当前状态。其中,“持续时间”和“关闭时间”是互斥的。
例如,我要设置一个当前立即开始,延迟5分钟关闭gpio0输出的计时器,那么这四个变量应如下设定:
当前时间 = ??? —当前模块时间戳,应定期更新
开始时间 = os.time() —根据当前时间戳设定数值
持续时间 = os.time() + 300 —当前时间戳 + 持续时间,设定数值
关闭时间 = 0 —因“持续时间”已设定,所以“关闭时间”置0
当前状态 = True —当前的状态,开启/关闭
随后代码轮询是否到达“持续时间”的设定值。如果到达,则执行对应操作(如果设定“关闭时间”,则“持续时间”应为0)。
一切看似很美好,但是问题来了:一旦意外重启,模块的os.time()返回值必然出错,那么如何处理?答案并不复杂:上电开机后先根据“当前状态”参数去执行对应操作,打开gpio输出;然后重新设定:
当前时间 = ??? —当前模块时间戳,应定期更新
开始时间 = os.time() —根据当前时间戳设定数值
持续时间 = os.time() + “持续时间”–“当前时间”
—重新设定持续时间
关闭时间 = 0 —因“持续时间”已设定,所以“关闭时间”置0
当前状态 = True —当前的状态,开启/关闭
随后代码轮询是否到达“持续时间”的设定值即可。当然,更稳妥的方式是把计时交给服务端,完全受控即可避免计时出错的尴尬。
关于“坑3”,就是未发出的数据(uart、socket、mqtt等),如果是非重要数据,丢就丢了吧……如果是比较重要的数据,同样可以使用nvm保存,上电后读取并继续处理。
最后,送给大家一个法宝,放在代码里,保证无bug哦:
神马?你看到的是乱码?好吧,bug太多,佛祖已瘫……
–[[ _ooOoo_
o8888888o
88″ . “88
(| -_- |)
O\ = /O
____/`—‘____
.’ \| |//
`.
/ \||| :
|||// \
/ _||||| -:- |||||- \
| | \\ – ///
| |
| _| ”-–/” | |
\ .-__ -
___/-. /
___. .'<span> </span>/--.--\<span> </span>
. . __
.”” ‘<
`.___<|>/___.’
>'””.
| | : - \
.;\ _ /
;./ -
: |
|
\ \ -.<span> </span>\_ __\ /__ _/<span> </span>.-
/
/
-.____
-._____/.-`____.-‘
`=—=’
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
佛祖保佑 永无BUG ]]