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

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

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

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

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

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

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

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

2. 遍歷本地資源文件夾,取出全部的素材文件。測試

3. 把全部素材文件歸類,將對應路徑格式化爲標籤,作文件名的正則校驗,篩選出知足要求的素材。優化

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

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等細節,不少地方都是能夠做爲優化點的。但願有時間有機會能夠採用這種方案進行改進,而且經過代碼的重構使得圖片導入的這個過程更加智能和方便。

相關文章
相關標籤/搜索