線上事故竟然是自己的鍋!!!


前言

前段時間,我們線上系統出現了一個事故:用戶創建了商品,在商城的商品列表頁看不到,也搜索不到。、

這個問題持續了大概半個小時,最后發現竟然是我的鍋。

這個事情怎么說呢,完全是我自己把自己坑了。到底怎么回事呢?

1. 從需求說起

1.1 背景

由於我們這個迭代是個大版本,上線的日子要臨近了。這次上線需要運營配合提供很多商品屬性的數據,他們需要把第三方的屬性和我方系統的屬性,在excel表格中匹配起來。

原本是這樣規划的:由運營同學在excel表格中手動對應雙方屬性的映射關系。

但后來,他們覺得屬性太多了,如果他們人工在excel表格中對應屬性映射關系,可能時間上有點來不及。

於是,他們在某次會議上,特意給我提了需求,希望我可以通過程序幫他們在excel中,把雙方的屬性值映射上。

有一個要求就是要:

因為其他同事,還要基於這份excel數據,做一些后續處理。

1.2 原始需求

剛開始開會時,運營說的需求是:他們提供一個excel表格,里面有分類和屬性字段,然后讓我在程序中全匹配,把能夠匹配上的屬性編號和屬性,在excel的另外兩列中返回給他們。

然后,他們根據這份excel數據,把匹配不上的(即另外兩列為空)數據,在我們系統中手動錄入,這樣最終都能匹配上。

1.3 加戲了

本來我覺得這個需求挺簡單的。

但后來,運營加戲了(加新需求)。

其實,剛開始運營沒說完。

后來發現,他們要接入兩個廠商。

而且運營提供的兩個廠商的excel表格中字段的格式不一樣,沒法用一套程序搞定。

而且,我們發現有部分屬性中包含了一個區間范圍,跟我們系統的數據肯定是對應不上的,必須要拆分屬性后再匹配。

很顯然,運營是不願意做這種手動拆分的工作的,這事他們想我幫他們用程序處理,這就給我增加了不少工作量。

此外,廠商1還有一個特殊需求:運營手動把excel中的部分數據剔除掉,然后基於這份新數據重新匹配一份新excel數據。

2. 最快的方案

了解運營的需求之后,我簡單的分析了一下。按需求的優先級,排了一個順序:

  1. 導出廠商1的屬性數據。
  2. 導出廠商2的屬性數據。
  3. 給廠商1導一份特殊的屬性數據。
  4. 導出區間范圍能匹配上的數據。

如果這些需求都寫程序處理,可能要寫4個程序,而且還需要花時間部署代碼,我怕時間上來不及。

於是我想了一個快速處理需求1、2、3的辦法即:直接通過sql語句查詢出所需數據

不過這套方案的前提是:需要把excel中的數據導入到生產環境中

為了保險起見,我先把excel中的數據導入dev環境中。等我寫好sql,測試好數據之后,再導入生產環境。

使用數據庫管理工具:Navicat PremiumImport Wizard功能,可以輕松將excel表格中的數據直接導入一張新表中。

它里面可以指定excel的sheet對於哪張表,指定excel中的列對應表中哪些列。

由於這些需求都是新表,無需特別指定,我就按默認的表名和字段名導入數據了。

但有個問題就是:表名和字段名都是中文的,因為excel中的sheet名和sheet中的字段名都是中文的。

其實,我當時已經發現了這個問題。

但當時又想了想,表中字段比較多,要一一改成英文的,光起名字要花些時間。這些字段最終還是要轉換成運營可以看得懂的中文的字段名,這樣轉來轉去有點畫蛇添足,浪費時間。

而且這張表導入生產環境之后,是一張臨時表,用完了就會被刪除的,影響不大。

此外,這張表是新加的,如果沒有程序使用的話,應該是不會有問題的。

所以,當時沒多想,就找人把數據導入生產環境了。

導出數據的方法很簡單:

使用Navicat PremiumDump SQL File中的Structure + Data即可。

這樣該數據庫工具,就會把相關表的建表的create語句,和插入數據的insert語句,導出到一個.sql后綴的文件中。

有個小問題就是:每條數據會生成一個insert語句,如果太多了放到生成環境執行,執行效率會比較低。

這時可以將insert腳本復制到idea或者其他的工具中打開,然后全文替換一下,去掉多余的insert,拼接成一個insert語句。

然后再用在線的sql壓縮工具,比如:https://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文件。

拿到這個需求我腦子里想了三個方案:

  1. 寫一個可執行的springboot工具項目,直接放到線上環境中執行jar包。
  2. 使用一個job處理,本身已經有xxl-job了,接入非常方便。
  3. 寫一個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個需求順利完成了。

總結

這次給運營導數據,是一次比較難得的經歷,遇到了很多問題,值得總結一下。

當然這其中有一部分是自己給自己挖的坑,也有一部分是被其他人坑了。

不要怕踩坑,其實踩坑,也是成長的機會,我通過這次經歷也收獲了不少寶貴的經驗。

  1. 生產環境的表名或字段名,一定不能用中文的。不要抱僥幸心里,說不定哪天就出問題了。
  2. 生產環境創建的臨時表,用完之后,一定要記得及時清理。
  3. 使用canal時,最好別全庫監聽。用到什么表,就監聽什么表,避免出現一些意外事故。
  4. 版本不兼容,會導致類找不到問題。
  5. 如果使用了代理,要考慮代理出現問題的情況。
  6. 代碼發版之后,一定要再三確認分支是否正確。
  7. 刪除meta.dat文件,重新canal服務,可以解決canal的很多問題。
  8. postman真的非常強大,建議大家都好好用一下。
  9. 把多條insert語句合成一條執行,效率更高。可以使用https://tool.lu/sql,這里在線工具,壓縮一下sql去掉多余的空格。
  10. excel導入和導出用阿里的easyexcel工具,真的非常方便。

還有挺多收獲的,這里就不一一列舉了。

希望你看了我的文章,自己也會有點收獲,能從我的經歷中,學到一點點東西,我就已經心滿意足了。

如果這篇文章對你有點幫助的話,請記得給我點贊喔,謝謝你的支持。

我們下期再見。

最后說一句(求關注,別白嫖我)

如果這篇文章對您有所幫助,或者有所啟發的話,幫忙掃描下發二維碼關注一下,您的支持是我堅持寫作最大的動力。

求一鍵三連:點贊、轉發、在看。

關注公眾號:【蘇三說技術】,在公眾號中回復:面試、代碼神器、開發手冊、時間管理有超贊的粉絲福利,另外回復:加群,可以跟很多BAT大廠的前輩交流和學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM