GithubHelp home page GithubHelp logo

ageiport's Introduction

AGEIPort Alibaba Generic Export Import Framework

Gitter License

长期招聘,联系邮箱:[email protected]

简介

AGEIPort 是数字供应链孵化并在阿里巴巴集团内广泛使用的一套性能卓越、稳定可靠、功能丰富、易于扩展、生态完整的数据导入导出方案,致力于帮助开发者在toB复杂业务场景下能够快速交付高性能、体验优、易维护的数据导入导出功能,如用户页面上的Excel/CSV数据文件上传和下载。目前在阿里巴巴集团内部已有盒马、菜鸟、本地生活、阿里健康、钉钉、淘系等部门有较多使用,并成为多个技术组件的基础底座,经历多次618和双11大促考验,稳定导入导出数据300~400亿条/月。

AGEIPort 基于事件驱动架构设计整体框架,并遵循先进的设计理念:

  1. 透明化的集群/单机执行、串行/并行执行,可以大幅提升数据处理性能,开发者只需关注业务逻辑处理。
  2. 支持实时任务进度计算和反馈,避免MOCK数据处理进度,提升用户体验。
  3. 面向toB复杂业务场景,从多种方式(声明定义、动态定义)、多种维度(配置、插件、策略、SPI)可以满足各种场景的个性需求,可作为平台化、PaaS/SaaS型产品的基础底座。
  4. 沉淀多种组件,多种场景、多种功能开箱即用。
  5. 秉承GitOps设计理念,将相关的不可变基础设施封装在应用Git仓库内部,可以使交付物更快、更稳定和更安全的发布和回滚。
  6. 去中心化架构,业务应用自组集群资源隔离,保证业务功能有较高的隔离性、可伸缩性和可用性。
  7. 标准化任务处流程和代码编写,定义出一个数据处理任务的流程与用户需实现的接口,接口间职责分离,标准化用户导入导出代码的编写,提高代码的可维护性。
  8. 明确业务领域对象,通过设计泛型接口,明确导入导出代码中的领域模型,可以避免业务代码中大量使用Map、JSON传参,提高代码的可维护性。
  9. 记录业务代码执行过程,辅助支持业务代码性能优化

GEI整体架构如图所示

image

代码层面主要主要分为3个模块

  1. ageiport-processor(必须模块),processor模块是框架的核心,对应上图的大部分逻辑。开发者在需要执行数据处理的业务应用中依赖并实现此模块中对应的接口,将业务逻辑编写到接口实现中,任务执行过程中会回调用户实现的接口,向用户的业务代码传输数据执行业务逻辑。processor 模块中包括本地API和HTTPAPI,用户可以在当前或者外部应用调用接口,创建任务实例在processor所在的业务应用创建并执行。
  2. ageiport-task(必须模块),task模块是框架任务处理模块,与数据库交互,向processor模块暴露HTTP接口,以支持processor模块任务执行过程中对任务定义和任务实例进行增删改查。开发者需要部署此模块并连接自己的数据库,设置部署此模块的节点网络(如DNS/K8S Service等)保证processor模块网络访问到此task模块的部署节点
  3. ageiport-web(可选模块),web模块为前端页面提供的HTTP/Websocket接口(如任务创建、查询、上传文件、下载文件等),减少开发者重复开发Controller代码,对应上图中红色部分。若web模块的功能不符合要求用户可以自行编写Controller代码,调用processor模块的HTTPAPI创建任务实例在processor所在的业务应用创建并执行。后续会开源与web模块配套的前端组件,提高开发者生产效率。

基本概念

主任务(Main Task)

执行一次导入导出任务,框架会选择一台业务机器作为主任务机器,主任务机器执行GEI框架的代码,执行一些逻辑包括接受本次任务、任务分片,任务分发、任务进度统计、文件合并等工作。 ps:单机模式主任务和子任务在一台机器

子任务(Sub Task)

子任务是用户逻辑代码的执行者,每个子任务执行的是整体任务的一部分,举个例子,导出1000条数据,如果分成10个子任务执行,每个子任务只负责自己范围的100条数据的导出。默认的子任务是根据totalCount和sliceSize计算得出切分为几个子任务,子任务分片逻辑可自定义。

分片(Slice)

分片顾名思义,就是将一次导入导出的全量数据或条件分成一个个的片段,每个分片是整体的一部分。以导出来说,根据本次导出数据量和配置的分片大小,框架计算总共分多少片,每一片的size和偏移( offset)是多少。

偏移(Offset)

框架中偏移的概念用在分片中,举一个例子,一次导出10000条数据,分片大小为1000,则第一个分片的偏移为0,第二个分片的偏移为1000,依次类推。

动态列(Dynamic Column)

很多场景下导入导出文件的数据列是动态变化的,比如7月8日导出的数据列名称是7.8/7.9/7.10,7月9日导出的数据列名称是7.9/7.10/7.11

泛型参数QUERY

QueryObject,映射到查询参数的类,比如查询参数{"name":"tom"},则QueryObject应包含name字段,前端传递{"name":"tom"}参数时,会构造出一个 name=tom的QueryObject。

泛型参数VIEW

ViewObject,映射到文件中某行数据的类,比如Excel中的每行数据会被构造为这里的一个对象。

泛型参数DATA

DataObject,映射到实际写入数据源或接口的类型,一般是ViewObject执行转换后得到的类型,从文件中读取的数据,很多情况下不能直接插入数据源,需要补齐一些数据,或者添加一些额外的字段,这时候就需要有个补齐或转换操作。如果没有这种需求,V和D可以定义为相同的类型。

快速开始

可以直接下载本项目代码,运行 ageiport-test 中的单元测试用例

请注意运行单元测试时框架会将任务存储在本机内存中、将生成的文件存储在本机硬盘中,在部署应用至生产环境时参考"生产环境部署"文档进行相关调整

可参照下列文档,体验框架的更多特性

API参考文档

生产环境部署

导入样例及文档说明

导出样例及文档说明

集群模式任务执行

谁在使用

阿里巴巴:数字供应链、盒马、菜鸟、本地生活、阿里健康、钉钉、淘系、阿里云

联系我们

目前钉钉群受到了一些管控策略影响暂无,若有问题优先提交Issue。AGEIPort的研发同学会定期解答问题,紧急问题可联系龄一([email protected]

ageiport's People

Contributors

22gnus avatar clsaa avatar hly3825 avatar jadechenfei avatar peterjiao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ageiport's Issues

使用HttpApiTest改造为读取真实的容器应用初始化报错

代码片段

String url = ''http://ageiport-task-server.demo.xxxxx.com.cn";
AgeiPortOptions options = new AgeiPortOptions();
        HttpTaskServerClientOptions clientOptions = new HttpTaskServerClientOptions();
        clientOptions.setEndpoint(host);
        clientOptions.setPort(80);
        options.setTaskServerClientOptions(clientOptions);
        AgeiPort ageiPort = AgeiPort.ageiPort(options);

调试出调用了
请求url http://ageiport-task-server.demo.xxxxx.com.cn:80/v1/CreateTaskSpecification

请求json:

{
    "action": "CreateTaskSpecification",
    "domain": "http://ageiport-task-server.demo.xxxxx.com.cn:80",
    "responseClass": "com.alibaba.ageiport.task.server.model.CreateTaskSpecificationResponse",
    "taskCode": "CSVExportProcessor",
    "taskDesc": "",
    "taskExecuteType": "STANDALONE",
    "taskHandler": "com.alibaba.ageiport.test.processor.core.exporter.CSVExportProcessor",
    "taskName": "CSVExportProcessor",
    "taskType": "EXPORT",
    "timestamp": 0,
    "url": "/v1/CreateTaskSpecification",
    "version": "v1"
}

task-server控制台报错

2023-07-04 23:57:29,986 ERROR [com.ali.age.tas.ser.htt.TaskSpecificationApiV1] (vert.x-eventloop-thread-1) TaskSpecificationApiV1#create failed, request:CreateTaskSpecificationRequest(taskCode=CSVExportProcessor, taskName=CSVExportProcessor, taskDesc=, taskType=EXPORT, taskExecuteType=STANDALONE, taskHandler=com.alibaba.ageiport.test.processor.core.exporter.CSVExportProcessor): javax.persistence.PersistenceException: org.hibernate.HibernateException: java.util.concurrent.CompletionException: org.hibernate.PropertyValueException: not-null property references a null or transient value : com.alibaba.ageiport.task.server.entity.TaskSpecificationEntity.app
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.reactive.session.impl.ReactiveExceptionConverter.convert(ReactiveExceptionConverter.java:31)
at org.hibernate.reactive.session.impl.ReactiveSessionImpl.lambda$firePersist$18(ReactiveSessionImpl.java:685)
at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:930)
at java.base/java.util.concurrent.CompletableFuture.uniHandleStage(CompletableFuture.java:946)
at java.base/java.util.concurrent.CompletableFuture.handle(CompletableFuture.java:2266)

数据库表都是空表,从文档中的建表语句创建的

导出样例报错

version: 0.1.6

java.lang.IllegalStateException: No such extension com.alibaba.ageiport.processor.core.spi.task.callback.MainTaskCallback by name TestMainTaskCallback

导出示例跑不起来

image
如图,这个jar包好像缺失了类
image
导致debug第一步就报错了,麻烦确认下是不是我maven导包的问题导致
image

EventBusManager 类代码存在错误

image

EventBusOptions clusterEventBusOptions = options.getLocal().getEventBusOptions();
应该是 EventBusOptions clusterEventBusOptions = options.getCluster().getEventBusOptions();

导出示例执行报错

version 0.0.1

java.lang.NullPointerException: null
at com.alibaba.ageiport.processor.core.spi.service.TaskServiceImpl.executeTask(TaskServiceImpl.java:41)

AgeiPortOptions.Debug

AgeiPortOptions.Debug debug = new AgeiPortOptions.Debug();
这里的Debug是私有的 我本地做demo的时候会引用不到

ImportProcessor返回的View数据, 无法生成文件

ImportMainTaskWorker.java中doReduce()中对existView赋值逻辑有误,导致View数据, 无法生成文件
image

验证
前提:只有两个子任务
测试代码基于ClusterImportProcessorTest.java改造

public BizImportResult<View, Data> convertAndCheck(BizUser user, Query query, List<View> views) {
      BizImportResultImpl<View, Data> result = new BizImportResultImpl<>();

      List<Data> data = new ArrayList<>();
      for (View view : views) {
          Data datum = new Data();
          datum.setId(view.getId());
          datum.setName(view.getName());
          datum.setGender(view.getGender());
          data.add(datum);
      }

      result.setData(data);
      ImportSubTaskContextImpl context = getContext();
      String subTaskId = context.getSubTask().getSubTaskId();
      String no = subTaskId.substring(subTaskId.lastIndexOf("_") + 1);
      // 第一个子任务输出View
      if ("1".equals(no)){
          result.setView(views);
      }else{
          // 最后一个子任务没有输出View
          result.setView(new ArrayList<>());
      }
      return result;
  }

导入测试文件ClusterImportProcessor.xlsx

测试结果:
image
image

LocalMemoryBigDataCache导致的内存泄露

在执行Standalone模式的Processor时,subtask使用LocalMemoryBigDataCache作为缓存,但是在MainTask进行merge操作之后,并没有清理缓存,最终导致这部分内存无法回收。
com.alibaba.ageiport.processor.core.task.exporter.worker.ExportMainTaskWorker#doReduce
image

Jprofiler的最大对象显示LocalMemoryBigDataCache占用内存
image
老年代内存占满,且gc无法回收这部分内存
image

能批量导入图片吗?

我们会有很多图片压缩成zip。服务端需要解压Zip,拿到一张张图片,服务将图片一张张上传到文件中心获得文件ID,根据规则解析图片名称,将文件ID按照要求存库。不知道这个框架能否导入含有图片的ZIP包

导入时存在错误数据并设置导出错误数据时有问题

在分为多片导入时,其中一个子任务存在错误,并将错误数据进行导出时,主任务结束后
com.alibaba.ageiport.processor.core.task.importer.worker.ImportMainTaskWorker#doReduce方法中
image
由于循环导致最后的existView变量为false而无法生成错误数据的文件。

ExcelFileWriter的空指针问题

AGEIPort版本:0.0.9
问题:执行非MultiSheetExportProcessorTest以外的测试用例都会失败,原因NPE
错误堆栈:
17:35:41.685 [AGEI-MainWorker-t-2] DEBUG com.alibaba.excel.context.WriteContextImpl - Initialization 'WriteContextImpl' complete 2023-01-11 17:35:41.687 [AGEI-MainWorker-t-2] ERROR c.a.a.p.c.t.exporter.worker.ExportMainTaskWorker - StandaloneExportMainTaskWorker#doReduce failed, main:20230111173540-65bdcde1 java.lang.NullPointerException: Cannot invoke "java.util.Map.get(Object)" because "meta" is null at com.alibaba.ageiport.processor.core.file.excel.ExcelFileWriter.write(ExcelFileWriter.java:85) at com.alibaba.ageiport.processor.core.task.exporter.worker.ExportMainTaskWorker.doReduce(ExportMainTaskWorker.java:194) at com.alibaba.ageiport.processor.core.spi.task.factory.MainTaskWorker.run(MainTaskWorker.java:34) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) at com.alibaba.ageiport.common.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly(TrustedListenableFutureTask.java:95) at com.alibaba.ageiport.common.concurrent.InterruptibleTask.run(InterruptibleTask.java:50) at com.alibaba.ageiport.common.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:49) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833) 2023-01-11 17:35:41.688 [AGEI-MainWorker-t-2] INFO c.a.a.test.processor.core.TestMainTaskCallback - ---beforeError:20230111173540-65bdcde1 2023-01-11 17:35:41.690 [AGEI-MainWorker-t-2] INFO c.a.a.p.core.spi.task.monitor.TaskStageEvent - main:20230111173540-65bdcde1, stage:执行失败, cost:-ms 2023-01-11 17:35:41.690 [AGEI-MainWorker-t-2] INFO c.a.a.test.processor.core.TestMainTaskCallback - ---afterError:20230111173540-65bdcde1 2023-01-11 17:35:41.690 [AGEI-eb-local-t-2] INFO c.a.a.p.core.task.monitor.TaskProgressServiceImpl - update progress, main:20230111173540-65bdcde1, stage:执行失败 17:35:41.910 [AGEI-MainWorker-t-2] DEBUG com.alibaba.excel.context.WriteContextImpl - Finished write. 17:35:41.937 [main] INFO com.alibaba.ageiport.test.processor.core.TestHelper - getTaskProgress, percent:1.0, stageName:主任务执行失败

空指针原因:ExcelFileWriter执行write函数时未对meta进行判空或者初始化。只有需要多sheet页导出时,在实现ExportProcessor的group方法时才会设置meta数据,其余场景未设置meta的ExportProcessor在执行时都会由此问题。
修改建议:判空然后初始化meta
image

请教

开发者,你好,我完全按照你的导出示例来跑,还是会报出:java.lang.NullPointerException: null at com.alibaba.ageiport.processor.core.spi.service.TaskServiceImpl.executeTask(TaskServiceImpl.java:41)的错误,名称我都核对了,请问为啥呢?

关于使用的一些问题请教

1.测试类中的示例最终好像都是基于反射调用的,这样对于使用 spring 管理的 bean(比如使用 @resource 或者 @Autowired 修饰),反射构建执行时会报出空指针,因此需要对实现类做特殊处理,请问有比较优雅的使用示例嘛,求解
image

2.测试示例的使用方式就是生产使用的最终形态嘛,是否有其他构建和调用的方式,如果有,方便给出示例不
image

导出示例问题一大堆 遇到的问题的解决办法 最后 建议文档进行修改以及完善

1、TestHelper中 assertWithFile和assertWithoutFile 方法中 GetTaskProgressParam 这个类有误
解决办法: 将其修改为TaskProgressParam 而不是GetTaskProgressParam
2、重点 扩展类找不到 文档中的描述

  1. 项目目录的resources文件夹下创建META-INF文件夹
  2. META-INF文件夹下创建名为com.alibaba.ageiport.processor.core.Processor的文本文件
    解决办法 一路debug下去发现 扩展类要放到 resources/META-INF/ageiport 目录下扩展类才能被加载到
    image

可使用如下方式测试扩展有无加载成功

@Slf4j
public class StandaloneExportProcessorTest {
   
    @Test
    public void test1() {
        Set<Processor> instances = ExtensionLoader.getExtensionLoader(Processor.class).getSupportedExtensionInstances();
        log.info(instances);
    }
}

也可以查看打印的示例是否是自己的
3、导出测试类中报错

AgeiPortOptions.Debug debug = new AgeiPortOptions.debug();
#不存在这个属性。。
options.setDebug(debug);

解决办法:注释掉即可
3、依赖下载不到 (可能是网络原因?)

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>ageiport-processor-core</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <scope>compile</scope>
</dependency>

官方文件推荐如上 依赖无法下载
解决办法:源码构建 在主pom ageiport-parent 中注释掉maven的插件 maven-gpg-plugin 和 maven-javadoc-plugin (可选 不然可能遇到很多坑。。需要使用经验)
源码构建成功 install到本地 可直接使用

<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>ageiport-processor-core</artifactId>
      <version>0.0.4</version>
      <scope>compile</scope>
</dependency>

4、示例无法跑起来 以及没有正确的配置步骤
遇到agei-server-task 未配置的问题

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.