系統乾崩了,只認代碼不認人

来源:https://www.cnblogs.com/mangod/p/18007504
-Advertisement-
Play Games

各位朋友聽我一句勸,寫代碼提供方法給別人調用時,不管是內部系統調用,還是外部系統調用,還是被動觸發調用(比如MQ消費、回調執行等),一定要加上必要的條件校驗。千萬別信某些同事說的這個條件肯定會傳、肯定有值、肯定不為空等等。這不,臨過年了我就被坑了一波,弄了個生產事故,年終獎基本是涼了半截。 為了保障 ...


各位朋友聽我一句勸,寫代碼提供方法給別人調用時,不管是內部系統調用,還是外部系統調用,還是被動觸發調用(比如MQ消費、回調執行等),一定要加上必要的條件校驗。千萬別信某些同事說的這個條件肯定會傳、肯定有值、肯定不為空等等。這不,臨過年了我就被坑了一波,弄了個生產事故,年終獎基本是涼了半截。

為了保障系統的高可用和穩定,我發誓以後只認代碼不認人。文末總結了幾個小教訓,希望對你有幫助。

一、事發經過

我的業務場景是:業務A有改動時,發送MQ,然後應用自身接受到MQ後,再組合一些數據寫入到Elasticsearch。以下是事發經過:

  1. 收到一個業務A的異常告警,當時的告警如下:

  2. 咋一看覺得有點奇怪,怎麼會是Redis異常呢?然後自己連了下Redis沒有問題,又看了下Redis集群,一切正常。所以就放過了,以為是偶然出現的網路問題。

  3. 然後技術問題群里 客服 反饋有部分用戶使用異常,我警覺性的感覺到是系統出問題了。趕緊打開了系統,確實有偶發性的問題。

  4. 於是我習慣性的看了幾個核心部件:

    1. 網關情況、核心業務Pod的負載情況、用戶中心Pod的負載情況。
    2. Mysql的情況:記憶體、CPU、慢SQL、死鎖、連接數等。
  5. 果然發現了慢SQL和元數據鎖時間過長的情況。找到了一張大表的全表查詢,數據太大,執行太慢,從而導致元數據鎖持續時間太長,最終資料庫連接數快被耗盡。

SELECT xxx,xxx,xxx,xxx FROM 一張大表
  1. 立馬Kill掉幾個慢會話之後,發現系統仍然沒有完全恢復,為啥呢?現在資料庫已經正常了,怎麼還沒完全恢復呢?又繼續看了應用監控,發現用戶中心的10個Pod里有2個Pod異常了,CPU和記憶體都爆了。難怪使用時出現偶發性的異常呢。於是趕緊重啟Pod,先把應用恢復。
  2. 問題找到了,接下來就繼續排查為什麼用戶中心的Pod掛掉了。從以下幾個懷疑點開始分析:
    1. 同步數據到Elasticsearch的代碼是不是有問題,怎麼會出現連不上Redis的情況呢?
    2. 會不會是異常過多,導致發送異常告警消息的線程池隊列滿了,然後就OOM?
    3. 哪裡會對那張業務A的大表做不帶條件的全表查詢呢?
  3. 繼續排查懷疑點a,剛開始以為:是拿不到Redis鏈接,導致異常進到了線程池隊列,然後隊列撐爆,導致OOM了。按照這個設想,修改了代碼,升級,繼續觀察,依舊出現同樣的慢SQL 和 用戶中心被乾爆的情況。因為沒有異常了,所以懷疑點b也可以被排除了。
  4. 此時基本可以肯定是懷疑點c了,是哪裡調用了業務A的大表的全表查詢,然後導致用戶中心的記憶體過大,JVM來不及回收,然後直接乾爆了CPU。同時也是因為全表數據太大,導致查詢時的元數據鎖時間過長造成了連接不能夠及時釋放,最終幾乎被耗盡。
  5. 於是修改了查詢業務A的大表必要校驗條件,重新部署上線觀察。最終定位出了問題。

二、問題的原因

因為在變更業務B表時,需要發送MQ消息( 同步業務A表的數據到ES),接受到MQ消息後,查詢業務A表相關連的數據,然後同步數據到Elasticsearch。

但是變更業務B表時,沒有傳業務A表需要的必要條件,同時我也沒有校驗必要條件,從而導致了對業務A的大表的全表掃描。因為:

某些同事說,“這個條件肯定會傳、肯定有值、肯定不為空...”,結果我真信了他!!!

由於業務B表當時變更頻繁,發出和消費的MQ消息較多,觸發了更多的業務A的大表全表掃描,進而導致了更多的Mysql元數據鎖時間過長,最終連接數消耗過多。

同時每次都是把業務A的大表查詢的結果返回到用戶中心的記憶體中,從而觸發了JVM垃圾回收,但是又回收不了,最終記憶體和CPU都被乾爆了。

至於Redis拿不到連接的異常也只是個煙霧彈,因為發送和消費的MQ事件太多,瞬時間有少部分線程確實拿不到Redis連接。

最終我在消費MQ事件處的代碼里增加了條件校驗,同時也在查詢業務A表處也增加了的必要條件校驗,重新部署上線,問題解決。

三、總結教訓

經過此事,我也總結了一些教訓,與君共勉:

  1. 時刻警惕線上問題,一旦出現問題,千萬不能放過,趕緊排查。不要再去懷疑網路抖動問題,大部分的問題,都跟網路無關。
  2. 業務大表自身要做好保護意識,查詢處一定要增加必須條件校驗。
  3. 消費MQ消息時,一定要做必要條件校驗,不要相信任何信息來源。
  4. 千萬別信某些同事說,“這個條件肯定會傳、肯定有值、肯定不為空”等等。為了保障系統的高可用和穩定,咱們只認代碼不認人
  5. 一般出現問題時的排查順序:
    1. 資料庫的CPU、死鎖、慢SQL。
    2. 應用的網關和核心部件的CPU、記憶體、日誌。
  6. 業務的可觀測性和告警必不可少,而且必須要全面,這樣才能更快的發現問題和解決問題。

======>>>>>> 關於我 <<<<<<======

本篇完結!歡迎點贊 關註 收藏!!!

原文鏈接https://mp.weixin.qq.com/s/TvIpTZq0XO8v9ccYSsM37Q


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ZooKeeperServer 實現了單機版zookeeper服務端功能,子類實現了更加豐富的分散式集群功能: ZooKeeperServer |-- QuorumZooKeeperServer |-- LeaderZooKeeperServer |-- LearnerZooKeeperServer ...
  • 臨時接到一個需求說讓根據按照下麵的這個圖片的結構來打包下載指定位置下的文件到指定位置! 實現思路: 1.把已經實現的樹形結構的代碼進行調用,拿到他的數據進行創建對應的文件夾 2.因為結構下方的文件沒有特別直觀的資料庫中的關聯關係,所以還需要對於管理關係進行梳理 3.創建好階級文件,然後調用網上找的工 ...
  • 在該文章中,我們基於OpenVINO™ Python API 向大家展示了包含後處理的RT-DETR模型的部署流程,但在實際工業應用中,我們為了與當前軟體平臺集成更多會採用C++平臺,因此在本文中,我們將基於OpenVINO™ C++ API 向大家展示了不包含後處理的RT-DETR模型的部署流程,... ...
  • 目錄1. 引言2. 優化過程2.1. 進程對象定義與初步分析2.2. 排除Json序列化2.3. 使用BinaryWriter進行二進位序列化2.4. 數據類型調整2.5. 再次數據類型調整與位域優化3. 優化效果與總結 1. 引言 在操作系統中,進程信息對於系統監控和性能分析至關重要。假設我們需要 ...
  • C# Switch 語句 使用 switch 語句選擇要執行的多個代碼塊中的一個。 示例: switch(expression) { case x: // 代碼塊 break; case y: // 代碼塊 break; default: // 代碼塊 break; } 它的工作方式如下: 評估 s ...
  • 背景:今天接到客戶一個需求,就是在收銀員在用掃碼槍掃顧客會員碼或者微信付款碼的時候判斷用戶有沒有加企微好友和進企微群,然後根據這個狀態進行語音播報,判斷顧客能不能享受優惠價。關鍵難點就是用戶用的收銀系統是別家的,線上小程式用的是我們家的,兩家不互通,所以立即決定採用Hook鉤子技術做一工具掛在其他收 ...
  • 使用C#中的Dictionary與ConcurrentDictionary進行多線程操作 在C#中,Dictionary是一個常見的字典類型,但它不是線程安全的。為了在多線程環境中確保全全的操作,我們可以使用ConcurrentDictionary,這是一個專門設計用於多線程場景的線程安全字典。 1 ...
  • 在 .NET 中,Task 和 ValueTask 都是用於表示非同步操作的類型,但它們有一些重要的區別。 Task Task 是最常見的表示非同步操作的類型。它通常用於表示耗時的、非同步的操作,比如從文件讀取數據、執行資料庫查詢等。Task 是一個引用類型,它封裝了非同步操作的狀態和結果。 using S ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...