【问题标题】:Parse Json efficiently with small memory footprint [duplicate]以较小的内存占用有效地解析 Json [重复]
【发布时间】:2018-08-08 17:11:08
【问题描述】:

情况:

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

我需要检查这个数据的日期字段,并获取最大的那个。

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

虽然我的应用程序工作正常,但它使用了相当多的内存来做一些相当轻量级的事情。我怀疑 JSON 解析是罪魁祸首。

或者更确切地说,是我没有编写正确的代码。

问题:

如何降低我的内存占用(在 GC 到来之前可能会飙升超过 1GB 并节省时间) 我正在考虑“查找”每个 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 中发送,但这不是重点。

【问题讨论】:

  • 嗨,汉瓦尔!您可以使用 jsoniter-scala 高效地解析具有 JSON 数组的文件并处理每个元素的数据,而无需将整个文件的内容保存在内存中。 github.com/plokhotnyuk/jsoniter-scala/blob/master/…
  • 看来我需要事先定义类才能让这个库工作

标签: java json scala memory apache-kafka


【解决方案1】:

我认为这里有几件事可以帮助您。

  1. 在您的 JVM 垃圾收集器中打开字符串重复数据删除

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

  2. 找到一个可能更适合您需求的轻量级 JSONParser。用谷歌搜索一下会帮助你找到你需要的东西。

  3. 当您下载兆字节块时,不要将它们全部存储在内存中,而是考虑将它们插入数据库表中。您的速度会有所下降,但不会对内存施加太大压力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-05
    • 2018-10-07
    • 1970-01-01
    • 2017-04-25
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多