「重啟程式」對我來講,太熟悉了不過了,我很糾結,因為它能幫我解決問題,但出於程式設計師對於程式健壯的強迫症,我又本能的抗拒。
這篇文章, 我想分享 "工作十年,我對「重啟程式」的認知升級過程",希望對大家有所啟發。
2010 - 2014 年 ,蠻幸運的,我經歷了一家彩票網站重構的整個過程 ,負責過使用者服務,訂單服務,支付系統,入口網站等 ,基本把公司的系統都做了一遍。
行動網際網路時代,彩票 APP 也做到了垂直類的第一名,我特別珍惜這段時間,工作上我全情投入,學習技術如飢似渴,遇到了極多稀奇古怪的問題,取得了很大的進步 。
第一次生產環境重啟,也是我的人生第一次重大 BUG ,我負責的使用者中心在上線後隔一段時間變會記憶體溢位。我站在運維同學那裡,看著他調整 tomcat jvm 引數 ,不知所措 。但就算調整了,只能是延緩溢位的時間,過了幾個小時服務還是記憶體溢位了。運維每隔一段就主動的把應用重啟了,這樣業務看起來能正常執行。
後來發現我在使用 ibatis 的時候 ,使用類似的 SQLMap,前端又沒有驗證,資料庫執行了全表查詢,從而導致 JVM OOM 。
這次事故給了我很大的刺激,事故的原因只是因為我寫的程式存在嚴重的 BUG, 程式並不能控制好記憶體資源,只能通過外力暴力的「重啟」來釋放系統資源。
隨著彩票訂單量的激增,彩票系統遇到了越來越多的問題,採取重啟程式方案頻率也越來越高。
《我與訊息佇列的八年情緣》這篇文章提到了核心服務「排程中心」重啟的一個案例:
某一天雙色球投注截止,排程中心無法從訊息佇列中消費資料。訊息匯流排處於只能發,不能收的狀態下。 整個技術團隊都處於極度的焦慮狀態,「要是出不了票,那可是幾百萬的損失呀,要是使用者中了兩個雙色球?那可是千萬呀」。大家急得像熱鍋上的螞蟻。
這也是整個技術團隊第一次遇到消費堆積的情況,大家都沒有經驗。
首先想到的是多部署幾臺排程中心服務,部署完成之後,排程中心消費了幾千條訊息後還是 Hang 住了。 這時,架構師只能採用重啟的策略。你沒有看錯,就是重啟大法。說起來真的很慚愧,但當時真的只能採用這種方式。
排程中心重啟後,消費了一兩萬後又 Hang 住了。只能又重啟一次。來來回回持續20多次,像擠牙膏一樣。而且隨著出票截止時間的臨近,這種思想上的緊張和恐懼感更加強烈。終於,通過1小時的手工不斷重啟,訊息終於消費完了。
我當時正好在讀畢玄老師的《分散式 Java 應用基礎與實踐》,猜想是不是執行緒阻塞了,於是我用 Jstack 命令檢視堆疊情況。 果然不出所料,執行緒都阻塞在提交資料的方法上。
我們馬上和 DBA 溝通,發現 oracle 資料庫執行了非常多的大事務,每次大的事務執行都需要30分鐘以上,導致排程中心的排程出票執行緒阻塞了。
技術部後來採取瞭如下的方案規避堆積問題:
1、生產者傳送訊息的時候,將超大的訊息拆分成多批次的訊息,減少排程中心執行大事務的機率;
2、資料來源設定引數,假如事務執行超過一定時長,自動拋異常,回滾。
排程中心做為彩票交易最核心的系統,團隊願意投入資源去優化,可是周邊的系統呢 ?舉兩個例子:
1、團建路上,運維同學半開玩笑的說:」這一路上,幾個小時,我都重啟了三個系統了,要不我定時給你們重啟得了"。大家都尷尬的笑著。
2、駭客打電話給我們客服,嘲笑我們:「你們的程式設計師沒腦子,寫個 JSP 都能讓我來拖庫「。最後勒索了公司幾萬塊錢。這次駭客勒索事件,也讓當時的很多同事倍感挫敗感。
現在想來,彩票技術團隊的管理還是太過於粗糙,技術管理者不重視技術儲備和流程管理,再加上研發人員的工作負擔重,基本沒有精力優化好程式碼,非核心程式碼質量很差,發生了很多的生產事故,重啟程式也成為了常態 。
當我先後服務於藝龍,神州優車等團隊,每當設計系統的時候,我都會將系統骨架設計好,並且思考哪些場景容易造成資源洩露問題(比如記憶體洩露,socket 連線洩露),並且嚴格控制程式碼質量,也就再也沒有使用過「重啟程式」的方案了。
兩年前的一次效能優化,讓我從架構設計層面對「重啟程式」有了另外的思考 。
當時接手了一個轉碼服務,轉碼是將老師上傳的檔案轉換成目標格式。 比如課件檔案 ppt 或者 word ,轉換成 HTML , 或者 PDF 格式等。
轉碼服務部署在多臺物理機上,每隔一段時間,服務的效能就下降得極快,一次轉碼的耗時從幾十秒增長到十幾分鍾 。而且業務量增長很快,已經有100多萬轉碼任務在堆積了。
通過一週的不間斷的觀察,發現國外的一個商業版的轉碼外掛,存在記憶體洩露的問題。
可是怎麼解決呢 ? 看原始碼嗎 ? 軟體閉源。我試圖反編譯,但反編譯的程式碼可讀性極差。為了讓任務快速執行完成,我還是使用了非常抗拒的方案:"讓運維同學寫指令碼,每隔一個小時重啟轉碼服務"。效果和我預期中的一樣,堆積的任務不久就執行完成了。
看起來解決了,但我深知:"這僅僅是臨時的方案"。可是有什麼好的解決方案嗎?
當時正好在讀周志明老師的《鳳凰架構》,書中的一句話讓我思考良久:
「如果系統中某個部分採用了由極不靠譜的人員所開發的極不靠譜的程式,哪怕存在嚴重的記憶體洩露問題,哪怕最多隻能服務三分鐘就會崩潰,只要整體架構設計有恰當自動化的錯誤熔斷,服務淘汰,重試機制,從系統外部來看,架構依然表現出穩定和健壯的服務能力」。
按照這個思路,只要在架構設計層面遮蔽商用轉碼軟體的 BUG,不就可以了嗎?
將轉碼角色分為三部分:排程器 ,使用者端,轉碼服務 ,轉碼服務是 worker ,負責執行任務即可,排程器會將不同的任務分配到不同的伺服器上,使用者端會上報每個轉碼服務的狀態,當轉碼服務出現問題時,排程器可以通過使用者端重啟/關閉/暫停轉碼服務,在排程任務的過程中,需要保證任務訊息不丟失。
我完成了心理建設:「做為程式設計師需要避免使用「重啟程式」的方案,假如遇到迫不得已的場景,需要從架構層面做好設計,從系統外部來看,架構依然表現出穩定和健壯的服務能力」。
可是這樣就結束了嗎 ?
2021年,我無意中讀到了自媒體九邊的一篇文章《中國製造,比德國製造到底差在哪?》,看完之後,我恍然大悟:
「企業本身對於產品質量並不重視,因為人力資源充沛,也不太在意質量和管理方式的缺陷,大不了通過加班方式補償,質量問題頻現也就很自然了,大量的質量問題並不以個人的意志為轉移。」
下文摘自《中國製造,比德國製造到底差在哪?》:
還在我大學的時候,當時院裡請了一個國內著名的軟體公司負責人去演講,當時他講到一個我當時覺得很牛逼的事。
他說,他們的軟體在伺服器上線後,有個記憶體洩露問題,非常緩慢,差不多一個禮拜能洩露完,到時候伺服器就會重啟。如果那個時候你正在玩他們的遊戲,就會出現「伺服器不線上的狀態」,過一會兒伺服器重啟完就好了。
這個問題也不是解決不了,不過需要很大的人力排查程式碼,成本非常高。後來他們的技術骨幹想了一個辦法,說是每隔六天凌晨主動重啟一次伺服器,這樣既不影響業務(一般凌晨還線上的使用者比較少),還可以給公司省一筆排查程式碼的錢。
當時大家非常感慨,這麼一目瞭然的解決方案,為啥自己沒想到,大神就是大神。
很快地,我畢業進了一家公司,我們這家公司在業界已經基本沒了對手,無論是海外還是國內。工作了一些時間,我才意識到大學聽到的那個故事毒性有多大,到底是多麼傻逼的人,才會想出來這樣的辦法,只有低階作坊才會幹這麼缺心眼的事。稍微高階點的作坊會怎麼做呢?
只有一個辦法就是把這個問題徹底解決了,不惜代價,不計成本,把這個問題解決了,並且把經驗推廣,避免今後再出現這類問題。
很簡單的道理,你做任何一個產品,其實整個開發過程,其實就是一個個「設計-開發-發現問題-解決問題」的過程。
現代的產品還有個更重要的特性,就是需要不斷的迭代,本來只開發了一個簡單功能的產品,後來客戶有了新需求,又得加,後來新需求越來越多,過幾年變得幾乎看不出來原本的產品到底長啥樣。就好像手機最早只能打電話,後來傳簡訊,再後來功能越來越多,現在啥都幹,唯獨打電話非常少了。
再深入一點,那種複雜的產品,比如手機或者火箭,每個部件都需要打到恐怖的精度,因為每個部件精度差一點點,集合在一起就成一堆太空垃圾了,根本沒法用。國內長期以來飽受這類毒雞湯困擾,把各種偷奸耍滑當成本事。
還有另一層次,最關鍵的是流程。即使每個人都兢兢業業,也難免會偶爾出錯,就需要測試、閉環流程追蹤測試出來的問題,防止哪天有誰懈怠了,照樣可以保證產品質量,這就是流程驅動。
第三層次就是需要經驗豐富的大神對系統改進,留有更多升級迭代的空間餘量。
如果能夠與國外本行業頂尖公司使用同一套開發流程和標準,把質量提高,產品還便宜,自然會活得好。
我們要想打出局面,必須紮紮實實一步一步走,以客戶為中心,不抖機靈,把流程思維融入企業執行中。這個邏輯就是「勤勤懇懇做技術,不斷迭代,用流程來保證質量」,但是需要時間。
某種意義上講,我國很多企業之前過得太舒服,因為以前我國的人力實在是太便宜,打得國外低端產品根本沒有任何還手之力。大部分企業也不太在意質量和管理方式的缺陷,畢竟完全可以通過堆人力來解決,就比如我上文提到的那事,很多企業對質量興趣不大,怎麼省錢怎麼來,也是建立在一種觀念上:企業主覺得就算出問題,將來也可以通過廉價勞動力不斷加班來補償問題。
歐美學者有個斷言,說是為啥歐洲有工業革命而中國沒有?因為中國當時人太多,有啥事砸人力就可以了,根本沒必要發展機械,任何機械和新發明都會因為找不到用的地方最後歸於湮滅。人口下降當然有壞處,但是也預示著一個更加尊重勞動者的時代,而不是那種「你不幹就滾,有的是人幹」,這才是更加健康更加長久的道路。
人口太充裕,是中國崛起的重要力量,也造成了大量企業對人力的濫用,只有資源不足的時候,大家才會通過複雜工具和流程來仔細控制成本。
我國接下來肯定是兩條腿走路,既要修復之前被「毒雞湯」毒害的心靈,把質量意識灌輸到一代人腦子裡,也要鼓勵突破,給年輕人和夢想家機會,除此之外也沒啥好的選擇。
最近 ChatGPT 大火,我也嘗試讓他回答「如何看待重啟程式」 這個問題。
ChatGPT 真的是一個耿直 Boy , 他的回答我完全認同。
重啟程式是一個簡單而有效的解決問題的方法,但是,如果程式頻繁出現問題並需要經常重啟,那麼可能需要深入調查和解決程式的根本問題,以確保程式的穩定性和可靠性。
最後,我想說:"偷奸耍滑和濫用人力並不能持久,勤勤懇懇做技術/產品,不斷迭代,用流程來保證質量才是王道"。
如果我的文章對你有所幫助,還請幫忙點贊、在看、轉發一下,你的支援會激勵我輸出更高質量的文章,非常感謝!