外观
netease-image — 图像/视频帧违规检测算法引擎
分层:算法与核心平台层(算法检测层) | 部署单元:约 40 个独立部署(80+ 子工程) | 数据库:MySQL
media_md5、yidun_black_white等 | base image:多基线(tomcat8-arm、jdk8-image-arm、jdk-8u221-minideb-stretch等)
一、模块定位与架构
本模块是易盾内容安全(NISP)的图像检测引擎:对输入的图片或视频帧,经下载预处理后并行调度色情、暴恐、违禁品、涉政、广告、二维码、OCR、黑白名单、人脸识别、自定义分类等多个算法,再按规则合并多帧结果,输出带标签、置信度与处置建议的判定,供业务层机审放行或拦截。
架构分层(HTTP 服务层 → Dubbo 接口层 → Provider 算法层 → 数据层):
- 接入层:
image-service-yidun(对外 HTTP,YidunApiControllerV5)、image-service-modify(数据修改入口)、image-web(管理后台) - 接口层:
image-api(所有 Dubbo 检测服务接口 / DTO / 枚举 / V5 结果模型的唯一定义处) - 算法层:
image-provider-*(约 40 个按检测域拆分的 Dubbo 算法服务) - 数据层:
image-base(MyBatis 访问 + 配置缓存)、image-cache、image-config - 支撑:
image-data-collector/image-data-sink(数据管道)、image-schedule、init-db、infrastructure/redis - 本地算法:
image-native-recognizer、image-base-lib(JNI/so,caffe/opencv)
关键数据流:
YidunApiControllerV5.detect→packRequestContext(参数校验/上下文)getPreprocessResult(下载 / md5 / resize / 切分)→adjustCheckParams(模型路由)YidunAlgoHandlerFactory分派各算法 handler → 各*CheckService.check(Dubbo 调 Provider)YidunAlgoMergeFactory多帧合并 →ResultHandler输出- 命中记录落
media_md5/yidun_black_white,经image-data-sink回写数据管道
核心概念:算法类型由
AlgoTypeEnum的 code 唯一标识(如100=色情、300=暴恐、420=易盾黑白名单),经model_config表路由到具体模型/Provider;处置语义由ConfidenceLevelEnum(OK/SUSPECT/CONFIRM)与 label/subLabel 体系承载。
二、可部署服务清单
技术栈结论:纯 Java(仓库内无 *.py)——JDK 1.8 + Spring 4.2.x + Dubbo 2.7.15(原 Dubbox)+ Tomcat 8.5.51(WAR)+ thrift + JNI/so 本地算法库 + MyBatis + log4j2 + Elastic-Job。唯一 Spring Boot 应用是 image-web;其余多为 main() + Dubbo container(org.apache.dubbo.container.Main)或 XML 上下文,由 k8s command 显式指定主类启动,不是 gunicorn/uwsgi/systemd。
| 部署单元目录 | artifactId | 镜像名(online / private) | 端口 | 服务类型 | 独立 Dockerfile | 是否进 kubernetes.yml |
|---|---|---|---|---|---|---|
image-service-yidun | image-service-yidun | .../ai/image-service-yidun | Tomcat 8282(健康 /health/status) | WAR(HTTP 入口) | 是(CMD catalina.sh run) | 分散在各子工程模板 |
image-service-modify | image-service-modify | .../ai/image-service-modify | Tomcat | WAR | 是(CMD catalina.sh run) | 同上 |
image-web | image-web | .../ai/image-web | Spring Boot Web | 管理后台(唯一 Boot 应用) | 是 | 同上 |
image-provider-preprocess | image-provider-preprocess | .../ai/image-provider-preprocess | Dubbo 随机 + thrift 9090 | Dubbo Provider(预处理) | 是(无 CMD,靠 RUN_SERVER) | 同上 |
image-provider-porno-plp | image-provider-porno-plp | .../ai/image-provider-porno-plp | Dubbo/thrift | Dubbo Provider(色情) | 是(无 CMD) | 同上 |
image-provider-terror | image-provider-terror | .../ai/image-provider-terror | Dubbo/thrift | Dubbo Provider(暴恐) | 是(有 CMD + RUN_SERVER) | 同上 |
image-provider-contraband-* | image-provider-contraband-* | .../ai/image-provider-contraband-* | Dubbo/thrift | Dubbo Provider(违禁品族:weapon/drug/flag/clothes/bloodiness/scene/behavior/logo/custom) | 是(多为无 CMD) | 同上 |
image-provider-ocr* | image-provider-ocr / -accurate / -youdao / -facade | .../ai/image-provider-ocr* | Dubbo/thrift | Dubbo Provider(OCR 族) | 是 | 同上 |
image-provider-ad-common / -ad-handwriting | 同名 | .../ai/image-provider-ad-* | Dubbo/thrift | Dubbo Provider(广告) | 是 | 同上 |
image-provider-black-white-* / -hash / -md5 | 同名 | .../ai/... | Dubbo/thrift | Dubbo Provider(黑白名单/哈希/MD5) | 是 | 同上 |
image-provider-politics-cnmap | 同名 | .../ai/... | Dubbo/thrift | Dubbo Provider(涉政) | 是 | 同上 |
image-provider-face-* / -insightface-recognizer | 同名 | .../ai/... | Dubbo/thrift | Dubbo Provider(人脸族:detect/recog/attribute/cartoon/search) | 是 | 同上 |
image-provider-logo-* / -feature-search / -similar-search | 同名 | .../ai/... | Dubbo/thrift | Dubbo Provider(Logo/特征/相似检索) | 是 | 同上 |
image-provider-cnn / -sift-gpu / -self-training-feature | 同名 | .../ai/... | Dubbo/thrift | Dubbo Provider(GPU) | 是 | 同上 |
image-provider-clustering | image-provider-clustering | .../ai/image-provider-clustering | 30043(readiness tcpSocket)+ QoS 42222 + shutdown 42223 | Dubbo + Kafka 分片消费者 | 是(无 CMD) | 同上 |
image-provider-normal / -quality / -daily-scene / -text / -text-http / -qr / -custom-classify* | 同名 | .../ai/... | Dubbo/thrift | Dubbo Provider(其余检测域) | 是 | 同上 |
image-data-collector | image-data-collector | .../ai/image-data-collector | 无 | Kafka→数据管道 Worker | 是 | 同上 |
image-data-sink | image-data-sink | .../ai/image-data-sink | 无 | 数据落库 Worker | 是 | 同上 |
image-schedule | image-schedule | .../ai/image-schedule | 无 | Elastic-Job 定时 | 是 | 同上 |
image-config | image-config | .../ai/image-config | 无 | 配置拉取 Worker | 是 | 同上 |
init-db | — | mysql:5.7.29(一次性 Job) | 3306 | DB 初始化 | 是 | 同上 |
image-api / image-base / image-common* / image-cache / image-native-recognizer / image-base-lib / image-regression-test | 同名 | — | 无 | 类库/本地算法/测试 | 多数无(不构建) | 否 |
镜像仓库两套:online 用
hub.c.163.com/neteaseis/ai/<model>;private 用private-registry.yidun.internal/neteaseis/ai/<model>,tagmaster-private-YYYYMMDD-<短commit>。docker-build.sh的白名单仅 26 个模块。
三、同模块启动顺序
init-db— 建库建表(create_db.sql/create_table.sql)与初始配置(model_config.sql/sub_label_all.sql/label_name.sql等)。- Redis / LRU Redis —
image-cache/k8s/lru-redis-config.yml、sift-lru-redis.yml、video-cnn-lru-redis.yml。 - 各
image-provider-*— 算法 Dubbo 服务,越底层的域(preprocess、md5、hash、黑白名单)越先起。 image-service-yidun/image-service-modify— HTTP 入口与数据修改入口。image-web— 管理后台。image-data-collector/image-data-sink/image-schedule— 数据管道与定时。
理由:算法 Provider 必须先注册到 Dubbo/ ZooKeeper,HTTP 入口才能在启动期完成算法路由与预热;数据管道在业务入口之后承接回流。
四、逐服务启动逻辑
单元目录 image-web(唯一 Spring Boot 应用)
- 启动类:
com.netease.is.ni.web.AdminApplication(image-web/src/main/java/com/netease/is/ni/web/AdminApplication.java) @SpringBootApplication(scanBasePackages = {"com.netease.is.ni.web","com.netease.is.ni.common"}) + @EnableWebSecurity + @PropertySource("classpath:base.properties") + @ImportResource({"classpath:base-application-context.xml","classpath:application-context-management-security.xml"})— Spring Boot + XML 混合。main():无自定义逻辑,SpringApplication.run。
单元目录 image-service-yidun(WAR / 非 Boot)
- 装配:
src/main/webapp/WEB-INF/web.xml→contextConfigLocation=classpath:yidun-server-application-context.xml+ContextLoaderListener+DispatcherServlet(yidun-server-web,load-on-startup=1,映射/*)+CharacterEncodingFilter。 - 主 context
yidun-server-application-context.xml:importbase-application-context.xml、yidun-server-dubbo-application-context.xml(按客户增减的 Dubbo 订阅文件,部署时整体替换)、yidun-server-kafka-config.xml、image-common-aspect.xml;context:component-scan base-package="com.netease.is.yidun.server"(排除@Controller)。 - 启动参数:
-Dskip.algo.types.list=100,110,120,210,220,241,245,401,403,405,407,408,409,800,811,1000,与订阅文件必须成对修改。 - 容器:base image
tomcat8-arm,CMD catalina.sh run,健康/health/status。
单元目录 image-provider-*(算法 Provider 群,约 40 个)
- 启动方式:
main()内log.info("... 服务启动...")后调用org.apache.dubbo.container.Main.main(args),由 Dubbo container 自动加载META-INF/spring/*.xml。示例ClusteringMain(image-provider-clustering/src/main/java/com/netease/is/ni/provider/clustering/ClusteringMain.java)。 - 容器:多数 provider 的 Dockerfile 无 CMD,靠 k8s env
RUN_SERVER指定主类(如ENV RUN_SERVER=com.netease.is.ni.provider.clustering.ClusteringMain);仅-hash/-terror/-text等少数 Dockerfile 内置CMD ... ${RUN_SERVER}。 - k8s 启动命令链(
clustering-deployment.template.yml为范式):/etc/init.d/nagent start→ 等/etc/nagent_sn→curl认领 CMDB 分组(claimUrl=http://imagemodify-nis.service.163.org/cmdb/claim-to-group.json)→kinit→/etc/init.d/cron start→java ${EXTRA_JAVA_OPTS} -Dcom.cmdb.appname=... ${RUN_SERVER}。 EXTRA_JAVA_OPTS典型含:-Ddubbo.application.qos.port=42222、-Dkafka.consumer.group.id、-Dkafka.partition.number/offset、-Dthrift.servers=127.0.0.1:9090、-XX:InitialRAMPercentage=50 -XX:MaxRAMPercentage=70、-Xloggc:/app/logs/gc-%t.log、sentry javaagent、-Dmaster.server.address=config.service.163.org。- 生命周期:
readinessProbe: tcpSocket 30043 initialDelaySeconds=30;preStop: curl localhost:42222/offline && curl localhost:42223/clustering/shutdown && sleep 90;terminationGracePeriodSeconds=95;strategy: Recreate;Pod 反亲和。 - 启动钩子:Dubbo container 加载的 XML 内各
@PostConstruct;GPU provider 的模型版本由MODEL_IMAGE_VERSION决定。
单元目录 image-data-collector / image-data-sink / image-schedule
DataCollectorLauncher:new ClassPathXmlApplicationContext("image-data-collector-application-context.xml")+new CountDownLatch(1).await()阻塞主线程。DataSinkLauncher/SchedulerLauncher:同构(各自*-application-context.xml)。- 均为 XML 上下文型 Worker,非 Spring Boot。
单元目录 image-config
- 启动类:
com.netease.is.ni.launcher.LauncherMain(image-config/src/main/java/com/netease/is/ni/launcher/LauncherMain.java) AnnotationConfigApplicationContext(ProviderConfiguration.class)+context.start()+CountDownLatch.await()阻塞。
单元目录 init-db
mysql:5.7.29一次性 Job,执行create_db.sql、create_table.sql及model_config.sql等初始化脚本。
五、启动前置依赖
| 依赖 | 配置键/地址 | 阻塞 or 弱依赖 | 配置文件 |
|---|---|---|---|
| MySQL | media_md5、yidun_black_white(init-db/ 建库) | 阻塞 | conf/<env>/*.properties |
| Redis | 含 LRU 专用实例 image-cache/k8s/lru-redis-config.yml、sift-lru-redis.yml、video-cnn-lru-redis.yml | 阻塞 | 各 provider conf/ |
| ZooKeeper / Dubbo | provider 注册与路由 | 阻塞 | conf/ |
| Kafka | isolation / collector / sink / clustering(按分片消费) | 阻塞(clustering) | 部署 env -Dkafka.* |
| HDFS | bash /usr/local/hadoop/kinit.sh + hadoop 客户端 | 阻塞(部分 provider) | k8s args |
| nagent / CMDB | curl claimUrl=http://imagemodify-nis.service.163.org/cmdb/claim-to-group.json | 阻塞(启动第一步) | k8s args |
| GPU | image-provider-sift-gpu、-cnn、-self-training-feature | 阻塞(调度到 GPU 节点) | Deployment 模板 |
| thrift | -Dthrift.servers=127.0.0.1:9090 | 阻塞(clustering) | 部署 env |
| 配置中心 | -Dmaster.server.address=config.service.163.org | 阻塞 | 部署 env |
六、启动参数与 Profile
- 无 Spring profile 概念:构建靠 ant
-DenvType=online|test+conf/<env>目录整体覆盖配置;Jenkinsfile按分支选择(master→online,dev→test)。 - 构建脚本:
docker-build.sh <all|模块名>,私有化白名单 26 个模块,tagmaster-private-YYYYMMDD-<短commit>;image-service-*用web-build.xml,其余用javaapp-build.xml。 - base image 多样:
yidun/base-image:tomcat8-arm、...:jdk8-image-arm、harbor.yidunai.service.163.org/neteaseis/base:jdk-8u221-minideb-stretch、...:openjdk8u242-tomcat8.5.51-removeExampleDirectory、...:openjdk-8u242、...:java-8u221-oracle-debian9、hub.c.163.com/neteaseis/image-provider-terror:20181211。 - JVM/启动参数:见四中的
EXTRA_JAVA_OPTS;默认-XX:InitialRAMPercentage=50 -XX:MaxRAMPercentage=70,-Xloggc:/app/logs/gc-%t.log。 - 启动命令:WAR 型
CMD catalina.sh run;Provider 型由 k8scommand: ["/bin/bash","-c"]+args中的 nagent/kinit/java 启动链显式拉起主类。
七、启动期踩坑
- 启动命令第一步是 CMDB 认领(
/etc/init.d/nagent start+curl claimUrl),失败日志不在应用日志里,表现为 Pod 起不来但应用无输出。 - 多数 provider 的 Dockerfile 无 CMD,漏配 k8s env
RUN_SERVER时容器无启动入口,直接退出。 image-service-yidun的 Dubbo 订阅文件yidun-server-dubbo-application-context.xml硬编码算法订阅,必须与-Dskip.algo.types.list成对修改,否则某算法漏订阅 → 检测静默缺项。image-provider-preprocess预处理下载超时默认 5000ms,且调大无效(受上游 SDK 限制)。image-provider-clustering必须strategy: Recreate+terminationGracePeriodSeconds=95+preStop sleep 90,否则索引未写完就重启导致数据/索引错乱。- GPU provider(
-sift-gpu/-cnn/-self-training-feature)的模型版本(MODEL_IMAGE_VERSION)与代码镜像不匹配时,会静默产出错误特征而非报错。 readinessProbe探 Dubbo 端口 30043 且initialDelaySeconds=30,对大模型 provider 偏短,易被误杀重启。image-web是 Spring Boot + XML 混合(@ImportResource),Bean 覆盖与扫描顺序需同时看 Java 配置与 XML。- 仓库无根
kubernetes.yml,Deployment 分散在各子工程.yml模板(含{{...}}占位符),需deployment.sh渲染后才能 apply。
八、跨模块前置
antispam-image(下游依赖本模块):app.image.check-url=http://imageapi-nis-gz.service.163.org即指向本模块的 HTTP 入口,因此本模块必须早于antispam-image的 dubbo-check-provider 启动,否则其检测调用失败。- 上游业务层(
antispam-business-image、antispam-business-video、antispam-video-solution、antispam-livevideo-solution)通过 HTTP 提交图片/视频帧;image-web维护名单库与模型配置后影响检测行为。 - 数据面:
image-data-collector消费 Kafka 采集分错样本回流,image-data-sink回写media_md5/yidun_black_white。 yidun-cms:审核后台展示检测标签/命中结果(推断)。