外观
antispam-bill — 反垃圾计费结算(用量采集 → 账单结算 → 云支付扣费)
分层:业务层(计费结算域)| 部署单元:1 个(另有 4 个有启动类但不构建)| 数据库:MySQL/TiDB
antispam| base image:private-registry.nis.netease.com/library/base-image:jdk17(tagbase-250409)
一、模块定位与架构
它把易盾各产品线(文本/图片/音视频/解决方案/审核系统)上报的用量、审核量、试用量汇聚成账单,按客户套餐类型折算费用,再通过云支付平台完成扣费/退款,并为运营后台提供套餐、账单、统计查询。核心诉求是“不少扣(营收)、不多扣不重扣(客诉/资损)”。
架构分层
- 采集层:
collect(RequestStatConsumer/ArchiveStatConsumer/CensorStatConsumer/SupplierStatConsumer/TrialStatConsumer,Kafka 消息入账判定与去重) - 业务计算层:
service/business(component.stat.*、PackageInfoService、BillStatArithmeticSelector、费用项 Worker、PayRemoteService对接) - 数据访问层:
service/base(DAO/Manager/MyBatis Mapper)+domain(RequestStatMessage/ArchiveStatMessage等)+common(套餐/账单类型、状态码)+client(套餐缓存与事件插件) - 定时结算层:
scheduler(40+ ElasticJob:计费、费用项、统计、套餐生命周期、通知、回退) - 对外接口层:
facade/dubbo-provider(套餐/账单/配置/统计 Dubbo 门面)、facade/http-api(骨架)、console/api(控制台骨架)
关键数据流
- 检测业务 → Kafka 用量消息(如
Antispam_Text_RequestStat、yidun_request_stat、Antispam_Bill_ArchiveStat) collect的RequestStatConsumer.handleMessage判套餐/判状态/判重跑RequestStatComponentV2.collectRedis 累计 + 落库scheduler的RequestStatWorkerV2/BillStatWorker定时汇总 →package_bill_record结算记录BillRecordPayWorker→PayRemoteService云支付扣款 → 平台余额/流水- 套餐状态变更事件(
Antispam_Bill_Package_Change)驱动AbstractPackageStatusChangeEventListener分支处理
二、可部署服务清单
| 部署单元目录 | artifactId | 镜像名 | 端口 | 服务类型 | 独立 Dockerfile | 是否进 kubernetes.yml |
|---|---|---|---|---|---|---|
facade/dubbo-provider | antispam-bill-facade-dubbo-provider | private-registry.yidun.internal/yidun/antispam-bill-dubbo-provider:1.0.0.private | Dubbo port=-1(无 Web) | Dubbo Provider | 有 | 是(replicas=2,cpu 1/2,mem 1024/2048) |
collect | antispam-bill-collect | 无(不构建) | — | Kafka Consumer + 内置 Qos | 无 | 否 |
scheduler | antispam-bill-scheduler | 无(不构建) | — | ElasticJob(40+ 任务) | 无 | 否 |
facade/http-api | antispam-bill-facade-http | 无(不构建) | — | HTTP | 无 | 否 |
console/api | antispam-bill-console-api | 无(不构建) | — | 控制台后端 | 无 | 否 |
本仓库
kubernetes.yml仅一个 Deployment:antispam-bill-facade-dubbo-provider(namespaceyidun);其余单元虽含完整启动类与配置,却没有 build.sh/Dockerfile。
三、同模块启动顺序
facade/dubbo-provider—— Dubbo 契约注册主体,为 CMS/运营与内部消费方提供套餐/账单/配置接口,也是scheduler/collect的配置读取对象。collect—— 用量消息入账入口,依赖套餐/产品配置已可读(经business.clientZK 与本地 DB),须在结算前启动以累计 Redis 数据。scheduler—— 依赖collect累计的用量数据与套餐状态,跑计费/汇总/扣费;无数据时任务会空跑但不应先于 collect 上线。facade/http-api/console/api—— 纯读侧展示与查询,最后启动。
四、逐服务启动逻辑
facade/dubbo-provider
- 启动类:
com.netease.is.antispam.bill.facade.dubbo.DubboApplication(facade/dubbo-provider/src/main/java/com/netease/is/antispam/bill/facade/dubbo/DubboApplication.java) @SpringBootApplication:无 exclude@Enable*注解:@EnableAspectJAutoProxy、@EnableTransactionManagement、@EnableRecoverComponent(com.netease.is.antispam.components.recover.spring)、@EnableBusinessClient、@EnableConfigurationProperties({BillPlatformProperties, BillStatProperties})- Apollo 接入:无
@EnableApolloConfig,靠apollo.bootstrap.enabled=true+apollo.cluster=default+app.id=antispam-bill_dubbo+apollo.bootstrap.namespaces=application自动注入 - 动态数据源 / Mapper:由
service/base的 Dao 与mybatis.mapper-locations驱动;dubbo.scan.basePackages=com.netease.is.antispam.bill.facade.dubbo.provider暴露 Provider main():仅SpringApplication.run(...)- 启动钩子:未发现显式
@PostConstruct/ApplicationListener;@EnableRecoverComponent会拉起失败重放组件(recover.config.*:recoverFileSizeLimitInMB=-1、recoverThreshold=15、clusterRecoverPoolSize=2),属框架级。
collect(有启动类,不构建)
- 启动类:
com.netease.is.antispam.bill.collect.CollectApplication @EnableBusinessClient、@SpringBootApplication、@EnableAspectJAutoProxy、@EnableTransactionManagement、@EnableConfigurationProperties({BillCollectProperties, BillCacheProperties})、@EnableApolloConfig、@EnableScheduling、@EnableIsolateComponent- Kafka Consumer:
netease.kafka.consumer.enable=true、groupId=netease-antispam-collect、concurrency=4;生产者netease.kafka.producer.enable=true - 内置
YidunQosApplication(collect/configruation/YidunQosApplication,@QosRegister)提供 Qos 限流 app.id=antispam-bill_collect;main()仅 run;启动钩子:未发现
scheduler(有启动类,不构建)
- 启动类:
com.netease.is.antispam.bill.scheduler.SchedulerApplication @SpringBootApplication、@EnableElasticJob、@EnableRecoverComponent、@EnableBusinessClient、@EnableConfigurationProperties({BillPlatformProperties, BillStatProperties, BillCacheProperties})、@EnableApolloConfig、@EnableEventClient(mplatform-event)- 任务:40+
@ElasticJobConf,如amountBillWorker、chargeDailyWorker、monthlyBillWorker、billStatWorker、packageExpireWorker、fixNosBillWorker等,elastic.job.<worker>.overwrite=true大量声明 - 内置
YidunQosApplication(scheduler/configuration/YidunQosApplication);app.id=antispam-bill_scheduler;main()仅 run
facade/http-api 与 console/api(有启动类,不构建)
com.netease.is.antispam.bill.facade.http.HttpApplication、com.netease.is.antispam.bill.console.api.ConsoleApplication:均无独立 Dockerfile,仅有@SpringBootApplication骨架与application*.properties;启动钩子未发现。
五、启动前置依赖
| 依赖 | 配置键 / 地址 | 阻塞 or 弱依赖 | 配置文件 |
|---|---|---|---|
| MySQL/TiDB | spring.datasource.url=jdbc:mysql://tidb-cluster0-tidb.tidb.svc:4000/antispam | 阻塞(dubbo-provider) | application-private.properties |
| ZK — Dubbo 注册中心 | dubbo.registry.address=zookeeper://zk-0.zookeeper.yidun-infra:2181?backup=...,group /yidun/antispam/online-new/yidun-antispam-dubbo | 阻塞 | application-private.properties |
| ZK — business.client(配置源) | business.client.options.zookeeper.*(operateTargetTypes=PRODUCT,PRODUCT_CONFIG,TARGET,TARGET_CONFIG,TARGET_CHECKER) | 阻塞(配置读取) | application.properties + application-private.properties |
| Apollo | app.id=antispam-bill_dubbo / antispam-bill_collect / antispam-bill_scheduler,apollo.bootstrap.enabled=true | 弱 | application.properties |
| Redis(Sentinel) | spring.redis.sentinel.master=master01,spring.redis.sentinel.nodes=redis0-redis-ha.yidun-infra.svc:26379 | 弱 | application-private.properties |
| Kafka | netease.kafka.producer.cluster.[default].bootstrap.servers=yidun-test-commonkafka01...(private 指向测试集群);collect 另有 consumer | 弱 / collect 阻塞 | application-private.properties、application.properties |
| OSS(NOS) | oss.client.instance-map.yidun-antispam.endpoint=nos-eastchina1.126.net(含 AK/SK) | 弱 | application.properties |
| 云支付平台 | bill.platform.url=http://yidun-api.service.163.org,bill.platform.secret-id/key=1 | 弱 | application-private.properties |
| ElasticJob ZK | elastic.job.zk.* | 阻塞(scheduler) | scheduler 配置 |
六、启动参数与 Profile
-Dspring.profiles.active:base 默认dev;仓库含dev/test/private/online/jiande-online/jiande-validate/test-validate;容器统一private(Dockerfile ENV + k8s env)- maven profile:本仓库根
pom.xml未自定义 profile,-P private由父/平台 POM 提供 - JAVA_OPTS:Dockerfile
-Xmx512m -Xms512m -XX:+UseG1GC -Dspring.profiles.active=private;k8s 覆写-Xmx1024m -Xms1024m -XX:+UseG1GC ...(resources limits 2048Mi 与之匹配) - base image 与镜像仓库:
private-registry.nis.netease.com/library/base-image:jdk17;build.shDOCKER_REPOSITORY=private-registry.nis.netease.com/yidun,产出antispam-bill-dubbo-provider:base-250409;k8s 引用的是private-registry.yidun.internal/yidun/antispam-bill-dubbo-provider:1.0.0.private(仓库与 tag 与 build.sh 默认值不一致,依赖 K8s 侧拉取策略/重打 tag) build.sh关键参数:MODEL_NAME=facade/dubbo-provider、BUILD_ENV=private、DOCKER_IMAGE_NAME=antispam-bill-dubbo-provider、DOCKER_IMAGE_TAG=base-250409、docker buildx build --platform linux/amd64,linux/arm64 --push(双架构);buildAll.sh固定GLOBAL_ENV=private并遍历find . -name build.sh
七、启动期踩坑
- 本仓库只有
facade/dubbo-provider能出包:collect/scheduler/facade/http-api/console/api有启动类与配置,但无build.sh/Dockerfile,buildAll.sh不会构建它们。 - scheduler 40+ 任务全
overwrite=true+ ElasticJob namespace 跨环境共用 → 同一 ZK namespace 下多环境任务互相覆盖,改 cron 会串环境。 collect/scheduler缺application-private.properties:两模块仅有dev/test/online/jiande/test-validate配置,一旦以-Dspring.profiles.active=private启动将取不到数据源等关键配置。- private Kafka 指向测试集群:
netease.kafka.producer.cluster.[default].bootstrap.servers=yidun-test-commonkafka01/02/03.service.163.org:9092,collect 的supplier.monitor.kafka.bootstrap.servers同样是测试集群。 @EnableRecoverComponent的recover.config.recoverFileSizeLimitInMB=-1(不设上限)在失败重放积压时可能撑爆磁盘。- 凭据硬编码:
oss.client.instance-map.yidun-antispam.access-key/secret-key、bill.platform.secret-id/secret-key=1直接写在 properties。 - 仓库/tag 双轨:build.sh 推
private-registry.nis.netease.com/yidun:base-250409,kubernetes.yml 拉private-registry.yidun.internal/yidun:1.0.0.private,需人工对齐。 dubbo.protocol.port=-1:dubbo-provider 随机端口,消费方必须走 ZK 注册发现。- dubbo-provider 不用
@EnableApolloConfig:只靠apollo.bootstrap.enabled=true+app.id=antispam-bill_dubbo生效,apollo.bootstrap.namespaces=application(只有 application 一个 namespace,与 business 的application,application.yml不同)。 - 结果包名与部署名不一致:
collect/scheduler的finalName是${project.artifactId}-${project.version}-application(版本号内嵌),而唯一有 Dockerfile 的 dubbo-providerfinalName=antispam-bill-dubbo-provider;若日后给 collect/scheduler 补 Dockerfile,COPY ./target/*.jar必须按版本化命名。 dubbo.consumer.retries=1/timeout=10000:bill 消费端短超时 + 1 次重试,下游抖动会较快抛出,定时任务侧需依赖@EnableRecoverComponent重放兜底。bill.platform.secret-id/secret-key=1:private 用占位凭据直连http://yidun-api.service.163.org,扣费链路在 private 实际不可用,验证计费只能看落库的package_bill_record而看水面账单。k8s引用 2 副本而 Dubbo 随机端口:replicas=2+dubbo.protocol.port=-1决定了两个 Pod 端口不同,任何固定端口探测/网络策略都会失效,只能依赖 ZK 注册。
八、跨模块前置
- 配置源:依赖
antispam-business(Dubbo Provider + ZK/netease-antispam/online/config)—— 经business.client读取 Product/Target/Checker 配置,属启动期阻塞的配置读取,建议antispam-business先运行。 - 运行期弱依赖:云支付平台(
yidun-api.service.163.org/bill.platform.url)、yidun-message(套餐到期/超额通知,bill.platform.email-url)、mplatform-event(套餐变更事件,@EnableEventClient)。 - 上游数据源:
antispam-business-*、antispam-solution等把用量消息投到 Kafka,本模块collect才能累计——它们不是启动前置,但未上线时账单为空。 - 客户端插件:
client模块(PackageInfoCache/EventListenerPlugin)会被下游集成,套餐变更需通过它把缓存推给消费方。 - 除此之外无其它业务模块硬前置。