數據對比場景

一、案例


公元2015年8月7日,星期五,立秋的前一天;在內陸,在北方,有秋老虎、秋扒皮一說,用於形容立秋那段時間的炙烤程度。但是在美麗的濱海之城深圳,並沒有秋老虎、秋扒皮這一說法,因爲在深圳,根本就沒有嚴格意義上的秋天。


我的美味早餐被“打翻”了


從班車下來,走到食堂,短短10分鐘路程,已經讓我這個體型偏瘦的人汗流浹背,幾近溼身。好在食堂的空調可以緩解下暑氣。當我還在品嚐着煎雞蛋的可口香味時,一個電話讓我連打包帶走的時間都沒有,直奔項目現場,也全然不顧烈日當空酷暑灼熱。


生產環境出現了性能問題,由於下午14點給上級領導演示的功能清單包含該功能,所以必須要在上午12點前修復。


當我趕到現場時,已經圍上了好幾個人,湊上去,一股汗漬味直撲而來。這其中我只認識一個人,就是給我電話的SE,其餘的都不認識。大家都神情嚴肅,全然不顧瀰漫在四周的汗漬味。


撲朔迷離的現象,跌宕起伏的劇情


“這個邏輯很簡單,就是將Excel的數據合併到數據表中,沒有業務邏輯處理,絕對是SQL的問題。”


看來他們也剛來不久,還在討論問題的原因。


“那就看下日誌,看是哪條SQL處了性能問題。


坐在電腦前的應該是這個功能的開發者或維護者,能明顯看到他的手在顫抖,以至於鼠標找了很久才點中“服務器日誌下載”所在的菜單項。這是必然的,自己做的功能出了問題,尤其是在給上級領導演示的節骨眼上,一種無形的壓力自然會干擾到人的正常行爲。


“你起來,我來操作。”


站在一旁的一位高個子看不下去了,幾乎是把他從座位上提着衣服拽起來了。

很快,在日誌中找到了導致超時的SQL。


“看看,我就說過是SQL導致的了,快,黃工,你趕快優化優化這個SQL”

SE顯得很興奮,大有爲自己的未卜先知而拍手稱快之意。


“不對呀,這是一條很簡單的insert語句,不會有性能問題吧。”


那位高個子小聲的說:“insert語句?怎麼可能,肯定是找錯了,再找找看。”


的確,從日誌上看,確實是由於一條insert values語句引發的超時。但是一條簡單的insert values語句會如何引發超時異常呢?說update或者delete或者還有可能。


“要不我們看下應用程序代碼吧。”


因爲在最近的幾起優化案例中,有一半是與Java程序代碼有關,既然日誌的記錄存在問題,我就建議迴歸本原。


在繼續看代碼之前,我在這裏先賣個關子,先把該功能的邏輯示意圖展現出來,如下圖:


640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy


一個蹩腳的設計方案


現在,如果你作爲該功能的設計者,你該如何設計呢?可以停頓下來,完成設計後再往下看,看下開發人員是如何設計的?又存在哪些更優的設計方案?對比自己的設計,是否是最優的?


“這個方案是誰設計的?”


還沒看到一半,SE按耐不住發飆了。當我看完真個代碼後,也爲設計人員捏了把汗,確實是一個非常蹩腳的設計。我們來看看設計人員的方案示意圖:


640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy


對於DB來說,一個非常簡單的數據同步,被設計得如此複雜,用當時的話說“也是一個人才”。


這個設計最致命的地方就是頻繁的訪問DB。


整個同步操作被封裝在一個事務中,事務的超時被設置爲120秒,即2分鐘如果這個事務還不能完成提交,就會拋出超時異常。這次的演練測試案例,按照開發人員的設計方案,會產生超達120萬次的BD訪問,每次訪問加處理,按1毫秒計算,120萬次的訪問也需要120萬毫秒,即1200秒,20分鐘,不超時纔怪。


據理力爭


近一小時過去了,稀拉拉空蕩蕩的辦公區已經人聲鼎沸,每個人都在用不同的方式驅趕身上的暑期汗漬,有擡頭望空調的,有拿着摺扇搖動的,有拽着書本搖晃的,有光手在額頭上抹漢的。都在談論這炙烤的天氣,而埋怨空調的“虛情假意”。而在靠東南的一個角落,三五個人已經忘卻了周圍的一切,正在商討着解決方案。


沒得說,這不是單條SQL的性能問題,方案必須得整改。


SE當即要求在方案上做出整改:將臨時表與正是表對比的步驟放在DB中,其它保持不變。他這樣做的理由是:一方面代碼改動量小,風險少;另一方面也符合他的設計理念:儘量在應用程序中處理數據。


我的方案是:像這種批量數據同步,應該全部在DB中完成。方案如下:


640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy


SE並沒有認可我的方案,他給的理由很充分:這樣改動太大,目前時間緊迫,根本無法消化。萬一弄出點功能上的問題,誰也擔當不起。


要知道,如果一旦將問題上升到功能的穩定性,基本上都需要讓步。而此刻的我也顧不了太多,據理力爭:


  • 首先Oracle是關係型數據的典範,批量處理這種數據具有先天優勢;

  • 其次,批量數據如果放在java端,勢必會帶來數據的批量遷移,兩臺服務器間數據傳輸也是需要消耗諸如IO、CPU、網絡帶寬等系統資源;

  • 最後,將所有處理封裝在SQL中也便於日後維護及擴展,如果有改動,只需要維護SQL語句,而無需改動java代碼,而且SQL寫起來簡潔易讀。


最後,從我近十年的ETL經驗,邏輯處理放在DB中,尤其是批量處理,是最佳實踐。


經過我的一番據理力爭,SE也放棄了他的堅持,決定選用我的方案。


方案出來了,誰來實施呢?開發人員怯生生的,驚魂未定的表示自己不會寫這麼複雜的SQL。


“你自己挖的坑,就由你自己來填吧。”SE對着我笑了笑。


二、批判


兩相對比,何其相似


該案例與第一個案例《WM_CONCAT優化》既有相似之處,也存在很大的差別,先說相似之處。


兩個案例最終的方案都是一樣的:在應用層面改架構,在DB層面改SQL。也就是說都是因爲應用架構引發的性能問題。現在我們就來說說這個架構規範。該項目的總架構師給該項目定了兩條規範,其一是邏輯處理要放在Java應用程序端;其二是不允許在DB端寫存儲過程。其實不難看出,第二條規範是對第一條的加強。存在即合理,更何況是有着各類項目實踐經驗的理論框架,更應該值得遵守。而問題是如何遵守纔是正確的?


理論框架只給出了一個指導方法,告訴你普世之下應該這麼做,然而並沒有告訴你,當遇到這種情況時,如何判斷?


再回到應用架構規範,到底是哪裏出了問題呢?顯然是在於開發人員對規範的應用上出了問題,也就是沒有理解規範的真正內容及目的。規範是出於擴展及性能考量,要求邏輯處理應放在應用程序服務器上完成,如果一味的生搬硬套,像本案例這樣,只能適得其反得不償失。


敏捷之殤:能力之輕,無法承受責任之重


事後開發兄弟聊天:


“這個當初是誰設計的?”

“是我自己”

“你覺得自己有足夠的設計能力嗎?”

“沒有,我工作不到兩年,開發能力還很欠缺,但是沒有辦法,項目上,大家都很忙,各自負責各自的模塊,從需求到交接後,就要承擔設計和開發的工作。”


看着開發兄弟滿臉的焦慮和自責,我也不知道該如何勸導。


“沒關係,大家都是這麼經歷過來的。大風大浪才能鍛煉出優秀水手不是?”


敏捷開發講究的是快速迭代與交付,因此在開發過程中,往往是重進度而輕質量。在快速交付過程中,對開發人員的要求是極高的。在常規的傳統軟件開發時,從方案到開發,是要層層評審的,而設計與開發的角色往往是由不同人來承當的。


而敏捷開發則不然,爲了輕裝上陣,快速推進,項目權限向一線授權,開發人員有了很多的權限;另一方面,將評審環節直接砍掉。這樣開發人員就具有了生殺大權。


權利越大,責任就也越大,也就意味着開發人員要有足夠的知識、經驗及能力去駕馭。所以,敏捷開發對項目成員的要求是非常高的。理想的要求是能做到自我管理,這是何其高的境界呀,終其一生也難帶到這個高度。因爲只有這樣的人員,才能保質保量的完成敏捷交付。


而事實上,在人員技能上,該項目遠沒有達到要求,這個項目的開發工作全部是由外包承接,剛畢業的應屆生充當經驗豐富的急先鋒,當然,這樣能得以成形,也離不開外包商在商務公關上的運作。這種想馬兒不吃草,又想馬兒跑得快的做法,最終導致了上線不到一年的系統,已經滿目瘡痍,各種性能問題頻發。好在項目組也即時發現了這個問題,即時搶救,大量從外部招聘中斷顧問來從事開發工作,不惜血本。


      總結:查詢在db中,對比用程序,將對比後的數據存放在兩個容器中,一個容器存入要刪除的數據,一個容器存入要寫入的數據,之後批量操作數據庫

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