Jack Jiang

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

          本文作者:丁同舟,來自金蝶隨手記技術(shù)團(tuán)隊。

          1、引言

          接上篇《金蝶隨手記團(tuán)隊的Protobuf應(yīng)用實踐(原理篇)》,本文將以iOS端的Objective-C代碼為例,圖文并茂地向您菔救綰臥趇OS工程中快速使用Protobuf,希望對你有幫助。

           

          學(xué)習(xí)交流:

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

          2、系列文章

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

          另外:如果您還打算系統(tǒng)地學(xué)習(xí)IM開發(fā),建議閱讀《新手入門一篇就夠:從零開發(fā)移動端IM》。

          3、基本介紹

           

          Protobuf(全稱 Protocol buffers) 是 Google 提出的一種跨平臺、多語言支持且開源的序列化數(shù)據(jù)格式。相對于類似的 XML 和 JSON,Protobuf 更為小巧、快速和簡單。相對于傳統(tǒng)的 XML 和 JSON, Protobuf 的優(yōu)勢主要在于:更加小、更加快,其語法目前分為proto2和proto3兩種格式。

          如果你沒不了解Protobuf是什么,建議先閱讀本系列的前幾篇《Protobuf從入門到精通,一篇就夠!》、《快速理解Protobuf的背景、原理、使用、優(yōu)缺點》、《金蝶隨手記團(tuán)隊的Protobuf應(yīng)用實踐(原理篇)》,本篇就不再重復(fù)介紹了。

          目前 Google 官方的 Protobuf最新 release 版本為3.21.12,但本文寫作時用的是3.5.1,以下截圖都是基于此版本的環(huán)境搭建,如果你使用最新版本,差異并不大,因為只是小版本更新。

          關(guān)于 Protobuf的使用可以查閱官方文檔:https://developers.google.com/protocol-buffers/docs/overview,建議養(yǎng)成閱讀文檔的習(xí)慣。

          4、準(zhǔn)備工作

          4.1環(huán)境要求

          最低開發(fā)環(huán)境要求:

          • 1)Objective-C 2.0 Runtime (32bit & 64bit iOS, 64bit OS X)
          • 2)Xcode 7.0 以上版本

          注意:Protobuf 出于性能考慮沒有使用 ARC,但在 ARC 下是可以使用的。

          4.2下載安裝

          下載 Protobuf 代碼包(https://github.com/protocolbuffers/protobuf/releases/tag/v21.12),因文章截圖時用的是v3.5.1,所以我這里的為了保持一致選擇的是 protobuf-objectivec-3.5.1.tar.gz,版本區(qū)別不大,建議依此類推。

          4.3解壓代碼包

          編譯 Protobuf,這里可能需要安裝部分工具:

          $ brew install autoconf

          $ brew install automake

          $ brew install libtool

          運行下面腳本進(jìn)行編譯:

          $ ./autogen.sh

          $ ./configure

          $ make

          $ makeinstall

          檢查protobuf是否安裝成功:

          $ protoc --version

          如果成功打印版本號則安裝成功:

          libprotoc 3.5.1

          5、在 iOS 中使用 Protobuf

          5.1創(chuàng)建.proto文件

          這里使用官方文檔上的一份示例數(shù)據(jù)結(jié)構(gòu)創(chuàng)建Person.proto:

          syntax = "proto3";

           

          message Person {

            string name = 1;

            int32 id = 2;

            string email = 3;

           

            enumPhoneType {

              MOBILE = 0;

              HOME = 1;

              WORK = 2;

            }

           

            message PhoneNumber {

              string number = 1;

              PhoneType type = 2;

            }

           

            repeated PhoneNumber phone = 4;

          }

          使用命令行編譯Person.proto為objective-c的文件,編譯出來的文件為Person.pbobjc.h和Person.pbobjc.m:

          protoc Person.proto --objc_out=./

          5.2引入 Protobuf 運行時資源

          Google 官方的文檔提供了兩種引入方式,但使用第一種的時候編譯不能通過,所以這里選擇了第二種。

          具體就是:復(fù)制protobuf目錄下的:objectivec/*.h, objectivec/google/protobuf/*.pbobjc.h, objectivec/google/protobuf/*.pbobjc.m, 以及除去 objectivec/GPBProtocolBuffers.m 后的objectivec/*.m。

          這里直接用命令行操作。

          首先進(jìn)入protobuf下objectivec的目錄:

          $ cdprotobuf-3.5.1/objectivec

          然后復(fù)制符合規(guī)則的文件到指定的工程目錄下:

          $mkdir~/ProtobufDemo/ProtocolBuffers~/ProtobufDemo/ProtocolBuffers/google~/ProtobufDemo/ProtocolBuffers/google/protobuf

          $ cp*.h *.m ~/ProtobufDemo/ProtocolBuffers

          $ cpgoogle/protobuf/*.pbobjc.h google/protobuf/*.pbobjc.m ~/ProtobufDemo/ProtocolBuffers/google/protobuf

          注意:上面的命令并沒有排除 GPBProtocolBuffers.m 文件,引入時需要手動排除。

          現(xiàn)在把ProtocolBuffers目錄下所有文件以及上面編譯出來的 Person.pbobjc.h 和 Person.pbobjc.m 都引入到工程中。

          現(xiàn)在工程目錄結(jié)構(gòu)大概是長這樣:

           

          注意:由于protobuf沒有使用 ARC,因此需要為所有.m文件加上-fno-objc-arc來關(guān)閉 ARC。

          結(jié)果如下:

          提示:需要留意工程中的 Header Search Paths 要增加 $(PROJECT_DIR)/ProtocolBuffers(具體的路徑視情況而定)

          5.3直接引入 ProtocolBuffers 工程

          如果覺得手動引入文件的方式過于復(fù)雜,可以直接引入ProtocolBuffers工程作為依賴項。

          1)進(jìn)入解壓后的protobuf目錄下,復(fù)制objective目錄下的所有文件到ProtobufDemo/ProtocolBuffers目錄下。

          2)在ProtobufDemo工程中引入ProtocolBuffers_iOS工程:

          3)在Build Phases中加入依賴關(guān)系并鏈接庫:

           

          4)引入Person.pbobjc.hPerson.pbobjc.m文件并為.m加上-fno-objc-arc

          5)修改工程配置中部分路徑為 $(PROJECT_DIR)/ProtocolBuffers

          5.4運行測試

          首先引入頭文件:

          #import "Person.pbobjc.h"

          生成Person對象并進(jìn)行編碼和解碼:

          Person *p = [[Person alloc] init];

          p.id_p = 1;

          p.name = @"person1";

          p.email = @"123@qq.com";

           

          //encode

          NSData*data = [p data];

          NSLog(@"Protocol Buffers:\n%@\nData: %@\nData Length: %lu", p, data, data.length);

           

          //decode

          Person *newP = [[Person alloc] initWithData:data error:nil];

          NSLog(@"Decoded: %@", newP);

          運行程序,打印日志如下:

          Protocol Buffers:

          <;Person 0x60c0000da2b0>: {

              name: "person1"

              id: 1

              email: "123@qq.com"

          }

          Data: <0a077065 72736f6e 3110011a 0a313233 4071712e 636f6d>

          Data Length: 23

          Decoded: <;Person 0x6040000d9c90>: {

              name: "person1"

              id: 1

              email: "123@qq.com"

          }

          6、參考資料

          [1] Protobuf 官方開發(fā)者指南(中文譯版)

          [2] Protobuf官方手冊

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

          [4] 如何選擇即時通訊應(yīng)用的數(shù)據(jù)傳輸格式

          [5] 強列建議將Protobuf作為你的即時通訊應(yīng)用數(shù)據(jù)傳輸格式

          [6] APP與后臺通信數(shù)據(jù)格式的演進(jìn):從文本協(xié)議到二進(jìn)制協(xié)議

          [7] 面試必考,史上最通俗大小端字節(jié)序詳解

          [8] 移動端IM開發(fā)需要面對的技術(shù)問題(含通信協(xié)議選擇)

          [9] 簡述移動端IM開發(fā)的那些坑:架構(gòu)設(shè)計、通信協(xié)議和客戶端

          [10] 理論聯(lián)系實際:一套典型的IM通信協(xié)議設(shè)計詳解

          [11] 58到家實時消息系統(tǒng)的協(xié)議設(shè)計等技術(shù)實踐分享

          [12] 金蝶隨手記團(tuán)隊的Protobuf應(yīng)用實踐(原理篇)

          [13] 新手入門一篇就夠:從零開發(fā)移動端IM

          Coffee time!

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

          posted @ 2023-02-14 12:52 Jack Jiang 閱讀(62) | 評論 (0)編輯 收藏

          本文由釘釘技術(shù)專家嘯臺、萬泓分享,為了獲得更好的閱讀效果,本文已對內(nèi)容進(jìn)行少修訂和重新排版。

          1、引言

          釘釘后端架構(gòu)的單元化工作從2018年開始到今年,已經(jīng)是第五個年頭了。五年的時間,釘釘單元化迭代了三個版本,從最初的毛頭小子,到達(dá)今年已經(jīng)小有成就。

          我們在進(jìn)行單元化架構(gòu)建設(shè)的過程中,除了網(wǎng)上能找到的屈指可數(shù)的文章外,可以直接使用的系統(tǒng)更是乏善可陳,使我們不得不從最基礎(chǔ)的系統(tǒng)開始造輪子,極大的影響建設(shè)效率。幸運的是,近幾年云原生技術(shù)的興起,讓我們能復(fù)用很多基礎(chǔ)設(shè)施,進(jìn)而快速提升我們的單元化建設(shè)能力,助力釘釘?shù)陌l(fā)展。

          今天想借此文和大家分享我們在釘釘單元化架構(gòu)實施過程中的心路歷程和一些最佳實踐。因涉及的技術(shù)和業(yè)務(wù)面太廣,本文的分享無法做到面面俱到,主要是想在同路人中形成共鳴,進(jìn)而能復(fù)用一些架構(gòu)或子系統(tǒng)的設(shè)計和實現(xiàn)思路。

          學(xué)習(xí)交流:

          (本文同步發(fā)布于:http://www.52im.net/thread-4122-1-1.html

          2、系列文章

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

          3、術(shù)語概念

          本文內(nèi)容中使用了一些專有的技術(shù)名詞,為了方便大家理解,我把關(guān)鍵的幾個術(shù)語概念的縮寫及其含義專門列出來,供大家參考。

          主要是以下幾個

          • 1)Geo:釘釘專有化部署單位,解決數(shù)據(jù)合規(guī)需求,Geo間數(shù)據(jù)按需互通,并且互通數(shù)據(jù)在Geo內(nèi)部做鏡像拷貝,解決兩化問題;
          • 2)Unit: Geo內(nèi)部資源物理分區(qū)隔離的最小單位,解決Geo內(nèi)的容災(zāi)和容量的問題;
          • 3)L0:客戶端路由,決定了用戶客戶端接入釘釘服務(wù)器的所屬單元,用戶長連接所在的邏輯單元,起到連接加速作用。用戶接入單元;
          • 4)L1:接入層路由,以用戶為維度進(jìn)行調(diào)度,即用戶操作發(fā)生的單元。用戶歸屬單元;
          • 5)L2:業(yè)務(wù)層路由,以業(yè)務(wù)資源為維度進(jìn)行調(diào)度,大部分的業(yè)務(wù)資源所在單元應(yīng)該和用戶調(diào)度單元一致,但一些業(yè)務(wù)無法按照用戶劃分單元,如IM的會話,音視頻的會議。 業(yè)務(wù)歸屬單元;
          • 6)DMB:負(fù)責(zé)釘釘應(yīng)用跨單元RPC調(diào)用的轉(zhuǎn)發(fā),可以認(rèn)為是釘釘單元化RPC路由中間件;
          • 7)DMR:負(fù)責(zé)釘釘應(yīng)用跨單元MQ消息的轉(zhuǎn)發(fā),可以認(rèn)為是釘釘單元化MQ路由中間件;
          • 8)DTIM:釘釘IM系統(tǒng)。

          4、單元化架構(gòu)1.0版:合規(guī)驅(qū)動下的部署架構(gòu)

          2018年,部分大客戶出于法律政策、商業(yè)機(jī)密數(shù)據(jù)存儲的要求,要求釘釘?shù)臄?shù)據(jù)存儲、訪問接入、服務(wù)部署需要在其信任的區(qū)域內(nèi)。既需要滿足其數(shù)據(jù)存儲私有化要求,同時需要滿足跨地區(qū)網(wǎng)絡(luò)的rt性能要求。

          于是我們結(jié)合阿里云機(jī)房部署位置、物理距離、用戶數(shù)據(jù)安全等方面出發(fā),釘釘在客戶的阿里云機(jī)房內(nèi)建設(shè)了一個單元,將通訊錄、IM信息等企業(yè)數(shù)據(jù)單獨存儲在客戶機(jī)房。

          我們通過一條專線,將兩個機(jī)房邏輯串聯(lián)到一起,內(nèi)部通過DMB/DMR系統(tǒng),實現(xiàn)了請求互通,這就是釘釘單元化架構(gòu)的1.0版。

          1.0版比較簡單,純粹是業(yè)務(wù)驅(qū)動,和支付寶單元化建設(shè)的初衷——“容災(zāi)驅(qū)動”有較大區(qū)別。兩個站點通過UID分段,將用戶劃分為中心用戶和專有用戶。

          上圖只是一個簡化的邏輯結(jié)構(gòu),內(nèi)部實現(xiàn)遠(yuǎn)比上圖復(fù)雜,但是1.0建設(shè)主要是從0到1,和大多數(shù)異地多活的系統(tǒng)較相似,這里就只簡單的和大家分享一下。

          5、單元化架構(gòu)2.0版:逼出來的容量架構(gòu)

          2020年是一個特殊的年份,由于疫情的原因,帶給大家非常多的改變,其中也包括釘釘。

          由于在線辦公與教育流量的突增,開年第一天上班就給釘釘一個下馬威,平峰的流量已經(jīng)和除夕跨年的持平,但是和除夕不同的是這個流量是持續(xù)的,即使節(jié)前準(zhǔn)備了三倍容量,也抵擋不住流量對系統(tǒng)的沖擊。只能借助阿里云的能力,不斷的擴(kuò)容。

          但是每天將近30%的流量增幅,單純的擴(kuò)容也能難保障服務(wù)的連續(xù)性,最終也遇到了擴(kuò)無可擴(kuò)的場景,張北機(jī)房沒有機(jī)位了,有機(jī)器資源但是沒有機(jī)位讓我們有力無處使。我們不得不不斷進(jìn)行系統(tǒng)優(yōu)化,同時借助限流、降級、雙推等措施,勉強抗住了流量的最高峰。

          疫情之前,我們一直在做高可用,但是這個高可用主要集中在容災(zāi)機(jī)制上,比如搭建容災(zāi)單元。如同支付寶一樣,是因為當(dāng)時光纖被挖斷;又比如銀行的兩地三中心架構(gòu),是擔(dān)心某一個地域由于天災(zāi)或者戰(zhàn)爭導(dǎo)致數(shù)據(jù)丟失。疫情的流量給我們上了一課,僅僅關(guān)注容災(zāi)是不夠的,特別是釘釘?shù)腄AU從千萬走向億級別之后,更需要在容量上做出提前規(guī)劃。

          正因如此,我們認(rèn)為“容量架構(gòu)不是設(shè)計出來而是真真切切被逼出來的”,所以容量架構(gòu)就成為我們單元化核心要素之一。

          容量架構(gòu)是將流量劃分到不同單元,每個單元承載各自的流量。容災(zāi)架構(gòu)是單元異常時,能保障核心的能力可用,也可以將流量動態(tài)調(diào)度到別的單元,實現(xiàn)服務(wù)的快速恢復(fù)。

          因此釘釘單元化進(jìn)入了2.0時代,專注于容量和容災(zāi)的建設(shè)。

          6、2.0版是基于什么維度進(jìn)行流量劃分的?

          要實現(xiàn)流量的劃分,必然要基于一個維度進(jìn)行劃分,一部分到A單元,一部分到B單元。

          釘釘單元化架構(gòu)也是參考了淘系和支付寶的單元化架構(gòu),前兩者都是基于UID劃分,釘釘單元化的第一個版本其實也是一樣的,基于UID做拆分。

          但是當(dāng)我們設(shè)計容量架構(gòu)時,發(fā)現(xiàn)基于UID劃分無法解決我們的容量問題。

          以IM為例:一條消息其實屬于聊天雙方的,群聊亦是如此。用戶能和任意一個人聊天,這樣我們根本無法找到一個切入點來劃分流量,強行按照UID拆分,必然導(dǎo)致一個用戶的消息出現(xiàn)在N個單元,單元的自封閉就無法做了。

          也有同學(xué)會說:為什么消息不按照每個人存儲,這不就能按照UID劃分了嗎?結(jié)論是不行。首先這個消息變成了寫擴(kuò)散,持久化的時候會變成多單元寫,其次是成本翻倍,在DTIM這種過億規(guī)模的場景這條路走不通。這里可以多說一點,因為這個觀點來之不易,大家都知道,人是有慣性的,既然淘寶、支付寶甚至是微信都是UID劃分,為什么釘釘要特立獨行?當(dāng)時我們團(tuán)隊受到了絕大部分釘釘技術(shù)團(tuán)隊的挑戰(zhàn),持續(xù)長達(dá)將近一個月的技術(shù)選型的“爭吵”,最終還是達(dá)成了一致意見。

          DTIM主要有3個維度,分別是UID、會話(CID)、消息。其中會話和消息是綁定的,而系統(tǒng)中最大量的是消息,按照第一性原則來看,一定要將消息劃分開來,才能做到將容量劃分開來的效果。

          我們再來看看音視頻,是按照房間維度組織流量和數(shù)據(jù)的,和IM又完全不同。

          同樣,文檔其實更適合按照企業(yè)維度來劃分。

          不同的業(yè)務(wù)擁有不同的維度,因此我們認(rèn)為:單元化最重要的找到自身“最大”的業(yè)務(wù)維度,將這個維護(hù)拆分,才能實現(xiàn)單元的橫向擴(kuò)展,我們稱之為“業(yè)務(wù)路由”。

          回頭來看:我們之前其實是進(jìn)入了思考誤區(qū),以為淘系和支付寶都是UID維度,我們也要這個維度,其實UID正是前者的業(yè)務(wù)維度,比如訂單,也是圍繞用戶,并不會有交集的情況,會話就是IM的劃分維度,因此做單元化之前要先找到屬于自己的業(yè)務(wù)維度。

          7、2.0版是如何實現(xiàn)IM消息的全局路由能力的?

          7.1概述

          UID路由有個最大的好處,就是可以按照UID分段,能實現(xiàn)高效的靜態(tài)路由,也不用擔(dān)心多單元之間的一致性問題。但是這種分段路由局限性也比較明顯,需要預(yù)先分配,單元之間動態(tài)調(diào)度流量和數(shù)據(jù)成本極高,而且只能支持這種數(shù)值+順序的場景。

          在釘釘?shù)膱鼍爸校袝捑S度、房間維度、企業(yè)維度等等,想簡單采用這種預(yù)分段機(jī)制難以滿足業(yè)務(wù)需求。因此我們需要構(gòu)建一個業(yè)務(wù)路由系統(tǒng)(RoutingService),實現(xiàn)消息流量的精確路由。

           

           以IM為例:每次消息的發(fā)送,在單元化框架層面,會通過消息的會話(CID),查詢路由信息,如果是本單元,流量下行并持久化;如果是非本單元,路由到對應(yīng)的單元中。

          下圖是三個會話:分別是cid:1001、cid:1002、cid:1003,三個會話隸屬不同單元,不管用戶從哪個單元發(fā)送消息,都會路由到會話所在的單元。比如:用戶在Unit B的cid:1001 中發(fā)送消息,當(dāng)消息進(jìn)入Receiver之后,會先查詢此cid:1001所在的單元,發(fā)現(xiàn)是Unit A,路由框架將請求轉(zhuǎn)到A單元,消息在A單元持久化并通過A單元的同步協(xié)議,將數(shù)據(jù)推送到客戶端。

           

           

           從上圖可知:每次消息發(fā)送,都要查詢路由服務(wù),DTIM百萬的峰值,對路由必然會帶來超大的壓力,同時我們能發(fā)現(xiàn),路由數(shù)據(jù)在多單元實現(xiàn)一致性是一個巨大的挑戰(zhàn)。

          7.2邊緣計算:端到端路由

          在DTIM的場景中,會話的路由信息幾乎不會變更,只有當(dāng)我們決定將某些超大的會話或者企業(yè)騰挪到新單元時,才會發(fā)起路由的變更,因此會話的路由信息幾乎可以認(rèn)為是恒定不變的。那么每次查詢路由服務(wù)端,效費比太低,是極大的浪費。

          既然路由信息幾乎不可變,是否將路由信息緩存呢?最常見的是使用一個集中式的Cache系統(tǒng),緩存Hot的會話,我們也是這么做的,但是這么做還是不夠,一旦Cache系統(tǒng)失效,DTIM還是會出現(xiàn)大面積故障,而且這個百萬級的請求對Cache也是一個極大的壓力。

          考慮到釘釘有強大的客戶端,借用邊緣計算的思路,我們將用戶的會話數(shù)據(jù)緩存到客戶端。對于客戶端來說,也只用緩存用戶自身最熱的N會話路由數(shù)據(jù),消息發(fā)送時,通過Header將路由數(shù)據(jù)攜帶到服務(wù)端,服務(wù)端路由SDK只要做合法性和續(xù)約即可,這樣就將路由流量降低了95%以上。當(dāng)路由服務(wù)出現(xiàn)異常時,還可以繼續(xù)使用客戶端路由,將路由的可用性提升到一個新的高度。

          SDK本地會依據(jù)上行請求的返回中是否有新的路由信息,進(jìn)而更新客戶端路由。同時可以借助釘釘有主動下推的能力,通過同步協(xié)議將新的路由信息主動推送給客戶端,使會話遷移做到更平順。

          7.3計算下沉:多單元一致性


          對于新會話:比如小明要創(chuàng)建一個群聊,是應(yīng)該創(chuàng)建在那個單元呢?

          如果在A單元創(chuàng)建了,當(dāng)會話消息來到B單元,系統(tǒng)怎么能第一時間知道會話已經(jīng)在被綁定到A單元。

          這里一般的方式有兩種

          • 1)單元之間的存儲系統(tǒng)采用類似DTS的機(jī)制進(jìn)行異步同步,這種機(jī)制有秒級延遲;
          • 2)在應(yīng)用層主動同步,比如接入消息隊列。


          這兩種方式由于都是異步的原因,都會出現(xiàn)不一致的問題,如果會話同時被綁定在兩個單元,邏輯上會導(dǎo)致用戶的歷史消息丟失,這個是不能接受的。

          多地域(Region)數(shù)據(jù)同步其實是通用的技術(shù)挑戰(zhàn),我們認(rèn)為存儲系統(tǒng)提供是最好的方式,正如Google的Spanner一樣,這樣對我們上層才是最友好的方式。

          因此我們找到了存儲的OTS、Nuwa團(tuán)隊一起共建了GlobalTable。GlobalTable的核心原理還是借助Nuwa的一致性組,組分布在多個地域,采用多數(shù)派寫入成功即返回的原理,做到20ms以內(nèi)的一致性寫。

          8、2.0版的容災(zāi)能力

          釘釘單元化的容災(zāi)能力是深度結(jié)合釘釘?shù)臉I(yè)務(wù)層場景落地的,和淘系支付寶等有明確的區(qū)別。

          以DTIM為例,最大的特點是當(dāng)服務(wù)單元異常時,服務(wù)側(cè)仍能提供最核心的服務(wù),保障最基本的能力。本質(zhì)上是由于DTIM是最終一致性系統(tǒng),可以短暫允許部分環(huán)節(jié)失敗。

          可以看一下DTIM發(fā)送消息的容災(zāi)場景。當(dāng)某個單元完全不可用的情況下,用戶消息發(fā)送鏈路通過降級為local模式,在本地校驗非本單元會話數(shù)據(jù)通過之后直接做消息發(fā)送,processor遇到非本單元的會話消息數(shù)據(jù)可以做單元間投遞做數(shù)據(jù)回放,本地是否落庫可選,同步協(xié)議推送不必區(qū)分是否為本單元會話消息數(shù)據(jù)直接通過本單元的topic推送給客戶端,配合用戶無狀態(tài)快速遷移能力,單元間可以實現(xiàn)真正的分鐘級別容災(zāi)切換能力。

          9、2.0版的成果與突破

          以上是釘釘單元化2.0提供給應(yīng)用的核心能力,在滿足容災(zāi)和容量設(shè)計需求之后,釘釘單元化給應(yīng)用帶來了更多的能力和想象空間。

          比如:

          • 1)快速遷移:當(dāng)某一地域資源不足時,釘釘單元化可以將業(yè)務(wù)快速的從A單元遷移到B單元;
          • 2)常態(tài)化切流:比如新建的教育會話,可以放到獨立的單元;
          • 3)熱點治理:當(dāng)前某一個會話過熱,特殊時期可以遷移到獨立集群;
          • 4)SLA:滿足不同的VIP客戶需求,基于不同的SLA和售賣價格,將VIP客戶放到對應(yīng)地單元。

          核心還是我們擁有單元化能力之后,實現(xiàn)了多單元流量的快速調(diào)度,為業(yè)務(wù)解決了后顧之憂。

          10、2.0版在新時代面臨的新挑戰(zhàn)

          10.1魚和熊掌不可兼得

          2022年對釘釘來說是成本之年,成本的壓力不光落到了團(tuán)隊,還落到了每個人身上。

          正如存儲的CAP理論是一樣的,我們同時只能滿足兩個維度,對于流量(性能P)、成本(C)、體驗(E)也是一樣,在流量不可預(yù)知和干預(yù)的情況下,選擇成本必然導(dǎo)致體驗受損,反之選擇體驗,必然導(dǎo)致成本升高。進(jìn)入下半年,疫情反復(fù)帶來流量的反復(fù),為了實現(xiàn)可控的教育成本,只能在高峰期降級部分能力,這又導(dǎo)致體驗受損,這段時間的工單量可以窺見一斑。

          流量是用戶側(cè)觸發(fā)的,我們無法干預(yù),只能在成本和體驗之間尋求平衡。和前面提及的一樣,為了減小成本的消耗這就導(dǎo)致我們在擴(kuò)容和縮容之間疲于奔命,反應(yīng)不及時甚至有故障的危險,這種機(jī)制不可取也不可持續(xù)。到底是要流量與成本,還是要流量與體驗,給我們技術(shù)團(tuán)隊帶來了巨大的挑戰(zhàn)和矛盾。

          10.2商業(yè)化路在何方

          當(dāng)前釘釘為支持大客戶提供了多種解決方案,專業(yè)釘釘、專屬存儲與打包、專有釘釘。

          專屬釘釘通過APP專屬化以及部分專屬功能,比如為一個企業(yè)定制一個擁有獨立Logo的APP,能滿足一般的中大型客戶的業(yè)務(wù)訴求。

          對于大型以及超大型客戶,我們提供專有釘釘,提供專有化輸出,完全隔離的方案,比如浙政釘。

          伴隨著釘釘?shù)纳虡I(yè)化進(jìn)入深水區(qū),客戶對釘釘提出了新的訴求,特別是數(shù)據(jù)安全與歸屬、互聯(lián)互通、完整的能力棧等訴求,當(dāng)前釘釘輸出產(chǎn)品形態(tài)都無法同時地滿足以上需求。

          前幾年互聯(lián)網(wǎng)上出現(xiàn)的幾起數(shù)據(jù)安全事件,數(shù)據(jù)丟失與泄露,未經(jīng)客戶授權(quán)私自訪問客戶數(shù)據(jù),讓大多數(shù)客戶不信任服務(wù)提供商,即使服務(wù)商的安全能力已經(jīng)是業(yè)界一線能力。其實這個是可以理解的,數(shù)據(jù)即客戶的生命線,數(shù)據(jù)無法在自身可控范圍內(nèi),特別是對于很多特殊行業(yè),這是無法接受的,自身性命豈能假手于人。專屬釘釘在面臨這種客戶時,前線售賣同學(xué)是無能為力。

          那么很多同學(xué)肯定會提“如果專屬釘釘滿足不了需求,我們專有釘釘不是能解決這些問題嗎?”,其實單單從訴求來看,專有釘釘場景是切合客戶的業(yè)務(wù)訴求,提供完全獨立運行環(huán)境、可控的數(shù)據(jù)安全。但是專有釘釘由于其獨特的架構(gòu)帶來高昂的售價以及后期的運維代價,對于超大型的客戶來說也難以承擔(dān)如此高的成本。對于釘釘自身來說,從研發(fā)到后續(xù)運維,維護(hù)一套獨立體系也難以在客戶側(cè)大面積推廣。

          11、單元化架構(gòu)3.0版:混合云架構(gòu)

          11.1概述

          釘釘單元化經(jīng)過四年的發(fā)展,在容災(zāi)和容量上做出一定的積淀,同時完成了一些核心技術(shù)的積累。

          當(dāng)整體架構(gòu)成熟之后,我們也在思考,單元化能否從技術(shù)架構(gòu)升級為業(yè)務(wù)架構(gòu),比如搭建獨立的高可用單元,按照售賣的SLA提供給VIP客戶,支持釘釘商業(yè)化的發(fā)展。

          同時我們在云原生逐步發(fā)力,將部分核心應(yīng)用放到云上,經(jīng)過這一年多的運行,遇到了新的挑戰(zhàn),但更獲得云下無法獲得的計算彈性能力,云上的彈性對云下是一個降維打擊,從一個新的方向解決計算問題。

          如上文提到的兩個核心挑戰(zhàn),釘釘單元化同樣面臨這個問題,在持續(xù)的發(fā)展中找到了一個合適的架構(gòu)方向。

          基本思路是:

          • 1)云下作為基本盤,保障核心流量的問題,畢竟云下經(jīng)過集團(tuán)多年的打磨,不管是穩(wěn)定性還是流程的合理性都有保障;
          • 2)云上應(yīng)對高漲異常的流量,比如和疫情正相關(guān)的教育流量,既保證了服務(wù)的穩(wěn)定性,又能充分利用云上彈性能力,在提供完整能力的前提下做到一個相對較低的成本。

          其次是升級Geo概念:

          • 1)將Geo作為一個獨立的業(yè)務(wù)域,實現(xiàn)Geo級別完全獨立部署,分布式云模式;
          • 2)同時Geo之間按需互通,從研發(fā)體系上能做到一套代碼。

          因此,釘釘單元化來到了3.0版本,我們稱之為釘釘單元化混合云架構(gòu)。

          混合云主要是從兩個維度來看:

          • 第一:是云上云下,我們認(rèn)為云上云下并不是取代的關(guān)系,而是相互補充的關(guān)系,是一個長期的狀態(tài),正如很多大客戶隨著規(guī)模的持續(xù)擴(kuò)張,最終依賴的部分核心能力必然走向自研道理一樣,這能做成本的進(jìn)一步降低,所以架構(gòu)是一個混合云架構(gòu);
          • 第二:業(yè)務(wù)架構(gòu)上也是混合云架構(gòu),通過不同的Geo,將不同的業(yè)務(wù)邏輯上聚合到一起,構(gòu)建起一張釘釘?shù)拇缶W(wǎng),不同Geo按需互通,實現(xiàn)了業(yè)務(wù)架構(gòu)的混合。

          3.0從系統(tǒng)架構(gòu)上相對于2.0,最大的區(qū)別就是云原生技術(shù)的運用和互通網(wǎng)關(guān)的建立。

          11.2云原生技術(shù) :抵抗系統(tǒng)架構(gòu)熵增的有效手段

          近幾年,互聯(lián)網(wǎng)圈最火的技術(shù)莫過于以Docker為代表的云原生技術(shù)最為火熱,各大云廠商也都在不遺余力的推廣云原生技術(shù)以及對應(yīng)的產(chǎn)品。同時釘釘服務(wù)過億DAU的客戶,面對各種可靠性、服務(wù)連續(xù)性、并發(fā)、容災(zāi)等技術(shù)挑戰(zhàn),也都走到了現(xiàn)有技術(shù)的邊界。

          所以我們也在不斷吸收新的技術(shù)和架構(gòu),希望從體系與架構(gòu)上降低我們的技術(shù)復(fù)雜度,以抵抗熵增。

          我們在2021年底啟動了云原生升級戰(zhàn)略,升級云原生技術(shù)并不是為了技術(shù)而升級,而是切實面臨巨大的技術(shù)挑戰(zhàn)。

          1)首先我們面臨多語言的挑戰(zhàn):

          我們以IM為例,IM的核心邏輯都是使用C++構(gòu)建,但是我們常用的中間件三大件:存儲、緩存、異步隊列,其中緩存和異步隊列在C++客戶端上長期建設(shè)不足,導(dǎo)致IM長期在使用低版本。

          低版本由于長時間缺乏維護(hù),經(jīng)常會出現(xiàn)異常,比如隊列假死、消費不均等,導(dǎo)致我們自己不得不親自上陣修改SDK的代碼,以致最后難以使用到產(chǎn)品的新能力,阻礙IM服務(wù)能力的提升。

          2)其次是多產(chǎn)品多云的挑戰(zhàn):

          我們以阿里云為例,數(shù)據(jù)庫類目下的產(chǎn)品,從類別上就有關(guān)系數(shù)據(jù)庫、NoSQL數(shù)據(jù)庫、數(shù)倉等等,還有存儲也是一樣。

          對于我們上層業(yè)務(wù),其實絕大部分服務(wù)都只依賴了底層的CURD,這么多產(chǎn)品,每次對接一個產(chǎn)品都要開發(fā)一輪。

          配置系統(tǒng)也是一樣,彈內(nèi)有Diamond,云上有Nacos、Mse,K8s有自己的Configmap等,而且這些配置系統(tǒng)不像數(shù)據(jù)庫有標(biāo)準(zhǔn),而是百花齊放,但是這樣卻苦了我們使用者。

          這些內(nèi)容不是我們的核心路徑,浪費大把時間在各種產(chǎn)品接口的適配上,明顯拖累了釘釘?shù)陌l(fā)展。

          3)最后就是通用的流量治理挑戰(zhàn):

          釘釘很多系統(tǒng)都是最終一致的系統(tǒng),IM就是典型的最終一致系統(tǒng),這類系統(tǒng)和強同步系統(tǒng)在架構(gòu)設(shè)計有一個明顯的區(qū)別,強一致系統(tǒng)如果遇到失敗,必須要持續(xù)重試直到成功,所以一般編程上都是重試+退避。

          但是最終一致系統(tǒng)不是,這類系統(tǒng)允許部分節(jié)點失敗,不要阻礙其他流程,失敗的流量通過一個異步回旋的隊列,將數(shù)據(jù)逐步回放回來即可。這種回旋需要借助異步隊列,而且要設(shè)計各種消費機(jī)制,比如限速、比如丟棄等等,這是一個通用的邏輯,但是每個業(yè)務(wù)方或多或少都在實現(xiàn)自己的回旋系統(tǒng),重復(fù)的造輪子。又比如各種故障注入,單元化路由流量等等,要想擁有這個能力,團(tuán)隊不得不投入人力研發(fā)。

          在對付架構(gòu)復(fù)雜度上,我們主要從兩個維度來屏蔽復(fù)雜度。

          首先代碼層面我們選擇了DDD模式,我們使用DDD分層核心是把對外系統(tǒng)的依賴全部收攏到Infrastructure這一層,全部采用純虛函數(shù)(Interface)對外提供接口。屏蔽底層中間件差異和細(xì)節(jié)。

          在架構(gòu)上采用Sidecar的模式,類似于Dapr的思想,通過標(biāo)準(zhǔn)的GRPC和PB實現(xiàn)應(yīng)用與中間件解耦。Sidecar中集成了各種中間件、配置系統(tǒng)、灰度系統(tǒng)等,等價實現(xiàn)了應(yīng)用和中間件的解耦。上文中提到的不管是多語言挑戰(zhàn)、多云多產(chǎn)品的挑戰(zhàn)、重復(fù)造輪子等問題,都能很好的解決。

          11.3互通網(wǎng)關(guān) :混合架構(gòu)的基石

          云上云下互通,或者說多個云賬戶VPC之間的互通,我們常見的有兩種方案:

          • 1)其一是VPC直接打通,讓多個VPC之間形成一個大的局域網(wǎng),RealServer實現(xiàn)點對點互通;
          • 2)其一是中間搭建一個負(fù)載均衡器,通過暴露EIP實現(xiàn)互通。

          兩個方案都有自己的優(yōu)缺點。

          對于方案一:打通的VPC涉及到IP規(guī)劃,如果前期沒有合理規(guī)劃,后續(xù)很難打通;還有這種方案有水桶短板安全問題,一旦一個VPC被攻破,這張網(wǎng)也被攻破;但是對于內(nèi)部的應(yīng)用來說架構(gòu)就比較簡單,可以僅僅借助K8s DNS service就能做到服務(wù)發(fā)現(xiàn)。

          對于方案二:最大的缺點就是中間有一個集中式的負(fù)載均衡,需要申請獨立的LB才可訪問;但是這種方案隔離性好。

          對于釘釘單元化來說,涉及N個業(yè)務(wù)方,N * M個應(yīng)用,對應(yīng)X個VPC,要想VPC之間打通,幾乎沒有可能性,而且VPC打通,還面臨應(yīng)用之間的安全性問題。要實現(xiàn)Geo之間互通,環(huán)境之間的隔離性是基本要求,與此同時,我們也要考慮到系統(tǒng)的可擴(kuò)展性,所以我們必須要構(gòu)建一套獨立的流量網(wǎng)關(guān),實現(xiàn)流量加密、尋址、轉(zhuǎn)發(fā)等通用能力。

          釘釘互通網(wǎng)關(guān)是構(gòu)建在Envoy之上的系統(tǒng),雙向Ingress和Egress,支持GRPC和釘釘自研協(xié)議。具備流量管理、傳輸加密、單元尋址等能力。釘釘單元化借助互通網(wǎng)關(guān)的能力,再配合全局流控系統(tǒng),我們可以在多單元之間實現(xiàn)精確的流量控制和調(diào)度。

          12、寫在最后

          伴隨著專屬集群的持續(xù)輸出,客戶對專屬的場景需求會越來越多,需要我們投入更多的人力持續(xù)的建設(shè)。

          比如:

          • 1)在架構(gòu)側(cè):首先是Sidecar持續(xù)強化,支持更多的中間件和環(huán)境,提供不同維度的安全能力,滿足客戶和應(yīng)用的安全需求;
          • 2)在運維側(cè):我們需要構(gòu)建多Geo管理能力,完善Geo和單元之間流量快速調(diào)度能力,提供自動化的自檢系統(tǒng)等;
          • 3)在交付側(cè):如果實現(xiàn)快速交付,比如是否能做到新應(yīng)用一周完成單元化改造,新Geo一天部署完成。這些挑戰(zhàn)都是接下來我們要重點投入的方向。

          對于標(biāo)準(zhǔn)釘釘來說,這個是我們的基本盤,一個穩(wěn)定可靠且低成本的釘釘是我們持之以恒的目標(biāo),接下來我們會加大云上流量的占比,充分的借助云上彈性能力,實現(xiàn)可控的成本。

          今天我們只是站在釘釘?shù)慕嵌壬蠏伭艘粋€“磚”,希望在異地多活這個領(lǐng)域激起一層浪花,歡迎大家一起討論。

          13、相關(guān)資料

          [1] 現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲方案探討

          [2] 企業(yè)級IM王者——釘釘在后端架構(gòu)上的過人之處

          [3] 深度解密釘釘即時消息服務(wù)DTIM的技術(shù)設(shè)計

          [4] 釘釘——基于IM技術(shù)的新一代企業(yè)OA平臺的技術(shù)挑戰(zhàn)(視頻+PPT)

          [5] 企業(yè)微信的IM架構(gòu)設(shè)計揭秘:消息模型、萬人群、已讀回執(zhí)、消息撤回等

          [6] IM系統(tǒng)的MQ消息中間件選型:Kafka還是RabbitMQ?

          [7] 深度揭密RocketMQ在釘釘IM系統(tǒng)中的應(yīng)用實踐

          (本文同步發(fā)布于:http://www.52im.net/thread-4122-1-1.html

          posted @ 2023-02-13 10:50 Jack Jiang 閱讀(133) | 評論 (0)編輯 收藏

          一、更新內(nèi)容簡介

          本次更新為次要版本更新,進(jìn)行了若干優(yōu)化(更新歷史詳見:碼云 Release Nodes)。可能是市面上唯一同時支持 UDP+TCP+WebSocket 三種協(xié)議的同類開源IM框架。

          二、MobileIMSDK簡介

          MobileIMSDK 是一套專為移動端開發(fā)的原創(chuàng)IM通信層框架:

          • 歷經(jīng)8年、久經(jīng)考驗;
          • 超輕量級、高度提煉,lib包50KB以內(nèi);
          • 精心封裝,一套API同時支持UDP、TCP、WebSocket三種協(xié)議(可能是全網(wǎng)唯一開源的);
          • 客戶端支持 iOSAndroid標(biāo)準(zhǔn)JavaH5小程序(開發(fā)中..)、Uniapp(開發(fā)中..);
          • 服務(wù)端基于Netty,性能卓越、易于擴(kuò)展;??
          • 可與姊妹工程 MobileIMSDK-Web 無縫互通實現(xiàn)網(wǎng)頁端聊天或推送等;??
          • 可應(yīng)用于跨設(shè)備、跨網(wǎng)絡(luò)的聊天APP、企業(yè)OA、消息推送等各種場景。

          MobileIMSDK工程始于2013年10月,起初用作某產(chǎn)品的即時通訊底層實現(xiàn),完全從零開發(fā),技術(shù)自主可控!

          您可能需要:查看關(guān)于MobileIMSDK的詳細(xì)介紹

          三、代碼托管同步更新

          OsChina.net

          GitHub.com

          四、MobileIMSDK設(shè)計目標(biāo)

          讓開發(fā)者專注于應(yīng)用邏輯的開發(fā),底層復(fù)雜的即時通訊算法交由SDK開發(fā)人員,從而解偶即時通訊應(yīng)用開發(fā)的復(fù)雜性。

          五、MobileIMSDK框架組成

          整套MobileIMSDK框架由以下5部分組成:

          1. Android客戶端SDK:用于Android版即時通訊客戶端,支持Android 2.3及以上,查看API文檔
          2. iOS客戶端SDK:用于開發(fā)iOS版即時通訊客戶端,支持iOS 8.0及以上,查看API文檔
          3. Java客戶端SDK:用于開發(fā)跨平臺的PC端即時通訊客戶端,支持Java 1.6及以上,查看API文檔
          4. H5客戶端SDK:暫無開源版,查看精編注釋版
          5. 服務(wù)端SDK:用于開發(fā)即時通訊服務(wù)端,支持Java 1.7及以上版本,查看API文檔

          整套MobileIMSDK框架的架構(gòu)組成:

           另外:MobileIMSDK可與姊妹工程 MobileIMSDK-Web 無縫互通,從而實現(xiàn)Web網(wǎng)頁端聊天或推送等。

          六、MobileIMSDK v6.3更新內(nèi)容 

          【重要說明】:

          MobileIMSDK v6.3 為次要版本,進(jìn)行了若干優(yōu)化! 查看詳情

          【新增的特性】:

          • 1. [所有端] 提供了靈活的接口供開發(fā)者定制和開啟SSL/TLS加密傳輸;

          【其它優(yōu)化和提升】:

          • 1. [iOS] 解決了iOS端Demo在iOS16下的適配問題;
          • 2. [iOS] 解決了iOS端Demo在黑暗模式下背景和標(biāo)題欄是黑色的問題;
          • 3. [Android] 優(yōu)化了Android端Demo在最新Android系統(tǒng)下的適配等;
          • 4. [Android/Java] 對全局單例增加線程安全處理,防止在高版本JDK中出現(xiàn)并發(fā)調(diào)用而導(dǎo)致單例被重復(fù)實例化。

          【版本地址】:

          https://gitee.com/jackjiang/MobileIMSDK/releases/tag/6.3

          posted @ 2023-02-07 10:27 Jack Jiang 閱讀(71) | 評論 (0)編輯 收藏

               摘要: 本文引用了“鮮棗課堂”的《史上最強5G科普》文章內(nèi)容。為了更好的內(nèi)容呈現(xiàn),在引用和收錄時內(nèi)容有改動,轉(zhuǎn)載時請注明原文來源。1、內(nèi)容概述? 5G技術(shù)的關(guān)注度越來越高:在此之前,5G技術(shù)對于普通老百姓來說,似乎還很遙遠(yuǎn),關(guān)注度并不高。但從去年開始,美帝赤裸裸打壓中興和華為的國際事件,讓5G技術(shù)在國內(nèi)有了很高的關(guān)注度。美帝打壓中興、華為固然是壞事,但因為這個事情,相當(dāng)于反過來為5...  閱讀全文

          posted @ 2023-02-04 16:21 Jack Jiang 閱讀(82) | 評論 (0)編輯 收藏

               摘要: 本文由金蝶隨手記技術(shù)團(tuán)隊丁同舟分享。1、引言跟移動端IM中追求數(shù)據(jù)傳輸效率、網(wǎng)絡(luò)流量消耗等需求一樣,隨手記客戶端與服務(wù)端交互的過程中,對部分?jǐn)?shù)據(jù)的傳輸大小和效率也有較高的要求,普通的數(shù)據(jù)格式如 JSON 或者 XML 已經(jīng)不能滿足,因此決定采用 Google 推出的 Protocol Buffers 以達(dá)到數(shù)據(jù)高效傳輸。本文將基于隨手記團(tuán)隊的Protobuf應(yīng)用實踐,分享了Protobuf的技術(shù)原...  閱讀全文

          posted @ 2023-01-28 16:57 Jack Jiang 閱讀(131) | 評論 (0)編輯 收藏

               摘要: 1、前言Protobuf是Google開源的一種混合語言數(shù)據(jù)標(biāo)準(zhǔn),已被各種互聯(lián)網(wǎng)項目大量使用。Protobuf最大的特點是數(shù)據(jù)格式擁有極高的壓縮比,這在移動互聯(lián)時代是極具價值的(因為移動網(wǎng)絡(luò)流量到目前為止仍然昂貴的),如果你的APP能比競品更省流量,無疑這也將成為您產(chǎn)品的亮點之一。現(xiàn)在,尤其IM、消息推送這類應(yīng)用中,Protobuf的應(yīng)用更是非常廣泛,基于它的優(yōu)秀表現(xiàn),微信和手機(jī)QQ這樣的主流IM...  閱讀全文

          posted @ 2023-01-05 16:14 Jack Jiang 閱讀(155) | 評論 (0)編輯 收藏

          本文由釘釘技術(shù)專家尹啟繡分享,有修訂和重新排版。

          1、引言

          短短的幾年時間,釘釘便迅速成為一款國民級應(yīng)用,發(fā)展速度堪稱迅猛。

          IM作為釘釘最核心的功能,每天需要支持海量企業(yè)用戶的溝通,同時還通過 PaaS 形式為淘寶、高德等 App 提供基礎(chǔ)的即時通訊能力,是日均千億級消息量的 IM 平臺。

          在釘釘?shù)腎M中,我們通過 RocketMQ實現(xiàn)了系統(tǒng)解耦、異步削峰填谷,還通過定時消息實現(xiàn)分布式定時任務(wù)等高級特性。同時與 RocketMQ 深入共創(chuàng),不斷優(yōu)化解決了很多RocketMQ本身的問題,并且孵化出 POP 消費模式等新特性,使 RocketMQ 能夠完美支持對性能穩(wěn)定性和時延要求非常高的 IM 系統(tǒng)。本文將為你分享這些內(nèi)容。

          學(xué)習(xí)交流:

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

          2、系列文章

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

          3、釘釘IM面臨的巨大技術(shù)挑戰(zhàn)

          3.1 概述

          釘釘作為企業(yè)級 IM 領(lǐng)先者,面臨著巨大的技術(shù)挑戰(zhàn)。市面上DAU過億的App里,只有釘釘是2B產(chǎn)品,我們不僅需要和其他 2C 產(chǎn)品一樣,支持海量用戶的低時延、高并發(fā)、高性能、高可用,還需保證企業(yè)級用戶在使用釘釘時能夠提升溝通協(xié)同效率。

          下圖是概括的是釘釘?shù)闹饕芰Γ?/strong>

          3.2 技術(shù)挑戰(zhàn)1:ToB與ToC的差異

          作為企業(yè)級應(yīng)用,需要保證幫助用戶提升溝通體驗。

          ToB 的工作溝通和 ToC 的場景生活溝通存在較大差異, ToC的IM產(chǎn)品比如微信,在有完整的關(guān)系鏈后,只需滿足大部分用戶需求即可。

          然而微信的很多體驗其實并不友好:比如聊天消息中的視頻圖片在固定時間內(nèi)沒有打開則會無法下載,卸載重裝之后聊天記錄全部丟失。

          而 ToB 場景下:聊天記錄是非常重要的內(nèi)容,釘釘為保證用戶消息不丟失,提供了多端同步和消息云端存儲的能力,用戶任意換端都能查看完整的聊天記錄。

          在工作過程中,大量會議是工作效率殺手,釘釘還提供了已讀、Ding 等效率套件,為工作溝通提供新選項。

          3.3 技術(shù)挑戰(zhàn)2:安全要求高

          在ToB 的工作場景下,用戶對信息安全要求非常高,信息安全是企業(yè)的生命線。

          釘釘提供了人和組織架構(gòu)打通的工作群,用戶離開組織后自動退出企業(yè)工作群,這樣就很好地保障了企業(yè)信息的安全。

          同時,在已經(jīng)支持的全鏈路加密能力上提供了三方加密能力,可以最大程度保障企業(yè)用戶的信息安全性。

          3.4 技術(shù)挑戰(zhàn)3:穩(wěn)定性要求高

          企業(yè)用戶對穩(wěn)定性的要求也非常高,如果釘釘出現(xiàn)故障,深度使用釘釘?shù)钠髽I(yè)都會受到巨大影響。

          因此,釘釘 IM 系統(tǒng)在穩(wěn)定性上也做了非常深入的建設(shè),架構(gòu)上對依賴和流量做了深入治理,核心能力所有依賴都為雙倍。

          比如雖然 RocketMQ 已經(jīng)非常穩(wěn)定,也沒有發(fā)生過故障,但是對 RocketMQ 可能出現(xiàn)故障的產(chǎn)品依然做了很好的保護(hù),使用 RocketMQ 定時消息和堆積能力做熱點治理和流量防護(hù),讓系統(tǒng)面對大規(guī)模流量時能從容應(yīng)對,并且建設(shè)了異地多活和可彈性擴(kuò)縮容能力,疫情期間很好地保證了學(xué)生們的在線課堂。

          在穩(wěn)定性機(jī)制上,常態(tài)化容災(zāi)演練、突襲演練、自動化健康巡檢等也能很好地保證線上穩(wěn)定性。比如波浪式流量就是在做斷網(wǎng)演練時發(fā)現(xiàn)。

          3.5 技術(shù)挑戰(zhàn)4:業(yè)務(wù)多樣性

          針對不同行業(yè)的業(yè)務(wù)多樣性,還要盡可能地滿足用戶的通用性需求,比如萬人群、全員群等,目前釘釘已經(jīng)做到能夠支持 10 萬人級別的群。

          更多的業(yè)務(wù)需求將依賴于我們抽象出的通用開放能力,將 IM 能力盡可能地開放給企業(yè)和三方 ISV,使得不同形態(tài)的業(yè)務(wù)都能在釘釘平臺上得到滿足 。

          4、消息隊列在釘釘IM系統(tǒng)中的重要作用

          4.1 概述

          在如此豐富的企業(yè)級能力下,釘釘IM要與微信等 ToC 產(chǎn)品一樣,支持億級用戶低時延溝通,系統(tǒng)架構(gòu)需要具備高并發(fā)、高性能、高可用的能力,挑戰(zhàn)非常之大。

          IM 本身是異步化溝通系統(tǒng),與開會或者電話溝通相比,讓溝通雙方異步處理消息能夠減少打斷次數(shù),提升溝通效率。這種異步的特性和消息隊列的能力很契合,消息隊列可以很好地幫助 IM 完成異步化解耦、失敗重試、削峰填谷等能力。

          這里,我們以釘釘IM系統(tǒng)最核心的發(fā)消息和已讀鏈路簡化流程(如下圖所示),來詳細(xì)說明消息隊列在系統(tǒng)里的重要作用。

           

          4.2 發(fā)消息鏈路

          釘釘IM系統(tǒng)的發(fā)消息鏈路流程如下:

          • 1)處于登錄狀態(tài)的釘釘用戶發(fā)送一條消息時,首先會將請求發(fā)送到 receiver 應(yīng)用;
          • 2)為保證發(fā)消息體驗和成功率,receiver 應(yīng)用只做這條消息能否發(fā)送的校驗,其他如消息入庫、接收者推送等都交由下游應(yīng)用完成;
          • 3)校驗完成之后將消息投遞給消息隊列,成功后即可返回給用戶;
          • 4)消息發(fā)送成功,processor 會從消息隊列里訂閱到這條消息,并對消息進(jìn)行入庫處理,再通過消息隊列將消息交給同步服務(wù) syncserver 做處理,將消息同步給在線接收者。

          上述過程中,對于不在線的用戶:可以通過消息隊列將消息推給離線 push 系統(tǒng)。離線 push 系統(tǒng)可以對接接蘋果、華為、小米等推送系統(tǒng)進(jìn)行離線推送。

          用戶發(fā)消息過程中的每一步,失敗后都可通過消息隊列進(jìn)行重試處理。如 processor 入庫失敗,可將消息打回消息隊列,繼續(xù)回旋處理,達(dá)到最終一致。同時,可以在訂閱的過程中對消費限速,避免線上突發(fā)峰值給系統(tǒng)帶來災(zāi)難性的后果。

          4.3 消息已讀鏈路

          釘釘IM系統(tǒng)的消息已讀鏈路流程如下:

          • 1)用戶對一條消息做讀操作后,會發(fā)送請求到已讀服務(wù);
          • 2)已讀服務(wù)收到請求后,直接將請求放到消息隊列進(jìn)行異步處理,同時可以達(dá)到削峰填谷的目的;
          • 3)已讀服務(wù)處理完之后,將已讀事件推給同步服務(wù),讓同步服務(wù)將已讀事件推送給消息發(fā)送者。

          從上面兩個鏈路可以看出,消息隊列是 IM 系統(tǒng)里非常重要的組成部分。

          5、釘釘IM選擇RocketMQ的原因

          阿里內(nèi)部曾有 notify、RocketMQ 兩套應(yīng)用消息中間件,也有其他基于 MQTT 協(xié)議實現(xiàn)的消息隊列,最終都被 RocketMQ 統(tǒng)一。

          IM 系統(tǒng)對消息隊列有如下幾個基本要求:

          • 1)解耦和削峰填谷(這是消息隊列的基礎(chǔ)能力);
          • 2)高性能、低時延;
          • 3)高可用性。

          對于第 3)點:要求消息隊列的高可用性方面不僅包括系統(tǒng)可用性,也包括數(shù)據(jù)可用性,要求寫入消息隊列時消息不丟失(釘釘 IM 對消息的保證級別是一條都不丟)。

          RocketMQ 經(jīng)過多次雙 11 考驗,其堆積性能、低時延、高可用已成為業(yè)屆標(biāo)桿,完全符合對消息隊列的要求。

          同時它的其他特性也非常豐富,如定時消息、事務(wù)消息,能夠以極低的成本實現(xiàn)分布式定時任務(wù),消息可重放和死信隊列提供了后悔藥的能力,比如線上系統(tǒng)出現(xiàn) bug ,很多消息沒有正確處理,可以通過重置位點、重新消費的方式,訂正之前的錯誤處理。

          另外:消息隊列的使用場景非常豐富,RocketMQ 的擴(kuò)展能力可以在消息發(fā)送和消費上做切面處理,實現(xiàn)通用性的擴(kuò)展封裝,大大降低開發(fā)工作量。 Tag & SQL 過濾能讓下游針對性地訂閱定業(yè)務(wù)需要的消息,無需訂閱整個 topic 里的所有消息,大幅降低下游系統(tǒng)的訂閱壓力。

          RocketMQ 至今從未發(fā)生故障,集群峰值 TPS 可達(dá) 300w/s,從生產(chǎn)到消費時延能夠保證在 10 ms 以內(nèi),支持 30 億條消息堆積,核心指標(biāo)數(shù)據(jù)表現(xiàn)搶眼,性能異常優(yōu)秀。

          6、RocketMQ的消息必達(dá)3重保險

          如上圖所示,發(fā)消息流程中,很重要的一步是 receiver 應(yīng)用做完消息能否發(fā)送的校驗之后,通過 RocketMQ 將消息投遞給 processor做消息入庫處理。

          投遞過程中,將提供三重保險,以保證消息發(fā)送萬無一失。

          第一重保險:receiver 將消息寫進(jìn) RocketMQ 時, RocketMQ SDK 默認(rèn)會重試五次(每次嘗試不同的 broker ,保障了消息寫失敗的概率非常小)。

          第二重保險:寫入 RocketMQ 失敗的情況下,會嘗試以 RPC 形式將消息投遞給 processor 。

          第三重保險:如果 RPC 形式也失敗,會嘗試將本地 redoLog 通過 Crontab 任務(wù)定時將消息回放到 RocketMQ 里面。

          此外,如何在系統(tǒng)異常的情況下做到消息最終一致?

          Processor 收到上游投遞的消息時,會嘗試對消息做入庫處理。即使入庫失敗,依然會將消息投給同步服務(wù),將消息下發(fā),保證實時消息收發(fā)正常。異常情況時會將消息重新投遞到異常 topic 進(jìn)行重試,投遞過程中通過設(shè)置RocketMQ 定時消息做退避處理,對異常 topic 做限速消費。

          重試寫不同的 topic 是為了與正常流量隔離,優(yōu)先處理正常流量,防止因為異常流量消費而導(dǎo)致真正的線上消息處理被延遲。

          另外:Rocket MQ 的一個 broker 默認(rèn)只有一個 Retry 消息隊列,如果消費失敗量特別大的情況下,會導(dǎo)致下游負(fù)載不均,某些機(jī)器打死。

          此外:如果系統(tǒng)持續(xù)發(fā)生異常,則會不斷地進(jìn)行回旋重試,如果不做限速處理,線上容易出現(xiàn)流量疊加,導(dǎo)致整個系統(tǒng)雪崩。

          7、RocketMQ的獨門絕技——分布式定時任務(wù)

          在幾千人的群里發(fā)一條消息,假設(shè)有 1/4 的成員同時開著聊天窗口,如果不對服務(wù)端已讀服務(wù)和客戶端需要更新的已讀數(shù)做合并處理,更新的 QPS 會高達(dá)到 1000/s。釘釘能夠支持十幾萬人的超大群,超大群的活躍對服務(wù)端和客戶端都會帶來很大沖擊,而實際上用戶的需求只需實現(xiàn)秒級更新。

          針對以上場景:可以利用 RocketMQ 的定時消息能力實現(xiàn)分布式定時任務(wù)。

          以已讀流程為例(如下圖所示),用戶發(fā)起請求時,會將請求放入集中式請求隊列,再通過 RocketMQ 定時消息生成定時任務(wù),比如 5 秒后批量處理。5秒之后,RocketMQ 訂閱到任務(wù)觸發(fā)消息,將隊列里面所有請求都取出處理。

          ▲ 用 RocketMQ 實現(xiàn)分布式定時任務(wù)的流程原理

          我們抽象了一個分布式定時任務(wù)的組件,提供了很多其他實時性可達(dá)秒級的功能,如萬人群的群狀態(tài)更新、消息擴(kuò)展更新都接入了此組件。通過組件的定時合并處理,大幅降低系統(tǒng)壓力。

          如上圖(右邊部分),在一些大群活躍的時間點成功地讓流量下降并保持平穩(wěn)狀態(tài)。

          8、釘釘IM使用RocketMQ遇到的技術(shù)問題

          8.1 概述

          RocketMQ 的生產(chǎn)端策略如下:

          • 1)生產(chǎn)者獲取到對應(yīng) topic 所有 broker 和 Queue 列表,然后輪詢寫入消息;
          • 2)消費者端也會獲取到 topic 所有 broker 和Queue列表;
          • 3)還需要要從 broker 中獲取所有消費者 IP 列表進(jìn)行排序(按照配置負(fù)載均衡,如哈希、一次性哈希等策略計算出自己應(yīng)該訂閱哪些 Queue)。

          上圖中:ConsumerGroupA的Consumer1被分配到MessageQueue0和MessageQueue1,則它訂閱MessageQueue0和MessageQueue1。

          在RocketMQ的使用過程中,我們面臨了諸多問題,下面我們來逐一分享。

          8.2 問題1:波浪式流量

          我們發(fā)現(xiàn)訂閱消息集群滾動時,CPU 呈現(xiàn)波浪式飆升。

          經(jīng)過深入排查發(fā)現(xiàn),斷網(wǎng)演練后進(jìn)行網(wǎng)絡(luò)恢復(fù)時,大量 producer 同時恢復(fù)工作,同時從第一個 broker 的第一個 Queue 開始寫入消息,生產(chǎn)消息波浪式寫入 RocketMQ ,進(jìn)而導(dǎo)致消費者端出現(xiàn)波浪式流量。

          最終,我們聯(lián)系 RocketMQ 開發(fā)人員,調(diào)整了生產(chǎn)策略,每次生產(chǎn)者發(fā)現(xiàn) broker 數(shù)量或狀態(tài)發(fā)生變化時,都會隨機(jī)選取一個初始Queue寫入消息,以此解決問題。

          另一個導(dǎo)致波浪式流量的問題是配置問題。

          排查線上問題時,從 broker 視角看,每個 broker 的消息量都是平均的,但 consumer 之間流量相差特別大。最終通過在 producer 側(cè)嘗試抓包得以定位到問題,是由于 producer 寫入消息時超時率偏高。

          梳理配置后發(fā)現(xiàn),是由于 producer 寫入消息時配置超時太短,Rocket MQ 在寫消息時會嘗試多次,比如第一個 broker 寫入失敗后,將直接跳到下一個 broker 的第一個 Queue ,導(dǎo)致每個 broker 的第一個 Queue 消息量特別大,而靠后的 partition 幾乎沒有消息。

          8.3 問題2:負(fù)載均衡維度太粗

          負(fù)載均衡只能到Queue維度,導(dǎo)致需要不時地關(guān)注 Queue 數(shù)量。

          比如線上流量增長過快,需要進(jìn)行擴(kuò)容,而擴(kuò)容后發(fā)現(xiàn)機(jī)器數(shù)大于 Queue 數(shù)量,導(dǎo)致無論怎么擴(kuò)容都無法分擔(dān)線上流量,最終只能聯(lián)系 RocketMQ 運維人員調(diào)高 Queue 數(shù)量來解決。

          雖然調(diào)高 Queue 數(shù)量能解決機(jī)器無法訂閱的問題,但因為負(fù)載均衡策略只到 Queue 維度,負(fù)載始終無法均衡。從下圖可以看到, consumer 1 訂閱了兩個 Queue 而 consumer 2 只訂閱了一個 Queue。

          8.4 問題3:單機(jī)夯死導(dǎo)致消息堆積

          單機(jī)夯死導(dǎo)致消息堆積,這也是負(fù)載均衡只能到 Queue 維度帶來的副作用。

          比如 Broker A 的 Queue 由 consumer 1 訂閱,出現(xiàn)宿主機(jī)磁盤 IO 夯死但與 broker 之間的心跳依然正常,導(dǎo)致 Queue 消息長時間無法訂閱進(jìn)而影響用戶接收消息。最終只能通過手動介入將對應(yīng)機(jī)器下線來解決。

          8.5 問題4:rebalance

          Rocket MQ 的負(fù)載均衡由 client 自己計算,導(dǎo)致有機(jī)器異常或發(fā)布時,整個集群狀態(tài)不穩(wěn)定,時常會出現(xiàn)某些 Queue 有多個 consumer 訂閱,而某些 Queue 在幾十秒內(nèi)沒有 consumer 訂閱的情況。

          因而導(dǎo)致線上發(fā)布的時候,出現(xiàn)消息亂序或?qū)Ψ揭鸦叵⒌@示未讀的情況。

          8.6 問題5:C++ SDK 能力缺失

          釘釘IM的核心處理模塊Receiver、processor 等應(yīng)用都是通過 C++ 實現(xiàn),而RocketMQ 的 C++ SDK 相比于 Java 存在較大缺失。經(jīng)常出現(xiàn)內(nèi)存泄漏或 CPU 飆高的情況,嚴(yán)重影響線上服務(wù)的穩(wěn)定。

          9、釘釘IM與RocketMQ的相互促進(jìn)

          面對以上困擾,在經(jīng)過過多次討論和共創(chuàng)后,最終孵化出 RocketMQ 5.0 POP 消費模式。

          這是 RocketMQ 在實時系統(tǒng)里程碑式的升級,解決了大量實時系統(tǒng)使用 RocketMQ 過程中遇到的問題(如下圖所示)。

          1)Pop消費模式下,每一個 consumer 都會與所有 broker 建立長連接并具備消費能力,以 broker 維護(hù)整個消息訂閱的負(fù)載均衡和位點。重云輕端的模式下,負(fù)載均衡、訂閱消息、位點維護(hù)都在客戶端完成,而新客戶端只需做長鏈接管理、消息接收,并且通用 gRPC 協(xié)議,使得多語言比如 C++、Go、 Python 等語言客戶端都能輕松實現(xiàn),無需持續(xù)投入力去升級維護(hù) SDK 。

          2)broker能力升級更簡單。重云輕端很好地解決了客戶端版本升級問題,客戶端改動的可能性和頻率大大降低。以往升級新特性或能力只能推動所有相關(guān) SDK 應(yīng)用進(jìn)行升級發(fā)布,升級過程中還需考慮新老兼容等問題,工作量極大。而新模式只需升級 broker 即可完成工作。

          3)單機(jī)夯死消息能繼續(xù)被消費。新模式下 consumer 和 broker 進(jìn)行網(wǎng)狀連接和消息訂閱,由 broker 通過負(fù)載均衡策略平均分配消息給 consumer 進(jìn)行消費,以往宕機(jī)夯死導(dǎo)致的 Queue 消息堆積問題也迎刃而解。如果 broker 發(fā)現(xiàn) consumer 長時間沒有進(jìn)行消息 ACK ,則將不再對其投遞消息,徹底解決單機(jī)夯死問題。

          4)無需關(guān)注partition數(shù)量。

          5)徹底解決rebalance。

          6)負(fù)載更均衡。通過新的訂閱模式,不管上游流量如何偏移,只要不超過單個 broker 的容量上限,消費端都能實現(xiàn)真正意義上的負(fù)載均衡。

          POP 模式消費模式已經(jīng)在釘釘 IM 場景磨合得非常成熟,在對可用性、性能、時延方面要求非常高的釘釘 IM 系統(tǒng)證明了自己,也證明了不斷升級的 RocketMQ 是即時通訊場景消息隊列的不二選擇。

          10、相關(guān)資料

          [1] 現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲方案探討

          [2] 企業(yè)級IM王者——釘釘在后端架構(gòu)上的過人之處

          [3] 深度解密釘釘即時消息服務(wù)DTIM的技術(shù)設(shè)計

          [4] 釘釘——基于IM技術(shù)的新一代企業(yè)OA平臺的技術(shù)挑戰(zhàn)(視頻+PPT)

          [5] 企業(yè)微信的IM架構(gòu)設(shè)計揭秘:消息模型、萬人群、已讀回執(zhí)、消息撤回等

          [6] IM系統(tǒng)的MQ消息中間件選型:Kafka還是RabbitMQ?

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

          posted @ 2022-12-30 12:05 Jack Jiang 閱讀(116) | 評論 (0)編輯 收藏

          1、引言

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

          怎么辦呢?學(xué)過密碼學(xué)的朋友可能就想到了一個解決辦法,聊天的時候?qū)ο⒓用埽幚淼臅r候再對消息進(jìn)行解密。是的,道理就是這樣。

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

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

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

          學(xué)習(xí)交流:

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

          2、相關(guān)文章

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

          3、什么是PKI?

          我們需要先了解一下公鑰和私鑰的加密標(biāo)準(zhǔn)體系PKI。

          3.1 基本概念

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

          通俗講:PKI是集機(jī)構(gòu)、系統(tǒng)(硬件和軟件)、人員、程序、策略和協(xié)議為一體,利用公鑰概念和技術(shù)來實現(xiàn)和提供安全服務(wù)的、普適性的安全基礎(chǔ)設(shè)施。

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

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

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

          例如:誰來發(fā)證書?如何發(fā)證書?不同機(jī)構(gòu)的證書怎么互認(rèn)?紙質(zhì)證書作廢容易,數(shù)字證書如何作廢?解決這些問題,需要制定統(tǒng)一的規(guī)則,即PKI體系。

          PKI體系是通過頒發(fā)、管理公鑰證書的方式為終端用戶提供服務(wù)的系統(tǒng),最核心的元素是證書。

          圍繞證書構(gòu)成了PKI體系的要素:

          • 1)使用PKI的用戶;
          • 2)頒發(fā)證書的機(jī)構(gòu)(Certificate Authority,CA);
          • 3)保存證書的倉庫。

          總之:PKI是一個總稱,既包括定義PKI的基礎(chǔ)標(biāo)準(zhǔn),也包括PKI的應(yīng)用標(biāo)準(zhǔn)。

          3.2 PKI體系現(xiàn)狀

          事實上PKI已經(jīng)有兩代了。

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

          第二代PKI標(biāo)準(zhǔn)是由微軟、VeriSign和webMethods三家公司在2001年發(fā)布的基于XML的密鑰管理規(guī)范也叫做XKMS。

          事實上現(xiàn)在CA中心使用的最普遍的規(guī)范還是X.509系列和PKCS系列。

          X.509系列主要由X.209、X.500和X.509組成,其中X.509是由國際電信聯(lián)盟(ITU-T)制定的數(shù)字證書標(biāo)準(zhǔn)。在X.500基礎(chǔ)上進(jìn)行了功能增強,X.509是在1988年發(fā)布的。

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

          而PKCS是美國RSA公司的公鑰加密標(biāo)準(zhǔn),包括了證書申請、證書更新、證書作廢表發(fā)布、擴(kuò)展證書內(nèi)容以及數(shù)字簽名、數(shù)字信封的格式等方面的一系列相關(guān)協(xié)議。它定義了一系列從PKCS#1到PKCS#15的標(biāo)準(zhǔn)。

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

          4、什么是SSL?

          4.1 基本概念

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

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

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

          4.2 與TLS的關(guān)系

          SSL是網(wǎng)景公司(Netscape)設(shè)計,但I(xiàn)ETF將SSL作了標(biāo)準(zhǔn)化,即RFC2246,并將其稱為TLS(Transport Layer Security),其最新版本是RFC5246、版本1.2。

          實際上:TLS是IETF在SSL3.0基礎(chǔ)上設(shè)計的,相當(dāng)于SSL的后續(xù)版本。所以我們通常都是SSL/TLS放一起說。

          5、什么是OpenSSL?

          5.1 基本概念

           

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

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

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

          • 1)SSL協(xié)議庫;
          • 2)應(yīng)用程序;
          • 3)密碼算法庫。

          OpenSSL的目錄結(jié)構(gòu)自然也是圍繞這三個功能部分進(jìn)行規(guī)劃的。

          OpenSSL 可以運行在 OpenVMS、 Microsoft Windows 以及絕大多數(shù)類 Unix 操作系統(tǒng)上。

          5.2 具體來說

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

          OpenSSL實現(xiàn)了ASN.1的證書和密鑰相關(guān)標(biāo)準(zhǔn),提供了對證書、公鑰、私鑰、證書請求以及CRL等數(shù)據(jù)對象的DER、PEM和BASE64的編解碼功能。

          OpenSSL提供了產(chǎn)生各種公開密鑰對和對稱密鑰的方法、函數(shù)和應(yīng)用程序,同時提供了對公鑰和私鑰的DER編解碼功能。并實現(xiàn)了私鑰的PKCS#12和PKCS#8的編解碼功能。

          OpenSSL在標(biāo)準(zhǔn)中提供了對私鑰的加密保護(hù)功能,使得密鑰可以安全地進(jìn)行存儲和分發(fā)。

          在此基礎(chǔ)上,OpenSSL實現(xiàn)了對證書的X.509標(biāo)準(zhǔn)編解碼、PKCS#12格式的編解碼以及PKCS#7的編解碼功能。并提供了一種文本數(shù)據(jù)庫,支持證書的管理功能,包括證書密鑰產(chǎn)生、請求產(chǎn)生、證書簽發(fā)、吊銷和驗證等功能。

          5.3 發(fā)展歷程

          OpenSSL 計劃在 1998 年開始,其目標(biāo)是發(fā)明一套自由的加密工具,在互聯(lián)網(wǎng)上使用。

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

          ▲ 上圖為 Tim Hudson

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

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

          5.4 下載方法

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

          6、各類證書

          6.1 證書類型

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

          以下是最常見的幾種:

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

          6.2 常用OpenSSL命令

          下面的命令可以用來查看文本證書內(nèi)容:

          openssl x509 -incert.pem -text -noout

          openssl x509 -incert.cer -text -noout

          openssl x509 -incert.crt -text -noout

          下面的命令可以用來查看二進(jìn)制證書內(nèi)容:

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

          下面是常見的PEM和DER相互轉(zhuǎn)換。

          PEM到DER的轉(zhuǎn)換:

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

          DER到PEM的轉(zhuǎn)換:

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

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

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

          7.1 關(guān)于Netty

          Netty是一個Java NIO技術(shù)的開源異步事件驅(qū)動的網(wǎng)絡(luò)編程框架,用于快速開發(fā)可維護(hù)的高性能協(xié)議服務(wù)器和客戶端,事實上用Java開發(fā)IM系統(tǒng)時,Netty是幾乎是首選。

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

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

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

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

          史上最通俗Netty框架入門長文:基本介紹、環(huán)境搭建、動手實戰(zhàn)

          基它有關(guān)Netty的重要資料:

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

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

          7.2 啟動SSL Server代碼示例

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

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

          讓服務(wù)器端支持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的實現(xiàn)有兩種方式,默認(rèn)情況下使用的是OpenSSL,如果OpenSSL不可以,那么將會使用JDK的實現(xiàn)。

          要創(chuàng)建SslContext,可以調(diào)用SslContextBuilder.forServer或者SslContextBuilder.forClient方法。

          這里以server為例,看下創(chuàng)建流程。

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

          publicstaticSslContextBuilder forServer(File keyCertChainFile, File keyFile) {

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

          }

          該方法接收兩個參數(shù):

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

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

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

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

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

          7.3 啟動SSL Client代碼示例

          同樣的在client中支持SSL也需要創(chuàng)建一個handler。

          客戶端的SslContext創(chuàng)建代碼如下:

          // 配置 SSL.

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

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

          什么是trustManager呢?

          當(dāng)客戶端和服務(wù)器端進(jìn)行SSL連接的時候,客戶端需要驗證服務(wù)器端發(fā)過來證書的正確性。

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

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

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

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

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

          openssl x509 -fingerprint -sha256 -inmy_certificate.crt

          8、小結(jié)一下

          上面我們對Netty聊天用到的加密技術(shù)和相關(guān)概念進(jìn)行了梳理,我來簡單這些概念之間的關(guān)系。

          這些概念之間的關(guān)系,簡單來說就是:

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

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

          9、參考資料

          [1] 公鑰基礎(chǔ)設(shè)施(PKI)國際標(biāo)準(zhǔn)進(jìn)展

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

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

          [4] OpenSSL是什么軟件

          [5] netty系列之對聊天進(jìn)行加密

          [6] 跟著源碼學(xué)IM

          [7] 基于Netty,從零開發(fā)IM

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

          [9] 快速理解TCP協(xié)議一篇就夠

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

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

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

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

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

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

          關(guān)于MobileIMSDK

          MobileIMSDK 是一套專門為移動端開發(fā)的開源IM即時通訊框架,超輕量級、高度提煉,一套API優(yōu)雅支持UDP 、TCP 、WebSocket 三種協(xié)議,支持iOS、Android、H5、標(biāo)準(zhǔn)Java平臺,服務(wù)端基于Netty編寫。

          工程開源地址是:

          關(guān)于RainbowChat

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

           

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

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

          v8.3 版更新內(nèi)容

          此版更新內(nèi)容更多歷史更新日志):

          (1)Android端主要更新內(nèi)容bug修復(fù)及優(yōu)化!】:

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

          (2)服務(wù)端主要更新內(nèi)容:

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

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

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

          僅列出標(biāo)題
          共51頁: First 上一頁 15 16 17 18 19 20 21 22 23 下一頁 Last 
          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 溧阳市| 广宁县| 花莲市| 双辽市| 江阴市| 望奎县| 安康市| 宜都市| 红桥区| 古蔺县| 兴隆县| 色达县| 集安市| 永丰县| 万州区| 新闻| 石首市| 长沙县| 凯里市| 绵竹市| 衡山县| 宜兰市| 五家渠市| 调兵山市| 根河市| 青河县| 文山县| 新津县| 朝阳县| 左权县| 石棉县| 万宁市| 泰兴市| 江川县| 慈溪市| 桃江县| 高雄县| 莱芜市| 昂仁县| 阿克苏市| 德兴市|