我们给项目换了个编码

前言

经过多次的摸索和测试,终于把我们的一个GBK编码Web项目大致成功转到了UTF-8编码。之所以没有实现完美转换,也是因为这两种编码本质上还是有区别的,有部分数据覆盖不到的地方,确实没办法处理。这里简单总结下我们的辛路手术历程,供有需要的人参考。

术前方案讨论 - 动哪,怎么动?

前期我们决定立项的时候,讨论了转码难点和可执行方案,我们的项目涉及Web后台,PC/APP/开放平台接口,数据对接等。主要难点在于,这项工作一旦测试通过,短期内必须要及时上线,否则新功能迭代就会出问题,一旦有公共数据覆盖,可能造成不可挽回的脏数据。手术的结果应该是把病治好,不能更糟。基本上需要解决或者说兼容处理的地方主要有数据转码,文件转码,调用逻辑转码,内外接口兼容,原则上应该以UTF-8数据交互,转码的流程基本上如下图所示:
我们给项目换了个编码_第1张图片
图1 数据转码示意

下面我依次来总结下各个方面的处理:

  1. 稳住之前的记录

要说什么是最重要的东西,当然是客户数据。无数血的教训,警示我们客户数据一定要保证安全准确。我们的数据主要来源Mysql, MongoDB,ES,Memcached,Redis等,其中MongoDB,ES,Redis数据基本上都是UTF-8编码,所以不需要特殊处理,需要处理的是mysql 和memcached。由于mysql数据量巨大,且不容易在很短的时间内准确无误的转换完毕,所以本阶段保持了mysql数据编码不变。memcached的数据类型复杂,字符串、数组、序列化数据,全部遍历并转换,也不太现实。故针对这两个数据源采取了兼容处理,即读取GBK->UTF-8,mysql写入UTF-8 -> GBK,memcached数据写入更新成UTF-8编码。即增加了一个中间代理层,负责统一转码处理。

  1. 文件转码

项目文件编码转换相对较容易,iconv和enca都可以,这里我推荐使用enca,简单,方便,自动检测编码,不需要单独写脚本处理。
例如: 单独对文件转码的话可以执行:enca -L chinese -x UTF-8 file
如需要对目录递归转码的话可以执行: find . -type f | xargs -I {} enca -L zh_CN -x UTF-8 {}

  1. 数据驱动层兼容

数据不变的话,只能在驱动层和代理层操作转码了,mysql那边做了读写转码,memcached那边做了读取转码,写入更新。mongodb取消了以前转码逻辑。es和redis没动。

  1. 处理业务调用逻辑

改动较多的是项目代码,凡是涉及到转码相关函数的地方,都需要原样返回,很多时候是递归操作,所以这里写了一个脚本,正则转码函数,并替换。当然也不是万能的,有几个文件写法特殊的,是手动修改的。

  1. API兼容处理

由于我们的各版本客户端用户多达百万,API接口的输入、输出格式和结果不变,必须准确无误。最早端的接口数据要求GBK,这里输入的地方,由于涉及底层改动,本着最小化影响的原则,跟web做了标识区分,检测数据来源是端的,进行转码。输出的地方,重点说下base64编码的问题,开始时想对base64加密的数据做检测,尝试了多种方法之后,总有遗漏,不够准确,后来了解了下base64编码规则和stack overflow前辈们的留言,否定了这个,改成脚本去检测代码加密和解密的调用地方,批量替换了下。这里也印证了那句话“源码面前无秘密”,找不到答案的时候,就去看原理。

做完手术数据读取不出来了?

虽然我们对数据逻辑做了可靠性推理和测试验证,灰度和线上切换的时候,还是遇到了部分数据读取异常和数据缺失的问题。这里主要说下
unserialize数据、带中文key的数据坑。灰度测试的时候,发现memcached数据部分没读取出来,查看了错误日志,发现存在中文key的情况,开始的转码逻辑并没有对中文key做处理,增加之后恢复正常。也有部分序列化的数据解析失败,检查日志发现,不同编码下的中文长度不一致,导致了序列化解析失败,于是写了兼容解序列化的方法,替换了全局函数。还有些是强类型问题带来的,比如mongodb数据,这里主要也是以前封装的方法有些问题。好在都有备份,找到问题之后及时处理了。后来又有部分乱码的,分析之后发现由于检测达不到十分准确,存在二次转码的问题,又进行了转码标记。

做完手术成老牛拉破车了?

在灰度跑了2周之后,我们终于决定在周五晚上10点上了预发布,启动局部客户更新,但是效果并不理想。主要是问题是部分客户数据复杂,非常慢。部分接口响应时长达到了20多s,抓包分析之后,发现统一转码递归的次数太多。部分存在二次调用;cache层由于转码,失去了加速效果等。随后进行了性能优化,响应时长恢复正常。

本次大动干戈学到了点儿啥?

看不懂的代码不要随便动。
经验主义也会害死人。
写的复杂并不代表性能一定差。
新项目一定要想清楚透彻,千万不要为了一时快,毁了下一代。

【完】

你可能感兴趣的:(服务架构)