本文首發於51CTO技術棧公眾號
作者 陳彩華
文章轉載交流請聯絡 caison@aliyun.com
複製程式碼
隨著蓬勃發展的開源時代的到來,為了減少開發成本,提高開發效率,越來越多的公司使用各種開源專案,作為開發者,如果能充分利用好開源專案中的資源,不僅能提高實踐能力,專業知識水平,還能從中其中學到的優秀的架構思想。
本文將提供一些學習開源專案的思路,相信看了這篇文章,小白也可學習讀懂開源專案,不必再對著高大上的開源專案望而生畏,淺嘗輒止。
1 學習的價值
總結起來,學習開源專案的價值主要包括以下幾點:
- 專業水平的提升 很多通用的專業知識,在專業領域內去到哪個公司都能通用,特別是底層方面的知識,可以在開源專案中學到,比如多執行緒處理、網路通訊、作業系統處理等。 舉個例子,通過學習Redis 的 RDB 持久化模式的“會將當前記憶體中的資料庫快照儲存到磁碟檔案中”,可以學習到其實就是在作業系統fork一個子程式來實現,再繼續深入的話,就涉及到父子程式機制, copy-on-write 技術。
這些專業知識之間是可以聯絡起來的並且像一顆大樹一樣自我生長,但是當沒理解透徹,自然沒法產生聯絡,也就不能夠自我生長了。當我們對開源專案的關鍵的點理解清晰,知識也隨著自我生長,也就如滾雪球一樣可以滾起來了。
- 解決問題能力的提升
通過學習開源專案的實現,出現線上問題時,可以快速定位問題癥結所在,通過修改配置或者修改原始碼來解決;或者當業務需求沒有合適的開源專案能滿足時,可以改造現有的開源專案來滿足業務。 作為要優秀開發,避免陷入“API操作工”的被動局面,學習開源專案的一個很重要目的就是知道其功能點是如何實現且優化的,學習其中的知識好比公式的推導過程,掌握基本API使用好比會數學公式可以應付考試,但是理解好的推導過程根據有助於記憶和理解,知其然也要知其所以然,當遇那些沒法套公式的情況下,我們也知道如何解決。
- 思維的提升
通過學習成熟的開源專案的優秀架構,可以總結和理解一些軟體設計常用的架構思路,例如實現高可用,主要是通過叢集的資料冗餘,例如Kafka叢集,HDSF叢集;實現可擴充套件可以考慮把變化層和不變層隔離,把業務實現抽象化,例如Spring的預留的一些可擴充套件介面。
2 常見錯誤觀點
學習開源專案有一些常見的錯誤觀點,導致新手容易望而生畏而輕易放棄,或者浪費大量時間而收穫不大:
學習開源專案是架構師,技術大牛的事,我作為新手根本難以學會,就算學了也用不到。
複製程式碼
學習是一個過程,不是一朝一夕就可以成為大牛的,但是隻要踏出第一步,總會有可能實現的大牛夢想的;另一方面,通過不斷覆盤不斷總結,加以合適的方法論指導,相信是可以有所收穫的,能力得到提升的。 學習之後對於邏輯思維,知識體系的構建有相信會有很大提升,即使專案沒用到具體的開源專案,以後遇到相關問題可以觸類旁通,舉一反三,也是一種進步。
資料結構和演算法很重要,我只要學習這專案中的2方面就可以了
複製程式碼
不要只盯著資料結構和演算法,這2點在開源專案中並沒有那麼重要,例如Netty中的超時佇列是基於紅黑樹來實現的,我們其實只需要知道這一點就夠了,除非需要改造這方面的功能。更重要的是理解系統的設計,功能的實現方案。
一頭扎進原始碼進行學習
複製程式碼
很多新手篤信社群論壇流行的一句話“Talk is cheap, show me the code”,一頭扎進原始碼閱讀,卻最後陷入原始碼的泥潭中,在層層程式碼函式跳轉中迷失了方向。
其實學習開源專案應該是自頂而下的,最底層的原始碼應該是最後才開始學習,在此之前,需要學習專案相關架構設計方面的知識,有了這些知識,就彷彿資料庫有了索引,按照知識索引來進行原始碼針對性突破,如巡航導彈精準爆破,自然比地毯式轟炸更起到事半功倍的作用。
3 學習的4個層次
根據學習理解的深入程度不同,可以把學習分為4個層次
-
基礎學習 對專案有一個大概性、基礎性的瞭解,比如專案是什麼,有什麼作用,大概怎麼用,解決了什麼問題。 在面試中,不少初入職場的人的簡歷寫到用到眾多的技術框架,實際上往往僅僅只到了這個層次,再深入往下問,便支支吾吾答不上來了。
-
檢視學習 對專案有一個系統性的瞭解,系統的各方面功能,基本原理,優缺點,使用場景,各配置項、API使用。 在實際工作中,如果作為一個團隊的普通成員,達到這個級別已經可以滿足基本業務開發需求,但是如果想有更高的技術追求,僅僅到此是不夠的。
-
分析學習 在檢視學習的基礎上,對開源專案的各項效能引數,各自場景效能調優有比較全面的瞭解和實踐經驗。 到達這個層次,在專案生產中,已經有獨當一面的能力,有一定能力承擔核心主力開發的角色。
-
主題學習 在分析學習的基礎上,對開源專案的關鍵功能模組的原始碼有所瞭解,能夠根據實際需要封裝、修改原始碼,或者借鑑專案造出新的輪子。 到達這個層次,往往有一定能力承擔技術負責人、技術帶頭人的角色。
4 學習的4個步驟
針對上面提到的學習的層次,下面介紹如何“自頂而下”學習,來達到這4個層次。
4.1 基礎性瞭解學習
目標是達到基礎學習的層次,對專案有大概性的瞭解,包括專案背景,解決的問題場景,專案功能,使用場景,基本的API使用。通過查詢官方文件、相關部落格、視訊資料學習即可。
通過對系統有大概性瞭解之後,會自然而然有一些疑問,例如實現的原理,優缺點等,後續學習帶著這些疑問進行學習會更高效。
4.2 系統性學習與實踐
目標是達到檢視學習的層次,對專案有系統性、全面性的瞭解,包括專案的功能、組成模組、基本原理、使用場景、配置項、API使用、與其他類似專案的優缺點比較等。
方法步驟如下:
-
1 安裝執行 按照相關文件,安裝執行專案。在這個過程中,需要關注:
- 系統的依賴元件 因為依賴元件是系統設計和實現的基礎,可以瞭解系統一下關鍵資訊,例如 Memcached最重要的依賴是高效能的網路庫 libevent,我們就能大概推測 Memcached 的網路實現應該是 Reactor 模型的。
- 安裝目錄 常見的安裝目錄是conf存放配置檔案,logs存放日誌檔案,bin存放日誌檔案,而不同專案有些特殊目錄,比如Nginx有html目錄,這種目錄能促使我們帶著相關疑問繼續去研究學習,帶著問題去學習效率是最高的。
- 系統提供的工具 需要特別關注命令列和配置檔案,它們提供2個非常重要的關鍵資訊,系統具備哪些能力和系統將會如何執行。這些資訊是我們學習系統內部機制和原理的一個觀察視窗。 通常情況下,如果對每個命令列引數和配置項的作用和原理基本掌握瞭解的話,基本上對系統已經很熟悉了。實踐中,可以不斷嘗試去修改配置項,然後觀察系統有什麼變化。
-
2 系統性研究原理與特性 這點相當重要,因為只有清楚掌握技術的原理特性,才能算真正掌握這門技術,才能做架構設計的時候做出合理的選擇,在這個過程中,需要重點關注:
-
關鍵特性的基本實現原理 關鍵特性是該開源開源專案流行的重要賣點,常見的有高效能、高可用、可擴充套件等特性,專案是如何做到的,這是我們需要重點關注的地方。
-
優缺點比對分析 優缺點主要通過對比來分析,即:我們將兩個類似的系統進行對比,看看它們的實現差異,以及不同的實現優缺點都是什麼。典型的對比有 Memcached 和 Redis、Kafka和ActiveMQ、RocketMQ的比較。
-
使用場景 專案在哪些場景適用,哪些場景不適用,業界適用常見案例等。
-
在此階段可以通過學習官方技術設計文件文件,架構圖,原理圖,或者相關技術部落格,通常比較熱門的開源專案都有很多分析文件,我們可以站在前人的基礎上避免重複投入。但需要注意的是,由於經驗、水平、關注點、使用的版本不同等差異,不同的人分析的結論可能有差異,甚至有的是錯誤的,因此不能完全參照。一個比較好的方式就是多方對照,也就是說看很多篇分析文件,比較它們的內容共同點和差異點。
同時,如果有些技術點難以查到資料,自己又不確定,可以通過寫Example進行驗證,通過日誌列印、除錯、監測工具觀察理解具體的細節。例如可以寫一個簡單程式使用Netty,通過抓包工具觀察網路包來理解其中的實現。
4.3 系統測試
如果是隻是自己學習和研究,可以參考網上測試和分析的文件,但是如果要在生產環境投入使用必須進行測試。因為網上搜的測試結果,不一定與自己的業務場景很契合,如果簡單參考別人的測試結果,很可能會得出錯誤的結論,或者使用的版本不同,測試結果差異也比較大。
要特別注意的是,測試必須建立在對這個開源專案有系統性瞭解的基礎上,不能安裝完就立馬測試,否則可能會因為配置項不對,使用方法不當,導致沒有根據業務的特點搭建正確的環境、沒有設計合理的測試用例,從而使得最終的測試結果得出了錯誤結論,誤導了設計決策。
下面提供測試常見的思路參考,需要根據具體專案具體業務進行測試用例的設計。
- 核對每個配置項的作用和影響,識別出關鍵配置項
- 進行多種場景的效能測試
- 進行壓力測試,連續跑幾天,觀察 CPU、記憶體、磁碟 IO等指標波動
- 進行故障測試:kill,斷電、拔網線、重啟 100 次以上、倒換等
4.4 關鍵原始碼學習
鑽研、領悟該專案的各種設計思想與程式碼實現細節,基本定位是“精通”,精益求精,學無止境。這是大神們追求的境界。如果希望成為團隊技術擔當、專案社群的重要貢獻者,則應當以這個層次作為努力的目標。
程式碼不僅是讀,還要理和試,有的人連API都沒有呼叫過,上來就看程式碼,以為省了時間,實際是邁向自我摧殘。
對原始碼進行理和試的關鍵如下:
-
1 在IDE拿到呼叫棧 在IDE裡讀。IDE裡可以方便跳轉,檢視定義,比起網頁上看效率高得多。 通過IDE工具,執行example程式進行跟蹤除錯,通過打斷點可以得到程式執行的呼叫棧。 儘可能編譯除錯。能除錯的程式碼,幾乎沒有看不懂的。
-
2 把呼叫棧畫下來 把程式碼的呼叫邏輯梳理出來之後,再通過畫圖工具,把程式碼的圖畫出來,可以畫:流程圖、類圖、呼叫圖、時序圖,更具實際情況選擇最有表現力的圖。
此外,平時多瞭解一些設計模式。這樣看到名字裡有proxy,builder,factory之類的,就心領神會了。橫向分層,縱向分塊。程式碼都是分模組的,有的是core,有的是util,parser之類的,要知道看的是哪一層,那一塊。
有的小專案分層不明顯,也不必強求。要看的不只是語法上的技巧,更重要的是設計上的思路和原理。讀沒讀懂,最簡單的標準是,假如給充足的時間,有沒有信心寫出一個差不多的東西來。
5 步驟總結
實際實踐操作中,完整執行上面5個步驟花費時間就長,通常情況下,前面2個步驟,在研究開源專案的時候都必不可少,第3個步驟可以在工作中打算採用開源專案才實施,第4個步驟在有一定的時間和精力下靈活安排時間做。
與其每個專案走馬觀花去簡單瞭解,不如集中火力把一個專案研究吃透,即使半年才吃透一個,積累幾年之後數量還是很可觀的。而且很多專案的思想是共同的,例如高可用方案、分散式協議等,研究透一個,再研究類似專案,會發現學習速度非常快,因為已經把共性的部分掌握了,只需要再研究新專案差異的部分。
同時,在學習的過程中,需要不斷總結,覆盤,輸出學習筆記,一方面鍛鍊邏輯思維能力,一方面有利於建立知識索引,過一段時間回顧的時候通過索引可以快速重新掌握知識,不容易遺忘。
6 面向新手友好的幾個開源專案推薦
介紹理論之後,下面就是需要通過實踐來檢驗了,下面介紹服務端開發常見的幾個比對對新手友好,而且資料比較多的開源專案參考:
-
Spring
Spring作為業界最流行的框架,其重要性不言而喻。需要注意的是,由於Spring的生態圈非常龐大,精力有限,建議新手先選最簡單的模組進行入門,例如Spring JDBC Template,Spring IOC, Spring AOP, Spring MVC -
Mybatis
MyBatis 作為業界流行的優秀持久層框架,支援普通 SQL 查詢,儲存過程和高階對映,程式碼量不大,網上相關原始碼解析的資料也比較多,專案的程式碼質量也是比較高,值得一讀。
-
Elastic-Job
Elastic-Job作為一個噹噹網開源的分散式任務排程解決方案,其社群活躍度,受歡迎程度較高,通過學習,可以對分散式一些通訊、排程方面的知識有所掌握。 -
Dubbo
Dubbo是阿里巴巴公司開源的一個高效能優秀的服務治理框架,使得應用可通過高效能的RPC 實現服務的輸出和輸入功能。Dubbo在17年年底重新啟動維護,在業務廣泛使用,通讀了解原始碼,在服務治理,分散式協議方面的技術實力相信會有質的飛躍。
(本文同時發表於作者個人部落格 www.jianshu.com/u/ced6b70c7…)