如何高效的處理第三方接口數據?

很多公司業務都需要進行第三方接口的對接工作,特別是那種大部分數據都來自第三方的項目。比如亞馬遜商家服務的saas系統,基本上所有的數據都來自亞馬遜平臺。

背景

像這種需要定期獲取亞馬遜接口數據,然後存儲到本地數據庫中的項目,一般就會涉及到數據轉換過程。這邊我將會給大家介紹一個實際項目案例,平臺從亞馬遜獲取數據,進行解析的過程中,因爲數據過大,導致內存溢出的場景。

接口說明

亞馬遜平臺返回的是json格式數據,然後通過jackson進行json解析,將最後的解析結果保存到我們自己的數據庫中。但是json反序列也是需要技巧的,否則會因爲使用不當導致內存溢出。

json解析

一開始我們通過jackson工具類,將json流解析爲JsonNode,如下所示:

ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree((GZIPInputStream) reportMap.get("data"));

但是當請求量過大的時候,內存中就會出現大量的LinkHashMap、Entry、HashMap、Node之類的集合對象,時間一長就OOM內存溢出了。

image

解析改造

集合對象如果沒有管理好,會很難被GC回收,所以一開始我們想到的辦法是將JsonNode設置爲null,後面發現這樣做沒起到任何作用,所以只能進行徹底的改造,直接用jackson解析成我們需要的對象,如下所示:

private List<ReportAdvertisementDto> parseJsonIO(GZIPInputStream gzipInputStream) {
ObjectMapper mapper = new ObjectMapper();
List<ReportAdvertisementDto> advertisementDtoList =new ArrayList<>();
try {
    advertisementDtoList = mapper.readValue(gzipInputStream, new TypeReference<List<ReportAdvertisementDto>>() {
            });
} catch (IOException e) {
    logger.error("parseJsonIO轉化異常,錯誤信息爲:{}", ExceptionUtil.formatException(e));
}
return advertisementDtoList;
}

修改完之後可以很明顯的看到,LinkHashMap、Entry、HashMap、Node之類的對象數量大量減少,內存的佔用率明顯降低,大大的減少了內存OOM的風險。

image

深入改造

寫到這一步是不是就優化完畢了呢?不!!!一開始的時候我是將所有的字段全部設置爲String,然後通過Long.value()和Integer.value()轉換爲數據庫需要的字段類型,如下所示:

campaignSearchTermReport.setImpressions(Integer.valueOf(impressions));
campaignSearchTermReport.setTotalspend(Long.valueOf(cost));
campaignSearchTermReport.setSales(BigDecimal.valueOf(sales));

所以爲了避免這種情況發生,我們需要將轉換的對象字段提前設置好,數據庫需要什麼類型,我們就設置爲同樣的類型,這樣的好處就是我們不需要進行轉型,直接就可以set進去,如下所示:

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ReportAdvertisementDto {
    private double cost;
    private String attributedSales1d;
    private int impressions;
    private int clicks;
    private long campaignId;
    private String campaignName;
    private String adGroupName;
    private long adId;
    private long adGroupId;
    private String sku;
    private String asin;
    private long keywordId;
    private String matchType;
    private String query;
    private String keywordText;
    private int attributedConversions7d;
    private double attributedSales7d;
    private int attributedUnitsOrdered7d;
    private int attributedConversions7dSameSKU;
    private double attributedSales7dSameSKU;
}

總結

在數據量不大的情況下,代碼就算效率不高,也不會出現什麼問題,但是當數據量達到一定級別,代碼問題就會被凸顯出來。比如我們平時用Map來存儲臨時數據,但是map集合的大小要比對象更加佔用內存,如果服務器硬件不高,很容易就發生內存溢出。

所以我們在處理接口數據的時候,一定要本着簡單、適用。儘量不要將json數據解析爲map等集合,對象字段儘量設置爲和入庫的的表字段類型一致,減少轉型的發生。禁止出現大量對象和對象之間數據流轉,儘量做到一個解析後的對象直接入庫,不需要進行任何轉型操作。

想學習分佈式、微服務、JVM、多線程、架構、java、python的童鞋,千萬不要掃碼,否則後果自負~

林老師帶你學編程https://wolzq.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章