👋 大家好,我是十三!
当 UGC 业务让用户体系不堪重负,如何优雅破局? 最近一周我都在思考这个问题,是的,我们目前遇到了这个问题,直到我们的资深产品架构专家提出「角色」的概念,让我有了破局这道,所以在此分享下我们的痛点、目标以及迁移蓝图
一、问题的提出:当"用户"不再是唯一的身份
在平台型业务的演进过程中,我们遇到一个棘手的挑战:随着业务边界的拓展,用户的身份也开始变得多元化。当前的场景是我们的电商平台为了增强用户黏性和内容生态,引入了创作者社区(UGC)。这个时候一个自然人,在平台上就不再仅仅是"买家",还可能是"内容创作者"。
这就是我们面临的局面,而其背后的技术实现,却揭示了一个深刻的架构性问题------用户体系的割裂。
1.1 历史包袱:两套独立的"身份系统"
问题的根源在于,在社区业务启动初期,因为用户实体团队和社区团队是两个独立的实体团队,社区团队为创作者独立构建一套全新的用户体系。这也是架构中很常见的一个问题:业务的领域边界会受到实体团队的影响。这导致平台内同时运行着两套用户系统:
- 电商用户体系:核心的平台账户,管理用户的购买行为。
- 社区创作者体系:独立的创作者账户,管理其内容创作和社区互动。
表面上看,这似乎只是多了一套系统,但当社区业务与电商平台业务深度融合时,这个架构缺陷就显得越发严重,并让我们产品、研发同学都为此头疼不已
1.2 "双向绑定":一个看似可行却后患无穷的补丁
为了让创作者发布的内容能在主站展示,并且能以"作者"身份与"买家"互动,一种常见的临时解决方案是:电商账号与社区账号的双向绑定。
这种"打补丁"式的做法,几乎不可避免地会引入魔鬼般的复杂性:
- 数据一致性噩梦:用户修改了手机号或个人资料,应该同步哪一方?以谁为准?双向同步带来的循环依赖和数据冲突如何解决?
- 体验的割裂:用户需要感知到自己有两个身份,甚至可能在不同场景下看到不一致的个人信息,这严重损害了信任感和产品体验。
- 不可持续的技术债:这套脆弱的同步逻辑在后续的类似功能都需要进行迭代并且会感到难以维护
这种割裂的用户体系的架构是不可接受且不可持续的。它就像是一个定时炸弹,在未来的业务迭代中随时被引爆。
二、架构北极星:从"实体"到"角色"的认知升维
在与我们的产品团队沟通中,产品架构专家提供出了账号体系重构的北极星---将"创作者"从一个独立的"用户实体",降级为统一"用户"实体上的一种"身份标识"。
2.1 架构蓝图:基于"角色"的统一模型
新方案的核心是废弃原有的 creators
、mapping
等复杂的多表结构,建立一个统一的 User 模型,关联一个独立的 Roles 表。
user_id (主键)
phone
nickname"] Unified_UserRoles["user_roles 表
id (主键)
user_id (外键)
role (角色标识)"] end Unified_Users -- "1..N" --> Unified_UserRoles UserCenter_Service -- "查询/管理" --> Unified_Users UserCenter_Service -- "查询/管理" --> Unified_UserRoles end subgraph "业务系统" Platform_BE["电商平台后端"] Community_BE["社区后端"] end User["用户"] --> |"登录/操作"| Gateway["API 网关"] Gateway --> Platform_BE Gateway --> Community_BE Platform_BE -- "获取/更新用户信息" --> UserCenter_Service Community_BE -- "获取/更新用户信息" --> UserCenter_Service
这个模型的优越性是压倒性的:
- 架构的优雅:逻辑判断从"查询用户是否有关联的创作者信息"变成了"检查用户的角色列表里是否包含『创作者角色』",复杂度呈指数级下降。
- 真正的单一事实源:用户的核心数据只存储在一处。修改手机号、昵称这类问题,将从设计层面被彻底根除掉双向同步的问题。
- 面向未来的高扩展性:如果未来增加了电商的"个人卖家(Seller)"、社区的"版主(Moderator)"等新身份,只需在角色表中增加新的角色,无需重蹈覆辙再造一套系统。
2.2 对于角色驱动业务的设想
三、对于迁移路线图构想
在上面与产品的沟通中,我们有了一个优雅的角色驱动的架构设计。但目前这个庞大的用户体系如果在用户无感知、业务不中断的前提下完成平滑迁移,是一个巨大的挑战,这就像为「飞行中的飞机更换引擎」。
在一个平台业务系统中完成此类迁移,必须遵守下面 4 点硬性要求:
- 用户无感知 (Zero Downtime):不允许计划性停机。
- 数据零丢失 (Data Integrity):确保数据 100% 一致与完整。
- 过程可验证 (Verifiability):每一步操作的结果都必须可量化、可验证。
- 随时可回滚 (Reversibility):在最终切换前,每个阶段都具备快速回滚能力。
基于此,我认为可以设计一个包含"双写"和"灰度读"策略的三阶段实施方案。
阶段 1:前置准备(Preparation)
- 新模型就绪 :完成"统一用户模型"的数据库表结构(
user_roles
)设计与创建。 - 关键工具链开发:
- 数据迁移脚本 :开发一个一次性的、幂等的脚本,用于将存量数据从旧的
creators
表和user_creator_mapping
表迁移到新的user_roles
表。 - 数据验证工具:开发一个对比工具,能实时比对同一个用户在新旧两个系统中的数据,并输出差异报告来验证数据一致性
- 代码层抽象 :在现有应用代码中,抽象出一个统一的
UserService
接口,并提供两种实现:LegacyUserService
(调用旧逻辑) 和NewUserService
(调用角色中心)。通过配置中心的开关实现动态切换。
阶段 1:数据同步与双写 (Shadowing & Dual-Writing)
- 上线双写逻辑:
- 改造所有写操作的入口(如注册、修改资料等)。
- 修改后的逻辑是:所有写请求必须同时写入旧系统和角色中心。
- 关键原则:以旧系统的写操作成功为准。即,只要旧系统写入成功,就认为本次操作成功。新系统的写入失败通过日志记录,后续由修复任务进行补偿。这保证了即使新系统不稳定,也不会影响现有业务。
- 存量数据迁移:选择业务低峰期(比如凌晨),执行迁移脚本,将全量历史数据一次性写入到角色中心的数据库。
阶段 2:灰度读切换 (Gradual Read Migration)
- 开启灰度读 :利用特性开关和白名单系统,将一小部分读请求(例如 1% 的流量或内部员工账号)切换到
NewUserService
,即从角色中心读取数据。 - 数据实时比对与验证:
- 对于被灰度到的读请求,在返回结果前,同步调用旧服务获取数据。
- 关键原则 :如果不一致,以旧系统的数据为准返回给用户,并将差异详情记入日志,用于排查问题和修复数据。
- 逐步扩大流量:在确认数据一致性达到 99.99% 以上,且新系统性能和稳定性符合预期后,逐步将读流量从 1% -> 10% -> 50% -> 100% 切换到角色中心。
阶段 3:写操作切换与旧系统下线 (Write Cutover & Decommissioning)
让新系统成为唯一的"事实源",并优雅地让旧系统退出历史舞台。
- 切换写操作:当所有读流量都已 100% 由新用户中心承载且稳定运行一段时间后,进行最终切换。修改特性开关,将所有写操作也指向角色中心。
- 关闭双写:移除向旧系统写入数据的逻辑。从这一刻起,角色中心成为唯一的事实源 (Source of Truth)。
- 清理旧代码与旧表:
- 在观察一段时间确保万无一失后,可以安全地从代码库中移除所有与旧用户体系相关的逻辑、接口和特性开关。
- 将旧的
creators
和user_creator_mapping
表进行备份归档。
四、结论
这不止于重构,更是架构的进化~
这次对用户体系的重构思考,不止是一次简单的技术债偿还。其最终目标是将一个混乱的、打补丁的系统,重构为一个清晰、健壮且面向未来的统一平台,可以支持未来三年甚至更久的业务发展
通过引入"角色"这一优雅的抽象,不仅能从根源上解决数据一致性的顽疾,更可以构建一个具备高度扩展性的用户中台,为未来更多元化的业务形态打下坚实的基础。
👨💻 关于十三 Tech
资深服务端研发工程师,AI 编程实践者。
专注分享真实的技术实践经验,相信 AI 是程序员的最佳搭档。
希望能和大家一起写出更优雅的代码!
📧 联系方式 :569893882@qq.com
🌟 GitHub :@TriTechAI
💬 微信:TriTechAI(备注:十三Tech)