存量字段加密数据迁移与双写策略实战教程 - 第1节

为什么需要字段加密?

说实话,做数据库和后台开发这么多年,真正让我下定决心全面搞字段加密的,是一次线上事故。

那次用户的身份证、手机号明文存在 MySQL 里。测试环境被拖库,虽然是内网,但日志里查出了大批量查询——嗯,有人通过慢查询日志还原了整张表。虽然最后没造成大规模泄露,但这个坑让我记到现在。从那以后,我个人习惯:只要涉及敏感字段,第一反应就是——绝不能明文落库。

为什么字段加密这么重要?三个层面说清楚:

  • 合规要求:GDPR、等保 2.0、金融监管都明确要求个人信息加密存储。明文?罚单和通报等着你。
  • 防止内鬼和拖库:DBA 拥有表级权限,但如果字段是密文,就算拿到数据也无法直接解读。这是最后一道防线。
  • 数据生命周期安全:备份文件、归档日志、甚至运维脚本,都可能无意中泄露明文。加密后至少多了一层防御。

小技巧:我一般把加密粒度放在“敏感字段”级别,而不是全表加密。全表加密牺牲太多查询灵活性,字段级加密刚好平衡安全与可用性。

常见的字段加密方案

我常用的就三种:

  • 应用层加密:在 Service 层用 AES-256 加密,密文存 varchar。控制灵活,但查询时需要解密,无法做条件索引。
  • 数据库内置加密:MySQL 有 AES_ENCRYPT / AES_DECRYPT,性能还行,但密钥管理麻烦。
  • HSM/TDE:硬件加密,成本高,一般只有大厂金融级场景才用。

我见过很多团队上来就上 HSM,最后发现运维跟不上、性能瓶颈严重,还不如老老实实在应用层加解密。


存量数据迁移面临的挑战

假设你已经有 500 万用户,20 亿条记录,现在要对手机号做加密迁移。你想想看,这工作量有多大?最头疼的是——不能停机。

我总结过存量迁移的四大坑:

  1. 全量扫描性能打满:一次性对所有旧数据加密,I/O 和 CPU 飙高,直接拖慢线上业务。有次我把查询连接池打满,业务告警了半小时。
  2. 增量数据冲突:你在加密旧数据的时候,新的写请求还在源源不断产生。如果新数据明文写进去,回头迁移又要把它们读出来加密一遍,怎么保证一致性?
  3. 回滚困难:迁移到一半发现密钥泄露,或者加密策略有问题,你想回滚?没有干净的备份就是噩梦。
  4. 数据验证失真:迁移之后怎么确认所有字段都被正确加密了?常见做法是逐记录对比原始明文和新密文,但一致性校验本身又很耗时。

警告:千万别在生产环境用脚本直接 UPDATE 全表加密!我曾经有一个客户,DBA 跑了个 UPDATE t SET phone = AES_ENCRYPT(phone),没有分批,数据库直接 Hang 了 20 分钟,导致前端大量 502。关键在于——没有限流、没有分批、没有监控。

典型迁移策略对比

我实际参与过的项目里,存量迁移策略无非以下几种。我画了个表格,一目了然:

策略名称 优点 缺点 适用场景
全量一次性迁移 实现简单,管理成本低 停机时间长,风险集中 可接受停机窗口的小表
分批限流迁移 对线上影响小,可控 需额外编写分页游标逻辑 大表、业务低峰期、可拆分批次
镜像双写 + 后台补迁 完全无感,支持回滚 架构复杂度高,需要双写逻辑 高可用 7×24 业务

我个人最推崇第三种——双写 + 后台补迁。这也是我们本章的核心话题。


双写策略的引入

好,问题来了:你在不停机的情况下,既要加密旧数据,又要保证新写入的数据也加密。如果旧数据用后台脚本分批加密,新插入的数据同时在写入——这两股流的时序怎么对齐?

双写策略说白了就是:

  • 在新增写请求时,同时把数据加密后写到新字段(或新表),同时保留旧字段的明文。
  • 旧字段的明文用于兼容老代码,直到所有读流量切走。
  • 后台任务以低优先级分批把存量旧数据加密补齐。

嗯,这里要注意:双写策略不是简单的“写两次”,而是要保证最终一致性和无脏读。我遇到过团队写双写,结果新字段写入失败后没有回滚旧字段,导致同一条数据在新旧两份中有差异。后来排查了三天才找到原因——没有使用事务或者分布式锁来保障原子性。

核心原则:双写必须具有幂等性和可重试性。单个写请求要么新旧都成功写入,要么都失败回滚。否则会出现数据叛逃——新字段有,旧字段没有,或者反过来。

双写策略典型架构

我用一张图来说明数据流向。这张图我每次给团队讲都会画白板上,现在用 SVG 画出来:

双写策略存量迁移数据流 业务应用 双写路由层 旧表(明文字段) 新表(密文字段) 后台补迁任务 双写期间,旧表字段仍可读;补迁完成后,切换读流量到新表,再下线旧表

你看这张图,红框是旧表,绿框是新表。业务写请求先经过“双写路由层”,同时写两份。后台补迁任务(橙框)负责遍历旧表里的存量数据,读出明文,加密后写入新表。这个任务设计为低优先级、小批量、可中断——不会影响在线业务。

双写策略的时机与反模式

双写不是万能药。什么时候该用,什么时候不该?

  • 该用:业务 7×24 不可停、表数据量千万级以上、要求零感知迁移。
  • 不该用:一次性迁移窗口充足(例如凌晨 2-6 点可以停机)、表很小、允许短时不可用。

我记得有个团队,只有 2 万条数据的表也硬上双写,搞得代码复杂了 3 倍,后来回滚成全量迁移了。双写本身有代价——代码复杂度、事务风险、存储冗余,得权衡。


小结

这一章我们聊了三个根本问题:

  • 为什么要加密?合规、防泄露、生命周期安全。别等到被罚才后悔。
  • 存量迁移有哪些坑?性能、增量冲突、回滚、校验。我全都踩过。
  • 双写策略怎么引入?应用层路由,新旧库分写,后台补迁保证一致性。

别着急,后面几章我会一步步带你把双写策略的代码写出来,包括事务保证、幂等设计、重试机制。这些都是你实战中一定会用到的硬技能。

自己动手试试:如果你现在已经在做加密迁移,可以先在本子上画一张双写数据流图,对照我们刚才的 SVG,看看你的架构是不是缺了“后台补迁”或者“回滚机制”。