如何编写避免系统故障的编码准则

2022-03-23  本文已影响0人  尘埃里的玄

第一,不要基于 JSON 格式打印太多、太复杂的日志

假设有一个特别复杂的类,其中包含了几十上百个字段,同时某些字段也是对象类型,该字段又嵌套了很多对象字段。如果在日志输出时,直接将该类通过 JSON 进行序列化,并进行日志输出,伪代码格式如下:

复杂Object obj=new 复杂Object();
logger.info(JSON.toJson(obj));

如果每一次请求,微服务的代码都会按上述格式打印日志,那么当调用量稍微上升时,很容易将微服务的 CPU 占满,进而导致服务宕机。导致上述现象的主要原因是:复杂的对象在序列化时非常消耗 CPU 资源。建议在打印日志时,按需输出。采用 toJson 方式序列化大对象,很多时候因为简单、粗暴,不需要太多开发量,所以就被研发同学大量、广泛地使用,与此同时也带来了系统宕机的风险。两害相较取其轻,建议采用如下按需的方式输出日志,规避宕机风险。

第二,需要具有日志级别的动态降级功能。

假如上述按需输出日志的方式还没有被大家广泛接受,你还是习惯使用 toJson 的方式输出日志。那么为了防止打印日志导致机器宕机,需要在日志输出前进行级别判断,使得当日志打印导致机器出现问题时,通过此方式可以将日志进行关闭。具体写法如下:

if(logger.isInfoEnabled()){
  复杂Object obj=new 复杂Object();
  logger.info(JSON.toJson(obj));
}

当 toJson 的日志打印把 CPU 占满之后,可以将日志级别调整为更高等级,比如 error 级别,禁止日志输出即可规避问题。此外,更进一步的是,此日志级别调整可以开发动态功能,结合配置中心,动态的修改日志级别,可以实现不重启应用即可生效日志级别修改的功能。

第三,for 循环不要嵌套太深,原则上不要超过三层嵌套。

实践中,for 循环迭代的数据是从数据库或远程 RPC 获取的,获取到的数据量是动态的,可多可少,极端情况下可能多达上千条。此时,三层嵌套下的时间复杂度则为:O(1000^3)=10 亿。上亿次的代码执行,分分钟就会把微服务打挂,建议在代码编写时,规避此种写法。

第四,多层嵌套需要有动态跳出的降级手段。

假设业务上无法规避上述的多层嵌套,在实现时,需要在嵌套内部开发主动跳出的降级开关。当上述数据量增多时,此方式可以通过开关主动地跳出嵌套,防止机器宕机。

第五,如果使用应用内的本地缓存,需要配置容量上限。

如果不显式地配置本地缓存的容量上限,有可能因为容量暴涨,导致进程 OOM。因此,需要根据机器的内存大小,显式地配置本地缓存的容量上线。

上一篇下一篇

猜你喜欢

热点阅读