以较小的内存占用空间有效地解析Json

时间:2018-08-02 14:56:52

标签: java json scala memory apache-kafka

情况:

我正在编写一个Kafka生产者,该生产者从Web请求中获取Json数据(以大兆字节为单位)。

我需要检查此数据是否有日期字段,并获取最大的日期字段。

接下来,我将Json数组对象切成较小的Json对象(“数据行”),并将它们序列化为avro(通用)记录。

虽然我的应用程序可以运行,但是它为相当轻量的东西使用了很多内存。我怀疑JSON解析是罪魁祸首。

或者,我是没有编写适当代码的人。

问题:

如何减少内存占用量(可能会超过1GB,直到GC出现并节省了一天的时间) 我正在考虑“发现”每个json对象并为每个json对象执行一个操作,而不是阅读全部内容。 但是,我不打算为此编写整个代码库,因为这只需要是一个JSON对象。这必须一般地工作。有我自己的自定义代码,每当出现边缘情况时,仅查找JSON对象就容易出错。

代码

def get(url: String, headers: List[String]): String = {
 val httpEntity = try {
   getRequest(url, headers)
 } catch {

  ....
 }

if (httpEntity == null) return "" 

val inputStream = httpEntity.getContent
    var content = ""
    try {
      content = scala.io.Source.fromInputStream(inputStream,Codec.UTF8.name).getLines.mkString
    } catch {
      case e: Exception => logger.error("can't fetch/parse data from http stream.")
        inputStream.close()
        throw e
    }
    inputStream.close()
    if (content == null) {
      throw new RuntimeException("...")
    }
    //logger.debug(content)
    content
}

这叫做这里:

val stringData= someclass.get(url, headers)
if (!stringData.trim.equals("[]")) parseJson(stringData, "some key", "date found in records","some yyyy/dd stuff here"))

解析代码:

private def parseJson(string: String, keyName: String, dateField: String, format: SimpleDateFormat): (Date, Array[(String, String)]) = {
    val arr = new JSONArray(string)
    val kvList = new ArrayBuffer[(String, String)]
    logger.debug(s"${arr.length} records found, will loop over json objects")
    if (arr.length() > 0) {
      logger.info(s"parsing ${arr.length} records")
      for (i <- 0 until arr.length ) {
        kvList.append((arr.getJSONObject(i).getString(keyName), arr.getJSONObject(i).toString))
      }
       //this is where I go and get the datefield I wanted

      (extractJsonDate.getMaxDate(arr: JSONArray, dateField: String, format: SimpleDateFormat), kvList.toArray)
    } else {
      logger.info("didn't parse JSON, empty collection received in parser.")
      (null, kvList.toArray)
    }
  }

...接下来,我遍历每个对象,将其解析为avro并将其发送到Kafka中,但这不在这里。

1 个答案:

答案 0 :(得分:-2)

我认为有些事情可以为您提供帮助。

  1. 在JVM垃圾收集器中启用字符串重复数据删除

    -Xmx20M -XX:+ UseG1GC -XX:+ UseStringDeduplication

  2. 找到可能更适合您需求的轻量级JSONParser。稍作谷歌搜索将帮助您找到所需的东西。

  3. 在下载兆字节块时,不要将它们全部存储在内存中,而是考虑将它们插入数据库表中。您会导致速度减慢,但不会对内存造成太大的压力。