简说代码健壮性

2023-03-21 20:21:21 浏览数 (1)

这两周一直在优化基于sparkStream的实时流,作为一个精致的猪猪程序媛,不堪忍受天天有问题的历史债。bug终于有所收敛,通过博客的形式给各位新手程序员一点点建议吧。。。

接口失败后异常处理

针对第三方接口,例如数据库对象初始化,打开text文件,请求服务等均会存在接口请求或者连接请求失败的情况,请求失败后通用处理方式是捕获异常,然后设置一定的等待时间(避免压力过大,造成接口雪崩),给予合理的重试次数,例如下图中redis对象初始化失败,等待20ms后发起一次重试。

代码语言:javascript复制
     var jedisClient: Jedis = null
      try {
        jedisClient = new Jedis(kvHost, kvPort.toInt)
        jedisClient.auth(kvAuth)
      } catch {
        case e: Exception => {
          println(s"error new jedisClient throw exception: ${e.getMessage} n"   e.printStackTrace())
        }
          // 20ms后重连
          Thread.sleep(20)
          jedisClient = new Jedis(kvHost, kvPort.toInt)
          jedisClient.auth(kvAuth)
      }

资源合理关闭

涉及第三方中间件或者数据库,例如mysql、redis、kafka等,资源对象分配使用完后要记得关闭,否则持续打开不关闭会造成Caused by: java.io.IOException: Too many open files 之类的问题,例如下图中在每个worker上分配 kafka producer对象,使用完毕后及时关掉。

代码语言:javascript复制
    outputData.foreachRDD { rdd =>
      rdd.foreachPartition { partition =>
        val producer = newProducerWithoutClose(outKafkaDesc)
        partition.foreach { record =>
          producer.send(outKafkaDesc.topic, record)
        }
        producer.close()
      }
    }

输入检查

这点写C 的人真应该深有体会,因为多年写C ,且C 中对指针的使用很频繁,所以本人一直保持,所以函数的指针入参在使用前必须检查是否为空,当然这里的输入包括:接口的返回结果,函数的参数,组件的属性等。例如下面对接口输入参数合法性检测,空指针判断等。

代码语言:javascript复制
int32_t DataProcess::VrInfoParse(const SearchRequest& request) {
  if (request.search_ext().find("vr_info") != request.search_ext().end()) {
    std::string vr_info = request.search_ext().at("vr_info");
    // json解析, fill PageInfo
    rapidjson::Document vr_doc;
    vr_doc.Parse(vr_info);
    if (!vr_doc.HasParseError()) {
      if (vr_doc.HasMember("vrid") && vr_doc["vrid"].IsString()) {
        vr_info_.vr_id = vr_doc["vrid"].GetString();
        
    } else {
      log.error("invalid vr info:" << vr_info);
      return -1; 
    }   
  } else {
    log.error("not find vr info");
    return -1; 
  }
  return 0;
}

业务边界

这次在排查调用对象池GenericObjectPool的方法returnObject报错时发现,流量峰值较高Obejct分配达到峰值时,这种情况若设置了对象池MaxIdle,且满足对象池中的idle对象数量大于MaxIdle,则可能导致归还的对象资源被释放掉。如下图所示,所以设置MaxIdle最好结合实际的业务场景,避免过小造成程序core,也避免过大,造成资源浪费。

returnObject源码returnObject源码

程序的边界,这点相信各位在刷leetcode题目的时候也深有体会,此处不在赘述。

最后,给大家的建议是:在排查问题的过程中,一定要深究其原因,看清楚问题的本质原理,切勿图快省事,看得多了遇到问题就能得心应手,信手拈来。同时要思考问题的解决办法是不是有多种,效率是本钱,效率是王道,用低成本修复遇到的问题,自己的人力也就释放了。

0 人点赞