首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >一套代码要跑几百个村:万村乐数字乡村的功能开关、配置中心与滚动更新

一套代码要跑几百个村:万村乐数字乡村的功能开关、配置中心与滚动更新

原创
作者头像
小小码农爱奋斗
发布2026-08-21 11:35:45
发布2026-08-21 11:35:45
680
举报

版本差异本身就是一组功能开关

万村乐数字乡村的 Java 独立版分四档:商业版 8 万元全加密,前端开源版 15 万元,全开源版 30 万元前后端全开源,早期还有 5 万元的标准版现已停售。PHP 版 V3.0 那边是商业版 6.5 万元、开源版 13 万元、买断版 20 万元和 30 万元。版本之间不只是价格差别,功能清单是真的不一样:可视化大数据在标准版是不开放的,商业版及以上才有;手机管理端、政务管理端、党建系统、DIY 装修这些属于增值插件,价格分别是 1000 元、6000 元、2000 元、1000 元,客户按需购买。

对研发来说,这意味着代码库只有一份,但运行时的功能形态有十几种组合。如果靠打包时裁剪代码来实现,每来一个客户就要出一个包,升级的时候得逐个重新编译,运维成本会失控。所以这套东西的正确做法是把版本差异当成功能开关来管,包永远是同一个,能力由配置决定。

开关模型:三层判定

开关不能只有开和关两个状态。万村乐的实际场景要同时考虑授权、区域、灰度三个维度,所以判定逻辑设计成三层,任何一层不通过就是关闭:

授权层的数据来自 license 文件,里面写明版本档位和已购插件清单,用私钥签名,客户端只做验签不做解析改写。区域层是给运营用的,万村乐的地区管理支持后台按区域创建村庄并分配管理者账号,新功能上线时通常先在两三个配合度高的村打开。灰度层是给研发用的,按村庄 ID 取模放量,从 5% 逐步推到 100%。

这里刻意让灰度维度选村庄而不是用户。村是数字乡村平台的自然边界,同一个村里一半人能用新功能一半人不能,村干部会被问爆。按村放量,村内体验是一致的。

配置中心:私有化部署下的取舍

万村乐所有版本都支持私有化独立部署,客户的数据掌握在自己手里。这个前提直接影响配置中心的选型。上一套重量级的配置中心,客户还得多维护一个组件,出了问题售后要远程排查,成本太高。

实际采用的是轻量方案:配置存 MySQL 8.0.28,应用启动时全量加载进本地缓存,变更通过版本号轮询感知。轮询间隔 10 秒,对基层平台的实时性要求完全够用。

有几个细节值得说。本地缓存要在启动阶段加载失败时直接让应用起不来,不能带着空配置对外提供服务,不然所有开关都读到默认值,行为完全不可预期。配置变更要写审计记录,谁在什么时间把哪个开关从关改成开,这条信息在事后复盘时价值很高。敏感配置比如阿里云短信的 AccessKey、微信支付的商户密钥,不能和普通配置混在一张表,单独加密存储并限制读取接口。

在线升级:点一下就更新的背后

万村乐的系统更新是在线升级,用户直接点更新即可自动升级。这个体验对基层客户很友好,村里没有专职运维,让人去服务器敲命令不现实。但自动升级这件事风险不小,做了几层保护。

升级包带版本号和 SHA-256 校验值,下载完先校验再解压,校验不过直接终止并保留旧版本。数据库变更走独立的脚本目录,按版本号顺序执行,每个脚本执行前后都记录状态,中途失败可以从断点续跑。所有 DDL 强制要求向后兼容,加列可以,删列和改列名不允许在同一个版本里做,需要分两个版本走:先上新列双写,确认无误后的下一个版本再摘掉旧列。

升级前自动打一次数据库备份,备份文件按万村乐的文件储存配置落到本地或者阿里云、腾讯云。这一步不能省,出过一次客户自行修改过表结构导致升级脚本执行失败的情况,有备份就是回滚,没备份就是事故。

滚动更新:Java 版微服务的处理

万村乐 Java 版采用微服务架构,前后端分离。部署在多节点环境时,滚动更新要处理两个问题。

一是流量摘除。节点更新前先从注册中心下线,等待 30 秒让在途请求跑完再停进程。这个等待时间要大于接口的超时时间,否则村民正在提交的表单会直接失败。

二是新旧版本共存期的兼容。滚动更新过程中,集群里一定会同时存在新旧两个版本,接口契约必须双向兼容。实践中的约束是:新增字段可以,删除字段要等一个版本;枚举值只加不改;接口返回结构不做破坏性调整。前端 Vue 3.2.31 那边配合做了兜底,遇到未知枚举值不报错,按默认分支渲染。

小程序和 APP 这两端比较特殊。UNI-APP 打包出来的小程序要走平台审核,审核周期不可控;APP 是混编模式,用户不一定及时更新。所以后端接口的兼容窗口要留得比 Web 端更长,通常按 3 个版本考虑,老接口不能说下就下。

开关的生命周期管理

功能开关最容易出的问题不是技术,是没人清理。上线时加了开关,功能稳定跑了半年,开关还在,代码里两条分支都留着,时间长了没人敢删。

我们的做法是给每个开关登记时就写明类型和到期时间。灰度开关默认 90 天有效期,到期后由发布负责人确认,要么全量放开并清理代码分支,要么明确改成长期开关。授权类开关是长期存在的,因为版本差异本来就是产品设计的一部分。运维类开关比如降级熔断,也是长期保留。

代码里做一个简单的统计任务,每月扫一遍配置表,把超期未处理的灰度开关列出来发给对应负责人。这个动作很小,但能有效防止开关堆积。到目前为止,把开关数量控制在几十个量级,配置页面翻两屏能看完,比动辄几百个开关的状态健康得多。

一点体会

灰度和配置这套机制,价值在故障发生的时候才能体现出来。新功能在 5% 的村庄跑出问题,改一个配置值就回退了,不用紧急发版,也不用惊动客户。相比每次上线都全量推的做法,出问题时的影响面小了一个数量级。

对于万村乐这类要覆盖大量村庄、还要支持私有化部署和多版本授权的平台来说,开关体系不是锦上添花,是把版本差异、分批开通、灰度放量这三件事统一到一处的基础设施。前期多花两周搭好,后面每次发布都在省时间。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档