外观
antispam-textclassify — 文本分类检测引擎
分层:检测引擎层 | 部署单元:2 个(另有 3 个有启动类但不构建) | 数据库:TiDB
antispam| base image:base-image:jdk17(构建 tagbase-250409)
一、模块定位与架构
本模块是反垃圾体系中的文本分类检测服务:按业务(targetId)预先配置的文本分类模型清单,把用户文本提交给底层算法引擎(textalg SpamFilterService)做分类,再把引擎返回的命中结果加工成统一的垃圾分级、垃圾类别、二级/三级标签与命中模型 ID,回答「这段文本是不是垃圾、属于哪类、命中了哪个模型」。
架构分层:
- 协议层:
facade/dubbo-check-api(TextClassifyCheckFacade接口)+facade/dubbo-check-provider(检测执行)、facade/dubbo-api+facade/dubbo-provider(模型配置管理)、facade/http-api - 逻辑层:
service/business(component/checker、component/remote、component/listener) - 数据层:
service/base、domain、common - 支撑:
console/api、scheduler、file
关键数据流:
TextClassifyCheckFacade.check(Dubbo 门面)→TextClassifyChecker(按 targetId 缓存)buildCheckConfig(模型筛选 / 白名单 / 降级)→TextClassifyRemoteService.checkTextClassifyDubboCheckService.doCheck→ 算法引擎SpamFilterService.checkhandleActionLevel→handleSubModelResult→ 组装响应- 上游流水线据 level/category 决定放行 / 拦截 / 标记
二、可部署服务清单
| 部署单元目录 | artifactId | 镜像名 | 端口 | 服务类型 | 独立 Dockerfile | 是否进 kubernetes.yml |
|---|---|---|---|---|---|---|
facade/dubbo-check-provider | antispam-textclassify-facade-dubbo-check-provider | antispam-textclassify-dubbo-check-provider | Dubbo 随机(-1) | Dubbo Provider(检测) | 是 | 是(replicas=2) |
facade/dubbo-provider | antispam-textclassify-facade-dubbo-provider | antispam-textclassify-dubbo-provider | Dubbo 随机(-1) | Dubbo Provider(模型管理) | 是 | 是(replicas=2) |
facade/http-api | antispam-textclassify-facade-http | — | 8080 | HTTP | 无(不构建) | 否 |
scheduler | antispam-textclassify-scheduler | — | 无 | 定时任务 | 无(不构建) | 否 |
console/api | antispam-textclassify-console-api | — | 8080 | 控制台后端 | 无(不构建) | 否 |
k8s 镜像地址
private-registry.yidun.internal/yidun/<镜像名>:1.0.0.private。
三、同模块启动顺序
facade/dubbo-provider— 模型配置管理侧先就绪,供 check 侧读取模型元数据。facade/dubbo-check-provider— 检测主体,依赖算法引擎与管理侧数据。
理由:check-provider 的检测器由事件驱动创建并按 targetId 读取模型配置,先起管理侧可减少冷启动期间的「无模型可检测」窗口。scheduler/http-api/console/api 为骨架,不参与线上顺序。
四、逐服务启动逻辑
单元目录 facade/dubbo-check-provider
- 启动类:
com.netease.is.antispam.textclassify.facade.dubbo.CheckDubboApplication(src/main/java/.../textclassify/facade/dubbo/CheckDubboApplication.java,包名无.check后缀) @SpringBootApplication:无 exclude。@Enable*:@EnableAspectJAutoProxy、@EnableBusinessClient、@EnableApolloConfig、@EnableConfigurationProperties({TextClassifyProperties.class, TextClassifyRemoteProperties.class, TextClassifyCheckerDynamicProperties.class})。main():无自定义逻辑,直接SpringApplication.run。- 启动钩子:
ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent>, Ordered:getOrder()=HIGHEST_PRECEDENCE,事件内调用businessClient.start(),外层 try/catch 兜底。TextClassifyRemoteService.@PostConstruct init():@ConditionalOnProperty("app.text-classify.remote.cluster.api-url")门控,用HttpClient4Utils.createNoResponseRetryInstance(maxTotal=600, maxConnPerHost=300, socket=2000, conn=150, connReq=100, retry=1)建 HTTP 客户端。TextClassifyModelCache.@PostConstruct init():两个 CaffeineLoadingCache,maximumSize=1000、refreshAfterWrite=1200000ms。- 检测器
TextClassifyChecker由TextClassifyCheckerManager静态缓存 +TargetCheckerEvent/PreTargetCheckerEvent事件驱动创建,非启动期。
单元目录 facade/dubbo-provider
- 启动类:
com.netease.is.antispam.textclassify.facade.dubbo.DubboApplication(同包) @SpringBootApplication:无 exclude。@Enable*:@EnableAspectJAutoProxy、@EnableBusinessClient、@EnableConfigurationProperties({TextClassifyProperties.class, TextClassifyRemoteProperties.class})+@ComponentScan(basePackages = {"com.netease.is.antispam.textclassify"})(显式扫全模块);无@EnableApolloConfig。business.client.options.operateTargetTypes=LABEL_INFO。main():无自定义逻辑。- 启动钩子:未发现(复用
service/business内组件的@PostConstruct)。
单元目录 scheduler
- 启动类:
com.netease.is.antispam.textclassify.scheduler.SchedulerApplication(.../textclassify/scheduler/SchedulerApplication.java) @SpringBootApplication + @EnableScheduling:无 exclude。main():无自定义逻辑。- 启动钩子:唯一任务
TextClassifyModelDemoTask.@Scheduled(cron="* * * * * *")(每秒打印do,demo 遗留);无 Dockerfile。
单元目录 facade/http-api / console/api
facade/http-api:com.netease.is.antispam.textclassify.facade.http.HttpApplication;端口 8080;无 Dockerfile。console/api:com.netease.is.antispam.textclassify.console.api.ConsoleApplication;端口 8080;无 Dockerfile。
五、启动前置依赖
| 依赖 | 配置键/地址 | 阻塞 or 弱依赖 | 配置文件 |
|---|---|---|---|
| TiDB | spring.datasource.url=jdbc:mysql://tidb-cluster0-tidb.tidb.svc:4000/antispam | 阻塞 | application-private.properties |
| ZooKeeper(Dubbo 注册) | zookeeper://zk-*.zookeeper.yidun-infra:2181,group /yidun/antispam/online-new/yidun-antispam-dubbo | 阻塞 | application-private.properties |
| Apollo | app.id=antispam-textclassify_dubbo-check;namespaces application,application.yml | 弱依赖(bootstrap.enabled=false) | application.properties |
| 业务配置缓存(antispam-business) | business.client.options.zookeeper.address,rootPath=/netease-antispam/online/config | 阻塞 | application-private.properties |
| textalg 算法引擎 | app.text-classify.remote.cluster.api-url=http://textalg-check.yidun-text.svc/filter | 阻塞(检测核心) | application-private.properties |
| Kafka(生产者) | netease.kafka.producer.cluster.[default]... | 弱依赖(白库消息) | application.properties |
| Sentinel | spring.cloud.sentinel.datasource.degrade.file.file=classpath:sentinel/online/DegradeRule.json | 弱依赖 | application-private.properties |
| Redis | 未发现(properties 内无 spring.redis.*) | — | — |
六、启动参数与 Profile
- Spring profiles:默认
dev;容器由JAVA_OPTS覆写-Dspring.profiles.active=private;仓库另含test、online、jiande-online、guizhou-online、guiyang-online、beijing-online、hz-aliyun-online等。 - Maven profile:与上述 online 变体对应。
- JAVA_OPTS:Dockerfile 内
-Xmx512m -Xms512m -XX:+UseG1GC;k8s 覆写为-Xmx1024m -Xms1024m -XX:+UseG1GC -Dspring.profiles.active=private。 - base image 与仓库:
private-registry.nis.netease.com/library/base-image:jdk17;推送private-registry.nis.netease.com/yidun,tagbase-250409。 - 启动命令:
ENTRYPOINT ["bash","docker-entrypoint.sh"],APP_NAME形如antispam-textclassify-dubbo-check-provider。
七、启动期踩坑
apollo.bootstrap.enabled=false(与其它模块相反):application.properties默认关闭 Apollo bootstrap,只有 dev/online 等 profile 才置 true;private 下若需 bootstrap 类配置(如日志/namespace)会不生效。dubbo.provider.warmup=200000+dubbo.consumer.retries=0:滚动发布会期间调用方无重试,易出现瞬时失败。TextClassifyRemoteService由@ConditionalOnProperty("app.text-classify.remote.cluster.api-url")决定是否装配;缺该配置时走另一条检测路径,行为差异隐式。scheduler的TextClassifyModelDemoTask是每秒执行的 demo 遗留任务,空跑产生大量日志。business.client.options.event.excludeListeners=TARGET_CHECKER,PRE_CHECKER:排除检测器事件监听,若业务侧配置变更不重放,检测器实例会错过更新窗口。dubbo.protocal.register=false拼写错误(protocal):该行不生效,Dubbo 注册行为与预期不符(正确键应为dubbo.protocol.register)。ContextRefreshedEventListener在HIGHEST_PRECEDENCE时机调用businessClient.start(),若 business-client 依赖的 ZK 不可用,异常被吞进日志不影响启动,但业务配置缓存为空。dubbo-provider显式@ComponentScan("com.netease.is.antispam.textclassify")扫全模块,与 check-provider 仅@Enable*的装配范围不一致,同一类在不同单元装配结果可能不同。- 两个 Dockerfile 的默认
JAVA_OPTS与 k8s 不一致(镜像 512m / k8s 1024m),本地直跑镜像时易 OOM。
八、跨模块前置
antispam-business:检测流水线经 Dubbo 调TextClassifyCheckFacade.check;发布TargetCheckerEvent/PreTargetCheckerEvent驱动检测器生命周期;本模块读TargetConfigCache/LabelInfoCache/TargetCache/GlobalOptions。textalg-service:底层算法引擎SpamFilterService.check,app.text-classify.remote.cluster.api-url指向的/filter接口。antispam-text-library:白名单库检测TextLibraryCheckFacade.check。antispam-common:SpamType/TextSpamLevel/CheckerType/Env等公共常量。antispam-components-kafka:白库消息KafkaSender.sendMessage。antispam-cms:控制台调TextClassifyModelFacade做模型配置管理。