開源項目SMSS開發指南


  

項目介紹

  SMSS是一個由我個人發起的開源項目,目的是建立一套輕量化,高可用,高安全和方便擴展的業務支撐框架。SMSS面向TCP/IP層開發,適合擴展上層業務接口。數據結構傳輸序列化通過Protobuf實現。傳輸過程中的數據經過OpenSSL加密再由接收端進行解密,文件傳輸也需要由發送方的秘鑰首先做簽名再由接收方驗簽。核心功能完全不需要DB支撐,降低學習、開發和部署的難度。客戶端使用Electron,也足夠簡單和保持跨平台特性。另一個方面,我相信對於每一個曾經心懷夢想進入IT行業的人來說,能夠創建屬於自己的開源項目都是一種對“個人價值”的體現。我也相信這樣的夢想從未消失,只是各種“福報”淹沒了。所以,三月前我決定與其等待他人給我“福報”不如自己動手來實現屬於自己的“福報”。

  目前項目已經發布在gitee上(源碼地址),技術驗證和原型開發已經完成。client目錄下是客戶端相關源碼,開發語言為JavaScript。server目錄下是服務端相關源碼,開發語言為C++。擴展功能可能會通過Java來支撐。doc目錄下主要是一些設計文檔和Protobuf結構文檔。

  開發過程中無論是技術要點還是架構方面都有很多收獲,本文主要就這些方面的感悟進行分享。更多實現細節我會在今后分專題介紹。

經驗分享

核心框架是越豐富還好還是越簡單越好

  一個框架無論大小最終都需要服務於具體業務,或提供支撐或提供具體實現。可是我們又不能僅僅通過具體業務來設計框架,那樣話就失去了通用性。一段沒有通用性的代碼是絕不能稱之為框架的。因此,為了設計一套優秀的系統,設計人員應該具備至少兩個方面的能力——高度抽象的能力和剝離依賴的能力。首先,設計師需要先將業務需求抽象,抽象出那些適合開閉原則的接口。例如,模塊A和模塊B需要通信,我們可以分別在兩個模塊中實現一對Socket。可是如果還有模塊C需要加入該怎么做呢?作為一個更加合理的方案是設計一個模塊X,所有需要通信的模塊都需要先向模塊X注冊,並且只需要向模塊X發送消息。轉發和消息緩存全部由X內部完成。說到轉發,X如何保證消息能夠正確的從A發送到B呢。或許你會想到將每一個模塊的通信端用一個map保存起來以方便點對點發送。點對點的發送是一個好方法,可是如果業務需求是A要同時向BCD發送消息呢?為了解決這個問題,我參考IP包TTL的概念,每一個需要發送的消息都添加一個計數器。無論該消息是廣播還是點對點發送,都會通知每一節點來讀取,每讀取一次計數器減一。當然只有正確的節點才會將消息發送出去,對應的模塊才會接收到。當計數器為0的時候表示該消息已經可以釋放。模塊X可以從緩存中取出下一條消息繼續廣播。沒錯,這就是微服務的本質,而模塊X還有一個更通俗的名字——網絡總線(netbus)。

我們何時應該考慮將代碼封裝

  這個問題也是我在開發工作中被問及最多的。這是一個簡單的問題,每一個開發人員都會面臨類似的難題。有時候我們發現,很多的代碼堆在一起既無法閱讀也無法維護。可是有時候我們也發現,過渡封裝讓簡單的邏輯難以理解。那么到底怎么做才是合理的呢?這里我提供封裝的三個層次。在這三個層次上你都可以對代碼進行封裝,除此之外先堆在一起也不失為一個策略。

  1. 分解代碼的規模:一段代碼太長了,僅僅是不好閱讀。那么你可以將他們用幾個方法先做簡單的分類。方法名要通俗易懂,讓別人一看就知道大概分幾步,需要修改也有的放矢。這種封裝也是對應復雜業務最常見的方法,畢竟在面對絕大多數的開發任務中,我們不會有足夠的時間深入對業務分解和抽象。
  2. 降低調用難度:針對一些復雜的邏輯,可能需要調用者傳遞多個參數。這時你可以考慮利用設計模式(建造者模式、代理模式等)將調用過程分解,必要的時候甚至可以通過返回值告訴調用者內部發生了什么。從而降低調用者出錯的幾率。
  3. 隱藏差異:設計接口和面向接口編程的目的是可以隱藏內部實現。優點不言而喻。這個方面C++沒有像Java那樣提供純粹的接口,但是設計思想卻是共同的。

注釋越多越好嗎

  要解釋這個問題,我們應該明確幾個概念。你的代碼給誰看?注釋需要解釋什么?注釋如何被利用?

  1. 代碼給誰看?答:如果你的代碼是讓新手能夠盡快上手並且在不需要看源碼的層次上就立刻着手開發。那么注釋應該越詳細越好,甚至一行代碼三行注釋都不為過。
  2. 注釋需要解釋什么?答:主要是兩個方面。首先是對這段代碼的作用加以解釋,讓別人能夠對業務首先有一個了解。其次是對算法做出說明。
  3. 注釋如何被利用?答:現在有越來越多的工具可以根據你的注釋生成文檔。因此,你應該學習這些工具的使用方法並充分利用它們為你的代碼加分。你所需要做的僅僅是按照規定的格式來寫注釋而已。
  4. 注釋越多越好嗎?答:為什么很多開發人員不願意寫注釋。不僅僅是因為浪費時間,更多的原因其實是寫注釋會打斷開發的思路。很多時候注釋都是在代碼開發完成后才補充上去的,這就成了一項額外的工作。大部分時候,企業也很少做代碼評審,寫的注釋也沒有人關注。並且我個人其實也很不喜歡看到注釋很多的代碼。光看注釋看不懂,看代碼又收到影響。

  因此,我對注釋的觀點是:按照文檔生成工具的規定格式寫注釋即可。提交源碼的同時生成一份document,既可以證明你的工作量又滿足了大多數情況下的要求。至於方法內部的注釋,關鍵地方說明一下即可。

我應該掌握更加底層的原理還是應該學習更加新穎的技術

  如果只能用一句話來回答,就是都要學。

  所有的發明本質上都是發現。新技術的產生並不是一個孤立的事件,它往往是為了解決一些以前不被重視的難題。Java中有IO和NIO的概念,相信很多人都了解。工作中我發現,很多人其實對NIO的理解不夠深刻,僅僅是知道它是一種non block IO。可是為什么它是非阻塞的,非阻塞就一定比阻塞好嗎?我通過學習libevent,理解了在操作系統層面本身就對IO提供了select、poll和epoll幾種驅動模型,目的是IO的多路復用。可是系統總線只有一條,復用的到底是什么。復用的其實是程序(CPU運算)。相比IO總線來說,CPU的運算效率高得多。傳統的阻塞IO當程序需要從文件或網絡上讀取/發送數據的時候就需等待在那里直到操作完成,而非阻塞IO模型使得程序可以在這個過程中先向下運行,直到數據准備好以后再回來處理。

  那么非阻塞IO一定比傳統IO好嗎?有過JavaScript開發經驗的人一定會對各種回調不陌生,甚至“深惡痛絕”。由於nio模型不會等待數據讀取,通常情況下我們需要通過注冊回調函數來完成任務。如果有大量的IO需要處理,回調函數就會層層遞進。這樣就增加了開發和維護的難度。

  你瞧,學習底層原理和理解新技術本身並不矛盾。理解一些底層原理也會更容易掌握新技術。除此以外,設計模式和算法也是我們平時需要積累的地方。SMSS中利用紅黑樹完成用戶ID和用戶名的查找,在用戶登錄和用戶離線的時候會觸發紅黑樹的旋轉。最后我想說,底層原理和新技術本身不矛盾,你都應該學習。更加多元的技術能讓你走的更遠,更加扎實的理論功底能讓你走的更穩。

  面對一項復雜的任務,我應該注意些什么

  和所有人一樣,這也是我在開發SMSS中經常思考的問題。目前,每次增加一個新的功能我都會首先考慮,這個功能應該如何測試,盡量做到每完成一塊都可以通過測試觀察是否達到了預期。傳統的瀑布式開發顯然已經不適用了,由於所有的設計和開發工作都由我個人在業余時間完成,時間並不容易自由控制。因此如果一個小的功能點在寫完后無法被驗證,幾天后我就極容易忘記當初的思路。完成一個較大的模塊往往需要幾周時間,如果等到那時再測試就很難發現問題了。如果你也能遵循這套標准來安排自己的工作和學習,那么恭喜你,你已經掌握了敏捷開發的關鍵要點。

  很多時候,有關設計方面的應用就是在這樣的一點一滴中得到實踐。

技術介紹

接下來簡單介紹一下我在SMSS中運用到的技術。

  • 利用libevent開發的網絡復用模型,並且在它的基礎上實現了一套線程池。使得多條連接可以復用在一個線程中運行,從而最大限度的利用系統性能。
  • 數據通信采用protobuf作為序列化方案。這要比json或xml更好的利用網絡,減小信道占用。並且,由於protobuf支持多語言的特性,后期擴展也很容易。不過,在使用protobuf后我也發現在js端的支持還有待改進。
  • 目前服務端的日志系統使用了log4cplus。作為一個Java開發人員,我對log4j非常熟悉,這也是我選擇它的原因。
  • 客戶端采用Electron,畢竟開發便捷和提供的跨平台特性是目前開發桌面系統的不二選擇——相對而言Qt就顯得略笨重。不過Electron畢竟是使用JavaScript作為開發語言,開發方式不如傳統語言來的順手(也可能是受個人能力限制)。
  • 用戶登錄驗證借鑒了git的方案,依賴linux系統來完成這些工作。
  • 信息加密由用戶獲取服務端通過OpenSSL生成的秘鑰來完成,nodejs也支持對應的加解密算法。

最后,希望大家能繼續關注我后面的技術分享,也歡迎加群來與我交流。

相關文章:

《開源項目SMSS開發指南(二)——基於libevent的線程池》

《開源項目SMSS開源項目(三)——protobuf協議設計》

《開源項目SMSS發開指南(四)——SSL/TLS加密通信詳解(上)

《開源項目SMSS發開指南(五)——SSL/TLS加密通信詳解(下)》


免責聲明!

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



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