我們給項目換了個編碼

前言

經過多次的摸索和測試,終於把我們的一個GBK編碼Web項目大致成功轉到了UTF-8編碼。之所以沒有實現完美轉換,也是因爲這兩種編碼本質上還是有區別的,有部分數據覆蓋不到的地方,確實沒辦法處理。這裏簡單總結下我們的辛路手術歷程,供有需要的人蔘考。

術前方案討論 - 動哪,怎麼動?

前期我們決定立項的時候,討論了轉碼難點和可執行方案,我們的項目涉及Web後臺,PC/APP/開放平臺接口,數據對接等。主要難點在於,這項工作一旦測試通過,短期內必須要及時上線,否則新功能迭代就會出問題,一旦有公共數據覆蓋,可能造成不可挽回的髒數據。手術的結果應該是把病治好,不能更糟。基本上需要解決或者說兼容處理的地方主要有數據轉碼,文件轉碼,調用邏輯轉碼,內外接口兼容,原則上應該以UTF-8數據交互,轉碼的流程基本上如下圖所示:
轉碼流程示意
圖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層由於轉碼,失去了加速效果等。隨後進行了性能優化,響應時長恢復正常。

本次大動干戈學到了點兒啥?

看不懂的代碼不要隨便動。
經驗主義也會害死人。
寫的複雜並不代表性能一定差。
新項目一定要想清楚透徹,千萬不要爲了一時快,毀了下一代。

【完】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章