1. 程式人生 > >圖片的批量導入實現和對主鍵生成策略的思考

圖片的批量導入實現和對主鍵生成策略的思考

自己 得到 分段 長度 不能 import labels 消費 步驟

CDX一期上線的那天是我來公司最緊張的一天,因為這一天我要負責公司近5000張車型圖的導入工作。雖然在完成上傳和導入的代碼之後測試了很多遍,但是真正到了正式環境,卻真的很怕出問題。內搜、gift、以及本地和線上數據庫的同步,哪一個環節出了問題都會影響上線的時間。現在一期上了線,也對自己圖片上傳導入這部分做一些總結,還有對現有方法不足之處的一些思考。

其實一張圖的上傳邏輯還是比較簡單的:

1. 上傳圖片到gift服務器。

2. 保存圖片信息到線上數據庫。

3. 將圖片信息按固定格式推送給內搜,便於之後檢索。

現在公司有幾千張圖片,不可能人工的一張一張在頁面上傳,這就需要我來做一個批量上傳導入的腳本,實現邏輯大概如下:

1. 從設計部門拷貝資源庫素材到本地。

2. 遍歷本地資源文件夾,取出所有的素材文件。

3. 把所有素材文件歸類,將對應路徑格式化為標簽,做文件名的正則校驗,篩選出滿足要求的素材。

4. 把取到的所有素材文件依次上傳到gift,壓縮圖傳到public空間,原圖傳到private空間。

5. 將上傳成功的素材信息,標簽等寫入本地數據庫。

6. 將圖片發布,信息推送到內搜系統的隊列中。

7. 完成這個過程後,將本地數據庫新增的數據和線上數據庫進行同步。

看完這個過程,可能自己都會有疑問,為什麽有一個本地和線上數據庫同步的步驟?這是由於線上數據庫的連接地址vip只能線上服務器訪問,而本地並無權限,並且又不能把素材包和導入腳本統統放到線上環境去跑。這就導致了在這個過程中間會產生短暫的不一致現象:展現在web端就是,搜索發現有了這個圖(因為內搜已經消費了推送數據),但是點開詳情卻發現無此圖片。

但這個問題還是小問題,有個問題更無法忽視:數據庫的主鍵是自增的,那如何保證數據庫同步的過程中不會出現主鍵的沖突?這些都是我在下面想說的。

1. 批量上傳代碼的實現中的要點:

  • 遍歷文件夾使用了非遞歸的方式,因為要記錄每一級的文件夾信息,作為該圖的標簽keyLabels;另外對於文件的格式,文件名的規則做了正則校驗,這個和設計部門達成了統一。
  • 由於瀏覽器端上傳的圖片到了服務端是作為MultipartFile類型去接收的,由於MultipartFile是個接口,我必須要有實現該接口的類去對接本地遍歷之後得到的File集合,這裏我仿照springfreamwork.mock.web包下的MockMultipartFile,寫了一個相似的類,其中加了一些符合需求的字段擴展。
  • 在測試的過程中出現了JVM的OOM問題,這是由於我把文件夾下所有的圖片一起讀取,然後寫到了幾千個MockMultipartFile中的buffer中,難怪會內存溢出。這裏我做了分段上傳的處理,對files文件列表進行了等間隔的劃分,解決了OOM的問題。

2. 導出過程錯誤日誌的配置:

  在這些圖片導入的過程中,如果某個圖片在某一環節拋了異常,有可能會出現內搜,gift,數據庫三方數據不一致的情況,這是我們絕對不允許的。所以一定要做錯誤日誌的記錄,導入完成去查看錯誤日誌,定位到某個圖片,從而解決對應的不一致數據。這裏的日誌配置如下:

 <!-- 圖片導入環境 -->
    <springProfile name="import">
        <logger name="com.xiaojukeji" level="error" />
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>${normal-pattern}</pattern>
                <charset>${encoding}</charset>
            </encoder>
        </appender>

        <root level="error">
            <appender-ref ref="console"/>
        </root>
    </springProfile>

  可以看到,我是新建了一個import的spring.profiles,在這個模式下,我只記錄錯誤的日誌信息,並且我這裏試輸出到了控制臺,便於我及時發現問題。(事實上,正式導入過程很順利,沒有出現任何問題~)

3. 數據庫同步的問題和思考

  剛剛說到在所有圖片都導入gift和內搜的正式環境之後,需要把數據庫的新增信息同步到線上數據庫。由於主鍵是自增的,實現的時候會有主鍵沖突的可能性。這裏暫時處理的方法並不好:取了一段主鍵間隔,並按歷史數據分析不會出現上傳量大於間隔的情況,然後來避免這一沖突。(事實上,理論上還是存在沖突的可能性)

  那關於這一點的改進,我也想過一些方法。

  首先想到的是希望用全局唯一的主鍵uuid代替自增主鍵。但是innodb的自增主鍵確實性能高,大多時候還是需要采用的,反觀uuid,由於長度很長,考慮因素頗多,導致其性能一直是人們詬病的地方。

  然後看到部門的代碼腳手架中有一個IDGeneratorUtils,是公司內的一個主鍵生成器,裏面的思想類似於uuid,也會包含時間戳、機器碼等信息,但是實現比較輕量級,性能也會更好。

  

  寫在最後:除了以上所說,這部分導入功能還包含了線程池,內存io等細節,很多地方都是可以作為優化點的。希望有時間有機會可以采用這種方案進行改進,並且通過代碼的重構使得圖片導入的這個過程更加智能和方便。

圖片的批量導入實現和對主鍵生成策略的思考