【问题标题】:collect a sequence of paged results ( 776 pages ) from REST API ( JSON response) and insert final result into DB SQL or create csv file从 REST API(JSON 响应)收集一系列分页结果(776 页)并将最终结果插入 DB SQL 或创建 csv 文件
【发布时间】:2021-06-28 09:42:46
【问题描述】:

我正在使用一个从 SQL Server 数据库公开 6212514 行的 Rest API。 REST API 的响应是 JSON,代表数据库行。

要调用此 API REST 并获取孔数据,我在每次迭代中使用通过参数 offsetlimit 进行分页: 例子:

  • 呼叫 1:

http://localhost:8080/myapi/dwcopa/getSlice?**limit**=8000&**offset**=1&buCd=XXX

  • 呼叫 2:

http://localhost:8080/myapi/dwcopa/getSlice?**limit**=8000&**offset**=2&buCd=XXX

。 . .

  • 拨打760:

http://localhost:8080/myapi/dwcopa/getSlice?**limit**=8000&**offset**=760&buCd=XXX

limit 是每次调用 API REST 返回的对象数,offset 是页码

例子:limit = 8000 and offset 1:调用会返回页码1的前8000个json对象

要获得 6212514 行,我需要执行 776 分页/调用客户端 API REST (= 6212514 /8000) 以获取我需要存储在数据库 SQL 服务器表中或使用这些 6212514 行创建 csv 文件的所有结果.

实际上,我在 Spring Boot 应用程序(2.5.1 版)(独立 Spring Boot 而非 REST API)(Java 11 / Spring webflux / Webclient)中使用此代码来使用客户端 REST API 并通过分页获取所有数据:

在服务 JAVA 类中:

我的 Spring Webclient 使用 REST API:

public DwCopaServiceImpl() {
        this.webClient = WebClient.builder()
                .codecs(codecs ->codecs.defaultCodecs().maxInMemorySize(memSize) )
                .baseUrl(API_BASE_URL)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, API_MIME_TYPE)
                .build();
    }

我正在使用 Reactive Mono 来不阻塞调用 API 并迭代所有分页工具,response.isLast() 为 false(此字段表示此页 REST API 是最后一页)

DwCopaEntity 是一个实体,它呈现一行 (JSON) 并包含许多字符串字段:

public Mono<List<DwCopaEntity>> getItems() {
        String url = "/dwcopa/getSlice?limit="+limit+"&offset="+offset+"&buCd="+BUCD;

        return fetchItems(url).expand(response -> {
            if (**response.isLast()** ) {
                return Mono.empty();
            }
            offset += 1 ;
            
            return fetchItems("/dwcopa/getSlice?limit="+limit+"&offset="+offset+"&buCd="+BUCD);
        }).flatMap(response -> Flux.fromIterable(response.getContent())).collectList();
    }

private Mono<ResponseApiNeo> fetchItems(String url) {

    System.out.println(url);
    return webClient.get().uri(url).retrieve().bodyToMono(ResponseApiNeo.class);
}

之后得到所有结果:

writeStreamToFile ( myService.getItems().block().parallelStream().map(data -> data.toString()), "C:\\Users\\myfolder\\Documents\\optfile.txt") ;

我是 webfluxWebclient 的新手。此解决方案需要 25 分钟才能获取所有 Api REST 页面并创建一个未经客户端验证的文件 txt:

多线程有没有更好的解决方案:

  • 分页一个孔休息API REST(760页):(大数据响应:JSON 6 GB)
  • 将所有响应插入 SQL 数据库或创建 csv 文件?
  • 性能至关重要(获取所有数据最多需要 5 分钟)
  • 我应该更正我的代码以提高速度/添加线程吗?

非常感谢您的帮助。

【问题讨论】:

    标签: java spring-boot performance stream reactive


    【解决方案1】:

    您的 API 是否返回计数(无论是自己返回还是通过分页响应的属性)?

    如果是这样(并且您的数据以一致的顺序返回),您可以将总数除以页面大小并生成并发请求块(同时执行 100% 的请求可能会过度加载您的服务和数据库并导致它比按顺序执行所有请求花费的时间更长)。

    然后您需要将所有响应重新组合到正确的位置。

    我假设您无法控制正在使用的 API,否则我建议将其转换为流式端点(但您会遇到长时间运行的操作、中断后恢复等问题)

    【讨论】:

    • 谢谢@jeremyt,是的,我的 API 通过分页响应的属性返回一个计数,您可以将总数除以页面大小并生成并发请求块(同时执行 100% 的请求可能过度加载您的服务和数据库并导致它比按顺序执行所有请求花费的时间更长)。为什么?
    • 假设您调用的 API 没有某种速率限制(获得 HTTP 429 响应表明有),您将遇到瓶颈。 API 将不得不在请求之间分配其资源,这意味着每个请求所花费的时间都比单独执行时要长。如果所需带宽太高,您甚至可能会发现瓶颈是您与 API 的连接。
    • 谢谢,那么在代码源方面的解决方案是什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-24
    • 2016-09-25
    • 2021-06-27
    • 1970-01-01
    相关资源
    最近更新 更多