<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

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

    本文由騰訊WXG客戶端開發工程師yecong分享,本文做了修訂和改動。

    1、引言

    相對于傳統的消費級IM應用,企業級IM應用的特殊之外在于它的用戶關系是按照所屬企業的組織架構來關聯的起來,而組織架構的大小是無法預設上限的,這也要求企業級IM應用在遇到真正的超大規模組織架構時,如何保證它的應用性能不受限于(或者說是盡可能不受限于)企業架構規模,這是個比較有難度的技術問題。

    本文主要分享的是企業微信在百對百萬級大規模組織架構后文簡稱大架構時,是如何對客戶端進行性能優化過程的,希望帶給你啟發。

    內容分成兩部分講述,第一部分是短線迭代的優化,主要是并發性能的優化。第二部分是長線迭代的優化,主要是從業務模式上做了根本性優化。

    以下是相關文章,推薦一并閱讀:

    企業微信客戶端中組織架構數據的同步更新方案優化實戰

    企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等

    釘釘——基于IM技術的新一代企業OA平臺的技術挑戰(視頻+PPT) [附件下載]

    阿里釘釘技術分享:企業級IM王者——釘釘在后端架構上的過人之處

     

    技術交流:

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

    2、100萬級組織架構時的性能問題

    當私有化的組織架構上升到100W的量級時,出現了嚴重影響組織架構使用的問題:打開二級部門時,加載緩慢。

    如圖所示,loading可能持續一分鐘以上:

    3、100萬級組織架構的問題分析

    我們分析一下加載二級部門的流程。

    下面是加載二級部門的流程圖:

    • 1)如果從來沒加載過該部門,需要從服務端拉取部門下的節點詳情(這里是因為之前我們已經做了優化,首次登錄時只拉取了部門的節點ID,沒有拉取詳情);
    • 2)如果加載過該部門,就直接從DB讀取該部門的數據,然后返回UI展示。

    當只有一條DB線程時,組織架構更新的任務,可能會插入到加載二級部門的任務的前面。而在百萬級別的組織架構中,全量更新的DB任務有可能比較久,全量更新的插入或者更新節點可能比較多,導致本來很快可以完成的二級部門加載任務,要排隊比較久才能執行完。

    下面是組織架構全量更新的流程圖:

    在這里,讀寫并發上出現了明顯的瓶頸。

    原因總結如下:

    • 1)加載二級部門和全量更新共用一條DB線程;
    • 2)當全量更新大量節點時,全量更新的低優先級任務卡住加載二級部門的高優先級任務。

    4、針對100萬級組織架構的優化方案

    4.1基本

    讀寫分離為了提高組織架構在大規模數據下的讀寫并發性能,我們開啟了wal模式,把讀寫任務分別放在不同的線程中執行。

    針對加載二級部門的流程,可以在讀線程中讀取部門的詳情節點,而組織架構更新可以在寫線程中單獨執行。

    由于加載二級部門的原流程是拉取數據、寫入DB、再從DB讀取數據,而且wal只支持一寫多讀,因此我們調整了緩存策略,把保存節點詳情的寫任務延遲到流程最后,優先構造了cache返回UI。

    這樣從DB中讀出數據的讀任務,就不需要等待保存節點詳情的寫任務。避免了保存節點的寫任務再次被其他寫任務阻塞,讀任務又被保存節點的寫任務阻塞,退化成串行操作。

    4.2WAL機制的原理

    調用方修改的數據并不直接寫入到數據庫文件中,而是寫入到另外一個稱為WAL的文件中,然后在隨后的某個時間點被寫回到數據庫文件中。

    在這個時間點的回寫操作,會降低數據庫當時的讀寫性能。

    但是通過設置對WAL文件大小的限制,這種性能影響是可控的。

    實際上線后也沒有遇到由于checkpoint同步導致數據庫慢的反饋。

    4.3緩存策略

    寫策略的步驟:先更新緩存中的數據,再更新數據庫中的數據。

    讀策略的步驟:

    • 1)如果讀取的數據命中了緩存,則直接返回數據;
    • 2)如果讀取的數據沒有命中緩存,則從數據庫中讀取數據,然后將數據寫入到緩存,并且返回給UI。

    4.4方案總結

    5、100萬級優化后的效果

     

    在優化前,只有52%的用戶能在1s內加載完二級部門。上線之后,93%的用戶都能在1s內打開二級部門。耗時小于1s的用戶占比提升40%!

    6、當對面300萬組織架構時的問題

    6.1概述

    當業務進一步發展時,我們預估未來將要到達300W量級的組織架構。于是我們就開始提前規劃如何能在組織架構數量一直增長的情況下,還能讓組織架構流暢好用。

    6.2問題

    主要是:

    • 1)選人控件閃退和ANR;
    • 2)組織架構全量更新閃退。

    在300w的組織架構環境中,舊的組織架構加載方案,在全量更新、選人控件中均出現了占用內存過大甚至閃退的問題。而且舊方案的加載時間會隨著節點數量的增加,不可避免地成正比增長。

    6.3分析

    當前方案的耗時、內存占用與用戶組織架構的大小成正比,單點優化無法滿足組織架構持續增長的需求。

    具體來說,會造成下面的一些問題:

    • 1)選人控件會加載全量的組織架構ID樹,數量過多時容易發生閃退和ANR;
    • 2)組織架構全量更新占用內存過大,造成閃退。

    因此,我們需要一個新的業務模式,即便總的組織架構規模一直上漲的情況下,也能維持較好的性能。

    7、針對300萬組織架構的優化方案

    比較容易想到的一個方案是web加載的模式,不保存本地數據,但是體驗比較差,每層都會出loading。

    聯系到我們的具體業務,由于私有化對不同的部門,劃分出了具有意義的獨立組織機構——單位。

    單位是具有管理意義的部門,不同單位可以獨立加載。而每個人,也擁有主單位和兼崗單位。所以可以按照單位加載的方式,從根本上解決目前組織架構面臨的瓶頸。

    按單位加載,可以簡單理解為按部門加載:

    概念定義:

    • 1)單位:政府行政組織結構中的職能部門,組建架構并承擔對應責任;
    • 2)主單位:“我”所在的單位;
    • 3)其他單位:除了“我”所在的其他單位;
    • 4)骨架:通訊錄骨架包含了所有的單位節點;
    • 5)普通部門:不屬于任何單位的部門節點。

    下圖是組織架構樹的示意圖:

    如上圖所示:藍色節點是優先加載的本單位,灰色節點是其他單位,紅色節點是骨架。不同的單位獨立加載。

    8、300萬優化方案中的“按單位加載”技術思路

    8.1加載策略

    接下來我們看看加載策略。

    第一:是對自己所在的主單位(藍色節點),每次喚醒時就會更新,跟舊組織架構的邏輯類似,但是會限制拉取節點的數量。

    第二:對于其他單位(灰色節點),點擊到該單位時才會拉取,2個小時后會淘汰刪除,避免數據表過大。

    第三:對于骨架(紅色節點),會全量加載節點ID,再拉取節點詳情。

    拉取策略限制了能夠拉取的節點詳情數量,如果單位節點數量超過了限制,首先拉取全量ID,再按照優先規則,拉取配置的節點詳請數量。

    8.2加載流程

    加載的流程是先拉取自己的單位列表,然后拉取每個單位的全量通訊錄ID,再按照后臺策略,拉取所需的詳細節點,最后拉取骨架。

    如果點擊到主單位:

    • 1)如果只有ID沒有節點,會立刻拉取節點詳情返回界面;
    • 2)如果ID和節點詳情都有,可以直接返回UI展示,然后延遲刷新節點。

    如果是點擊到其他單位:可能出現ID和詳情都沒有的情況,需要拉取其他單位的節點,界面loading等待。

    如果是骨架:就一定有節點和詳情,只需要延遲刷新。

    9、300萬優化方案的分層設計思路

    接下來我們看看如何分層。

    在300萬量級的大規模組織架構下,移動端和pc端都出現了組織架構卡頓、閃退的問題,所以我們希望能夠開發一套各端共用的邏輯,統一維護。

    第一:是要抽取公共的基礎庫,包括boost庫、任務框架、線程管理框架等。

    第二:是設計公共的數據結構。

    第三:因為不同端的網絡庫差異比較大,這里不好完全共用,所以需要抽取網絡任務接口,由各端獨立實現。

    具體到框架圖,我們從下往上看:

    • 1)底層是基礎庫;
    • 2)接著是C++實現的跨平臺業務層;
    • 3)Service層是移動端和pc端分開實現,主要是做接口調用和回調的簡單封裝;
    • 4)上層則各端界面實現。

    上層界面為了兼容新舊兩套組織架構,也做了接口抽象,可以通過開關自由切換。這樣優點就是有統一的業務邏輯代碼、DB設計和線程管理。

    關鍵點:

    • 1)抽取公共基礎庫;
    • 2)抽象公共的數據結構;
    • 3)抽象網絡層和數據庫層接口。

    優點:統一的業務邏輯代碼、DB設計、線程管理。

    10、300萬優化方案的整體架構設計思路

    在具體實現之前,我們來看看架構設計的一些概念。

    10.1架構整潔之道

    1)業務實體和用例:

    關鍵業務邏輯和關鍵業務數據是緊密相關的,所以它們很適合被放在同一個對象中處理。

    我們將這種對象稱為“業務實體”。業務實體這個概念中應該只有業務邏輯,沒有別的,與數據庫、用戶界面、第三方框架等內容無關。

    用例所描述的是某種特定應用情景下的業務邏輯,可以理解為:輸入 + 業務實體 + 輸出 = 用例。

    2)軟件架構:

    軟件的系統架構應該為該系統的用例提供支持。

    一個良好的架構設計應該圍繞著用例來展開,這樣的架構設計可以在脫離框架、工具以及使用環境的情況下完整地描述用例。

    3)整潔架構:

    下圖的同心圓分別代表了軟件系統中的不同層次,越靠近中心,其所在的軟件層次就越高。基本上,外層圓代表的是機制,內層圓代表的是策略。

    這其中有一條貫穿整個架構設計的規則,即依賴關系規則:

    10.2我們的架構

    我們的類圖與架構設計概念的對應關系如下:

    • 1)業務實體:ArchTask;
    • 2)用例:ArchProto;
    • 3)模型層:即最外層,各種第三方框架,如DbInterface(數據庫模塊)、ArchLogicHandler(網絡模塊)等。

    我們從一次具體的業務調用流程來看看這樣設計的意義。

    下面是從UI發起的一次架構更新流程,大家可以主要關注控制流是怎么穿越各層的邊界:控制流從最外層的用戶界面開始,穿過用例(Arch),最后調用最外層的組件:網絡模塊和數據庫模塊。但是我們源碼中的依賴方向卻都是向內指向用例的。

    這里,我們采用的是依賴反轉原則(DIP)來解決這種相反性。我們可以通過調整代碼中的接口和繼承關系,利用源碼中的依賴關系,限制控制流只能在正確的地方跨域架構邊界。

    在上面的流程圖中,主要有兩個應用依賴反轉原則的地方:

    1)CalcPreLoadArchIDs是從SyncUnitArchTask(業務實體)調用調用到ArchProto(用例)。

    業務實體這樣的高層概念,是無須了解像用例這樣的底層概念的。反之,底層業務用例卻需要了解高層的業務實體。

    所以在SyncUnitArchTask中,其實是通過調用ArchProto的接口來調用CalcPreLoadArchIDs。

    SyncUnitArchTask中的調用代碼如下:

    arch_service_context_->CalcPreLoadArchIDs(unit_id_, arch_service_context_->GetCurrentVid(), other_unit_click_partyid_, vecHashNode, all_tmp_ids, arch_ids, ptr_map_);

    ArchProto會在Task初始化時,把自己設置進Task中,給各類型的Task反向調用。

    classArchProto : publicArchServiceContext

    {

    ...

    };

    2)最外層的模型層一般是由工具、數據庫、網絡框架等組成的。

    框架與驅動程序層中包含了所有的實現細節。

    從系統架構的角度看,工具通常是無關緊要的,因為這只是一個底層的實現細節,一種達成目標的手段。

    當Task需要調用網絡模塊收發請求或者調用數據庫模塊獲取數據時,為了避免內層策略依賴外層機制,Task只會調用外層工具的接口層,而不會依賴實現細節。

    這樣的架構設計給我們帶來的好處是,我們可以輕松替換框架,而不影響內層策略。比如在桌面端,我們會有另外一套完全不同的網絡模塊實現,只需要掛接不同的網絡實現子類,我們就可以在桌面端復用新的大架構模塊。

    良好的架構設計應該盡可能地允許用戶推遲和延后決定采用什么框架、數據庫、網絡框架以及其他與環境相關的工具。

    總之,良好的架構設計應該只關注用例,并能將它們與其他的周邊因素隔離。

    10.3新舊組織架構模塊的交互

    大架構跨平臺層,跟原來的組織架構模塊是怎么交互的呢?

    原來的組織架構的數據表主要分成三部分:

    • 1)部門表;
    • 2)人員信息表;
    • 3)部門人員關系表。

    而出現性能問題的主要在于關系表上。所以數據設計上,人員信息保留在原組織架構底層,部門人員關系表、部門表在大架構底層。

    表結構設計:

    • 1)主要組成:人員信息表、部門表、部門人員關系表;
    • 2)大架構底層保存部門和部門人員關系表,人員信息保留在原組織架構底層。

    大架構底層與原組織架構底層的業務關聯:

    • 1)人員展示的部門鏈路如何獲取?從大架構底層獲取,因為關系表存放在大架構底層;
    • 2)搜索如何做?部門名字保存到原組織架構底層,復用原組織架構底層的索引建立邏輯。

    11、300萬優化方案的雙DB切換模式

    11.1舊的讀寫表切換方式

    舊方案里組織架構的全量更新流程:

    當后臺告訴客戶端需要全量更新時,客戶端會將所有節點標為待刪除,然后同步后臺的節點,清除待刪除標記。同步完成后,將寫表的數據同步到讀表,更新版本號。最后UI就可以從讀表中讀取到最新的數據。

    而之前通過用戶日志案例分析,最長的耗時主要是在將寫表的數據拷貝到讀表上面。在這個過程中,大架構下部分用戶的日志里有更新57w節點的數據用了2個半小時的情況,而且這個步驟是原子操作,如果不能夠一次完成,下次還得重新執行。

    原有流程里,讀表和寫表是固定的,導致全量更新需要等讀表同步完數據,界面才能讀到新數據。

    分析:寫表同步數據到讀表耗時很久,當全量更新時,如果有大量節點需要更新,會耗時很長。

    缺點:寫表和讀表固定,全量更新需要等數據同步完成,界面才能讀取到新數據。

    11.2新的雙DB切換方式

    針對舊方案中讀寫表同步過久的問題,大架構方案里我們換成了雙DB切換的模式。下面是我們的狀態機設計和業務代碼獲取表名的邏輯。

    這樣修改之后,不需要等讀寫表同步完,UI就可以讀取到最新數據。而同步的過程可以在后臺慢慢完成,并且不會受原子性操作的限制。業務代碼獲取讀表的邏輯,也收攏到了一個函數。

     

    因為單位模式下,每個單位的節點數量都不會很多,而且大多數用戶只會加載日常有交流的幾個單位,所以讀寫表同步這里,我們采用了把原表刪掉,全量拷貝的方式。

    12、200萬級優化后的效果

    對于耗時,優化前使用全量加載的方式使得耗時很長,而優化后采用的“本單位+骨架”的預加載邏輯使得加載耗時大幅度減小。優化后的內存占用大小在各場景下均有減小,通訊錄頁面的流暢度也得到了一定的提升。

    耗時:

    CPU占用率:

    內存占用大小:

    卡頓:

    13、相關資料

    [1] 企業微信客戶端中組織架構數據的同步更新方案優化實戰

    [2] 企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等

    [3] 釘釘——基于IM技術的新一代企業OA平臺的技術挑戰(視頻+PPT) [附件下載]

    [4] 阿里釘釘技術分享:企業級IM王者——釘釘在后端架構上的過人之處

    [5] 深度解密釘釘即時消息服務DTIM的技術設計

    [6] 深度揭密RocketMQ在釘釘IM系統中的應用實踐

    [7] IM開發干貨分享:萬字長文,詳解IM“消息“列表卡頓優化實踐

    [8] 手Q客戶端針對2020年春節紅包的技術實踐

    [9] 移動端IM實踐:Android版微信如何大幅提升交互性能(一)

    [10] 移動端IM實踐:Android版微信如何大幅提升交互性能(二)

    [11] 移動端IM實踐:iOS版微信的多設備字體適配方案探討

    [12] 愛奇藝技術分享:愛奇藝Android客戶端啟動速度優化實踐總結

    [13] 微信團隊分享:微信支付代碼重構帶來的移動端軟件架構上的思考


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



    作者:Jack Jiang (點擊作者姓名進入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時通訊開發交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: 亚洲成在人线aⅴ免费毛片| 亚洲AV无码国产精品麻豆天美| 亚洲 另类 无码 在线| 亚洲真人无码永久在线| 亚洲精品影院久久久久久| 亚洲熟妇AV一区二区三区宅男| 国产免费久久精品99久久| 最近中文字幕大全中文字幕免费| 岛国大片免费在线观看| 亚洲一区二区中文| 一本久久免费视频| 在线观看人成视频免费| 国产成人精品日本亚洲网站| 中文字幕亚洲一区二区三区 | 亚洲第一区精品日韩在线播放| 久久精品国产亚洲AV果冻传媒| 亚洲国产精品99久久久久久| 1000部拍拍拍18勿入免费视频下载| 亚洲成av人在片观看| 国产成人亚洲综合网站不卡| 亚洲免费在线观看视频| 亚洲AV无码成人精品区蜜桃| 男女一进一出抽搐免费视频| 国产免费人视频在线观看免费| 亚洲最大天堂无码精品区| 国产大片免费网站不卡美女| 亚洲色图在线观看| 中文字幕亚洲免费无线观看日本| 国产aⅴ无码专区亚洲av麻豆| 国产精品亚洲а∨无码播放麻豆| 一二三四免费观看在线电影 | 亚洲午夜福利AV一区二区无码| 无套内射无矿码免费看黄| 四虎www成人影院免费观看| 亚洲精品色播一区二区| 精品久久久久久久免费加勒比| 亚洲中文字幕无码亚洲成A人片 | 青青视频观看免费99| 国产成+人+综合+亚洲专| 拔擦拔擦8x华人免费久久| 亚洲AV综合色区无码一二三区 |