一行程式碼引發的恐懼

純潔的微笑發表於2019-04-08

一行程式碼引發的恐懼


我工作的前5年,都是從事基礎系統研發相關的工作。做過後臺的接入層,後臺的儲存系統,RPC框架。說來不怕你笑話,那個時期裡面,我對程式碼一直有一種恐懼感。這種恐懼是怎麼來的呢?且讓我慢慢說來。

我們所構建的基礎系統,都是使用在億級甚至十億級使用者產品的業務系統之上的。從客戶端(前端)到後臺業務邏輯層,再到基礎架構層,所寫的程式碼是跑在整個呼叫鏈路的最後端的。

你可以認為,幾乎每個使用者的每個請求都會跑到我們寫得那部分的程式碼。

這個對系統帶來的影響是: 一,程式碼出問題後,影響的使用者範圍會很大;二,在這億級甚至十億級使用者量的情況下,每天所帶來的請求可能是千億級,萬億級的,在如此龐大請求量的情況下,幾乎各種奇葩的異常,你都會遇到,程式碼要極其的健壯,一個小異常沒處理好就會帶來大麻煩。

這讓我想起來,我們故障時候的情形。

幾年前,我們每做完一次版本變更,晚上基本都會睡不好,擔心變更的程式碼有問題。對手機的報警簡訊特別敏感,一有風吹草動,立馬就會開啟電腦vpn看看,即使是在深夜凌晨的時候。

我自己有個習慣,每次變更完,都要間隔幾個小時去看看監控曲線和日誌,看看有沒有異常的苗頭,一旦發現有不對勁地方,就會立即著手排查,直到確保沒有問題為止。

不過即使如此,還是不可避免的會出現問題。

半夜兩三點的時候,你的手機突然響起,報警語音機器人跟你說,你有一個重要的監控曲線出現異常,請檢視。然後你的血壓立馬升高,心跳加速,你從床上,一躍而起,開啟電腦,連上公司的VPN,立馬著手排查起來。

幾分鐘後,QA(質量工程師)電話過來,告知你,這個故障目前已經上報到部門故障系統,目前影響的使用者有XXX的數量,請你加快處理的速度,然後你的心跳再次加速。

半小時後,終於有了眉目,這時,你的leader, 電話過來,詢問你是怎麼回事,大概還需要多長的時間,才能處理完畢。待你語焉不詳地回覆完你的leader, 你又開始埋頭,一行行的排查故障。

一個小時後,你終於,將問題定位出來,執行了故障處理方案,例如回滾新的程式碼,或者遮蔽某些機器等。你才終於有了喘息的時間。

(ps: 這裡正確的流程是,出問題後,立馬回滾程式碼,但儲存系統因為資料的關係,在沒有確定原因前不太敢回滾,怕對資料有影響)

你趕緊爬上床去,睡上2-3個小時,因為第二天還要早起,趕到公司,去處理故障的後遺症,資料損壞和資料錯亂。

2

那個時期,我們寫程式碼都是特別小心的,變更,更是極度的謹慎。所以使得自己對程式碼變更有了一種焦慮和恐懼的心理。至少在那時候,寫程式碼不是一件輕鬆的事情。

這個事情,我現在回過頭來看。你可以認為有一部分是人的原因,但仔細的想想,寫程式碼不出bug ,幾乎也是極難做到,所以這裡在研發流程上,其實也是有缺失的。

前期因為業務發展太快,團隊的整體人力跟不上,所以,一開始很多流程,都是很原始的,那時候,是想做但客觀條件不允許。

後來,業務穩定了,流程就規範了不少。比如引入了coverity的程式碼檢查,也推行過測試用例覆蓋,持續整合等。

但最終,並不是所有的流程都延續了下去。比如,程式碼測試用例覆蓋,有的團隊到後面就放棄了,需求變化太快,測試用例成本太高。

coverity倒是自動化程度高,沒啥人力投入,執行了下來。

但我相信不是所有的公司,所有的團隊,都會有這種規範的流程。一個是研發流程成熟度建設的問題,但除此,還有成本,業務迭代速度。在網際網路,產品高速迭代的時候,產品都還沒有存活下來,成熟流程就更不太可能有了。

綜合來看,一種規範,但相對較重的研發流程的建立,應該也是根據具體情況而定的。需要考慮產品的形態,產品迭代的速度,團隊的人力預算成本,產品的生命週期等等。當然,無論怎麼說,反正這不是個人可以決定的事情,如果你所在的團隊有完善的研發流程,那是最好的事情,但如果沒有那麼完善,自己又能夠做些什麼呢?

我的經驗來看,以下的一些措施,對於個人而言也有不錯的效果

測試驅動的開發(TDD)

有段時間,因為業務高速發展,對效能的要求不斷提高,儲存模型也跟隨著不斷迭代改進,所以那段時間的程式碼修改是比較多的,那個時間的焦慮感也特別重。

我記得是在 《重構:改善既有程式碼的設計》中瞭解到TDD的。

簡單來說, 就是先構建測試用例,再開始寫你的功能程式碼。在設計測試用例之前,你需要先定義好模組對外的介面,包括介面的種類,引數,返回值等。

然後,你針對定義好的介面,編寫測試用例。這過程中,你可能會發現介面設計不合理的地方,也需要隨著修改。待你測試用例寫完,基本你的介面也被修改的比較好了,所以TDD還能改善你的介面設計。

後續再為每個介面實現特定的程式碼邏輯。

我當時將這種方法運用到了一個磁碟儲存引擎中,發現相當不錯。我特地花了一週左右的時間寫測試用例。後面,每天實現部分的功能後,都立馬跑測試用例,每次跑完透過,你的心裡都有穩的一B的感覺。有種媽媽再也不擔心我寫的程式碼有bug,被被老闆叼,導致扣工資了。

因為有了完善的測試用例,而且隨著你測試用例不斷的增加和覆蓋,你的信心會越來越足,焦慮自然減少了很多。

不過這種方式,比較適合底層的系統和核心穩定的系統。對於需求多變的系統,構建測試用例的人力付出太大,而且需求一變,已有的測試用例可能失效,導致投入產出比不夠高。

灰度釋出

簡單來說,就是一個特性要上線的時候,不是一下就開放給所有的使用者使用。有點像產品上的內測,只不過是用在技術上。

比如我新增加了一個產品需求,例如就微信裡面的 “看一看”入口,不是一開始就對所有使用者開放的。

首先會上線一個新的客戶端版本,程式碼邏輯已經預埋,但設計了一個開關,對所有使用者都是關閉的。前期,可能會找個千分之一,甚至萬分之一的使用者(隨機或者特定的使用者群體),讓他們使用。

這過程中,收集各種log ,監控,使用者的反饋。來確認和fix 系統存在的各種問題。一般經過兩三週後,如果沒有大問題,就會進一步的放開使用的使用者。比如變成百分之一,十分之一,一直迭代,直至覆蓋全部使用者。

灰度這個思想,在網際網路是特別常用的。客戶端,前端,後臺都可以使用。比如後臺,上線一個新修改後,也不是一下就開放給所有使用者。而是按照某種規則,例如以QQ使用者為例,可能是這種規則

計算Hash值(QQ號) % 1000 <= 灰度使用者的比例(取0 --- 1000)

放量的最小力度就是千分之一,被灰度到的使用者,看到新功能,沒灰度到的使用者不受影響。

這招用在新功能,用在系統最佳化,程式碼重構上都很不錯。

付出的額外成本不大,有的公司有自研的灰度系統,那最好。沒有的話,在重大且沒有把握的功能上,自己加上幾行灰度控制程式碼也不難。

監控和log

監控和log不是什麼新鮮的東西。

工作第一年,我們的技術總監在一次會議上跟我們說:你寫完的程式碼是死的,只有線上上跑的程式碼是活的。監控和log(特別是監控),就像是你程式碼的體徵資訊,隨時反應著你程式碼在實際環境中的執行情況,要高度的重視。

這段話,在後面,我深有感觸。透過完善設計的監控和log,預先發現了很多的問題,也避免了很多,或程式碼bug,或系統設計缺陷導致重大故障。

後面,監控和log的設計,也成了我們方案設計的一部分。一般都會在方案最後,加上必須的監控的點和log點,例如請求數,成功數,失敗數,各種異常數,極端邏輯執行次數等等。

你應該要意識到監控和log的重要性,而且應該要花時間特別地設計。

經過良好設計的監控和log,能發揮的價值,是那種憑感覺隨便加的監控log不可比擬的。

雙寫,雙讀驗證

這招,新業務程式碼用的不多。更多用於基礎系統或者核心系統的最佳化和重構上面。而且有前置條件,需要一個操作可以重複執行(例如只讀操作和冪等的資料操作)。

簡單來說,就是將新舊程式碼,劃分為兩個流程(兩個介面),上線到實際環境,然後在同個模組裡面呼叫。

一個請求進來後,兩個流程分別執行一次,逐位元組做對比(例如 memcmp)新舊流程的結果。新流程的結果只用於對比,返回得依舊是舊流程的結果,所以不影響線上業務。

如果對比失敗,就可能存在異常,要查詢並解決,在實際環境跑了幾天後,都沒問題,就可以採用灰度的方式,進一步放量。不過,一般業務不常使用,在基礎系統上使用比較多,這裡就不展開了。

其他

另外,對於客戶端,還有熱補丁機制,客戶端log收集系統等。不過這種需要的開發量比較大,一個人不一定可以搞定,可能需要有個小團隊來完成。

最後

軟體工程是個龐大的話題,我也沒能力論述這麼大的話題。這裡給大家講了個以前的故事,並且分享了我常用的一些低成本,但可以提高線上程式碼質量的方法,給大家參考參考。大家有好的做法,也歡迎在留言裡分享出來。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31499124/viewspace-2640680/,如需轉載,請註明出處,否則將追究法律責任。

相關文章