NO IMAGE

 
  重大的科學技術突破沒有什麼神奇的,—— 在其背後, 是將知識、方法、想象力、行動、嘗試、測試反覆無盡地投入的過程。

 

      程式設計是一場思維與意志的戰爭,是與自己思維缺陷不斷抗爭的過程。解決問題,引起新的問題,再消解問題,一步步小心地縮小問題的生存空間,直到幸運地發現問題能縮減到可以接受的範圍,或者鬱悶地發現問題在逐級擴大無法收拾只得從頭再來。思維能力和意志力有多強大,決定了程式設計能力所能達到的高度。

  當只有一個村落的時候, 世界很美好, 人們生活很幸福; 當逐漸增長到四十多個村落的時候, 人們發現需要劃分出一些大的村落來管理小的村落更合適; 當逐漸增長到八十多個村落時, 人們發現需要消滅小的村落,
只留下大的村落。問題誕生了。 

 

  假設是在做資料合併指令碼, 將多個叢集的分資料庫的資料合併到一個主資料庫中。

      最開始, 熱情是 100%, 投入工作。 隨著時間的推移, 熱情逐漸降低, 任務也趨於完成狀態。 當熱情降到 60% 左右, 任務終於基本完成了, 意外發生了。

      1.  半路殺出個程咬金。 本來是負責5個表 A,B,C,D,E 的資料合併。 然而最近的專案又新增了一個表 C’, (C 和 C’具有相似的欄位, 但是針對不同的實體)
, 而且在資料訂正所在專案之前上線(但是此時還沒有上線, 因此線上沒有相關資料參考)。 必須把這個表的合併工作考慮進去, 將 C 和 C’ 均合併到主資料庫的 C 表中; 此時, 還是有不少熱情來完成工作的; No Problem.

      2.  再一次完成後, 突然又被告知: 由於歷史上的手工維護, 導致 C 表的線上叢集的多個分資料庫的一些主鍵資料重複, 合併到主資料庫時會導致主鍵衝突, 於是, 需要在主資料庫的C表增加一個叢集標識的欄位區分出來,
原來的單欄位主鍵變成聯合欄位主鍵。 再一次修改;

      3.  再一次完成後, 與虛擬化網路團隊的成員討論發現, 將 C 和 C’ 表合併, 與線上某個已知待解決的遺留問題結合, 會導致一些小概率的不可靠, 這些不可靠可能會導致大的網路故障。
為了消除這種不可靠性, 決定再增加一個欄位來解決問題。 此時, 突然發現對 C 和 C’ 表存在著重大的理解錯誤。 原來以為 C’ 表的主鍵資料是包含在 C 表中, 現在發現是完全無交集的關係。由於相關專案還沒有上線, 無法抓取線上進行驗證, 只能採用潛規則和人工溝通的方式來確認。毫無疑問, 這需要一次較大的改動。

     4.  資料合併是必須考慮合併驗證、回滾和回滾驗證的。 資料驗證分單表資料驗證和表關聯資料驗證。回滾是將主資料庫對應於每個叢集的分資料庫的資料重新遷移到原來的分資料庫。回滾之前必須做備份和備份驗證。每一次改動,
都必須確保“合併、 合併後驗證、備份、備份後驗證、 回滾、 回滾後驗證”均正確無誤。並且, 由於涉及到的是客戶的敏感資料, 幾百萬條資料, 只要有一條資料訂正出錯, 都可能對一個或多個客戶的業務產生重大影響, 導致不小的故障。 必須一遍一遍地修改,執行驗證程式, 查詢資料驗證失敗的原因, 修復, 再驗證, 再修復, 再驗證, 就像改論文、拍電影一樣, 幾個步驟翻來覆去, 真是令人頭暈目眩, 思緒混亂, 瀕臨崩潰。即便如此, 也無法保證絕對不出問題。與此同時, 還需要負責一個重要系統的維護和技術支援, 時不時有一些其它事務打斷。 

      這裡有兩點需要考慮: A. 程式的可擴充套件性和可維護性。 當需要改動時, 不至於大動筋骨,修改很多地方; B. 程式的健壯性和容錯能力。由於線上資料存在髒資料, 出現若干條資料驗證失敗是很容易的,
需要程式具有很好的健壯性和容錯能力。 當出現資料驗證失敗時, 是直接終止,還是繼續執行並記錄下失敗的資料呢? 

     5.  憑藉最後的熱情, 終於再一次完成。 由於部署上線要通過 DBA 系統來建立新表。 問題又出現了:  由於 D 表的欄位 usage 與 mysql 關鍵字衝突, 該欄位被
DBA 系統直接遮蔽, 不可以使用, 因此, 必須將主資料庫的 usage 欄位改成其他欄位。 新一輪的修改又要開始了。

     6.  細節問題。 一些特殊值, 比如 NULL, 在 mysql 與 python 之間的轉換, 從 mysql 取出的 NULL, 在 python 會變成 None
,  如果不小心, 插入到 MySQL 就會變成 ‘None’ , 而不是 NULL, 這會導致某些查詢失效。

     7.  記錄日誌: 操作過程中的所有修改, insert / update 語句都必須記錄日誌, 發現的異常資料和不合正常約束的資料也必須記錄下來以備後查。

     8.  合併策略: 當要合併多個分資料庫時, 存在合併策略: 是順序地合併每一個分資料庫, 還是同時併發地合併每一個分資料庫。 順序合併簡單而安全, 只要效能在可接受範圍就可以採用;
併發合併效率更高一點, 但是容易出現錯誤, 必須仔細控制。 僅在單個資料庫合併非常耗時、或者實際合併時發現效能問題需要採用應急方案時才應該採用併發策略。 後者在我入職時參與的一次資料訂正過程真實地發生過。 在一張百萬級的表中使用了子查詢, 結果插入一條記錄需要幾秒鐘, 根本無法滿足專案預期時間。衍生教訓是: 一定要考察線上資料, 避免認識不足導致重大偏差。就好比要理解真實戰場, 才不至於腿還沒動就被斃掉了。

     9.  環境模擬。 由於線上環境與本地環境存在差異, 必須在本地測試環境模擬線上環境。比如說, 必須匯入和使用線上的庫和工具, 但本地是沒有的,而且也無法安裝, 就需要做一層簡單的
MOCK; 雖然有開發自測環境可用, 由於多人在爭用,且資料存在缺失, 無法體現線上資料的複雜性, 還是選擇在本地搭建測試環境,匯入線上資料(只匯入一個叢集的分資料庫資料, 模擬合併多個叢集的分資料庫情況)。 此外, 由於檔案系統的差異, 本地 windows 無法使用 /tmp/xxx.log 的檔案路徑, 而線上必須使用, 必須維護兩個版本, 在測試版本和釋出版本切換。很容易忘記切換。

 

       也許無需多言, 你已經經歷過類似的“折磨”。 有時技術的強弱並不是最重要的, 耐心和意志反而是最關鍵的。就像馬拉松一樣, 速度並不是最重要的, 耐心、策略和堅持才是最有力的品質。

 

       程式碼已經不那麼重要了,重要的是,在你的腦海裡,內心裡,靈魂裡,孕育著怎樣的圖景。你所見的,不再是電腦與程式碼,它們只是思維粒子,蘊釀,衝突,碰撞,迸發出最終的火花。