Jack Jiang

          我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
          posts - 499, comments - 13, trackbacks - 0, articles - 1

          1、引言

          在社區中,分享了很多篇基于Netty編寫的IM聊天入門文章(比如《跟著源碼學IM》系列、《基于Netty,從零開發IM》系列等),在這些文章中分享了各種IM通信算法原理和功能邏輯的實現。但是這樣簡單的IM聊天系統是比較容易被竊聽的,如果想要在里面說點悄悄話是不太安全的。

          怎么辦呢?學過密碼學的朋友可能就想到了一個解決辦法,聊天的時候對消息加密,處理的時候再對消息進行解密。是的,道理就是這樣。

          但密碼學本身的理論就很復雜,加上相關的知識和概念又太多太雜,對于IM入門者來說,想要快速理清這些概念并實現合適的加解密方案,是比較頭疼的。

          本文正好借此機會,以Netty編寫的IM聊天加密為例,為入門者理清什么是PKI體系、什么是SSL、什么是OpenSSL、以及各類證書和它們間的關系等,并在文末附上簡短的Netty代碼實示例,希望能助你通俗易懂地快速理解這些知識和概念!

          補充說明:本文為了讓文章內容盡可能言簡意賅、通俗易懂,盡量不深入探討各個技術知識和概念,感興趣的讀者可以自行查閱相關資料進一步學習。

          學習交流:

          本文已同步發布于:http://www.52im.net/thread-4104-1-1.html

          2、相關文章

          1. 即時通訊安全篇(一):正確地理解和使用Android端加密算法
          2. 即時通訊安全篇(二):探討組合加密算法在IM中的應用
          3. 即時通訊安全篇(三):常用加解密算法與通訊安全講解
          4. 即時通訊安全篇(四):實例分析Android中密鑰硬編碼的風險
          5. 即時通訊安全篇(五):對稱加密技術在Android平臺上的應用實踐
          6. 即時通訊安全篇(六):非對稱加密技術的原理與應用實踐
          7. 即時通訊安全篇(十):IM聊天系統安全手段之通信連接層加密技術
          8. 即時通訊安全篇(十一):IM聊天系統安全手段之傳輸內容端到端加密技術

          3、什么是PKI?

          我們需要先了解一下公鑰和私鑰的加密標準體系PKI。

          3.1 基本概念

          PKI的全稱是Public Key Infrastructure,是指支持公鑰管理體制的基礎設施,提供鑒別、加密、完整性和不可否認性服務。

          通俗講:PKI是集機構、系統(硬件和軟件)、人員、程序、策略和協議為一體,利用公鑰概念和技術來實現和提供安全服務的、普適性的安全基礎設施。

          在公鑰密碼中,發送者用公鑰(加密密鑰)加密,接收者用私鑰(解密密鑰)解密。公鑰一般是公開的,不再擔心竊聽,這解決了對稱密碼中的密鑰配送問題。但是接收者依然無法判斷收到的公鑰是否合法(有可能是中間人假冒的)。

          事實上,僅靠公鑰密碼本身,無法防御中間人攻擊。于是,需要(認證機構)對公鑰進行簽名,從而確認公鑰沒有被篡改。加了數字簽名的公鑰稱為公鑰證書,一般簡稱證書。

          有了證書來認證,可以有效防御中間人攻擊,隨之帶來了一系列非技術性工作。

          例如:誰來發證書?如何發證書?不同機構的證書怎么互認?紙質證書作廢容易,數字證書如何作廢?解決這些問題,需要制定統一的規則,即PKI體系。

          PKI體系是通過頒發、管理公鑰證書的方式為終端用戶提供服務的系統,最核心的元素是證書。

          圍繞證書構成了PKI體系的要素:

          • 1)使用PKI的用戶;
          • 2)頒發證書的機構(Certificate Authority,CA);
          • 3)保存證書的倉庫。

          總之:PKI是一個總稱,既包括定義PKI的基礎標準,也包括PKI的應用標準。

          3.2 PKI體系現狀

          事實上PKI已經有兩代了。

          第一代的PKI標準主要是由美國RSA公司的公鑰加密標準PKCS、國際電信聯盟的ITU-T X.509、IETF的X.509、WAP和WPKI等標準組成。但是因為第一代PKI標準是基于抽象語法符號ASN.1進行編碼的,實現起來比較復雜和困難,所以產生了第二代PKI標準。

          第二代PKI標準是由微軟、VeriSign和webMethods三家公司在2001年發布的基于XML的密鑰管理規范也叫做XKMS。

          事實上現在CA中心使用的最普遍的規范還是X.509系列和PKCS系列。

          X.509系列主要由X.209、X.500和X.509組成,其中X.509是由國際電信聯盟(ITU-T)制定的數字證書標準。在X.500基礎上進行了功能增強,X.509是在1988年發布的。

          X.509證書由用戶公共密鑰和用戶標識符組成。此外還包括版本號、證書序列號、CA標識符、簽名算法標識、簽發者名稱、證書有效期等信息。

          而PKCS是美國RSA公司的公鑰加密標準,包括了證書申請、證書更新、證書作廢表發布、擴展證書內容以及數字簽名、數字信封的格式等方面的一系列相關協議。它定義了一系列從PKCS#1到PKCS#15的標準。

          其中最常用的是PKCS#7、PKCS#12和PKCS#10。PKCS#7 是消息請求語法,常用于數字簽名與加密,PKCS#12是個人消息交換與打包語法主要用來生成公鑰和私鑰(題外話:iOS程序員對PKCS#12不陌生,在實現APNs離線消推送時就需要導出.p12證明,正是這個)。PKCS#10是證書請求語法。

          4、什么是SSL?

          4.1 基本概念

          SSL(全稱 Secure Socket Layer)安全套接層是網景公司(Netscape)率先采用的網絡安全協議。它是在傳輸通信協議(TCP/IP)上實現的一種安全協議,采用公開密鑰技術。

          通俗地說:SSL被設計成使用TCP來提供一種可靠的端到端的安全服務,它不是單個協議,而是二層協議。低層是SSL記錄層,用于封裝不同的上層協議,另一層是被封裝的協議,即SSL握手協議,它可以讓服務器和客戶機在傳輸應用數據之前,協商加密算法和加密密鑰,客戶機提出自己能夠支持的全部加密算法,服務器選擇最適合它的算法。

          SSL特點是:它與應用層協議獨立無關。上層的應用層協議(例如:HTTP、FTP、Telnet等)能透明的建立于SSL協議之上。SSL協議在應用層協議通信之前就已經完成加密算法、通信密鑰的協商以及服務器認證工作。在此之后應用層協議所傳送的數據都會被加密,從而保證通信的私密性。

          4.2 與TLS的關系

          SSL是網景公司(Netscape)設計,但IETF將SSL作了標準化,即RFC2246,并將其稱為TLS(Transport Layer Security),其最新版本是RFC5246、版本1.2。

          實際上:TLS是IETF在SSL3.0基礎上設計的,相當于SSL的后續版本。所以我們通常都是SSL/TLS放一起說。

          5、什么是OpenSSL?

          5.1 基本概念

           

          OpenSSL是一個開放源代碼的軟件庫,應用程序可以使用這個包來進行安全通信,它包括代碼、腳本、配置和過程的集合。例如:如果您正在編寫一個需要復雜安全加密的軟件,那么只有添加一個安全加密庫才有意義,這樣您就不必自己編寫一大堆復雜的加解密函數(而且密碼學本身很復雜,要寫好它們并不容易)。

          其主要庫是以 C 語言所寫成,實現了基本的加密功能,實現了 SSL 與 TLS 協議。

          OpenSSL整個軟件包大概可以分成三個主要功能部分:

          • 1)SSL協議庫;
          • 2)應用程序;
          • 3)密碼算法庫。

          OpenSSL的目錄結構自然也是圍繞這三個功能部分進行規劃的。

          OpenSSL 可以運行在 OpenVMS、 Microsoft Windows 以及絕大多數類 Unix 操作系統上。

          5.2 具體來說

          密鑰和證書管理是PKI的一個重要組成部分,OpenSSL為之提供了豐富的功能,支持多種標準。

          OpenSSL實現了ASN.1的證書和密鑰相關標準,提供了對證書、公鑰、私鑰、證書請求以及CRL等數據對象的DER、PEM和BASE64的編解碼功能。

          OpenSSL提供了產生各種公開密鑰對和對稱密鑰的方法、函數和應用程序,同時提供了對公鑰和私鑰的DER編解碼功能。并實現了私鑰的PKCS#12和PKCS#8的編解碼功能。

          OpenSSL在標準中提供了對私鑰的加密保護功能,使得密鑰可以安全地進行存儲和分發。

          在此基礎上,OpenSSL實現了對證書的X.509標準編解碼、PKCS#12格式的編解碼以及PKCS#7的編解碼功能。并提供了一種文本數據庫,支持證書的管理功能,包括證書密鑰產生、請求產生、證書簽發、吊銷和驗證等功能。

          5.3 發展歷程

          OpenSSL 計劃在 1998 年開始,其目標是發明一套自由的加密工具,在互聯網上使用。

          OpenSSL 以 Eric Young 以及 Tim Hudson 兩人開發的 SSLeay 為基礎,隨著兩人前往 RSA 公司任職,SSLeay 在 1998 年 12 月停止開發。因此在 1998 年 12 月,社群另外分支出 OpenSSL,繼續開發下去。

          ▲ 上圖為 Tim Hudson

          OpenSSL 管理委員會當前由 7 人組成有 13 個開發人員具有提交權限(其中許多人也是 OpenSSL 管理委員會的一部分)。只有兩名全職員工(研究員),其余的是志愿者。

          該項目每年的預算不到 100 萬美元,主要依靠捐款。 TLS 1.3 的開發由 Akamai 贊助。

          5.4 下載方法

          OpenSSL可以從其官網上下載,地址是:https://www.openssl.org/source/,感興趣的讀者可以自行下載安裝研究。

          6、各類證書

          6.1 證書類型

          操作過證書的朋友可能會對各種證書類型眼花繚亂,典型的體現就是各種不同的證書擴展名上,一般來說會有DER、CRT、CER、PEM這幾種證書的擴展名。

          以下是最常見的幾種:

          • 1)DER文件:表示證書的內容是用二進制進行編碼的;
          • 2)PEM文件:是一個文本文件,其內容是以“ - BEGIN -” 開頭的,Base64編碼的字符;
          • 3)CRT和CER文件:基本上是等價的,他們都是證書的擴展,也是文本文件,不同的是CRT通常用在liunx和unix系統中,而CER通常用在windows系統中。并且在windows系統中,CER文件會被MS cryptoAPI命令識別,可以直接顯示導入和/或查看證書內容的對話框;
          • 4)KEY文件:主要用來保存PKCS#8標準的公鑰和私鑰。

          6.2 常用OpenSSL命令

          下面的命令可以用來查看文本證書內容:

          openssl x509 -incert.pem -text -noout

          openssl x509 -incert.cer -text -noout

          openssl x509 -incert.crt -text -noout

          下面的命令可以用來查看二進制證書內容:

          openssl x509 -incert.der -inform der -text -noout

          下面是常見的PEM和DER相互轉換。

          PEM到DER的轉換:

          openssl x509 -incert.crt -outform der-out cert.der

          DER到PEM的轉換:

          openssl x509 -incert.crt -inform der -outform pem -out cert.pem

          補充說明:上述命令中用到的openssl程序,就是本文中提到的OpenSSL開源庫提供的程序。

          7、Netty中的聊天加密代碼示例

          7.1 關于Netty

          Netty是一個Java NIO技術的開源異步事件驅動的網絡編程框架,用于快速開發可維護的高性能協議服務器和客戶端,事實上用Java開發IM系統時,Netty是幾乎是首選。

          有關Netty的介紹我就不啰嗦了,如果不了解那就詳讀以下幾篇:

          史上最強Java NIO入門:擔心從入門到放棄的,請讀這篇!

          Java的BIO和NIO很難懂?用代碼實踐給你看,再不懂我轉行!

          新手入門:目前為止最透徹的的Netty高性能原理和框架架構解析

          史上最通俗Netty框架入門長文:基本介紹、環境搭建、動手實戰

          基它有關Netty的重要資料:

          Netty-4.1.x 源碼 (在線閱讀版)

          Netty-4.1.x API文檔 (在線查閱版)

          7.2 啟動SSL Server代碼示例

          事實上這個標題是不對的,Netty中啟動的server還是原來那個server,只是對發送的消息進行了加密解密處理。也就是說添加了一個專門進行SSL操作的Handler。

          netty中代表ssl處理器的類叫做SslHandler,它是SslContext工程類的一個內部類,所以我們只需要創建好SslContext即可通過調用newHandler方法來返回SslHandler。

          讓服務器端支持SSL的代碼:

          ChannelPipeline p = channel.pipeline();

            SslContext sslCtx = SslContextBuilder.forServer(...).build();

            p.addLast("ssl", sslCtx.newHandler(channel.alloc()));

          讓客戶端支持SSL的代碼:

          ChannelPipeline p = channel.pipeline();

             SslContext sslCtx = SslContextBuilder.forClient().build();

             p.addLast("ssl", sslCtx.newHandler(channel.alloc(), host, port));

          netty中SSL的實現有兩種方式,默認情況下使用的是OpenSSL,如果OpenSSL不可以,那么將會使用JDK的實現。

          要創建SslContext,可以調用SslContextBuilder.forServer或者SslContextBuilder.forClient方法。

          這里以server為例,看下創建流程。

          SslContextBuilder有多種forServer的方法,這里取最簡單的一個進行分析:

          publicstaticSslContextBuilder forServer(File keyCertChainFile, File keyFile) {

              returnnewSslContextBuilder(true).keyManager(keyCertChainFile, keyFile);

          }

          該方法接收兩個參數:

          • 1)keyCertChainFile是一個PEM格式的X.509證書文件;
          • 2)keyFile是一個PKCS#8的私鑰文件。

          熟悉OpenSSL的童鞋應該知道使用openssl命令可以生成私鑰文件和對應的自簽名證書文件。

          具體openssl的操作可以查看我的其他文章,這里就不詳細講解了。

          除了手動創建證書文件和私鑰文件之外,如果是在開發環境中,大家可能希望有一個非常簡單的方法來創建證書和私鑰文件,netty為大家提供了SelfSignedCertificate類。

          看這個類的名字就是知道它是一個自簽名的證書類,并且會自動將證書文件和私鑰文件生成在系統的temp文件夾中,所以這個類在生產環境中是不推薦使用的。默認情況下該類會使用OpenJDK's X.509來生成證書的私鑰,如果不可以,則使用 Bouncy Castle作為替代。

          7.3 啟動SSL Client代碼示例

          同樣的在client中支持SSL也需要創建一個handler。

          客戶端的SslContext創建代碼如下:

          // 配置 SSL.

          finalSslContext sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();

          上面的代碼我們使用了一個InsecureTrustManagerFactory.INSTANCE作為trustManager。

          什么是trustManager呢?

          當客戶端和服務器端進行SSL連接的時候,客戶端需要驗證服務器端發過來證書的正確性。

          通常情況下,這個驗證是到CA服務器中進行驗證的,不過這樣需要一個真實的CA證書環境,所以在測試中,我們使用InsecureTrustManagerFactory,這個類會默認接受所有的證書,忽略所有的證書異常。

          當然:CA服務器也不是必須的,客戶端校驗的目的是查看證書中的公鑰和發送方的公鑰是不是一致的,那么對于不能聯網的環境,或者自簽名的環境中,我們只需要在客戶端校驗證書中的指紋是否一致即可。

          netty中提供了一個FingerprintTrustManagerFactory類,可以對證書中的指紋進行校驗。

          該類中有個fingerprints數組,用來存儲安全的授權過的指紋信息。通過對比傳入的證書和指紋,如果一致則校驗通過。

          使用openssl從證書中提取指紋的步驟如下:

          openssl x509 -fingerprint -sha256 -inmy_certificate.crt

          8、小結一下

          上面我們對Netty聊天用到的加密技術和相關概念進行了梳理,我來簡單這些概念之間的關系。

          這些概念之間的關系,簡單來說就是:

          • 1)PKI:是一套加密體系和標準的合集,它是理論方案;
          • 2)SSL:是利用了PKI理論體系,針對Socket網絡這個場景設計的一套安全通信標準,屬于是PKI的一個具體應用場景;
          • 3)OpenSSL:是PKI體系及SSL標準的算法和代碼實現,它包括了具體的開源代碼、工具程序等;
          • 4)各種證書:是在SSL或其它基于PKI體系的安全協議標準中需要使用的到一些加密憑證文件等。

          而具體到Netty中的聊天加密,那就是應用了上述的PKI體系,基于SSL協議,在OpenSSL等開源庫的幫助下實現的安全程序。

          9、參考資料

          [1] 公鑰基礎設施(PKI)國際標準進展

          [2] 一篇文章讓你徹底弄懂SSL/TLS協議

          [3] 什么是OpenSSL?它有什么用途

          [4] OpenSSL是什么軟件

          [5] netty系列之對聊天進行加密

          [6] 跟著源碼學IM

          [7] 基于Netty,從零開發IM

          [8] TCP/IP詳解(全網唯一在線閱讀版)

          [9] 快速理解TCP協議一篇就夠

          [10] Netty-4.1.x 源碼(在線閱讀版)

          [11] Netty-4.1.x API文檔(在線版)

          本文已同步發布于http://www.52im.net/thread-4104-1-1.html

          posted @ 2022-12-22 17:34 Jack Jiang 閱讀(105) | 評論 (0)編輯 收藏

               摘要: 本文由陶文分享,InfoQ編輯發布,有修訂和改動。1、前言本系列的前幾篇主要是從各個角度講解Protobuf的基本概念、技術原理這些內容,但回過頭來看,對比JSON這種事實上的數據協議工業標準,Protobuf到底性能到底高多少?本篇將以Protobuf為基準,對比市面上的一些主流的JSON解析庫,通過全方位測試來證明給你看看Protobuf到底比JSON快幾倍。學習交流:- 移動端IM開發入門文...  閱讀全文

          posted @ 2022-12-16 12:43 Jack Jiang 閱讀(126) | 評論 (0)編輯 收藏

          關于MobileIMSDK

          MobileIMSDK 是一套專門為移動端開發的開源IM即時通訊框架,超輕量級、高度提煉,一套API優雅支持UDP 、TCP 、WebSocket 三種協議,支持iOS、Android、H5、標準Java平臺,服務端基于Netty編寫。

          工程開源地址是:

          關于RainbowChat

          ► 詳細產品介紹:http://www.52im.net/thread-19-1-1.html
          ► 版本更新記錄:http://www.52im.net/thread-1217-1-1.html
          ► 全部運行截圖:Android端iOS端
          ► 在線體驗下載:專業版(TCP協議)專業版(UDP協議)      (關于 iOS 端,請:點此查看

           

          RainbowChat是一套基于開源IM聊天框架 MobileIMSDK 的產品級移動端IM系統。RainbowChat源于真實運營的產品,解決了大量的屏幕適配、細節優化、機器兼容問題(可自行下載體驗:專業版下載安裝)。

          * RainbowChat可能是市面上提供im即時通訊聊天源碼的,唯一一款同時支持TCP、UDP兩種通信協議的IM產品(通信層基于開源IM聊天框架  MobileIMSDK 實現)。

          v8.3 版更新內容

          此版更新內容更多歷史更新日志):

          (1)Android端主要更新內容bug修復及優化!】:

          • 1)[bug] 當首頁“消息”列表所有的item都是置頂時,取消其中任一個置頂,都會錯誤地將其排在列表首位而不是列表末尾;
          • 2)[bug] 解決了從首頁“消息”列表中遺留的陌生人聊天信息無法重置消息未讀數的問題;
          • 3)[bug] 解決了聊天界面中底部面板和輸入法軟鍵盤切換時ui發生彈跳的問題;
          • 4)[優化] 重構了APP包名、應用名,防止被某些手機誤報成惡意軟件。
          • 5)[優化] 重構了搜索功能相關的代碼,使之更易理解和維護;
          • 6)[優化] 優化了APP中各種文本輸入框UI效果,以及其它UI細節;
          • 7)[優化] 解決了自定義長按菜單在某些機型上item文字會換行的問題;
          • 8)[優化] 大文件發送時,選擇的圖片、視頻文件可以自動以圖片消息和短視頻消息的形式發送;
          • 9)[優化] 優化了APP處于后臺時,收到實時語音/視頻請求的通知形式(用高優先級的系統Notification方式提醒用戶)。 

          (2)服務端主要更新內容:

          • 1)[bug] 解決了uid登陸時的sql注入風險;
          • 2)[優化] 升級MobileIMSDK至v6.2正式版

          此版主要功能運行截圖更多截圖點此查看): 

          posted @ 2022-12-07 15:17 Jack Jiang 閱讀(105) | 評論 (0)編輯 收藏

               摘要: 本文由騰訊PCG后臺開發工程師的SG4YK分享,進行了修訂和和少量改動。1、引言近日學習了 Protobuf 的編碼實現技術原理,借此機會,正好總結一下并整理成文。接上篇《由淺入深,從根上理解Protobuf的編解碼原理》,本篇將從Base64再到Base128編碼,帶你一起從底層來理解Protobuf的數據編碼原理。本文結構總體與 Protobuf 官方文檔相似,不少內容也來自官方文檔,并在官方...  閱讀全文

          posted @ 2022-12-02 12:33 Jack Jiang 閱讀(138) | 評論 (0)編輯 收藏

               摘要: 本文由碼農的荒島求生陸小風分享,為了提升閱讀體驗,進行了較多修訂和排版。1、引言搞即時通訊IM方面開發的程序員,在談到通訊層實現時,必然會提到網絡編程。那么計算機網絡編程中的一個非常基本的問題:到底該怎樣組織Client與server之間交互的數據呢?本篇文章我們不討論IM系統中的那些高端技術話題,我們回歸到通訊的本質——也就是數據在網絡中交互時的編解碼原理,并由淺入深從底...  閱讀全文

          posted @ 2022-11-24 11:43 Jack Jiang 閱讀(142) | 評論 (0)編輯 收藏

          本文由vivo技術團隊Li Guanyun分享,為了提升閱讀體驗,行了較多修訂和重新排版。

          1、引言

          Protobuf 作為一種跨平臺、語言無關、可擴展的序列化結構數據通訊協議,已廣泛應用于網絡數據交換的場景中(比如IM通信、分布式RPC調用等)。

          隨著互聯網的發展,分布式系統的異構性會愈發突出,跨語言的需求會愈加明顯,同時 gRPC 也大有取代Restful之勢,而 Protobuf 作為gRPC 跨語言、高性能的法寶,我們技術人有必要深入理解 Protobuf 原理,為以后的技術更新和選型打下基礎。

          借此機會,我將個人的Protobuf學習過程以及實踐經驗,總結成文,與大家一起探討學習。本篇主要從Protobuf的基礎概念開始,包括技術背景、技術原理、使用方法和優缺點。

          PS:本篇本跟上篇《Protobuf從入門到精通,一篇就夠!》類似,都適合作為Protobuf的入門文章,但本篇力求簡潔,盡量不涉及Protobuf的具體技術細節,目的是降低閱讀的門檻、提升閱讀效果,希望對你有用。

          學習交流:

          (本文已同步發布于:http://www.52im.net/thread-4081-1-1.html

          2、系列文章

          本文是系列文章中的第 2 篇,本系列總目錄如下:

          • IM通訊協議專題學習(一):Protobuf從入門到精通,一篇就夠!
          • IM通訊協議專題學習(二):快速理解Protobuf的背景、原理、使用、優缺點》(* 本文
          • 《IM通訊協議專題學習(三):由淺入深,從通信編解碼原理上理解Protobuf》(稍后發布..)
          • 《IM通訊協議專題學習(四):從Base64到Protobuf,詳解Protobuf的數據編碼原理》(稍后發布..)
          • 《IM通訊協議專題學習(五):Protobuf到底比JSON快幾倍?請看全方位實測!》(稍后發布..)
          • 《IM通訊協議專題學習(六):手把手教你如何在Android上從零使用Protobuf》(稍后發布..)
          • 《IM通訊協議專題學習(七):手把手教你如何在NodeJS中從零使用Protobuf》(稍后發布..)
          • 《IM通訊協議專題學習(八):金蝶隨手記團隊的Protobuf應用實踐(原理篇)  》(稍后發布..)
          • 《IM通訊協議專題學習(九):金蝶隨手記團隊的Protobuf應用實踐(實戰篇) 》(稍后發布..)

          3、什么是Protobuf?

          Protobuf(全稱是Protocol Buffers)是一種跨平臺、語言無關、可擴展的序列化結構數據的方法,可用于網絡通信數據交換及存儲。

          在序列化結構化數據的機制中,Protobuf是靈活、高效、自動化的,相對常見的XML、JSON,描述同樣的信息,Protobuf序列化后數據量更小、序列化/反序列化速度更快、更簡單。

          一旦定義了要處理的數據的數據結構之后,就可以利用Protobuf的代碼生成工具生成相關的代碼。只需使用 Protobuf 對數據結構進行一次描述,即可利用各種不同語言(proto3支持C++, Java, Python, Go, Ruby, Objective-C, C#)或從各種不同流中對你的結構化數據輕松讀寫。

          PS:類似的介紹,在上篇《Protobuf從入門到精通,一篇就夠!》中也有涉及,有興趣可以一并閱讀之。

          4、為什么是 Protobuf?

          4.1 技術背景

          大家可能會覺得 Google 發明 Protobuf 是為了解決序列化速度的,其實真實的原因并不是這樣的。

          Protobuf最先開始是 Google用來解決索引服務器 request/response 協議的。

          在沒有Protobuf之前,Google 已經存在了一種 request/response 格式,用于手動處理 request/response 的編解碼。

          這種sstk式也能支持多版本協議,不過代碼不夠優雅:

          if(protocolVersion=1) {

              doSomething();

          } elseif(protocolVersion=2) {

              doOtherThing();

          } ...

          如果是非常明確的格式化協議,會使新協議變得非常復雜。因為開發人員必須確保請求發起者與處理請求的實際服務器之間的所有服務器都能理解新協議,然后才能切換開關以開始使用新協議。

          這也就是每個服務器開發人員都遇到過的低版本兼容、新舊協議兼容相關的問題。

          為了解決這些問題,于是Protobuf就誕生了。

          4.2 Protobuf 誕生了

          Protobuf 最初被寄予以下 2 個期望:

          • 1)更容易引入新的字段,并且不需要檢查數據的中間服務器可以簡單地解析并傳遞數據(而無需了解所有字段);
          • 2)數據格式更加具有自我描述性,可以用各種語言來處理(比如C++, Java 等各種語言)。

          但這個版本的 Protobuf 仍需要自己手寫解析的代碼。

          隨著Protobuf的發展、演進,它具有了更多的特性:

          • 1)自動生成的序列化和反序列化代碼(避免了手動解析的需要。官方提供自動生成代碼工具,各個語言平臺的基本都有);
          • 2)除了用于數據交換之外,Protobuf也被用作某些持久化數據的便捷自描述格式。

          Protocol Buffers 命名的由來:

          Why the name "Protocol Buffers"?

          The name originates from the early days of the format, before we had the protocol buffer compiler to generate classes for us. At the time, there was a class called ProtocolBuffer which actually acted as a buffer for an individual method. Users would add tag/value pairs to this buffer individually by calling methods like AddValue(tag, value). The raw bytes were stored in a buffer which could then be written out once the message had been constructed.

          Since that time, the "buffers" part of the name has lost its meaning, but it is still the name we use. Today, people usually use the term "protocol message" to refer to a message in an abstract sense, "protocol buffer" to refer to a serialized copy of a message, and "protocol message object" to refer to an in-memory object representing the parsed message.

          4.3 Protobuf 在谷歌業務中的地位

          Protobuf 現在是 Google 用于數據交換和存儲的通用語言。

          谷歌代碼樹中定義了 48162 種不同的消息類型,包括 12183 個 .proto 文件。它們既用于 RPC 系統,也用于在各種存儲系統中持久存儲數據。

          Protobuf 誕生之初是為了解決服務器端新舊協議(高低版本)兼容性問題,名字也很體貼——“協議緩沖區”,只不過后期慢慢發展成用于傳輸數據。

          5、Protobuf 協議的工作原理

          如下圖所示:可以看到,對于序列化協議來說,使用方只需要關注業務對象本身,即 idl 定義,序列化和反序列化的代碼只需要通過工具生成即可。

          6、Protobuf 協議的消息定義

          Protobuf 的消息是在idl文件(.proto)中描述的。

          下面是本次樣例中使用到的消息描述符 customer.proto

          syntax = "proto3";

           

          package domain;

           

          option java_package = "com.Protobuf.generated.domain";

          option java_outer_classname = "CustomerProtos";

           

          message Customers {

              repeated Customer customer = 1;

          }

           

          message Customer {

              int32 id= 1;

              string firstName = 2;

              string lastName = 3;

           

              enum EmailType {

                  PRIVATE = 0;

                  PROFESSIONAL = 1;

              }

           

              message EmailAddress {

                  string email = 1;

                  EmailType type= 2;

              }

           

              repeated EmailAddress email = 5;

          }

          上面的消息比較簡單,Customers包含多個Customer(Customer包含一個id字段、一個firstName字段、一個lastName字段以及一個email的集合)。

          除了上述定義外,文件頂部還有三行可幫助代碼生成器的申明:

          • 1)syntax = "proto3":用于idl語法版本,目前有兩個版本proto2和proto3,兩個版本語法不兼容,如果不指定,默認語法是proto2(由于proto3比proto2支持的語言更多,語法更簡潔,本文使用的是proto3);
          • 2)package domain:此配置用于嵌套生成的類/對象;
          • 3)option java_package:生成器還使用此配置來嵌套生成的源(此處的區別在于這僅適用于Java,在使用Java創建代碼和使用JavaScript創建代碼時,使用了兩種配置來使生成器的行為有所不同。也就是說,Java類是在包com.Protobuf.generated.domain下創建的,而JavaScript對象是在包domain下創建的)。

          Protobuf 提供了更多選項和數據類型,本文不做詳細介紹,感興趣可以參考官方文檔

          7、Protobuf 的代碼生成

          首先安裝 Protobuf 編譯器 protoc(點這里有詳細的安裝教程)。

          安裝完成后,可以使用以下命令生成 Java 源代碼:

          1protoc --java_out=./src/main/java./src/main/idl/customer.proto

          上述命令的意圖是:從項目的根路徑執行該命令,并添加了兩個參數 java_out(即定義 ./src/main/java/ 為Java代碼的輸出目錄;而 ./src/main/idl/customer.proto 是.proto文件所在目錄)。

          生成的代碼非常復雜,但幸運的是它的用法卻非常簡單:

          CustomerProtos.Customer.EmailAddress email = CustomerProtos.Customer.EmailAddress.newBuilder()

                  .setType(CustomerProtos.Customer.EmailType.PROFESSIONAL)

                  .setEmail("crichardson@email.com").build();

           

          CustomerProtos.Customer customer = CustomerProtos.Customer.newBuilder()

                  .setId(1)

                  .setFirstName("Lee")

                  .setLastName("Richardson")

                  .addEmail(email)

                  .build();

          // 序列化

          byte[] binaryInfo = customer.toByteArray();

          System.out.println(bytes_String16(binaryInfo));

          System.out.println(customer.toByteArray().length);

          // 反序列化

          CustomerProtos.Customer anotherCustomer = CustomerProtos.Customer.parseFrom(binaryInfo);

          System.out.println(anotherCustomer.toString());

          8、Protobuf 的性能數據

          我們簡單地以上述Customers為模型,分別構造、選取小對象、普通對象、大對象進行性能對比。

          序列化耗時以及序列化后數據大小對比:

          反序列化耗時:

          更多性能數據可以參考官方的測試Benchmark

          9、Protobuf 的優點

          9.1效率高

          從序列化后的數據體積角度,與XML、JSON這類文本協議相比,Protobuf通過 T-(L)-V(TAG-LENGTH-VALUE)方式編碼,不需要", {, }, :等分隔符來結構化信息。同時在編碼層面使用varint壓縮。

          所以描述同樣的信息,Protobuf序列化后的體積要小很多,在網絡中傳輸消耗的網絡流量更少,進而對于網絡資源緊張、性能要求非常高的場景。比如在移動網絡下的IM即時通訊應用中,Protobuf協議就是非常不錯的選擇(PS:這也是我為什么著手分享Protobuf系列文章的原因啦)。

          我們來簡單做個對比。

          要描述如下JSON數據:

          1{"id":1,"firstName":"Chris","lastName":"Richardson","email":[{"type":"PROFESSIONAL","email":"crichardson@email.com"}]}

          使用JSON序列化后的數據大小為118byte:

          7b226964223a312c2266697273744e616d65223a224368726973222c226c6173744e616d65223a2252696368617264736f6e222c22656d61696c223a5b7b2274797065223a2250524f46455353494f4e414c222c22656d61696c223a226372696368617264736f6e40656d61696c2e636f6d227d5d7d

          而使用Protobuf序列化后的數據大小為48byte:

          0801120543687269731a0a52696368617264736f6e2a190a156372696368617264736f6e40656d61696c2e636f6d1001

          從序列化/反序列化速度角度,與XML、JSON相比,Protobuf序列化/反序列化的速度更快,比XML要快20-100倍。

          9.2支持跨平臺、多語言

          Protobuf是平臺無關的,無論是Android、iOS、PC,還是C#與Java,都可以利用Protobuf進行無障礙通訊。

          proto3支持C++、Java、Python、Go、Ruby、Objective-C、C#(詳見《Protobuf從入門到精通,一篇就夠》)。

          9.3擴展性、兼容性好

          Protobuf具有向后兼容的特性:更新數據結構以后,老版本依舊可以兼容,這也是Protobuf誕生之初被寄予解決的問題,因為編譯器對不識別的新增字段會跳過不處理。

          9.4使用簡單

          Protobuf 提供了一套編譯工具,可以自動生成序列化、反序列化的樣板代碼,這樣開發者只要關注業務數據idl,簡化了編碼解碼工作以及多語言交互的復雜度。

          10、Protobuf 的缺點

          Protobuf的優點很突出,但缺點也很明顯。

          Protobuf的缺點主要是:

          • 1)不具備自描述能力:跟XML、JSON相比,這兩者是自描述的,而ProtoBuf則不是;
          • 2)數據可讀性非常差:ProtoBuf是二進制協議,如果沒有idl文件,就無法理解二進制數據流,對調試非常不友好。

          不過:Charles已經支持Protobuf協議,導入數據的描述文件即可,詳情可參考 Charles Protocol Buffers

          然而:由于沒有idl文件無法解析二進制數據流,ProtoBuf在一定程度上可以保護數據,提升核心數據被破解的門檻,降低核心數據被盜爬的風險(也算是缺點變優點的典型范例)。

          11、參考資料

          [1] Protobuf官方網站

          [2] Protobuf從入門到精通,一篇就夠!

          [3] 如何選擇即時通訊應用的數據傳輸格式

          [4] 強列建議將Protobuf作為你的即時通訊應用數據傳輸格式

          [5] APP與后臺通信數據格式的演進:從文本協議到二進制協議

          [6] 面試必考,史上最通俗大小端字節序詳解

          [7] 移動端IM開發需要面對的技術問題(含通信協議選擇)

          [8] 簡述移動端IM開發的那些坑:架構設計、通信協議和客戶端

          [9] 理論聯系實際:一套典型的IM通信協議設計詳解

          [10] 58到家實時消息系統的協議設計等技術實踐分享

          (本文已同步發布于:http://www.52im.net/thread-4081-1-1.html

          posted @ 2022-11-17 10:52 Jack Jiang 閱讀(95) | 評論 (0)編輯 收藏

          為了更好地分類閱讀52im.net 總計1000多篇精編文章,我將在每周三推送新的一期技術文集,本次是第5 期。

          * 評語:本系列文章盡量使用最淺顯易懂的文字、圖片來組織內容,力求通信技術零基礎的人群也能看懂。但個人建議,至少稍微了解過網絡通信方面的知識后再看,會更有收獲。特別推薦即時通訊開發者來閱讀,因為針對移動弱網的問題,確實可以找到很多有價值的答案。


          [- 1 -] IM開發者的零基礎通信技術入門(一):通信交換技術的百年發展史(上)

          [鏈接]http://www.52im.net/thread-2354-1-1.html

          [摘要] 本文(上下兩篇)將帶你了解當今通信交換技術最初的模樣以及發展過程。學習技術更要了解技術的前世今生,技術本無聊,故事很有趣。


          [- 2 -]IM開發者的零基礎通信技術入門(二):通信交換技術的百年發展史(下)

          [鏈接]http://www.52im.net/thread-2356-1-1.html

          [摘要] 接上篇,本篇里我們需要暫停一下,回過頭來看看我們國家的交換機發展情況。


          [- 3 -] IM開發者的零基礎通信技術入門(三):國人通信方式的百年變遷

          [鏈接] http://www.52im.net/thread-2360-1-1.html

          [摘要] 本文通過大量珍貴歷史圖片,從中國第一條電報線路,到如今觸手可及的5G網絡,回顧過去、展望未來,一起來看國人通信方式的百年歷史變遷。


          [- 4 -]IM開發者的零基礎通信技術入門(四):手機的演進,史上最全移動終端發展史

          [鏈接] http://www.52im.net/thread-2369-1-1.html

          [摘要] 本文將通過大量歷史圖片,講述手機這種移動終端的演化過程,為您呈現如今已深度融入人類生活的智能手機本來的樣子。了解過去,才能更好地展望未來。


          [- 5 -] IM開發者的零基礎通信技術入門(五):1G到5G,30年移動通信技術演進史

          [鏈接] http://www.52im.net/thread-2373-1-1.html

          [摘要] 今天的5G,3.5GHz+大規模MIMO+波束賦形,還有固定無線應用,不禁讓人看到了當年3G時代WiMax的影子,但WiMax為何輸給了LTE,難道命運也喜歡對技術開玩笑嗎?一部跨越三十年驚心動魄的移動通信史,為你揭曉答案。


          [- 6 -] IM開發者的零基礎通信技術入門(六):移動終端的接頭人——“基站”技術

          [鏈接] http://www.52im.net/thread-2375-1-1.html

          [摘要]自上個世紀70年代末移動通信網絡誕生以來,移動通信基站已經陪伴人類40年了,為人類社會帶來了空前的變革,但你知道它的故事嗎?


          [- 7 -] IM開發者的零基礎通信技術入門(七):移動終端的千里馬——“電磁波”

          [鏈接] http://www.52im.net/thread-2382-1-1.html

          [摘要] 本文將回歸到無線通信的技術之魂——“電磁波”,盡量用通俗易懂的文字講述這個稍顯枯燥的通信技術基礎知識。


          [- 8 -] IM開發者的零基礎通信技術入門(八):零基礎,史上最強“天線”原理掃盲

          [鏈接] http://www.52im.net/thread-2385-1-1.html

          [摘要] 實際生活中,無線通信中的天線都長什么樣?有哪些用途?更重要的是,天線的技術原理是怎樣的?本文將通過大量的圖片,為你講述這些內容。本文力求通俗易懂,面向零基礎讀者,希望繼續給即時通訊網的開發者帶來更多通信技術方面的收獲。


          [- 9 -] IM開發者的零基礎通信技術入門(九):無線通信網絡的中樞——“核心網”

          [鏈接]http://www.52im.net/thread-2391-1-1.html

          [摘要] 對于通信專業的人來說,幾乎每個人都認為核心網難(不只是難,而且是非常難),很難有人能通俗易懂地講明白它是什么東西。所以本文想借此機會,為零基礎的IM開發者或其他移動端應用層程序員們,講清楚這個話題。


          [- 10 -] IM開發者的零基礎通信技術入門(十):零基礎,史上最強5G技術掃盲

          [鏈接] http://www.52im.net/thread-2394-1-1.html

          [摘要] 作為IM開發者,或者移動端開發者來說,提前了解5G技術顯然是很有必要的。那么什么是5G技術?技術原理是怎么樣的?5G技術將帶來哪些技術革新?本文將以零基礎的應用程序開發者為閱讀對象,幫你找到這些問題的答案。


          [- 11 -] IM開發者的零基礎通信技術入門(十一):為什么WiFi信號差?一文即懂!

          [鏈接] http://www.52im.net/thread-2402-1-1.html

          [摘要] 為什么WiFi信號會受影響?什么情況下該使用何種方式組網?如何改善WiFi信號差的問題?等等,本文將通俗易懂地為你找到這些問題的答案。


          [- 12 -] IM開發者的零基礎通信技術入門(十二):上網卡頓?網絡掉線?一文即懂!

          [鏈接]http://www.52im.net/thread-2406-1-1.html

          [摘要] 本文將詳細介紹生活中遇到的常見網絡問題,及可能的解決方法,雖說是一篇技術文章,但內容將一如既往地通俗易懂,簡單實用。


          [- 13 -] IM開發者的零基礎通信技術入門(十三):為什么手機信號差?一文即懂!

          [鏈接] http://www.52im.net/thread-2415-1-1.html

          [摘要] 關于手機信號的問題真的不是大家想象得那么簡單。本文正好收集整理了這一塊的通信技術知識,一如既往的力求通俗易懂,希望對你有用。


          [- 14 -] IM開發者的零基礎通信技術入門(十四):高鐵上無線上網有多難?一文即懂!

          [鏈接] http://www.52im.net/thread-2419-1-1.html

          [摘要] 為什么在高鐵上手機信號會這么差?這個無線通信難題真的無法解決嗎?今天,作為通信老司機的筆者,就詳細和大家聊聊這個問題。


          [- 15 -] IM開發者的零基礎通信技術入門(十五):理解定位技術,一篇就夠

          [鏈接]http://www.52im.net/thread-2428-1-1.html

          [摘要] 定位技術到底是怎么實現的?技術原理怎樣?有哪些局限性?貌似我們平時也沒有做更多了解,既然這樣,那就跟著本文來一窺究竟吧。


          ??52im社區本周新文:《IM通訊協議專題學習(一):Protobuf從入門到精通,一篇就夠! http://www.52im.net/thread-4080-1-1.html》,歡迎閱讀!??

          我是Jack Jiang,我為自已帶鹽!https://github.com/JackJiang2011/MobileIMSDK/

          posted @ 2022-11-11 11:33 Jack Jiang 閱讀(219) | 評論 (0)編輯 收藏

               摘要: 本文由IBM開發者社區分享,有較多修訂和改動。1、引言在當今移動網絡時代,手機流量和電量是寶貴的資源,對于移動端最常見的即時通訊IM應用,由于實時通信基于Socket長連接,它對于流量和電量的需求較一般應用來說更高(詳見《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》)。在IM應用中,優化數據流量消耗過多的基本方法就是使用高度壓縮的通訊協議,而數據壓縮后流量減小帶來的自然結果也就...  閱讀全文

          posted @ 2022-11-10 11:49 Jack Jiang 閱讀(117) | 評論 (0)編輯 收藏

          關于MobileIMSDK

          MobileIMSDK 是一套專門為移動端開發的開源IM即時通訊框架,超輕量級、高度提煉,一套API優雅支持UDP 、TCP 、WebSocket 三種協議,支持iOS、Android、H5、標準Java平臺,服務端基于Netty編寫。

          工程開源地址是:

          關于RainbowChat

          ► 詳細產品介紹:http://www.52im.net/thread-19-1-1.html
          ► iOS端更新記錄:http://www.52im.net/thread-2735-1-1.html
          ► 全部運行截圖:iOS端全部運行截圖 (另:Android端運行截圖 點此查看
          ► 在線體驗下載:App Store安裝地址 (另:Android端下載體驗 點此查看

           

          RainbowChat是一套基于開源IM聊天框架 MobileIMSDK 的產品級移動端IM系統。RainbowChat源于真實運營的產品,解決了大量的屏幕適配、細節優化、機器兼容問題(可自行下載體驗:專業版下載安裝)。

          RainbowChat可能是市面上提供im即時通訊聊天源碼的,唯一一款同時支持TCP、UDP兩種通信協議的IM產品(通信層基于開源IM聊天框架 MobileIMSDK 實現)。

          v6.1 版更新內容

          此版更新內容更多歷史更新日志):

          • 1)[bug] 在聊天信息界面中查找消息時,點擊查看指定消息,在聊天界面中不能自動滾動到這條消息;
          • 2)[bug] 點擊首頁“消息”列表中遺留的陌生人聊天信息時,無法重置消息未讀數的問題;
          • 3)[bug] 在聊天界面中進入別的界面再回來時,底部面板沒有自動關閉/收起;
          • 4)[優化] 優化了標題欄彈出菜單的圓角效果(使之更符合最新iOS美感設計);
          • 5)[優化] 優化了APP中各種文本輸入框UI效果,以及其它UI細節;
          • 6)[優化] 優化了短視頻錄制界面在iOS16“靈動島”手機上的ui適配。

          此版主要功能運行截圖更多截圖點此查看):

           

          posted @ 2022-11-05 17:42 Jack Jiang 閱讀(92) | 評論 (0)編輯 收藏

          1、引言

          在《IM消息ID技術專題》系列文章的前幾篇中,我們已經深切體會到消息ID在分布式IM聊天系統中的重要性以及技術實現難度,各種消息ID生成算法及實現雖然各有優勢,但受制于具體的應用場景,也并不能一招吃遍天下,所以真正在IM系統中該如何落地消息ID算法和實現邏輯,還是要因地致宜,根據自已系統的設計邏輯和產品定義取其精華,綜合應用之。

          本文將基于網易嚴選的訂單ID使用現狀,分享我們是如何結合業內常用的分布式ID解決方案,從而在此基礎之上進行ID特性豐富,并不斷提升系統可用性和穩定性保障。同時,也對ID生成算法的落地實踐過程中遇到坑進行了深入剖析。

          本篇中的訂單ID雖然不同于IM系統中的消息ID,但其技術實踐仍然相通,希望能給你的IM系統消息ID技術選型也來更多的啟發。

          學習交流:

          本文已同步發布于:http://www.52im.net/thread-4069-1-1.html

          2、關于作者

          西狂:服務端研發工程師, 早期參與嚴選采購、嚴選財務、嚴選合伙人以及報警平臺等系統后端建設,目前主要致力于嚴選交易域技術演進以及業務研發工作。

          3、系列文章

          本文是系列文章中的第7篇,本系列總目錄如下:

          4、為什么需要分布式ID?

          4.1 業務背景

          如上圖所示,對于網易嚴選的主站、分銷和tob都會生成各自的訂單ID,在同步訂單數據到訂單中心的時候,訂單中心會生成一個訂單中心內部的一個訂單號,只是推送給到下游倉配時使用的訂單ID略有不同。

          4.2 帶來的問題

           因為訂單ID使用的混亂,導致了一系列問題的產生,例如: 溝通壁壘 、管控困難以及代碼腐化等等。

          4.3 技術目標

           我們希望通過分布式ID來幫助生成訂單ID,在業務規則上必須全局唯一、安全性高,在性能上要高可用、低延遲。

          5、我們的分布式ID架構原理

          5.1 技術選型

          下表是業內常見的分布式ID解決方案:

          綜合考慮是否支持水平擴展以及能夠顯示指定ID長度,最終選擇的是Leaf的Segment模式(詳見《深度解密美團的分布式ID生成算法》)。

          5.2 架構簡介

          Leaf采用了預分發的方式來生成ID(如下圖所示),在DB之上搭載若干個Server,每個Server在啟動的時候,都會去DB中拿固定長度的ID列表,存放于內存中,因為ID是基于內存分發的,所以可以做到很高效。

          在數據持久化方面,每次去DB拿固定長度的ID列表,只是把最大的ID持久化。

          整體架構實現比較簡單,主要是為了盡快解決業務層DB壓力的問題,但是在生產環境中也暴露出一些問題。

          比如:

          • 1)TP999數據波動大,當號段使用完之后還是會hang在更新數據庫的I/O上,tp999數據會出現偶爾的尖刺;
          • 2)當更新DB號段的時候,如果DB宕機或者發生主從切換,會導致一段時間的服務不可用。

          5.3 可用性優化

          為了解決上面提到這個兩個問題,引入雙Buffer機制和異步更新策略,當一個Buffer消耗到某個臨界點時,就會異步的觸發任務,把下一個號段加載到內存中。

          保證無論何時DB出現問題,都能有一個Buffer的號段可以正常對外提供服務,只要DB在一個Buffer的下發的周期內恢復,就不會影響整個Leaf的可用性。

          5.4 步長動態調整

          號段長度在固定不變的前提下,流量的突增和銳減都會使得正常流量下維持原有號段正常工作的時間縮短和提升。

          可以嘗試使用以下關系表達式來描述:

          Q * T = L

          (Q:服務qps  L:號段長度  T:號段更新周期)

          但是Leaf的本質是希望T固定,如果Q和L可以正相關,T就可以趨于一個定值。

          所以在Leaf每次更新號段的時候,會根據上一次號段更新的周期T和號段長度step,來決定下一次號段長度nextStep。

          如下所示:

          T < 15min,nextStep = step * 2

          15min < T < 30min,nextStep = step

          T > 30min,nextStep = step / 2

          (初始指定step <= nextStep <= 最大值(自定義:100W))

          6、我們做了什么改進?

          6.1 特性豐富

           

          通過結合嚴選的實際業務場景,進行了特性化支持,例如支持批量ID獲取、大促提前擴容以及提前跳段處理。

          6.2 可用性保障

          1)針對DB:

           DB(MySql)采用主從模式(讀寫分離、降低主庫壓力),一主兩從的配置方式,Master和Slave之間采用的是半同步復制(數據一致性要求,后期可考慮使用MySql Group Replication)。同時還添加了雙1配置,保證不丟數據。

          2)引入SDK:

          通過引入SDK可以降低各個業務方的接入成本、降低Leaf服務端壓力以及在Leaf服務不可用時,客戶端起到短暫降級的效果。

          SDK的實現原理和Leaf類似,在項目啟動之初會加載業務關心參數配置信息,在應用構建本地緩存,同樣采用了雙Buffer存儲模式。

          6.3 穩定性保障

          1)運維方面:

          主要分為3個方面:

          • 1)日志監控:可以幫助發現預期之外的異常情況;
          • 2)流量監控:流有助于號段長度的評估范圍,預防號段被快速消費的極端場景;
          • 3)線上巡檢:可以時刻對服務進行存活校驗。

          2)SLA高可用方面:

          除了運維之外還做了SLA的接入,通常用SLA來衡量系統的穩定性,除此之外我們還按照接口維度設定了SLO目標規則,目前的指標項比較單一只有請求延遲和錯誤率這兩項。

           


           

          7、我們遇到的坑

          7.1 問題發現

          如下圖所示,我們發現每次服務啟動上線接口的rt(響應時間)都要比平時高的多,但是過了一段時間之后卻又恢復成正常水平。

          7.2 問題探究

          在分析之前,我們可以先簡單的回顧下java虛擬機是如何運行Java字節碼的。

          虛擬機視角下Java字節碼如何被虛擬機運行:

          Java虛擬機將class文件加載到虛擬機中,然后將字節碼翻譯成機器碼給底層硬件執行,而這里的翻譯有兩種形式,解釋執行和編譯執行。前者的優勢在于無需等待編譯,后者的優勢在于實際運行速度更快。HotSpot默認采用混合模式,它會先解釋執行字節碼,然后將其中反復執行的熱點代碼,以方法為單位進行即時編譯,JVM是依據方法的調用次數以及循環回邊的執行次數來觸發JIT編譯的。

          在Java7之前我們可以根據程序的特性選擇對應的即時編譯器。Java7開始引入分層編譯機制(-XX:+TieredCompilation):綜合了C1的啟動性能優勢和C2的峰值性能優勢。

          分層編譯將JVM的執行狀態分為了5個層次:

          • L0:解釋執行(也會profiling);
          • L1:執行不帶profiling的C1代碼;
          • L2:執行僅帶方法調用次數和循環回邊執行次數profiling的C1代碼;
          • L3:執行帶所有profiling的C1代碼;
          • L4:執行C2代碼。

          對于C1編譯的三個層次,按執行效率從高至低:L1 > L2 > L3, 這是因為profiling越多,額外的性能開銷越大。通常情況下,C2代碼的執行效率比C1代碼高出30%以上。(這里需要注意的是Java8默認開啟了分層編譯)

          這張圖列出了常見的分層編譯的編譯路徑:

          • 1)通常情況下,熱點方法會被第三層的C1編譯器編譯,再被C2編譯器編譯(0-> 3-> 4);
          • 2)如果方法的字節數目比較少并且第三層的profilling沒有可收集的數據,jvm會判定該方法對于C1和C2的執行效率相同,在經過3層的C1編譯過后,直接回到1層的C1(0-> 3-> 1);
          • 3)在C1忙碌的情況下,JVM在解釋執行過程中對程序進行profiling,而后直接由4層的C2編譯(0-> 4);
          • 4)在C2忙碌的情況下,方法會被2層的C1編譯,然后再被3層的C1編譯,以減少方法在3層的執行時間(0-> 2-> 3-> 4)。

          上圖是項目啟動時的分層編譯日志以及整個過程接口響應RT。

          從圖中可以看到先是執行了C1編譯,再執行C2編譯(日志文件中的3和4分別打標L3和L4),滿足 0->3->4 編譯順序。

          發現從C1編譯到C2編譯耗時過程比較長,這符合我們一開始提出的疑問,為什么項目啟動需要經過一段時間接口RT才能趨于穩定。

          7.3 解決方案

          為了能在項目啟動之初,快速達到接口RT峰值,因此只要盡最大程度縮短解釋執行這個中間過程即可。

          相應的解決方案:

          • 方案 1:關閉分層編譯,降低編譯閾值;
          • 方案 2:Mock接口數據, 快速觸發JIT編譯以及C2編譯;
          • 方案 3:Java9 AOT提前編譯。

          針對方案3:Java9中支持新特性AOT提前編譯,相比較于JIT即時編譯而言,AOT在運行前就已經編譯好了,避免 JIT 編譯器的運行時性能消耗,同時避免解釋程序的早期性能開銷,可以極大提高java代碼性能。

          8、落地使用概況

          Leaf已經在線上環境投入使用,各個業務方(包括主站、渠道、tob)也相應接入進行統一整改,自此嚴選訂單ID生成得到統一收攏。

          在整個嚴選的落地情況,按照業務維度,目前累計接入3個業務,分別是訂單ID、訂單快照ID、訂單商品快照ID,都經受住了雙十一和雙十二考驗。

          9、參考資料

          [1] 微信的海量IM聊天消息序列號生成實踐(算法原理篇)

          [2] 解密融云IM產品的聊天消息ID生成策略

          [3] 深度解密美團的分布式ID生成算法

          [4] 深度解密滴滴的高性能ID生成器(Tinyid)

          本文已同步發布于:http://www.52im.net/thread-4069-1-1.html

          posted @ 2022-11-03 11:45 Jack Jiang 閱讀(114) | 評論 (0)編輯 收藏

          僅列出標題
          共50頁: First 上一頁 15 16 17 18 19 20 21 22 23 下一頁 Last 
          Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 永顺县| 五莲县| 南溪县| 鄂尔多斯市| 车致| 舟山市| 台中市| 鄱阳县| 鲁山县| 若尔盖县| 巴里| 虎林市| 丽水市| 宁晋县| 漠河县| 阿坝| 吴旗县| 岐山县| 渑池县| 日照市| 宁河县| 香港 | 兴宁市| 前郭尔| 库车县| 茂名市| 开化县| 巫溪县| 塘沽区| 安徽省| 临沧市| 威宁| 河间市| 嘉善县| 宜昌市| 曲松县| 庆元县| 胶州市| 会同县| 吉木萨尔县| 清丰县|