線上事故竟然是自己的鍋!!!
- 2022 年 4 月 10 日
- 筆記
前言
前段時間,我們線上系統出現了一個事故:用戶創建了商品,在商城的商品列表頁看不到,也搜索不到。、
這個問題持續了大概半個小時,最後發現竟然是我的鍋。
這個事情怎麼說呢,完全是我自己把自己坑了。到底怎麼回事呢?
1. 從需求說起
1.1 背景
由於我們這個迭代是個大版本,上線的日子要臨近了。這次上線需要運營配合提供很多商品屬性的數據,他們需要把第三方的屬性和我方系統的屬性,在excel表格中匹配起來。
原本是這樣規劃的:由運營同學在excel表格中手動對應雙方屬性的映射關係。
但後來,他們覺得屬性太多了,如果他們人工在excel表格中對應屬性映射關係,可能時間上有點來不及。
於是,他們在某次會議上,特意給我提了需求,希望我可以通過程式幫他們在excel中,把雙方的屬性值映射上。
有一個要求就是要:快
。
因為其他同事,還要基於這份excel數據,做一些後續處理。
1.2 原始需求
剛開始開會時,運營說的需求是:他們提供一個excel表格,裡面有分類和屬性欄位,然後讓我在程式中全匹配,把能夠匹配上的屬性編號和屬性,在excel的另外兩列中返回給他們。
然後,他們根據這份excel數據,把匹配不上的(即另外兩列為空)數據,在我們系統中手動錄入,這樣最終都能匹配上。
1.3 加戲了
本來我覺得這個需求挺簡單的。
但後來,運營加戲了(加新需求)。
其實,剛開始運營沒說完。
後來發現,他們要接入兩個廠商。
而且運營提供的兩個廠商的excel表格中欄位的格式不一樣,沒法用一套程式搞定。
而且,我們發現有部分屬性中包含了一個區間範圍,跟我們系統的數據肯定是對應不上的,必須要拆分屬性後再匹配。
很顯然,運營是不願意做這種手動拆分的工作的,這事他們想我幫他們用程式處理,這就給我增加了不少工作量。
此外,廠商1還有一個特殊需求:運營手動把excel中的部分數據剔除掉,然後基於這份新數據重新匹配一份新excel數據。
2. 最快的方案
了解運營的需求之後,我簡單的分析了一下。按需求的優先順序,排了一個順序:
- 導出廠商1的屬性數據。
- 導出廠商2的屬性數據。
- 給廠商1導一份特殊的屬性數據。
- 導出區間範圍能匹配上的數據。
如果這些需求都寫程式處理,可能要寫4個程式,而且還需要花時間部署程式碼,我怕時間上來不及。
於是我想了一個快速處理需求1、2、3的辦法即:直接通過sql語句查詢出所需數據
。
不過這套方案的前提是:需要把excel中的數據導入到生產環境中
。
為了保險起見,我先把excel中的數據導入dev環境中。等我寫好sql,測試好數據之後,再導入生產環境。
使用資料庫管理工具:Navicat Premium
的Import Wizard
功能,可以輕鬆將excel表格中的數據直接導入一張新表中。
它裡面可以指定excel的sheet對於哪張表,指定excel中的列對應表中哪些列。
由於這些需求都是新表,無需特別指定,我就按默認的表名和欄位名導入數據了。
但有個問題就是:表名和欄位名都是中文的,因為excel中的sheet名和sheet中的欄位名都是中文的。
其實,我當時已經發現了這個問題。
但當時又想了想,表中欄位比較多,要一一改成英文的,光起名字要花些時間。這些欄位最終還是要轉換成運營可以看得懂的中文的欄位名,這樣轉來轉去有點畫蛇添足,浪費時間。
而且這張表導入生產環境之後,是一張臨時表,用完了就會被刪除的,影響不大。
此外,這張表是新加的,如果沒有程式使用的話,應該是不會有問題的。
所以,當時沒多想,就找人把數據導入生產環境了。
導出數據的方法很簡單:
使用Navicat Premium
的Dump SQL File
中的Structure + Data
即可。
這樣該資料庫工具,就會把相關表的建表的create
語句,和插入數據的insert
語句,導出到一個.sql
後綴的文件中。
有個小問題就是:每條數據會生成一個insert語句,如果太多了放到生成環境執行,執行效率會比較低。
這時可以將insert腳本複製到idea或者其他的工具中打開,然後全文替換一下,去掉多餘的insert,拼接成一個insert語句。
然後再用在線的sql壓縮工具,比如://tool.lu/sql
,壓縮一下去掉多餘的空格。
這樣插入數據的sql放到生產環境執行,效率要快很多。
運營提供的excel表格中的數據,被導入生產環境之後。按計劃,通過一條sql語句,把運營所需要的結果直接查詢出來,然後把結果複製到excel表格中。(注意:如果查詢結果的數據太多,不建議這麼玩)。
按上面的做法,我很快完成了需求:1、2、3,並且把運營所需要的數據及時給他們了。
3. 一個插曲
原本按計劃,導完數據之後,生產環境中臨時表是要刪除的。
但出現了一個小插曲,運營給我提了一個臨時需求:需要重新導一份廠商2的數據給他們。
他們已經按照表格中的內容,把需要添加的屬性已經添加到系統中了。需要我們重新導一份數據,確認一下,現在是否所有數據都能匹配上。
此時,我當時在慶倖幸好數據沒刪。
運營的這個臨時需求,在線上執行相同的sql很快就把數據導出來了。
1分鐘實現需求,當時那叫一個:爽
。
而且我觀察了一下,系統沒有出現異樣。
給運營把數據導完之後,我就忙其他事情去了,把刪除數據這個事情給忘了。
4. 線上出現問題
第二天上午,領導把我叫過去說:canal服務掛了
。
我們分析canal了異常日誌後發現,這個問題是由於canal訂閱者,讀取中文的表名時,出現了亂碼,沒有成功讀取到。該程式直接拋了異常,導致canal訂閱者不能正常工作了。
這個問題對用戶的影響是:用戶創建了商品,在商城的商品列表頁看不到,也搜索不到,有用戶投訴到運營那邊了。
我當時的第一反應是:這也能掛?
我當時不知道下游的業務系統,通過canal監聽了我這邊的整個資料庫。
話不多說,先把問題解決了吧。
我們當時為了快速解決問題,先把中文的臨時表都刪了,然後把canal重啟一下。
果然,這個辦法是有效的。
canal監聽者立馬恢復正常了。
當天,沒有再出現過問題。
第二天,領導把我叫過去說:canal服務又掛了
。
我當時一臉懵逼。我什麼都沒幹呀。
Canal解析數據報錯:column size is not match for table xxxx 8 vs 9
。
後來,我們經過分析之後發現,canal有一份快取,如果canal出現異常,可能跟資料庫真實的情況不一致。
然後,我們把canal的meta.dat
刪除了,然後重啟服務,果然恢復正常了。
後面也一直沒出現過問題。
6. 確定需求4的方案
前面說過運營總共提了4個需求,我通過前面的騷操作,完成了3個需求。
但第4個需求,裡面還有點特殊要求,通過sql腳本不容易搞定,只能硬著頭皮寫java程式了。
運營的需求是把他們提供的excel表格中的數據導入系統,然後由系統匹配某個區間範圍內的數據,把結果寫入excel的另外兩列中,最後返回該excel文件。
拿到這個需求我腦子裡想了三個方案:
- 寫一個可執行的springboot工具項目,直接放到線上環境中執行jar包。
- 使用一個job處理,本身已經有xxl-job了,接入非常方便。
- 寫一個api介面。
最終我選擇了第3個方案。
為什麼?
其實這3個方案程式碼的工作量差不多,但前面兩個方案需要先上傳excel到應用伺服器
,或者到OSS
等文件伺服器
。
而如果運營需要導多次數據,每次都需要上傳一次excel,不僅浪費伺服器資源,而且比較費時,還麻煩。
如果用api介面的話,可以直接使用postman
遠程調用,直接上傳文件,通過輸入流的形式讀取數據,不保存到伺服器。然後處理完數據,在將excel內容以輸出流的形式返回給我們下載即可。
使用postman調用遠程介面時,入參選擇form-data
格式,key
那裡輸入File
,然後在右側下拉列表中選擇File
,就會出現Select Files
按鈕。
通過該按鈕,就能選擇我們需要上傳的excel文件。
如果想調用介面後直接下載excel文件:
在postman中可以選擇Send and Download
按鈕,即可下載文件。
注意,在圖片中的請求api介面地址是localhost,我只是舉了個例子,實際情況中是介面的域名。
此時,有些小夥伴可能會問題:這個介面不需要登錄就能訪問?
答:確實不需要登錄,我在網關層放開了該介面的訪問許可權。
那不是有安全問題?
答:為了解決介面安全問題,也避免發版影響正常用戶的使用。我的想法是基於master
分支新拉一個分支:hotfix
,而pre
環境(預生產環境,能訪問生產環境的資料庫)部署hotfix
分支的程式碼。
還有一個非常關鍵,而且我們一直在用的策略是:訪問pre的所有介面都必須使用指定的代理
。
公司外面的人肯定是不知道這個代理的存在的,換句話說,只有我們公司內部的人才能訪問pre環境的介面。
因此,新加的excel處理介面是非常安全的,而且該介面只部署pre環境,對正常用戶不會造成影響
這個方案看似挺完美的。
然後三下五除二,我把程式碼寫完,本地測試通過了,準備發到pre環境導數據。
7. jar包衝突
該功能部署pre環境其實非常簡單,只需要部署hotfix分支的程式碼即可。
程式碼部署好之後,我準備開始訪問介面。
先在postman的這個地方配置pre的代理。
程式碼部署好之後,就能通過上一節中介紹的內容上傳excel文件,然後下載結果excel文件了。
但我第一次調用介面時,沒有返回想要的數據。從應用伺服器的日誌中看到,該介面報錯了。
報的竟然是某個類找不到。。。。
我這次為了快速導入和導出excel文件,選擇了阿里的easyexcel
工具類。
本地開發環境,我確認過,那個類是有的。而且我這個功能是可以正常運行的,我都導出數據了。
但pre環境卻報了類找不到。
我猜可能是有jar包版本不兼容。
於是,調整了一下pom文件中引入的jar包的版本,之後,重新部署pre環境。
還真是這個原因,這一次介面能正常訪問,能夠返回數據了。
我心裡暗自竊喜。
後來,把運營所需要的excel文件及時發給他們了。
8. pre環境網路異常
又過了兩天,需求4有點調整。我把程式碼改了,還是那個hotfix分支,找人重新部署了pre環境。
打算用之前相同的方法導數據的。
但馬上被啪啪打臉。
用postman請求該介面很久都不返回,我知道肯定是出了什麼幺蛾子。
查了一下pre環境應用伺服器的日誌
,竟然沒有查到請求該數據處理介面的記錄。
接著,我查了一下pre環境應用網關層的日誌
,竟然也沒有記錄。
不對呀。
然後又查了一下生產環境應用網關層的日誌
,原來是請求到生產環境了。
不是配置了代理嗎?
為什麼會訪問到生產環境?
我帶著這兩個問題諮詢了一下公司的IT部門同事。他們追查了一下原因,發現原來網路頻寬被打滿,導致pre環境的代理出問題了。
經過一段時間之後,pre環境的代理恢復正常了。
其實,pre環境代理出問題後,我們也嘗試了一下登錄到遠程伺服器上,執行相關curl命令,直接調用伺服器的本地介面。最後,發現用這種方式不太好下載文件。
9. 部署錯分支了
pre環境代理恢復之後,我滿懷希望去用postman請求數據處理介面導數據。
但我發現導出的數據不對。
導出的excel文件根本打不開。
我打開excel文件看數據內容時,提示excel文件格式不對,或者已經被損壞了。
然後,我趕緊看應用伺服器的日誌,有請求記錄,但是沒有返回記錄,從這個日誌中看不出問題。
當時我靈機一動:既然保存成.xlsx
後綴的excel文件打不開,如果把文件後綴改成.csv
格式呢?
於是,我把導出的excel文件後綴改成了.csv
格式,果然可以打開文件。
文件內容中提示404
。
這時我就明白了,可能是pre環境的介面沒發成功,被其他分支的程式碼衝掉了。
然後,跟部署程式碼的同學溝通之後,他當時操作失誤,部署的master分支的程式碼,果然把hotfix的程式碼衝掉了。
後來,他重新部署了hotfix的程式碼,我順利的把數據導給運營了。
至此,這4個需求順利完成了。
總結
這次給運營導數據,是一次比較難得的經歷,遇到了很多問題,值得總結一下。
當然這其中有一部分是自己給自己挖的坑,也有一部分是被其他人坑了。
不要怕踩坑,其實踩坑,也是成長的機會,我通過這次經歷也收穫了不少寶貴的經驗。
- 生產環境的表名或欄位名,一定不能用中文的。不要抱僥倖心裡,說不定哪天就出問題了。
- 生產環境創建的臨時表,用完之後,一定要記得及時清理。
- 使用
canal
時,最好別全庫監聽。用到什麼表,就監聽什麼表,避免出現一些意外事故。 - 版本不兼容,會導致類找不到問題。
- 如果使用了
代理
,要考慮代理出現問題的情況。 - 程式碼發版之後,一定要再三確認分支是否正確。
- 刪除
meta.dat
文件,重新canal服務,可以解決canal的很多問題。 - postman真的非常強大,建議大家都好好用一下。
- 把多條insert語句合成一條執行,效率更高。可以使用
//tool.lu/sql
,這裡在線工具,壓縮一下sql去掉多餘的空格。 - excel導入和導出用阿里的
easyexcel
工具,真的非常方便。
還有挺多收穫的,這裡就不一一列舉了。
希望你看了我的文章,自己也會有點收穫,能從我的經歷中,學到一點點東西,我就已經心滿意足了。
如果這篇文章對你有點幫助的話,請記得給我點贊喔,謝謝你的支援。
我們下期再見。
最後說一句(求關注,別白嫖我)
如果這篇文章對您有所幫助,或者有所啟發的話,幫忙掃描下發二維碼關注一下,您的支援是我堅持寫作最大的動力。
求一鍵三連:點贊、轉發、在看。
關注公眾號:【蘇三說技術】,在公眾號中回復:面試、程式碼神器、開發手冊、時間管理有超贊的粉絲福利,另外回復:加群,可以跟很多BAT大廠的前輩交流和學習。