外观
netease-antispam — 全媒体反垃圾云服务平台核心(检测接口 / 人工审核 / 运营后台 / 数据流)
分层:业务层(反垃圾平台主体)| 部署单元:14 个独立部署(另 8 类非独立部署单元)| 数据库:MySQL/TiDB
antispam| base image:private-registry.nis.netease.com/library/base-image:jdk8-kylin(部分jdk17-kylin/tomcat8-kylin,tagbase-250409-kylin)
一、模块定位与架构
它承载易盾内容安全的“主干”:客户把文本、图片、直播、点播、音频五类数据经 HTTP 提交进来,机器检测实时判定,机器拿不准的进人工审核,审核结论再经回调交还客户,同时把结果送统计与计费。这一层不负责具体算法能力(文本/图片/音视频检测、敏感词、规则、名单、计费都已拆成独立微服务),而是负责流程编排、审核台、运营后台、配置与数据落库。
架构分层
- 协议层:
netease-antispam-open-api/netease-antispam-inner-api(WAR,对外/对内检测入口)、netease-antispam-platform/*(平台与代理 API,WAR)、netease-antispam-preonline(全流程校验) - 逻辑层:
netease-antispam-base(检测策略引擎:rule / ruleset / strategy / censorstandard 等)、netease-antispam-censor(人工审核台)、netease-antispam-management(运营后台)、netease-antispam-rule/*(规则异步校验) - 数据层:
netease-antispam-async、netease-antispam-ndc(Kafka 消费入库)、netease-antispam-stats(统计)、netease-antispam-calculation(Spark 计算) - 支撑:
netease-antispam-common(SpamType/CensorStatus/TargetTopic/Kafka topic 常量)、netease-antispam-dubbo*(Dubbo 契约与 Provider)
关键数据流
- 客户 HTTP 提交(
/v1..v3/text|image|live|video|audio)→ 认证鉴权 + 限流 + 参数校验 - Kafka(
yidun_text/yidun_image/yidun_live/yidun_video/yidun_audio等 topic 常量在common) async/ndc消费入库;base检测策略引擎按规则/敏感词/名单判定- 命中即自动处置,未命中或不确定 →
censor审核池 → 审核员判定 - 结论经回调返回客户,同时送
stats统计、外部antispam-bill计费 - 配置与策略改动由
management/platform后台落到 DB,经缓存/business.client推给各进程
二、可部署服务清单
| 部署单元目录 | artifactId | 镜像名 | 端口 | 服务类型 | 独立 Dockerfile | 是否进 kubernetes.yml |
|---|---|---|---|---|---|---|
netease-antispam-async | netease-antispam-async | .../yidun/antispam-async:base-250409-kylin | 无 Web | Spring XML 进程(Kafka 消费 + ElasticJob) | 有 | 是(replicas=1,mem 1024/2048,镜像 tag 写 base-250409) |
netease-antispam-censor | netease-antispam-censor | .../yidun/antispam-censor:base-250409-kylin | Tomcat 8080 | WAR + Tomcat | 有(另 Dockerfile-arm) | 是 |
netease-antispam-management | netease-antispam-management | .../yidun/antispam-management:base-250409-kylin | Tomcat 8080 | WAR + Tomcat | 有(另 Dockerfile-arm) | 是 |
netease-antispam-inner-api | netease-antispam-inner-api | .../yidun/antispam-inner-api:base-250409-kylin | Tomcat 8080 | WAR + Tomcat | 有(另 Dockerfile-arm) | 否 |
netease-antispam-platform/netease-antispam-platform-api | netease-antispam-platform-api | .../yidun/antispam-platform-api:base-250409-kylin | Tomcat 8080 | WAR + Tomcat | 有 | 否 |
netease-antispam-platform/netease-antispam-platform-proxy-api | netease-antispam-platform-proxy-api | .../yidun/antispam-platform-proxy-api:base-250409-kylin | Tomcat 8080 | WAR + Tomcat | 有 | 否 |
netease-antispam-dubbo/netease-antispam-dubbo-provider | netease-antispam-dubbo-provider | .../yidun/antispam-dubbo-provider:base-250409-kylin | Dubbo 随机端口 | Dubbo 容器(com.alibaba.dubbo.container.Main) | 有 | 否 |
netease-antispam-ndc | netease-antispam-ndc | .../yidun/antispam-ndc:base-250409-kylin | 无 Web | Spring XML 进程(Kafka 消费 + Dubbo consumer) | 有 | 是 |
netease-antispam-rule/netease-antispam-rule-async | netease-antispam-rule-async | .../yidun/antispam-rule-async:base-250409-kylin | 无 Web | Spring XML 进程(泛化 Dubbo 调用 + ElasticJob) | 有 | 是 |
netease-antispam-stats | netease-antispam-stats | .../yidun/antispam-stats:base-250409-kylin | 无 Web | Spring XML 进程(ElasticJob) | 有 | 是 |
netease-antispam-preonline | netease-antispam-preonline | .../yidun/antispam-preonline:base-250409-kylin | 无 Web | Spring XML 进程(jdk17) | 有 | 否 |
netease-antispam-privatization/netease-antispam-privatization-proxy | antispam-privatization-proxy | .../yidun/antispam-privatization-proxy:base-250409-kylin | 18181 | Spring Boot(jdk17) | 有 | 否 |
netease-antispam-privatization/netease-antispam-privatization-client-scheduler | antispam-privatization-client-scheduler | .../yidun/antispam-privatization-client-scheduler:base-250409-kylin | 8182 | Spring Boot + ElasticJob(jdk17) | 有 | 否 |
netease-antispam-union/netease-antispam-union-admin | netease-antispam-union-admin | .../yidun/antispam-union-admin:base-250409-kylin | 8182 | Spring Boot + ShenYu 客户端(jdk17) | 有 | 否 |
非独立部署类库 / 未构建单元(无 build.sh + Dockerfile,buildAll.sh 的 find . -name build.sh 不会扫到): netease-antispam-common、netease-antispam-base(检测策略引擎 + 全部 application-context-base-*.xml)、netease-antispam-calculation、netease-antispam-open-api(有 web.xml 却无构建脚本)、netease-antispam-dubbo/netease-antispam-dubbo-api、netease-antispam-dubbo-check/*(dubbo-check-provider 有 Main 但无 build.sh)、netease-antispam-privatization-consume、netease-antispam-privatization-server-http、netease-antispam-on-device-check/{admin(8182), http(8180)}。
kubernetes.yml只存在于 6 个单元:async、censor、management、ndc、rule-async、stats。
三、同模块启动顺序
netease-antispam-base所在制品的进程类单元(async/ndc/stats/rule-async)——所有 XML 进程都<import application-context-base.xml>,DB/Redis/AI-Redis/Kafka/Dubbo/OSS 全在这一层起,是其余单元的隐性前置。netease-antispam-dubbo-provider—— 对外暴露检测/查询 Dubbo 契约,censor/management/platform的 consumer 引用它;先注册再启动消费方。netease-antispam-ndc+netease-antispam-async—— 检测与入库管道,Kafka 上游有数据就能跑,但入库先于审核。netease-antispam-stats—— 依赖ndc/async已落库的明细,无明细时统计空跑。netease-antispam-censor—— 审核台,依赖 DB、Redis Session、Dubbo、以及内存缓存预热;前置缺一即失败(见第七节)。netease-antispam-management/platform-*/inner-api—— 纯运营与对外查询,最后。netease-antispam-rule-async/preonline—— 规则校验与全流程验证,属旁路,可独立启停。- 私有化组(
privatization-proxy→privatization-client-scheduler)与union-admin—— 独立业务线,不阻塞主链路。
四、逐服务启动逻辑
netease-antispam-async(Spring XML,非 Spring Boot)
- 启动类:
com.netease.is.antispam.async.Main(netease-antispam-async/src/main/java/com/netease/is/antispam/async/Main.java) main():new ClassPathXmlApplicationContext(new String[]{"application-context-async.xml"})+context.registerShutdownHook()- 无
@SpringBootApplication、无任何@Enable*、无@Import application-context-async.xml:<import application-context-base.xml>+async-elastic-job.xml+application-kafka-producer.xml+application-context-async-consumer.xml;<context:component-scan base-package="com.netease.is.antispam.async">;显式 beanyidunNosService、ossClientHolder、nosBucketManager、productDataCache、targetDataCache、javaappQosConfiguration- 启动钩子:无自定义 Runner;
ProductDataCache等为懒加载 bean(censor 侧init-method="init"的预热在 censor)
netease-antispam-ndc
- 启动类:
com.netease.is.antispam.ndc.Main;main()同构(application-context-ndc.xml) application-context-ndc.xml:base +application-kafka-consumer.xml+application-kafka-producer.xml+application-context-ndc-dubbo-consumer.xml;component-scan com.netease.is.antispam.ndc;beanproductDataCache、javaappQosConfiguration- 无
@Enable*
netease-antispam-preonline
- 启动类:
com.netease.is.antispam.preonline.Bootstrap(带@Slf4j,加载后打印启动日志) application-context-preonline.xml:base +application-context-preonline-dubbo.xml+application-kafka-consumer.xml+application-kafka-producer.xmlcomponent-scan com.netease.is.antispam.preonline,exclude-filter注解org.springframework.stereotype.Controller(DB 进程不注册 MVC)- bean
yidunNosService/ossClientHolder/nosBucketManager/javaappQosConfiguration
netease-antispam-stats
- 启动类:
com.netease.is.antispam.stats.Main(@Slf4j) application-context-stats.xml:base +stats-elastic-job.xml;component-scan com.netease.is.antispam.stats;beanproductDataCache/targetDataCache/javaappQosConfiguration
netease-antispam-rule-async
- 启动类:
com.netease.is.antispam.rule.async.Main(加载application-rule-async.xml) - 该文件没有 import base 顶层 XML,而是逐项 import
application-context-base-database/-redis/-kafka/-dubbo/-ai-redis.xml,再 importapplication-kafka-consumer.xml、application-context-rule-async-consumer.xml、rule-async-elastic-job.xml - 双
component-scan:com.netease.is.antispam.rule.async(排除@Controller)+com.netease.is.antispam.components.recover;另对com.netease.is.antispam.base扫描并exclude-filterregexcom.netease.is.antispam.base.kafka.* - bean:
ruleSetDataCache/targetDataCache/productDataCache/javaappQosConfiguration;consumer 侧对RuleFacade/ValidateFacade/RuleSetFacade/RuleSampleFacade/MatcherFacade使用 Dubbo 泛化 reference
netease-antispam-dubbo-provider(Dubbo 容器,非 Spring Boot)
- 启动类:
com.netease.is.antispam.dubbo.provider.Main,main()直接调com.alibaba.dubbo.container.Main.main(args) - Spring 侧:
application-context-dubbo-provider.xml= base +classpath:dubbo-service-provider.xml+application-context-dubbo-provider-consumer.xml+application-kafka-producer.xml;beandubboQosConfiguration - 无
@SpringBootApplication;Dockerfile 未设置JAVA_OPTS
netease-antispam-censor / -management / -inner-api / platform-api / platform-proxy-api(WAR + Tomcat)
- 均为 WAR:
src/main/webapp/WEB-INF/web.xml,无 Java 启动类 web.xml(censor 实测):contextConfigLocation=classpath:application-context-censor.xml+ContextLoaderListener+Log4jServletContextListener;DispatcherServletservlet 名nac、load-on-startup=2,映射*.html/*.json//webSocket/*//health/{active,online,offline,check,status};Filter 链CharacterEncodingFilter(UTF-8,force)→springSessionRepositoryFilter→requestContextFilter→springSecurityFilterChain→log4jServletFilter;401/403/404/500 与Throwable错误页指向/common/*.htmlapplication-context-censor.xml关键组件:component-scan com.netease.is.antispam.censor、base、application-context-censor-security.xml(Spring Security)、application-context-censor-dubbo-consumer.xml、application-kafka-producer.xml;RedisHttpSessionConfiguration(maxInactiveIntervalInSeconds=3600, redisNamespace=antispam-censor);init-method="init"的内存缓存TargetMemoryCache/ProductMemoryCache/ImageConfigGroupCache/RuleSetMemoryCache/ProductGroupMemoryCache(启动即预热);<task:executor id="asyncExecutor" pool-size="1" queue-capacity="200"/>+task:annotation-driven- 构建期做环境覆盖:
mvn war:exploded后把WEB-INF/classes/conf/${BUILD_ENV}/*拷回classes/,产物ADD ./target/<APP_NAME> /usr/local/tomcat/webapps/ROOT
netease-antispam-privatization-proxy
- 启动类:
com.netease.is.antispam.privatization.proxy.PrivatizationProxyApplication @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})+@EnableApolloConfig+@EnableOssClient+@EnableRecoverComponent- Dubbo:
dubbo.application.name=antispam-privatization-server-proxy、protocol.port=-1、protocol.threadpool=simplefixed;Redis Cluster(lettuce,spring.redis.cluster.nodes=10.196.38.116:6301,...);Kafka producer + consumer 双启 main()仅SpringApplication.run;启动钩子未发现
netease-antispam-privatization-client-scheduler
- 启动类:
...privatization.client.scheduler.PrivatizationSchedulerApplication;@EnableElasticJob+@SpringBootApplication - 任务:
strategyDataSyncWorker、privatizationConfigSyncWorker(cron=0 0/1 * * * ?、overwrite=true、当前disabled=true) server.port=8182;Redis Cluster 同上;dubbo.protocol.port=-1- 启动钩子未发现
netease-antispam-union-admin
- 启动类:
...union.admin.AntispamUnionAdminApplication;仅@SpringBootApplication,无任何@Enable* server.port=8182;集成 ShenYu 客户端:shenyu.register.registerType=http、contextPath=/${spring.application.name}、appName=${spring.application.name}- Apollo:
app.id=antispam-union、namespaces=application,admin - 启动钩子未发现
五、启动前置依赖
| 依赖 | 配置键 / 地址 | 阻塞 or 弱依赖 | 配置文件 |
|---|---|---|---|
| Apollo | app.id(如 antispam-censor-web/antispam-async),apollo.meta=http://yd-apollo-config.nistest.service.163.org | 阻塞 | 各单元 src/main/resources/META-INF/app.properties |
| MySQL / TiDB | base.properties → application-context-base-database.xml | 阻塞 | netease-antispam-base conf/<env>/base.properties |
| Redis(普通 + AI + 直播) | application-context-base-redis.xml / -ai-redis.xml / -ai-redis-live.xml | 阻塞(censor 还多一层 Session Redis) | 同上 |
| OSS / NOS | application-context-base-oss.xml + nos.properties | 阻塞 | base/resources/nos.properties |
| ZK + Dubbo | application-context-base-dubbo.xml;consumer 全部 init=false, check=false | 弱(consumer)/ 阻塞(provider 注册) | conf/<env>/application-context-base-dubbo.xml |
| Kafka | application-context-base-kafka.xml + application-kafka-producer.xml / application-kafka-consumer.xml | 弱(异步) | base 与各进程 resources |
| ElasticJob ZK | async-elastic-job.xml / stats-elastic-job.xml / rule-async-elastic-job.xml | 阻塞(有 job 的单元) | 各单元 conf/<env>/*-elastic-job.xml |
| 浏览器 / 客户 HTTP | censor/management 的 Redis Session 与 Spring Security 依赖 Cookie NTESwebSI 通路 | 阻塞(登录链路) | application-context-censor-security.xml |
六、启动参数与 Profile
- 环境覆盖:
src/main/resources/conf/<env>/,build.sh在war:exploded后覆盖WEB-INF/classes;可用 env 目录含test/online/jiande-online/jiande-pre/jiande-online-rule-validate/india/beijing-online/online-preonline - maven profile:
dev/test/online/jiande-online/jiande-pre/pre;buildAll.sh固定GLOBAL_ENV=online→mvn clean install -Ponline,随后遍历find . -name "build.sh"以-c false -p false -e online逐个构建 - Spring Boot 单元(
privatization-*/union-admin):-Dspring.profiles.active=private(Dockerfile ENV + k8s env) - JAVA_OPTS:
async/ndc/censor/management=-Xmx1024m -Xms1024m -XX:+UseG1GC;stats/rule-async=-Xmx512m;union-admin=-Xmx512m ... -Dspring.profiles.active=private;dubbo-provider与preonlineDockerfile 未设置 JAVA_OPTS - base image:
jdk8-kylin(async / ndc / stats / rule-async / dubbo-provider)、jdk17-kylin(preonline / privatization-* / union-admin)、tomcat8-kylin(censor / management / inner-api / platform-api / platform-proxy-api) - 仓库与 tag:
build.sh统一DOCKER_REPOSITORY=private-registry.nis.netease.com/yidun、DOCKER_IMAGE_TAG=base-250409-kylin;ARM 走buildAll-arm.sh(改写镜像路径为private-registry.yidun.internal/arm/yidun,加--platform linux/arm64,构建后git checkout -- .还原) - 无 Node/前端单元;本模块不含
package.json
七、启动期踩坑
- 这些进程基本不是 Spring Boot:
--spring.profiles.active、@Enable*、Actuator 全部无效,换环境只能靠conf/<env>在构建期覆盖classes;dubbo-provider走com.alibaba.dubbo.container.Main,行为与SpringApplication.run完全不同。 application-context-base.xml做全局component-scan base-package="com.netease.is.antispam"但exclude-filter排除components.kafka.*:在该包下新增 Bean 必须显式写进application-kafka-*.xml,否则静默不注册;rule-async还额外排除了com.netease.is.antispam.base.kafka.*,两处排除规则不同。- censor 的内存缓存
init-method="init"+RedisHttpSessionConfiguration:启动即预热TargetMemoryCache/ProductMemoryCache/ImageConfigGroupCache/RuleSetMemoryCache/ProductGroupMemoryCache并建 Session Redis 连接,DB/Redis 任一不可用直接起不来。 - WAR 的环境配置靠构建期覆盖:只
mvn war:exploded不执行cp -rf conf/${BUILD_ENV}/*,打出的镜像会带源码默认配置;Dockerfile-arm与build.sh的--platform linux/amd64,linux/arm64并存,改架构时以谁为准易混淆。 buildAll-arm.sh中途失败会残留 ARM 路径改写:它依赖构建完成后git checkout -- .还原,中断即污染后续普通构建(build.sh与Dockerfile都被改过)。- 有可运行入口却无构建脚本的单元易被误认已部署:
open-api、dubbo-check-provider、privatization-consume、privatization-server-http、on-device-check-{admin,http}都有启动类/web.xml,但buildAll.sh的find . -name build.sh扫不到它们。 kubernetes.yml与build.sh镜像 tag 不一致:例如netease-antispam-async/kubernetes.yml写antispam-async:base-250409,而build.sh产出base-250409-kylin;且 k8s 内ENABLE_SKYWALKING=false与其余单元true不同。union-admin只有裸@SpringBootApplication:业务配置、Dubbo 注册、ShenYu 注册全靠application.properties+ Apollo,注解层面「看不到」任何组件装配,排查 Bean 缺失只能看 properties。
八、跨模块前置
- 配置与策略源:依赖
antispam-business(business.client读 PRODUCT/TARGET/LABEL 等)与antispam-rule/antispam-keyword/antispam-list的 Dubbo facade;censor/management/platform的 consumer 若注册中心无 Provider,check=false时会带着空引用启动、首次调用才失败。 - 检测能力:
antispam-business-{text,image,audio,video,liveaudio,livevideo}、antispam-textclassify、antispam-video-solution、antispam-media-solution、antispam-stream-solution—— 作为下游能力被本模块 Dubbo/HTTP 调用。 - 计费与审核中台:
antispam-bill(结果/用量计费)、antispam-cms(人工审核与运营数据); - 消息与导出:
yidun-message(站内信)、yidun-export、yidun-cms(账号权限)、yidun-accountcenter-facade-dubbo-api(账号中心)—— 弱依赖,缺失只影响对应功能。 - 基础设施:Apollo → MySQL/TiDB → Redis → Kafka → ZK/Dubbo → OSS 的顺序启动;本模块 14 个单元全部依赖前四项,属全局硬前置。