外观
yidun-export — 异步导出任务中心(任务托管 + SDK + 定时清理)
分层:业务基础服务(导出域)| 部署单元:1 个可构建(另 3 个有启动类不构建,1 个类库)| 数据库:MySQL/TiDB(
export_task/export_task_log)| base image:private-registry.nis.netease.com/library/base-image:jdk8(tagbase-250409)
一、模块定位与架构
把各管理后台“把大批业务数据导出成 Excel/打包文件”这件事抽成通用能力:业务方只引入 yidun-export-client SDK 提交导出动作,任务创建、异步执行、状态回填、下载链接、过期清理全由本服务托管。核心约束是导出记录可追踪、可限流、可清理——清理任务误删会直接让用户已导出的文件永久丢失。
架构分层
- 公共层:
common(Const、ExportStatusEnum、ExportFormatEnum、ExportPhase)、domain(DO/BO) - 数据/服务层:
service/base(ExportTaskDao+ MyBatis Mapper)、service/business(ExportTaskServiceImpl,并行上限与expire默认值) - 门面层:
facade/http-api(ExportTaskController+ 内嵌 3 个 ElasticJob)、facade/dubbo-provider(ExportTaskProvider空实现桩)、console/api(控制台骨架) - 宿主层:
scheduler(空壳)、client(对外 SDK)
关键数据流
- 业务方
ExportTaskClient.export(context, action)→save()登记EXPORTING(1) - 提交线程池执行用户
action→ 成功后finish()回填EXPORT_SUCCESS(2)+ 文件 URL - 查询接口按
effective(export_time + duration)判断下载链接是否仍有效 ExportTaskTimeoutWorker把超时任务置为EXPORT_FAIL(3)(failureReason="导出超时")ExportTaskCleanWorker到期删除记录并清理 OSS 文件;ExportLogCleanWorker清理导出日志- 持久化删除为逻辑删除(
is_deleted=1),查询统一过滤is_deleted=0
二、可部署服务清单
| 部署单元目录 | artifactId | 镜像名 | 端口 | 服务类型 | 独立 Dockerfile | 是否进 kubernetes.yml |
|---|---|---|---|---|---|---|
facade/http-api | yidun-export-facade-http | private-registry.nis.netease.com/yidun/yidun-export-http-api:base-250409 | 8080(tomcat) | HTTP + 内嵌 ElasticJob | 有 | 否(无 kubernetes.yml) |
scheduler | yidun-export-scheduler | 无(不构建) | 无 Web | 定时任务(空壳) | 无 | 否 |
facade/dubbo-provider | yidun-export-facade-dubbo-provider | 无(不构建) | Dubbo port=-1 | Dubbo Provider(桩,且扫描路径错) | 无 | 否 |
console/api | yidun-export-console-api | 无(不构建) | 8080(undertow) | 控制台后端 | 无 | 否 |
client | yidun-export-client | — 类库,不部署 | — | 对外导出 SDK | 无 | 否 |
本仓库无
kubernetes.yml;buildAll.sh用find . -name build.sh只会构建facade/http-api;client是纯 SDK(@EnableExportTask),由上游以依赖方式引入。
三、同模块启动顺序
facade/http-api—— 唯一的真实服务:对外 REST + 内嵌 3 个 ElasticJob(超时/清理/日志清理),是任务落库与调度的唯一入口,必须最先起。facade/dubbo-provider—— 若要对外提供 Dubbo 契约(ExportTaskFacade),需在 http-api 之后起;但见第七节第 4 条,其 Provider 实际不会被扫描。console/api—— 控制台查询壳,按需启动。scheduler—— 空壳,无任务,不需要启动。
理由:任务生命周期与清理都在 http-api 内嵌的 ElasticJob 中运行,scheduler 不承担任何职责;dubbo-provider 与 http-api 共享库表但无强时序,晚起只会让 RPC 短期不可用。
四、逐服务启动逻辑
facade/http-api
- 启动类:
com.netease.is.yidun.export.facade.http.HttpApplication(facade/http-api/src/main/java/com/netease/is/yidun/export/facade/http/HttpApplication.java) @SpringBootApplication:无 exclude@Enable*:@EnableElasticJob(com.cxytiandi.elasticjob.annotation)、@EnableOssClient- 配置类:
FacadeHttpConfiguration(@Configuration+@ComponentScan({"com.netease.is.yidun.export.service","com.netease.is.yidun.export.manager"})+@MapperScan("com.netease.is.yidun.export.dao"));SwaggerConfiguration(@EnableSwagger2) main():有自定义——SpringApplication.run(...)之后ServiceStatus.setStatus(ServiceStatus.STARTED)- 内嵌定时任务(
facade/http-api/src/main/java/com/netease/is/yidun/export/facade/http/task/):ExportLogCleanWorker(@ElasticJobConf(name="exportLogCleanWorker"),默认 cron0 0 0 * * ?,在application.properties)ExportTaskCleanWorker(@ElasticJobConf(name="exportTaskCleanWorker"))ExportTaskTimeoutWorker(@ElasticJobConf(name="exportTaskTimeoutWorker"),isTimeout判定expireTime,无值时退化为exportTime + Const.MAX_EXPORT_TIMEOUT_MINUTE)
- cron 由
elastic.job.<name>.cron注入;未发现ApplicationRunner/CommandLineRunner/SmartLifecycle
scheduler(有启动类,不构建)
- 启动类:
com.netease.is.yidun.export.scheduler.SchedulerApplication;@SpringBootApplication+@EnableScheduling - 配置类:
SchedulerConfiguration(@ComponentScan({"...service","...manager"})+@MapperScan("...dao")) - 无任何任务类(无
@Scheduled/@ElasticJobConf),属空壳
facade/dubbo-provider(有启动类,不构建)
- 启动类:
com.netease.is.yidun.export.facade.dubbo.DubboApplication;@SpringBootApplication+@EnableAspectJAutoProxy - 配置类:
FacadeDubboConfiguration;Provider 类为com.netease.is.yidun.export.facade.dubbo.provider.ExportTaskProvider(@com.alibaba.dubbo.config.annotation.Service(version="1.0.0")),但get()/create()均为空实现(Result.ok()) dubbo.scan.basePackages=com.netease.is.yidun.facade.dubbo.provider(dev/test/online 一致),比真实包路径少了.export→ 该 Provider 实际不会被扫描注册main()仅 run;启动钩子未发现
console/api(有启动类,不构建)
- 启动类:
com.netease.is.yidun.export.console.api.ConsoleApplication;@SpringBootApplication - 配置类:
ConsoleConfiguration、SwaggerConfiguration(@EnableSwagger2);端口 8080(undertow)
client(类库)
@EnableExportTask = @Import(ExportTaskConfiguration.class) + @EnableConfigurationProperties({ExportTaskProperties.class})- 核心类:
ExportTaskClient(@PostConstruct初始化线程池)、ExportTaskContext、ExportLogManager、BatchContext
五、启动前置依赖
| 依赖 | 配置键 / 地址 | 阻塞 or 弱依赖 | 配置文件 |
|---|---|---|---|
| TiDB / MySQL | private spring.datasource.url=jdbc:mysql://tidb-cluster0-tidb.tidb.svc:4000/antispam;online ...yidun-rds-platform-online-jd-30178...:3331/yd_platform;test ...rds-public-test-jd-30108...:3331/platform | 阻塞(Hikari 启动即建池) | application-private/test/online.properties |
| ZK — ElasticJob | private elastic.job.zk.server-lists=zk-0/1/2.zookeeper.yidun-infra:2181;online nisp-zk5..9:2181;elastic.job.zk.namespace=netease-yidun-export-jobs-{dev,test,online} | 阻塞(http-api 内嵌任务) | 各 profile 配置 |
| Kafka | kafka_2.12 依赖存在(spring-boot-starter 侧),无强消费者声明 | 弱 | — |
| OSS / NOS | oss.client.default-instance=yidun、oss.client.instance-map.yidun.endpoint=nos.netease.com | 弱(清理 OSS 文件用) | application.properties |
| Dubbo / ZK | 仅 facade/dubbo-provider:dubbo.registry.address=127.0.0.1:2181 占位 | 阻塞(若部署) | facade/dubbo-provider/application-*.properties |
| Apollo | 未发现 Apollo 配置 | — | — |
注意
application-private.properties的elastic.job.zk.namespace=netease-yidun-export-jobs-online与 online 相同,private 会复用 online 的 ZK namespace。
六、启动参数与 Profile
spring.profiles.active:application.properties默认dev;仓库含default/test/online/private- maven profile(
facade/http-api/pom.xml):default/test/online/private,外加private-bes(排除spring-boot-starter-tomcat,引入com.bes.appserv-web:bes-lite-spring-boot-2.x-starter:9.5.5.002,用宝兰德 BES 替换内嵌容器),但deploy.env仍为private - Dockerfile:
ENV JAVA_OPTS=-Xmx512m -Xms512m -XX:+UseG1GC -Dspring.profiles.active=private;构建时把GIT_COMMIT/BUILD_TIME/GIT_BRANCH写入/app/version.txt - base image 与仓库:
private-registry.nis.netease.com/library/base-image:jdk8;DOCKER_REPOSITORY=private-registry.nis.netease.com/yidun,tagbase-250409 build.sh:MODEL_NAME=http-api、docker buildx build --platform linux/amd64,linux/arm64 --push,随后source ~/.zsh_private && bash $k8s_script_path/podupdate.sh <image> <tag>
七、启动期踩坑
scheduler是空壳,任务是内嵌在 http-api 里:三个 Worker(exportTaskTimeoutWorker/exportTaskCleanWorker/exportLogCleanWorker)都在facade/http-api/task/下由@EnableElasticJob拉起,改scheduler不会有任何效果。- ElasticJob namespace 复用 online:
application-private.properties的elastic.job.zk.namespace=netease-yidun-export-jobs-online,private 部署会与线上任务共用同一 ZK 命名空间,cron 相互覆盖。 - TiDB
socketTimeout=130000抖动易失败:private/test/online 连接串均带connectTimeout=60000&socketTimeout=130000,跨机房抖动时长查询会超时抛出,需靠任务重跑兜底。 main()后置ServiceStatus.STARTED:SpringApplication.run抛异常时该语句不执行,探活将永远失败(这是刻意设计,但让人误以为“进程活着就等于就绪”)。build.sh依赖外部脚本:source ~/.zsh_private与$k8s_script_path/podupdate.sh必须在构建机上存在,且WITH_PULL默认 true(会先cd ..再git pull)。private-bes切换需同步依赖:切到 BES 会 excludespring-boot-starter-tomcat,若忘记引入bes-lite或版本号(bes-lite-spring-boot-2.x-starter.version=9.5.5.002)缺失,将无 Web 容器可启动。- Dubbo 扫描路径写错:
dubbo.scan.basePackages=com.netease.is.yidun.facade.dubbo.provider(少.export),ExportTaskProvider不会被注册,等于没有 Dubbo 服务。 scheduler/dubbo-provider/console/api无 Dockerfile:buildAll.sh只处理有build.sh的目录,这些单元改代码不会产出镜像。
八、跨模块前置
- 上游(SDK 依赖):
antispam-cms、yidun-supervision-cms、yidun-website、antispam-bill、netease-antispam-platform等后台引入yidun-export-client,通过/api/export/task/save|batchSave|finish登记与回填任务。 - 下游(被依赖):
com.netease.is.platform.common(Result/Page/BaseDo/AssertKits)、com.netease.is.tools.http(HttpClient4Utils)、antispam-components-oss(清理文件)、elastic-job(cxytiandi)、MyBatis + MySQL。 - 基础设施前置(阻塞):TiDB 与 ElasticJob 的 ZooKeeper 必须可用——前者启动即建 Hikari 连接池,后者决定
http-api内嵌任务能否注册成功。 - 无强业务模块硬前置:除 DB / ZK / OSS 外,不依赖其他易盾业务模块启动;REST 接口的返回契约(限流阈值、状态码、
expire_time语义)是跨模块契约,改动需兼容上游。
与既有描述差异:既有描述称 Dubbo Provider 为
ExportTaskProvider(并暗示被注册);实际dubbo.scan.basePackages=com.netease.is.yidun.facade.dubbo.provider(缺.export,dev/test/online 一致),该类实际不会被扫描注册,故 dubbo-provider 对外无可用服务。