Jack Jiang

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

          2025年5月19日

          本文來自嗶哩嗶哩通用技術(shù)團(tuán)隊(duì)分享,下文進(jìn)行了排版優(yōu)化和修訂。

          1、引言

          隨著 AI 技術(shù)快速發(fā)展,業(yè)務(wù)對(duì) AI 能力的渴求日益增長。當(dāng) AI 服務(wù)面對(duì)處理大規(guī)模請(qǐng)求和高并發(fā)流量時(shí),AI 網(wǎng)關(guān)從中扮演著至關(guān)重要的角色。AI 服務(wù)通常涉及大量的計(jì)算任務(wù)和設(shè)備資源占用,此時(shí)需要一個(gè) AI 網(wǎng)關(guān)負(fù)責(zé)協(xié)調(diào)這些請(qǐng)求來確保系統(tǒng)的穩(wěn)定性與高效性。因此,與傳統(tǒng)微服務(wù)架構(gòu)類似,我們將相關(guān) API 管理的功能(如流量控制、用戶鑒權(quán)、配額計(jì)費(fèi)、負(fù)載均衡、API 路由等)集中放置在 AI 網(wǎng)關(guān)層,可以降低系統(tǒng)整體復(fù)雜度并提升可維護(hù)性。

          本文要分享的是B站在大模型時(shí)代基于多模型AI的網(wǎng)關(guān)架構(gòu)設(shè)計(jì)和實(shí)踐總結(jié),希望能帶給你啟發(fā)。

          * 相關(guān)閱讀:全民AI時(shí)代,大模型客戶端和服務(wù)端的實(shí)時(shí)通信到底用什么協(xié)議?

          技術(shù)交流:

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

          2、系列文章

          1. 長連接網(wǎng)關(guān)技術(shù)專題(一):京東京麥的生產(chǎn)級(jí)TCP網(wǎng)關(guān)技術(shù)實(shí)踐總結(jié)
          2. 長連接網(wǎng)關(guān)技術(shù)專題(二):知乎千萬級(jí)并發(fā)的高性能長連接網(wǎng)關(guān)技術(shù)實(shí)踐
          3. 長連接網(wǎng)關(guān)技術(shù)專題(三):手淘億級(jí)移動(dòng)端接入層網(wǎng)關(guān)的技術(shù)演進(jìn)之路
          4. 長連接網(wǎng)關(guān)技術(shù)專題(四):愛奇藝WebSocket實(shí)時(shí)推送網(wǎng)關(guān)技術(shù)實(shí)踐
          5. 長連接網(wǎng)關(guān)技術(shù)專題(五):喜馬拉雅自研億級(jí)API網(wǎng)關(guān)技術(shù)實(shí)踐
          6. 長連接網(wǎng)關(guān)技術(shù)專題(六):石墨文檔單機(jī)50萬WebSocket長連接架構(gòu)實(shí)踐
          7. 長連接網(wǎng)關(guān)技術(shù)專題(七):小米小愛單機(jī)120萬長連接接入層的架構(gòu)演進(jìn)
          8. 長連接網(wǎng)關(guān)技術(shù)專題(八):B站基于微服務(wù)的API網(wǎng)關(guān)從0到1的演進(jìn)之路
          9. 長連接網(wǎng)關(guān)技術(shù)專題(九):去哪兒網(wǎng)酒店高性能業(yè)務(wù)網(wǎng)關(guān)技術(shù)實(shí)踐
          10. 長連接網(wǎng)關(guān)技術(shù)專題(十):百度基于Go的千萬級(jí)統(tǒng)一長連接服務(wù)架構(gòu)實(shí)踐
          11. 長連接網(wǎng)關(guān)技術(shù)專題(十一):揭秘騰訊公網(wǎng)TGW網(wǎng)關(guān)系統(tǒng)的技術(shù)架構(gòu)演進(jìn)
          12. 長連接網(wǎng)關(guān)技術(shù)專題(十二):大模型時(shí)代多模型AI網(wǎng)關(guān)的架構(gòu)設(shè)計(jì)與實(shí)現(xiàn)》(* 本文

          3、AI網(wǎng)關(guān)技術(shù)概覽

          AI 網(wǎng)關(guān)是一個(gè)用于統(tǒng)一接入和調(diào)度大語言模型(LLM)服務(wù)的系統(tǒng),支持多供應(yīng)商、多模型、負(fù)載均衡調(diào)度的管理。同時(shí)具備統(tǒng)一鑒權(quán)、Token 配額管理、安全審計(jì)與可觀測能力,確保 API 調(diào)用的安全性和穩(wěn)定性。負(fù)載均衡模塊,能夠根據(jù)提供商多線路、多模型 和 API Key 進(jìn)行靈活路由,并適用于多模型接入、多租戶等復(fù)雜場景。

          4、整體架構(gòu)設(shè)計(jì)

          AI 網(wǎng)關(guān)的整體架構(gòu)和傳統(tǒng) API 網(wǎng)關(guān)及其類似,在數(shù)據(jù)面和控制面上有幾乎相同的設(shè)計(jì)。

          實(shí)際上 AI 網(wǎng)關(guān)就是衍生于之前微服務(wù)團(tuán)隊(duì)的 API Gateway,我們?cè)?API Gateway 的基礎(chǔ)上做了一些針對(duì) AI 業(yè)務(wù)接口的特性優(yōu)化,如無緩沖區(qū)的請(qǐng)求代理,支持域名、服務(wù)發(fā)現(xiàn)等混合調(diào)度,AI 超長響應(yīng)時(shí)間請(qǐng)求的優(yōu)雅退出等功能。

          在此基礎(chǔ)上我們使用于 API Gateway 相類似的數(shù)據(jù)面、控制面分離的架構(gòu),控制面會(huì)將變更后的網(wǎng)關(guān)配置準(zhǔn)實(shí)時(shí)下發(fā)至數(shù)據(jù)面節(jié)點(diǎn)。數(shù)據(jù)面節(jié)點(diǎn)識(shí)別配置有更新后在運(yùn)行時(shí)會(huì)動(dòng)態(tài)切換代理引擎至新的代理邏輯下,并保證老的代理邏輯會(huì)處理完當(dāng)下被分配的請(qǐng)求。

          在數(shù)據(jù)面中,我們對(duì)請(qǐng)求過濾器有兩種模式的抽象:請(qǐng)求過濾器和模型過濾器。請(qǐng)求過濾器作用于用戶的原始請(qǐng)求,這類過濾器往往被設(shè)計(jì)用于處理鑒權(quán)、限流等邏輯。而模型過濾器作用于請(qǐng)求被轉(zhuǎn)發(fā)至該模型時(shí),常用于模型 API 的兼容邏輯。比如模型發(fā)展中目前對(duì)深度思考 <think> 的標(biāo)簽處理,推理引擎自定義參數(shù)的兼容修正等。

          除此之外控制面也會(huì)提供 OpenAPI 供 AI 模型供給團(tuán)隊(duì)上架模型,新增 API Key 等日常運(yùn)營能力。模型提供方可以在上架模型時(shí)支持為模型配置相應(yīng)的 RPM、TPM 上限,并根據(jù)模型的推理引擎選擇相應(yīng)的兼容策略。也可以通過 OpenAPI 為單個(gè) API Key 授權(quán)相應(yīng)模型等功能。

          5、鑒權(quán)認(rèn)證

          在鑒權(quán)機(jī)制中,采用目前主流 OpenAI SDK 兼容的 API Key 認(rèn)證方案。

          Authorization: Bearer <YOUR_API_KEY>

          在 API Key 的認(rèn)證基礎(chǔ)上還提供細(xì)粒度的權(quán)限控制功能,允許為每個(gè) API Key 配置可訪問的模型范圍,以及對(duì)不同模型的設(shè)置不同的配額。

          另外支持靈活的 API Key 有效期配置,用戶可根據(jù)需求設(shè)置 API Key 的 過期時(shí)間 或 不過期。

          6、配額管理

          在配額管理體系里可以限制模型消費(fèi)者的調(diào)用速率,在這里主要參考了 OpenAI 的配額策略: RPM(每分鐘請(qǐng)求數(shù))和 TPM(每分鐘 Tokens 數(shù))。

          在這里可以按照為每個(gè)用戶分配不同模型的 Token 配額,或指定單位時(shí)間的請(qǐng)求數(shù)限制,以確保 AI 服務(wù)的高效運(yùn)行并防止超出預(yù)算。

          同時(shí)我們還支持月維度的 Token 配額,業(yè)務(wù)按自然月進(jìn)行預(yù)算申請(qǐng),超過預(yù)算時(shí)請(qǐng)求將被限制。對(duì)于接入 AI 能力而言,每個(gè)業(yè)務(wù)都需要提前申請(qǐng)預(yù)算額度,避免帶來難以負(fù)擔(dān)的成本。

          7、多模型訪問

          目前版本僅支持基于 OpenAI API 的協(xié)議轉(zhuǎn)發(fā)。以目前推理引擎發(fā)展和在線 AI 云服務(wù)而言,兼容 OpenAI API 協(xié)議已經(jīng)成為業(yè)界共識(shí),在此基礎(chǔ)上我們只需要實(shí)現(xiàn)根據(jù)用戶需求的模型名,擇優(yōu)選擇一個(gè)相應(yīng)模型的上游 API 提供商(公司自建 IDC或公有云),并替換成相應(yīng)服務(wù)商的 API Key 和 Upstream 域名就可以進(jìn)行負(fù)載均衡。

          對(duì)于公司 IDC 自建的模型服務(wù)而言,我們繼續(xù)沿用基于 discovery 等服務(wù)發(fā)現(xiàn)技術(shù)來發(fā)現(xiàn)推理引擎節(jié)點(diǎn),直接將請(qǐng)求包裝調(diào)度至這些自建模型。

          8、模型負(fù)載均衡

          LLM API 的負(fù)載均衡和傳統(tǒng)實(shí)時(shí) API 的模式有很大的不同。

          傳統(tǒng) API 開發(fā)中:一次請(qǐng)求往往被設(shè)計(jì)成會(huì)極大概率地命中一塊結(jié)果緩存,且緩存 Key 的計(jì)算都比較簡單,因此很多負(fù)載均衡都簡單基于請(qǐng)求相應(yīng)時(shí)間、連接數(shù)等等。

          在 LLM 推理場景下:每個(gè)推理請(qǐng)求都會(huì)帶來網(wǎng)關(guān)本身難以評(píng)估的計(jì)算時(shí)間和設(shè)備資源占用,此時(shí)基于 RPS、TTFB、連接數(shù)等負(fù)載均衡策略將不再適用。

          在 AI 網(wǎng)關(guān)的默認(rèn)負(fù)載均衡策略中:我們主要基于單模型服務(wù)節(jié)點(diǎn)處理 Token 的吞吐和時(shí)延能力,在黑盒模式下評(píng)估節(jié)點(diǎn)的飽和度。除此之外,推理引擎自身和顯卡其實(shí)也暴露了許多和執(zhí)行隊(duì)列相關(guān)的指標(biāo),綜合這些指標(biāo)同樣預(yù)計(jì)能獲得比傳統(tǒng)負(fù)載均衡更有效的體驗(yàn)。

          另外:基于 Prefix Cache 的節(jié)點(diǎn)選擇同樣會(huì)是一個(gè)相當(dāng)有效的調(diào)度策略,但 Prefix Cache 的計(jì)算能力往往需要外部服務(wù)來進(jìn)行,因此 AI 網(wǎng)關(guān)同樣支持接入外置的負(fù)載均衡算法,通過前置的 RPC 來讓外置服務(wù)選擇最合適的模型節(jié)點(diǎn)。

          9、多租戶隔離

          業(yè)務(wù)主要通過 域名 + API Key 進(jìn)行訪問大模型推理,可以通過域名進(jìn)行管理對(duì)接的接口路由,進(jìn)行配置轉(zhuǎn)發(fā)到指定 Model Provider 服務(wù)。如果需要進(jìn)行多業(yè)務(wù)隔離,只需要通過不同的域名訪問并配置不同的轉(zhuǎn)發(fā)目標(biāo)。

          10、可觀測能力

          從業(yè)務(wù)視角,主要分為 Gateway、 Domain、Consumer、Provider、UserModel、UpstreamModel 維度,進(jìn)行查詢和觀察請(qǐng)求接口的可用率,以及 QPS、Latency、5xx、Quota 等指標(biāo)。

          11、支持的API協(xié)議

          11.1 概述

          在 AI 網(wǎng)關(guān)中,我們主要以 OpenAI 提供的 API 作為基礎(chǔ)協(xié)議,讓開發(fā)者基于 OpenAI SDK 實(shí)現(xiàn)各種業(yè)務(wù)場景對(duì)接。

          目前支持的 API 協(xié)議有:

          • 1)對(duì)話式模型交互(CHAT_COMPLETION);
          • 2)通用文本向量接口(EMBEDDING);
          • 3)提示詞模板(CHAT_TEMPLATE);
          • 4)模型上下文協(xié)議(MODEL_CONTEXT_PROTOCOL) 。

          業(yè)務(wù)可以根據(jù)自己不同的場景進(jìn)行選擇對(duì)應(yīng)的協(xié)議。

          11.2 對(duì)話式模型交互(CHAT_COMPLETION)

          對(duì)話式模型交互是最基礎(chǔ)的協(xié)議,用于構(gòu)建具有復(fù)雜邏輯的對(duì)話交互。同時(shí) API 支持上下文感知的對(duì)話,使得模型能夠理解和響應(yīng)多輪交流,并在對(duì)話中保持合理的邏輯和語境一致性。

          對(duì)話接口是 LLM 與現(xiàn)實(shí)世界溝通的重要渠道,大量 AI 需求實(shí)際上就是在與模型進(jìn)行一輪或多輪對(duì)話實(shí)現(xiàn)的。

          例如業(yè)務(wù)希望通過 LLM 排查線上故障的潛在原因,簡單來說就是將應(yīng)用的各項(xiàng)可觀測指標(biāo)、故障期間的日志記錄或應(yīng)用上下游的變更記錄以對(duì)話形式告知 LLM,并讓 LLM 輸出一段便于程序理解的結(jié)果表達(dá)模式,讓 LLM 從模型數(shù)據(jù)中計(jì)算出符合直覺潛在故障原因。

          11.3 通用文本向量(EMBEDDING)

          通用文本向量(EMBEDDING)接口的核心功能是將文本轉(zhuǎn)化為高維向量,捕捉其語義特征。這在需要進(jìn)行大規(guī)模信息檢索、匹配和知識(shí)管理的場景中尤為關(guān)鍵。

          11.4 提示詞模板(CHAT_TEMPLATE)

          提示詞模板是一種結(jié)構(gòu)化的對(duì)話生成方式,允許業(yè)務(wù)通過設(shè)置預(yù)定義的模板來生成系統(tǒng)化的回復(fù)。這種方式將語言模型的生成能力與模板化結(jié)構(gòu)相結(jié)合,使業(yè)務(wù)能夠以普通 API 的方式進(jìn)行請(qǐng)求交互,并可以更集中化地控制生成內(nèi)容的樣式和格式。

          同時(shí)我們也支持內(nèi)嵌函數(shù),以方便在提示詞模板進(jìn)行處理內(nèi)容:

          • 1)len(v any) string
          • 2)jsonify(v any) string
          • 3)make_json_object(v ...any) map[string]any
          • 4)slice_to_index_map(v any, startBy int) map[int]any

          以評(píng)論內(nèi)容翻譯的場景:

          - path: /v1/reply-to-en

            protocol: HTTP

            timeout: 300s

            middlewares:

            - name: v1_chat_template

              options:

          '@type': type.googleapis.com/infra.gateway.middleware.llm.v1.contrib.ChatTemplateConfig

                provider: bilibili

                model_name: index

                prompt_template: |

                  你的任務(wù):以下給定文本是一個(gè)B站視頻的相關(guān)文本信息,可能為標(biāo)題、簡介、彈幕或評(píng)論,請(qǐng)你將給定的文本逐條翻譯成英文。輸入為一個(gè)json格式,key為序號(hào),value為待翻譯的彈幕,一共有{{ len .reply_list }}個(gè)文本。示例如下:

                  輸入: {"1": "xxx", "2": "xxx"}

           

                  輸出: {"1": "xxx", "2": "xxx"}

           

                  注意,用{dyn:xxx}符號(hào)包裹的是圖片引用,不需要翻譯,直接保留。用[xxx]包裹的是表情符號(hào),不需要翻譯,直接保留。現(xiàn)在請(qǐng)根據(jù)上述要求完成如下片段的翻譯,輸出一共{{ len .reply_list }}個(gè)翻譯后的結(jié)果,直接輸出翻譯后的英文,不要進(jìn)行任何解釋。

           

                  輸入: {{ jsonify (slice_to_index_map .reply_list 1) }}

           

                  輸出:

          提示詞模版接口實(shí)際上是基于對(duì)話接口的一種高效對(duì)接模式。眾所周知,自 OpenAI 發(fā)布 ChatGPT 后,提示詞工程(Prompt Engineering)本身被當(dāng)作一種技術(shù)路線而提出。提示詞工程主要關(guān)注提示詞開發(fā)與優(yōu)化,幫助用戶將大語言模型用于各場景和研究領(lǐng)域。研究人員可利用提示工程來提升大語言模型處理復(fù)雜任務(wù)場景的能力,如問答和算術(shù)推理能力。

          對(duì)于接入 LLM 的業(yè)務(wù)研發(fā)而言,他可能本身不具備很強(qiáng)的提示詞工程能力;甚至提示詞的優(yōu)化本身也取決于模型的迭代更新。因此對(duì)于解決特定領(lǐng)域的業(yè)務(wù)場景,AI 工程師往往會(huì)基于最優(yōu)模型寫出最精準(zhǔn)的提示詞,通過 AI 網(wǎng)關(guān)的提示詞模版接口發(fā)布。業(yè)務(wù)提交簡單 JSON KV 對(duì)后,渲染出最有效的完整提示詞,LLM 基于有效提示詞輸出最精確的結(jié)果。

          11.5 模型上下文協(xié)議(MODEL_CONTEXT_PROTOCOL)

          MCP (Model Context Protocol,模型上下文協(xié)議) 是由 Anthropic 在 2024 年底推出的一種開放協(xié)議,旨在讓大型語言模型(LLM)能夠以標(biāo)準(zhǔn)化的方式連接到外部數(shù)據(jù)源和工具。該協(xié)議抽象并標(biāo)準(zhǔn)化了 Resources、Prompts、Tools 等資源及其接入方式,允許 LLM Client 應(yīng)用以一致的方式連接到各種數(shù)據(jù)源和工具,如文件、數(shù)據(jù)庫、API 等。

          配置轉(zhuǎn)發(fā)到注冊(cè)中心的 MCP 服務(wù):

          - path: /example-mcp/*

            protocol: HTTP

            timeout: 300s

            middlewares:

            - name: v1_mcp_server

              options:

                '@type': type.googleapis.com/infra.gateway.middleware.llm.v1.contrib.MCPServerConfig

                proxy:

                  name: example-mcp

                  upstreams:

                  - url: 'discovery://infra.example.example-mcp'

          - path: /example-mcp/*

            protocol: HTTP

            timeout: 300s

            middlewares:

            - name: v1_mcp_server

              options:

                '@type': type.googleapis.com/infra.gateway.middleware.llm.v1.contrib.MCPServerConfig

                proxy:

                  name: example-mcp

                  upstreams:

                  - url: 'discovery://infra.example.example-mcp'

          12、MCP市場與API接入

          MCP 市場其實(shí)就是一個(gè)公司內(nèi)部的資源共享和協(xié)作平臺(tái)。簡單來說,它可以看作是企業(yè)內(nèi)的小型“App Store”,專門用來提供各種服務(wù)和資源的接入入口。可以讓業(yè)務(wù)通過這個(gè)平臺(tái)輕松獲取、整合、使用這些資源,使業(yè)務(wù)對(duì)接更加地簡單。

          用戶可以把自己的 MCP 服務(wù)快速發(fā)布到市場上,并且接入到 MCP Gateway 后即可使用。

          當(dāng)前的 MCP 協(xié)議中主要有兩個(gè)端點(diǎn):

          • 1)/sse:是一個(gè) Events 長連接通知協(xié)議,用于實(shí)時(shí)通知資源信息的變更;
          • 2)/message:用于 JSONRPC 通信端點(diǎn),能夠以 JSONRPC 方式進(jìn)行通信交互。

          而我們?cè)?MCP Gateway 中,我們?cè)谄髽I(yè)內(nèi)部將通過統(tǒng)一的域名進(jìn)行提供業(yè)務(wù)接入,并且進(jìn)行管理每一個(gè) MCP服務(wù)的接口,例如:https://mcp.example.com/logging-mcp

          同時(shí)在 MCP服務(wù)中,需要使用相同的根路徑 /logging-mcp,因?yàn)樵?MCP 協(xié)議中,會(huì)先連接到 /sse 端點(diǎn),再返回對(duì)應(yīng)的 /message 端點(diǎn)信息,所以請(qǐng)求路徑需要保持跟網(wǎng)關(guān)一致。

          13、本文小結(jié)

          AI 網(wǎng)關(guān)通過統(tǒng)一接入、鑒權(quán)、配額管理 和 模型調(diào)度支持,為大模型提供了高效、安全、定制的連接能力。同時(shí),支持了 OpenAI 協(xié)議、提示詞模板 和 MCP 市場等功能,進(jìn)一步擴(kuò)展了 AI 技術(shù)在企業(yè)中的應(yīng)用場景,為業(yè)務(wù)接入和資源整合提供了極高的便利性。

          14、相關(guān)資料

          [1] Web端即時(shí)通訊技術(shù)盤點(diǎn):短輪詢、Comet、Websocket、SSE

          [2] SSE技術(shù)詳解:一種全新的HTML5服務(wù)器推送事件技術(shù)

          [3] 網(wǎng)頁端IM通信技術(shù)快速入門:短輪詢、長輪詢、SSE、WebSocket

          [4] 搞懂現(xiàn)代Web端即時(shí)通訊技術(shù)一文就夠:WebSocket、socket.io、SSE

          [5] 全民AI時(shí)代,大模型客戶端和服務(wù)端的實(shí)時(shí)通信到底用什么協(xié)議?


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

          posted @ 2025-05-22 14:08 Jack Jiang 閱讀(8) | 評(píng)論 (0)編輯 收藏

          本文來自QCon全球軟件開發(fā)大會(huì)王勁鵬的技術(shù)分享,下文進(jìn)行了排版優(yōu)化和修訂。

          1、引言

          性能和體驗(yàn)在 iOS / Android 雙端場景下已經(jīng)是一個(gè)較為成熟的話題,但隨著鴻蒙 OS 的發(fā)展,端側(cè)開發(fā)者需要更多的關(guān)注多端場景的差異性。

          本次分享的主題是小紅書在鴻蒙平臺(tái)上的工程實(shí)踐,主要聚焦于性能優(yōu)化和探索。* PPT講稿原文下載:小紅書鴻蒙OS下的性能優(yōu)化探索與實(shí)踐(PPT)[附件下載]》)

          先介紹一下自己的背景。之前一直從事大前端領(lǐng)域的工作,主要專注于跨端和容器化方案。也曾手寫過一個(gè)跨端框架,名為 Doric,它可以對(duì)標(biāo) React Native、Vue Native 和 Flutter 等。Doric 框架在落地時(shí)表現(xiàn)良好,還支持了一些自研的 3D 引擎方案。除此之外,我還有播放器內(nèi)核研發(fā)經(jīng)驗(yàn),以及大前端常規(guī)體系建設(shè)和 CI/CD 流水線的工程經(jīng)驗(yàn)。未來,我將持續(xù)關(guān)注大前端的演進(jìn),尤其是鴻蒙這樣的多端和跨端平臺(tái)。

          從 2023 年開始,鴻蒙的優(yōu)勢愈發(fā)明顯,已經(jīng)成為可與 iOS、安卓媲美的第三大移動(dòng)操作系統(tǒng)。從一些抖音視頻中也可以看出,鴻蒙在流暢性方面甚至在某些層面上超過了 iOS。

          今天的分享內(nèi)容分為四個(gè)部分:

          • 1)介紹整個(gè)歷程和背景;
          • 2)介紹鴻蒙 OS 的相關(guān)能力和小紅書在該平臺(tái)上的優(yōu)化實(shí)踐;
          • 3)通過鴻蒙 OS 提供的性能驗(yàn)證工具,展示小紅書在鴻蒙平臺(tái)上的性能優(yōu)化驗(yàn)證方法、優(yōu)化后的性能提升以及具體的收益和結(jié)果;
          • 4)總結(jié)和展望。
           
           

          2、內(nèi)容分享和整理

          分享者:王勁鵬,內(nèi)容審校和編輯:Kitty。

           王勁鵬:小紅書鴻蒙工程師。目前主要負(fù)責(zé)小紅書鴻蒙版的研發(fā)和工程建設(shè),曾從事過大前端架構(gòu)設(shè)計(jì)、研發(fā)效能等方向的工作,在終端架構(gòu)演進(jìn)、性能優(yōu)化以及跨端容器和動(dòng)態(tài)化等方面具備長期實(shí)踐及深厚經(jīng)驗(yàn),持續(xù)關(guān)注大前端技術(shù)體系,鴻蒙以及多端的演進(jìn)。

          3、版本歷程和開發(fā)背景

          3.1 小紅書迭代歷程

          從 2023 年年中開始,鴻蒙的“千帆計(jì)劃”正式啟動(dòng),并很快升級(jí)為“鴻飛計(jì)劃”。小紅書作為 7 家頭部合作商之一,率先支持了鴻蒙,并于 2023 年 11 月中旬上線了一個(gè)基礎(chǔ)版的 beta 版本 APP。這個(gè)版本主要包含筆記瀏覽和視頻筆記瀏覽兩大功能,以及一些簡單的個(gè)人設(shè)置。當(dāng)時(shí),小紅書的動(dòng)作非常迅速,可以說是頭部應(yīng)用廠商中對(duì)華為支持最為積極的品牌之一。

          在整個(gè)鴻飛計(jì)劃中,我們規(guī)劃了三個(gè)核心里程碑:除了 2023 年 11 月的 beta 版本外,還包括 2024 年 6 月的 HDC 版本和 2024 年 9 月的商用版本。HDC 版本主要是針對(duì)華為正式宣發(fā)鴻蒙 3(HarmonyOS Next)開發(fā)者測試的情況。在 HDC 版本中,我們上線了許多小紅書特有的存量功能,包括視頻拍攝、圖文拍攝以及多設(shè)備協(xié)同等創(chuàng)新特性。而到了 2024 年 9 月的商用版本交付時(shí),小紅書的核心功能已經(jīng)基本與主端對(duì)齊。考慮到鴻蒙的開發(fā)周期僅有一年,小紅書的鴻蒙 APP 在這一年中要對(duì)齊開發(fā)了十年甚至十幾年的安卓和 iOS 版本,難度和壓力都非常巨大。

          到 2024 年 9 月,除了對(duì)齊雙端的所有功能外,我們還開發(fā)了許多其他功能,包括華為支持的創(chuàng)新特性,例如智能拖拽——用戶可以將圖片拖拽到中轉(zhuǎn)站或小藝等場景。此外,商用版本還支持了用戶呼聲較高的 HDR 或 Moonlight Photo 拍攝能力。

          3.2 純血鴻蒙與安卓的區(qū)別

          我從幾個(gè)維度來對(duì)比一下純血鴻蒙和安卓 OS 的主要區(qū)別。

          內(nèi)核架構(gòu)純血鴻蒙的本質(zhì)是微內(nèi)核,而安卓是基于 Linux 宏內(nèi)核。微內(nèi)核只提供基礎(chǔ)的內(nèi)存和文件管理能力,驅(qū)動(dòng)和其他系統(tǒng)能力都在 OS 之外。這樣做的好處是系統(tǒng)穩(wěn)定性極高,即使應(yīng)用崩潰,也不會(huì)導(dǎo)致整個(gè)系統(tǒng)崩潰(system crash)。而在 Linux 宏內(nèi)核中,應(yīng)用的不當(dāng)行為可能會(huì)直接導(dǎo)致系統(tǒng)崩潰。

          多設(shè)備適配鴻蒙目前支持多種設(shè)備類型:包括 Mate 60 Pro 這樣的直板手機(jī)、Mate X5 或非凡大師 XT 這樣的雙折疊和三折疊手機(jī)、平板電腦、車機(jī),甚至華為正在研發(fā)的鴻蒙 PC。鴻蒙真正實(shí)現(xiàn)了類似 iOS 的多端整合能力,通過一套代碼實(shí)現(xiàn)多端部署。其工程體系和架構(gòu)支持單 HAP(Harmony Ability Package)多 HSP(Harmony Service Package)模塊,指令集適配了 ARM64 等多種架構(gòu),開發(fā)者只需根據(jù)設(shè)備尺寸適配 UI 展示即可。例如,在 2024 年 9 月 的華為全場景設(shè)備發(fā)布會(huì)上,余承東展示了小紅書在從直板機(jī)到雙折疊、三折疊設(shè)備上的適配能力,完全實(shí)現(xiàn)了響應(yīng)式編程,不同設(shè)備形態(tài)下有不同的瀏覽體驗(yàn)。

          開發(fā)工具和編程模型鴻蒙的開發(fā)工具和編程模型與安卓差異較大。鴻蒙更類似于 Flutter 的嵌套型容器布局,而不是安卓那種面向?qū)ο蟮拈_發(fā)方式。在語言層面,鴻蒙完全封裝了底層邏輯,采用類似前端 Flux 單向數(shù)據(jù)流模式,通過數(shù)據(jù)變更驅(qū)動(dòng) UI 刷新。這種模式類似于前端 Redux 或 MobX 框架中的 state 管理 。

          從 2024 年 10 月 8 日公測開始,鴻蒙的應(yīng)用生態(tài)正在逐漸繁榮。不過,目前像微信這樣的應(yīng)用還處于搶先體驗(yàn)階段。相比之下,安卓的生態(tài)已經(jīng)相對(duì)成熟。鴻蒙的最終目標(biāo)是打造全場景智能設(shè)備生態(tài),涵蓋所有終端設(shè)備,以及基于 OpenHarmony 內(nèi)核開發(fā)的物聯(lián)網(wǎng)終端。它還支持多種芯片體系,例如瑞芯微 RK3568 等。

          3.3 小紅書鴻蒙應(yīng)用架構(gòu)層級(jí)

          小紅書經(jīng)過一年的迭代,其整體應(yīng)用架構(gòu)已經(jīng)基本成熟。目前,整體代碼量接近 200 萬行,達(dá)到了一個(gè)較高的復(fù)雜度。在一般成熟的 APP 架構(gòu)中,通常會(huì)包含一些基礎(chǔ)底層能力,例如網(wǎng)絡(luò)、磁盤存儲(chǔ)、埋點(diǎn)體系、APM(應(yīng)用性能管理)系統(tǒng),以及一些通用組件和能力。對(duì)于鴻蒙平臺(tái),小紅書還具備一些特殊的公共通用能力。

          我們開發(fā)了一個(gè)“一多框架”,這是一個(gè)支持一套代碼多端部署的具體框架體系。通過這個(gè)框架,我們實(shí)現(xiàn)了多設(shè)備的斷點(diǎn)控制功能。用戶可以根據(jù)設(shè)備的尺寸和類型進(jìn)行適配,因?yàn)槿A為設(shè)備支持多端投屏。例如,用戶可以在手機(jī)上瀏覽小紅書,然后將內(nèi)容投屏到車機(jī)上。比如用戶購買了一輛問界汽車,可以在車內(nèi)通過車機(jī)繼續(xù)瀏覽手機(jī)上的小紅書內(nèi)容,這種場景在駕駛時(shí)尤其有用。

          除了底層框架,對(duì)于上層業(yè)務(wù),小紅書還有一套自研的組件庫方案,這套組件庫承載了上層業(yè)務(wù)的多種功能,包括圖文筆記、視頻筆記瀏覽,以及一些 Hybrid 容器能力。小紅書本質(zhì)上在跨端開發(fā)中仍然使用了 React Native(RN)和類 Web 技術(shù)。RN 引擎由華為內(nèi)部合作提供,采用了自研的 ohos 方案,用于解決 React Native 的 bundle 和 JS 加載以及渲染問題。此外,還包括產(chǎn)品定制層,這里涵蓋了所有相關(guān)的設(shè)備適配內(nèi)容。

           3.4 性能優(yōu)化與實(shí)踐

          目前,安卓和 iOS 在性能優(yōu)化方面已經(jīng)相當(dāng)成熟,包括如何分析性能熱點(diǎn)問題、有哪些工具以及最佳實(shí)踐等。然而,對(duì)于鴻蒙來說,它是一個(gè)全新的系統(tǒng)。直到 2024 年年中,鴻蒙的穩(wěn)定性和流暢性都還存在一些問題。這里重點(diǎn)講述小紅書在 2024 年與華為一起進(jìn)行了哪些實(shí)踐,以提升應(yīng)用的性能和用戶體驗(yàn)。

          我們定義了一個(gè)性能指標(biāo)場景。這個(gè)指標(biāo)體系是小紅書與華為共同探討的結(jié)果,因?yàn)槿A為有一個(gè)性能工廠,它對(duì)每個(gè)應(yīng)用的評(píng)級(jí)都有一個(gè) S 標(biāo)標(biāo)準(zhǔn)。小紅書與華為一起確定了針對(duì)小紅書場景需要觀測的具體指標(biāo)。性能優(yōu)化的核心是慢函數(shù)指標(biāo),它主要包含兩部分:過程時(shí)長和應(yīng)用體驗(yàn)的流暢性。

          過程時(shí)長主要包含以下三點(diǎn):

          • 1)冷啟動(dòng)時(shí)長:這是用戶最關(guān)心的指標(biāo)之一,即從點(diǎn)擊應(yīng)用圖標(biāo)到應(yīng)用完成動(dòng)畫并展示第一幀的時(shí)間。對(duì)于多數(shù)應(yīng)用,首頁通常有緩存機(jī)制。例如,小紅書會(huì)緩存用戶上次刷新的筆記,淘寶會(huì)緩存用戶上次瀏覽的商品內(nèi)容;
          • 2)場景完成時(shí)長:指完成某個(gè)特定場景所需的時(shí)間;
          • 3)應(yīng)用響應(yīng)時(shí)長:指用戶操作界面后,界面真正發(fā)生變化的時(shí)間,即響應(yīng)時(shí)延。

          流暢性方面,最基礎(chǔ)的觀測指標(biāo)是平均 FPS(幀率),包括丟幀數(shù)、最大連續(xù)丟幀數(shù)、丟幀卡頓次數(shù)以及卡頓率。卡頓率可以通過量化計(jì)算得出:當(dāng)一個(gè)場景中出現(xiàn)丟幀時(shí),丟幀的時(shí)長與場景總時(shí)長的比值即為卡頓率,它是一個(gè)小于 1 的百分比數(shù)值。

          3.5 OS 能力 & 優(yōu)化實(shí)踐

          首先,針對(duì) IO 場景,我們進(jìn)行了相應(yīng)的優(yōu)化。

          鴻蒙 OS 的系統(tǒng)能力主要分為以下三個(gè)方面:

          • 1)并行化能力鴻蒙 OS 提供了兩種并行化能力:Worker 和 TaskPool。Worker 類似于傳統(tǒng)的線程模型,每個(gè) Worker 都有自己的內(nèi)存空間和執(zhí)行單元,支持通過消息(message)進(jìn)行通信。TaskPool 則類似于協(xié)程或線程池,能夠動(dòng)態(tài)管理線程數(shù)量,支持標(biāo)記為 @concurrent 的函數(shù)直接在任務(wù)池中調(diào)度和運(yùn)行。這兩種機(jī)制都支持線程間隔離,內(nèi)存不共享;
          • 2)多線程通信和數(shù)據(jù)傳輸在多線程通信方面,鴻蒙 OS 支持序列化數(shù)據(jù)傳輸和基于消息(message)的通信機(jī)制。此外,還引入了事件發(fā)射器(Emitter)用于系統(tǒng)事件的發(fā)布和訂閱。這種機(jī)制允許線程間通過消息傳遞來實(shí)現(xiàn)復(fù)雜的交互邏輯;
          • 3)同步轉(zhuǎn)異步機(jī)制鴻蒙 OS 支持基于 Promise 的異步編程模型,包括 async 和 await 語法,以及 then 和 catch 方法。這種機(jī)制能夠有效提升應(yīng)用的響應(yīng)性和用戶體驗(yàn)。

          4、并行化能力

          在并行化能力方面,鴻蒙 OS 提供了兩套基礎(chǔ)實(shí)現(xiàn)方式。開發(fā)者可以通過 RTS(運(yùn)行時(shí)系統(tǒng))實(shí)現(xiàn)并行化,也可以通過底層庫(如 C++ 標(biāo)準(zhǔn)庫中的)實(shí)現(xiàn)。不過,如果完全依賴底層庫,可能會(huì)導(dǎo)致開發(fā)效率下降。為了滿足業(yè)務(wù)需求,鴻蒙 OS 在年初引入了 Worker 和 TaskPool 能力。Worker 類似于傳統(tǒng)的線程模型,每個(gè) Worker 都有獨(dú)立的內(nèi)存空間和執(zhí)行單元,支持通過消息進(jìn)行通信。消息可以包含可序列化的數(shù)據(jù),也可以通過指針直接遷移數(shù)據(jù)。TaskPool 則類似于線程池,能夠動(dòng)態(tài)管理線程數(shù)量,支持標(biāo)記為 @concurrent 的函數(shù)直接在任務(wù)池中調(diào)度和運(yùn)行。與安卓平臺(tái)的線程池不同,鴻蒙 OS 的 TaskPool 會(huì)根據(jù)硬件條件和任務(wù)負(fù)載動(dòng)態(tài)調(diào)整線程數(shù)量。這種機(jī)制避免了安卓平臺(tái)中因線程池?cái)?shù)量過多而導(dǎo)致的系統(tǒng)資源消耗問題。

          接下來我們對(duì)比鴻蒙 OS 的 Worker 并行化能力和安卓端的相關(guān)特性。從多個(gè)維度來看,Worker 本質(zhì)上不推薦手動(dòng)創(chuàng)建,而是通過系統(tǒng)配置 build-provider.json 綁定 ETS 文件來實(shí)現(xiàn)創(chuàng)建。這一點(diǎn)與安卓端并無明顯差異,安卓端可以通過 THREAD 等方式啟動(dòng)線程。

          在鴻蒙 OS 5.0 以下版本(如 4.2 版本)中,主要運(yùn)行的仍然是安卓系統(tǒng)。這種情況下,安卓線程數(shù)量存在上限,這對(duì)應(yīng)用開發(fā)者來說是一個(gè)挑戰(zhàn)。如果 SDK 集成過多,線程數(shù)可能超標(biāo),進(jìn)而導(dǎo)致應(yīng)用被系統(tǒng)強(qiáng)制終止,或出現(xiàn)業(yè)務(wù)場景異常崩潰等穩(wěn)定性問題。

          數(shù)據(jù)傳輸方面:鴻蒙 OS 為了優(yōu)化 Worker 的性能和負(fù)載,對(duì) Worker 的數(shù)量和單個(gè) Worker 的傳輸上限進(jìn)行了限制。鴻蒙 Worker 的單個(gè)傳輸上限類似于安卓中的 Binder 機(jī)制,也存在類似的傳輸限制。不過,安卓線程通常沒有嚴(yán)格限制,因?yàn)榫€程本質(zhì)上是一個(gè)內(nèi)存拷貝過程,除非開發(fā)者通過指針等方式自定義線程間數(shù)據(jù)傳輸。

          在傳輸格式上:鴻蒙 OS 支持通過 Sendable 接口進(jìn)行數(shù)據(jù)傳輸。Sendable 是一種注解方式定義的數(shù)據(jù)結(jié)構(gòu),具有傳染性,即如果一個(gè)類被標(biāo)記為 Sendable,其關(guān)聯(lián)屬性也必須是 Sendable 類型。鴻蒙 OS 支持基礎(chǔ)數(shù)據(jù)類型(如 number、string)和集合類型作為 Sendable 傳輸?shù)膬?nèi)容。對(duì)于跨模塊調(diào)用,鴻蒙 OS 不允許 Worker 跨 HAP 或跨 HSP 調(diào)用。相比之下,安卓應(yīng)用通常運(yùn)行在一個(gè)或多個(gè) Dex 文件中,允許跨 Dex 或跨模塊的線程間調(diào)用。

          TaskPool 類似于雙端的協(xié)程概念,是一種輕量級(jí)線程,僅存儲(chǔ)函數(shù)。不過,TaskPool 與協(xié)程有所不同,它獨(dú)立于任務(wù)維度,且任務(wù)執(zhí)行時(shí)長有限制(超過 3 分鐘會(huì)被系統(tǒng)自動(dòng)回收)。安卓平臺(tái)可以通過 ASM 插樁技術(shù)對(duì)線程的創(chuàng)建和執(zhí)行進(jìn)行監(jiān)控和優(yōu)化,但輕量級(jí)線程或協(xié)程的實(shí)現(xiàn)通常依賴于線程池或協(xié)程機(jī)制。

          TaskPool 中的任務(wù)默認(rèn)支持?jǐn)?shù)據(jù)轉(zhuǎn)移(transfer),不支持拷貝。此外,TaskGroup 不支持 SDK 初始化包的加載。某些同學(xué)習(xí)慣在異步線程中觸發(fā) SDK 的行為,在鴻蒙 OS 上可能會(huì)因 TaskPool 生命周期結(jié)束而導(dǎo)致變量被釋放。

          關(guān)于并行化數(shù)據(jù)傳輸?shù)?Sendable 概念:Sendable 通過系統(tǒng)提供的 SharedHeap(共享堆)實(shí)現(xiàn)傳輸。共享堆與本地堆(local Heap)的區(qū)別在于,共享堆支持 Sendable 化數(shù)據(jù)的傳輸,而本地堆則需要序列化。共享堆的管理和控制耗費(fèi)了華為專家大量時(shí)間和精力,其中還涉及復(fù)雜的異步鎖(async lock)機(jī)制。在 RTS 并發(fā)實(shí)例期間(包括 Worker、TaskPool 等),數(shù)據(jù)可以通過 Sendable 傳遞,但 Worker 需要使用單獨(dú)的 API。TaskPool 則完全支持 Sendable 的直接傳輸。這種異步鎖機(jī)制允許在 TaskPool 或 Worker 中鎖定其他任務(wù)中的某些函數(shù),實(shí)現(xiàn)線程間的同步,類似于安卓中的 synchronized 或其他鎖機(jī)制。

          5、小紅書典型并行化場景

          小紅書在一些典型化場景中已經(jīng)實(shí)現(xiàn)了并行化處理。例如,網(wǎng)絡(luò)請(qǐng)求是一個(gè)典型的耗時(shí)操作,因?yàn)檎?qǐng)求過程中涉及驗(yàn)簽和安全能力的處理,這些操作如果在主線程中同步完成,可能會(huì)導(dǎo)致應(yīng)用掉幀。當(dāng)用戶滑動(dòng)時(shí),掉幀現(xiàn)象會(huì)非常明顯,這通常是由于大量計(jì)算引起的。為了解決這一問題,我們采用了 Worker 化的方式,將這些操作移到 Worker 線程中,從而避免主線程的卡頓。

          在進(jìn)行埋點(diǎn)時(shí),可能會(huì)涉及數(shù)據(jù)庫的 IO 操作,這些操作也不建議在主線程中執(zhí)行。通過將這些操作放到 Worker 線程中,可以有效避免對(duì)主線程的影響。

          針對(duì)雙列布局中的圖片和資源預(yù)加載,我們采用華為自研的 RCP 網(wǎng)絡(luò)解決方案(類似于 HTTP),通過 Worker 線程在遠(yuǎn)端進(jìn)行下載,并在完成后將結(jié)果返回到主線程。此外,TaskPool 的應(yīng)用場景也非常廣泛,例如文件上傳、多媒體操作以及啟動(dòng)任務(wù)的編排等。TaskPool 的優(yōu)勢在于輕量化,避免了線程上下文切換帶來的不必要耗時(shí)。

          關(guān)于冷啟動(dòng)和首刷場景的優(yōu)化。這部分主要包括兩個(gè)方面:模塊的懶加載和動(dòng)態(tài)組件的復(fù)用池。懶加載是應(yīng)用開發(fā)中常見的優(yōu)化手段,類似于安卓端的 class order 機(jī)制。當(dāng)應(yīng)用不需要某個(gè)類時(shí),可以延遲加載該類,直到真正需要使用時(shí)才加載。這種方式可以顯著提高冷啟動(dòng)階段的代碼加載效率,從而大幅降低冷啟動(dòng)時(shí)長。

          動(dòng)態(tài)組件和組件復(fù)用池則是為了解決 UI 組件重復(fù)創(chuàng)建的問題。在應(yīng)用中,可能會(huì)有多種相同類型的 UI 組件(例如小紅書中的筆記組件)。為了避免重復(fù)創(chuàng)建帶來的開銷,我們希望在運(yùn)行時(shí)盡量復(fù)用已有的組件,而不是頻繁地創(chuàng)建和銷毀。

          6、類前端視角下的模塊懶加載

          我們通過特定的分析工具對(duì)懶加載進(jìn)行了深入分析。如圖所示,我們能夠識(shí)別出啟動(dòng)過程中加載的各種模塊,包括 RNOH(React Native on Harmony)、Web engine(網(wǎng)頁引擎)、Red Player(播放器)等組件。這些模塊的加載過程涉及到多個(gè).so 文件,即共享對(duì)象文件。

           通過自上而下的分析方法,我們可以清晰地看到每個(gè)模塊加載的具體耗時(shí)。進(jìn)一步分析這些.so 文件與 RTS(運(yùn)行時(shí)系統(tǒng))的關(guān)聯(lián),以及它們所引入的 Napi 的 TS 文件。我們進(jìn)行了懶加載潛在對(duì)象的分析,發(fā)現(xiàn)許多 RTS 實(shí)際上并不需要的類文件已經(jīng)被加載。這是因?yàn)殚_發(fā)者在編寫代碼時(shí),可能并未充分考慮到導(dǎo)入一個(gè)類或方法對(duì)應(yīng)用啟動(dòng)延遲的影響。

          為了優(yōu)化這一過程,我們的目標(biāo)是減少字節(jié)碼中需要加載的類文件數(shù)量,從而加快應(yīng)用的冷啟動(dòng)速度。華為提供的編譯器能夠?qū)?RTS 編譯成 Ark bytecode(方舟字節(jié)碼),這是一種高效的字節(jié)碼格式。通過減少需要加載的類文件數(shù)量,我們可以顯著提高應(yīng)用的啟動(dòng)速度。

          華為還提供了一種懶加載的導(dǎo)入方式,只有在真正需要使用某個(gè)類時(shí),它才會(huì)被加載。這種懶加載機(jī)制有助于減少應(yīng)用啟動(dòng)時(shí)的資源消耗。這引發(fā)了一個(gè)問題:為什么華為不默認(rèn)采用全懶加載方式,即只有在使用時(shí)才加載類文件呢?我已經(jīng)將這個(gè)問題反饋給華為,并且系統(tǒng)側(cè)可能會(huì)考慮在未來的版本中默認(rèn)采用懶加載方式,同時(shí)仍然允許用戶手動(dòng)選擇非懶加載的方式進(jìn)行類文件的加載。

          7、動(dòng)態(tài)組件

          在小紅書的首頁場景中,筆記卡組件在多個(gè)場景中被復(fù)用。為了避免重復(fù)創(chuàng)建 UI 導(dǎo)致的性能消耗,我們采用了動(dòng)態(tài)組件的概念。動(dòng)態(tài)組件的核心原理是利用占位符來延遲組件的創(chuàng)建,這與 Android 開發(fā)中使用 Stub 模式的概念相似。在這種模式下,可以使用一個(gè)代理對(duì)象(stub)來代表尚未初始化的組件,從而延遲組件的創(chuàng)建過程。當(dāng)真正需要渲染組件時(shí),再將渲染內(nèi)容填充進(jìn)去,從而避免每次調(diào)用構(gòu)建函數(shù)(如 build)時(shí)的耗時(shí)。

          占位邏輯通過系統(tǒng)的 API 實(shí)現(xiàn),涉及到 NodeContainer 和 NodeController 的綁定關(guān)系。Container 和 Controller 一一映射,由 NodeCore 進(jìn)行管理。Container 僅管理當(dāng)前展現(xiàn)的內(nèi)存部分,使用完畢后需要將其放回池中進(jìn)行回收和再利用。以冷啟動(dòng)首刷為例,在啟動(dòng)階段可以先獲取磁盤上的筆記內(nèi)容,然后在 BuilderNode 中預(yù)先創(chuàng)建多個(gè) Image 組件。這樣,在等待網(wǎng)絡(luò)或推薦接口響應(yīng)時(shí),Image 組件已經(jīng)創(chuàng)建完畢,從而在首頁刷新時(shí)可以立即使用這些組件,這對(duì)于提高首刷非常有益。

           對(duì)于組件復(fù)用池,當(dāng)動(dòng)態(tài)組件不再使用時(shí),需要將其返回到組件池中。對(duì)于自定義組件,通過 NoteContainer 占位方式,由 NodeController 進(jìn)行管理。在需要?jiǎng)?chuàng)建子組件時(shí),先在 NodePool 中查找,如果找不到,則創(chuàng)建新組件;如果找到,則嘗試復(fù)用。流程圖展示了從 Container 裝載 NodeItem 開始,通過 NodePool 查找,如果找到則進(jìn)行條件判斷和復(fù)用。

          組件的新建和復(fù)用過程中,如果找到對(duì)應(yīng)的 NodeItem,則調(diào)用 build 方法并更新自定義組件的狀態(tài),完成復(fù)用。如果有對(duì)應(yīng)的 NodeItem,可以直接通過 update 函數(shù)更新內(nèi)部狀態(tài)并刷新 UI。但要注意,update 方法可能會(huì)因狀態(tài)變量過于復(fù)雜而導(dǎo)致更新延遲,出現(xiàn)圖像殘影。因此,需要拆分 state,使其足夠小,以確保狀態(tài)變更到通知 UI 的時(shí)間縮短,消除殘影。

          我們的策略是優(yōu)先在 NodePool(節(jié)點(diǎn)池)中查找可用的 NodeItem(節(jié)點(diǎn)項(xiàng))。如果 NodePool 中存在可用的 NodeItem,我們就直接使用它,并通過 getNode 方法進(jìn)行 item 綁定,隨后更新其狀態(tài)以實(shí)現(xiàn)復(fù)用。如果 NodePool 中沒有找到對(duì)應(yīng)的 NodeItem,那么我們將通過 makeNode 方法調(diào)用 build 函數(shù)來創(chuàng)建新的節(jié)點(diǎn)項(xiàng)。

          完成組件的復(fù)用后,我們需要將這些組件返回到緩存池中,以便在未來可以再次使用。這個(gè)過程涉及到 NodeContainer(節(jié)點(diǎn)容器)和 NodeController(節(jié)點(diǎn)控制器)的銷毀,并將 NodeItem 重新放回 NodePool 中。為了更有效地管理緩存,業(yè)務(wù)層可以利用 LRU(最近最少使用)算法,或者鴻蒙系統(tǒng)提供的 LRUCache 和 LiUHashMap 等數(shù)據(jù)結(jié)構(gòu),來自定義緩存的大小,從而優(yōu)化組件的復(fù)用和緩存策略。

          8、滑動(dòng)類場景

          在小紅書應(yīng)用中,滑動(dòng)類場景非常普遍,包括推薦頁的子頻道、個(gè)人頁中的收藏點(diǎn)贊以及用戶自己發(fā)布的筆記,還有搜索結(jié)果頁中的搜索結(jié)果和用戶商品等,這些都是雙列滑動(dòng)場景。這些雙列滑動(dòng)場景占據(jù)了小紅書用戶體驗(yàn)的 90% 到 95%,因此,滑動(dòng)體驗(yàn)的流暢性對(duì)于用戶的整體體驗(yàn)至關(guān)重要。

          為了提升滑動(dòng)場景的流暢性,小紅書采用了 RCP 框架來優(yōu)化網(wǎng)絡(luò)資源的獲取。RCP 是華為提供的一個(gè)系統(tǒng)組件能力,主要解決網(wǎng)絡(luò)資源獲取效率問題。通過 RCP,開發(fā)者可以在需要時(shí)發(fā)起網(wǎng)絡(luò)請(qǐng)求,并自定義資源的寫入地址,如文件或 ArrayBuffer。RCP 負(fù)責(zé)高效地將資源寫入指定位置,而在不需要時(shí),可以取消 RCP 請(qǐng)求,從而優(yōu)化資源管理。

           RCP 的核心能力在于能夠取消請(qǐng)求,并對(duì)弱網(wǎng)場景進(jìn)行了優(yōu)化,其建聯(lián)過程優(yōu)于 HTTP 1.1 或 2.0。基于 RCP,小紅書還應(yīng)用了華為俄研所提供的 Prefetch 方案。Prefetch 方案在瀑布流組件的可見區(qū)變更時(shí),通過 worker 線程(如 prefetched worker)啟動(dòng)資源獲取,當(dāng)不可見時(shí)關(guān)閉,從而優(yōu)化快速滑動(dòng)場景,減少不必要的帶寬消耗。

          在快速滑動(dòng)過程中,有些 item 可能短暫消失,對(duì)于雙端場景,網(wǎng)絡(luò)請(qǐng)求可能已經(jīng)發(fā)出且在途,無法取消,導(dǎo)致帶寬浪費(fèi)。Prefetch 和 RCP 結(jié)合的方式可以優(yōu)化這種快滑場景,防止真正想要看的內(nèi)容出現(xiàn)白塊。Prefetched worker 線程管理多個(gè) RCP 請(qǐng)求,每個(gè)請(qǐng)求都有完整的生命周期。當(dāng)通過 RCP 請(qǐng)求獲取到所需資源時(shí),會(huì)通知主線程,主線程根據(jù)地址加載資源到 Image 組件或占位符 RQI 組件中。

          在小紅書的開發(fā)過程中,我們遇到了一些性能熱點(diǎn)問題,這些問題大多是通過 Code Linter(代碼檢查工具)檢測出來的。由于開發(fā)節(jié)奏快,開發(fā)者在編寫代碼時(shí)可能難以關(guān)注到性能問題,因此需要 CI(持續(xù)集成)檢查工具來輔助檢查。

          常見的性能熱點(diǎn)包括:

          1)在列表場景中頻繁使用的 LadyForEach 組件,需要指定 key 以實(shí)現(xiàn)列表復(fù)用。如果開發(fā)者忘記指定 key,Code Linter 會(huì)報(bào)錯(cuò)提示;

          2)在 onClick 或 onVisible 等函數(shù)中編寫空 callback(回調(diào)函數(shù))。當(dāng)這些空 callback 積累到一定數(shù)量(如幾百個(gè)或上千個(gè))時(shí),可能會(huì)嚴(yán)重拖慢應(yīng)用性能。Code Linter 可以掃描出這類問題;

          3)未使用 TaskPool 處理網(wǎng)絡(luò)資源。例如,Image Bitmap 直接傳遞 URL 進(jìn)行同步加載,當(dāng)網(wǎng)絡(luò)阻塞時(shí)會(huì)導(dǎo)致 UI 線程卡頓;

          4)復(fù)雜的 ETS 組件在列表場景下未實(shí)現(xiàn)重用。未設(shè)置重用的 ETS 組件在列表滾動(dòng)時(shí)需要重新構(gòu)建,非常耗時(shí)。組件嵌套層級(jí)過深也會(huì)導(dǎo)致性能問題。在安卓端,布局檢查器建議容器嵌套不超過四層;

          5)使用 JSON.stringify 進(jìn)行對(duì)象序列化。JSON.stringify 有一定耗時(shí),尤其在處理 100KB 左右的數(shù)據(jù)時(shí),可能需要 10 毫秒左右。Code Linter 會(huì)提示這部分性能問題,但是否需要轉(zhuǎn)異步線程需要開發(fā)者自行判斷;

          6)調(diào)用 Image 的 syncLoad(同步加載)。在某些場景下,如轉(zhuǎn)場動(dòng)畫,需要同步加載 image 以保證連貫性。但如果 image 是非磁盤資源(如網(wǎng)絡(luò)資源),會(huì)導(dǎo)致卡幀。Code Linter 可以掃描出這類問題;

          7)關(guān)于編譯器的優(yōu)化。ETS 組件應(yīng)避免嵌套過深。如果嵌套過深,可以將每層函數(shù)通過系統(tǒng)的 builder param 或 builder 函數(shù)轉(zhuǎn)換。使用 @builder 注解標(biāo)識(shí)的函數(shù)會(huì)在編譯期間與 ETS 代碼整合,從而提高編譯器優(yōu)化效果。

          Code Linter 支持全量掃描和基于 Git DIFF 的增量掃描,但目前華為的 Code Linter 還不能與 Git Prehook 關(guān)聯(lián),導(dǎo)致無法在流水線上自動(dòng)檢查。雖然 CI 檢查階段已有 Code Linter,但本地代碼提交階段仍需手動(dòng)運(yùn)行腳本,無法實(shí)現(xiàn)自動(dòng)檢查。我們正在催促華為解決這一問題。

           

          9、UI 重載場景分幀方案

          在處理 UI 重載場景時(shí),我們采用了一種稱為分幀方案的方法。分幀這個(gè)術(shù)語的含義是,當(dāng)應(yīng)用在一幀內(nèi)無法完成所有繪制工作,或者在多幀內(nèi)都無法完成時(shí),會(huì)導(dǎo)致屏幕卡頓現(xiàn)象。盡管用戶可以看到畫面,但卻無法進(jìn)行滑動(dòng)或操作。在這種情況下,分幀方案就顯得尤為合適。雖然分幀方案可能看起來不是最優(yōu)雅的解決辦法,但它確實(shí)能夠有效地解決性能問題,使應(yīng)用性能達(dá)到預(yù)期標(biāo)準(zhǔn)。分幀方案雖然看似是一種應(yīng)急措施,但它能夠幫助應(yīng)用性能達(dá)標(biāo)。

          分幀方案的流程大致如下:假設(shè)我們有數(shù)據(jù) a、b、c 需要渲染,未采用分幀方案前,數(shù)據(jù) a、b、c 會(huì)同時(shí)到達(dá)并觸發(fā)狀態(tài)變更,進(jìn)而驅(qū)動(dòng)整個(gè) UI 進(jìn)行刷新。這會(huì)導(dǎo)致在一幀內(nèi)需要繪制大量 UI 組件,從而影響應(yīng)用性能。為了解決這個(gè)問題,我們采用分幀方案,將數(shù)據(jù) a、b、c 拆分開,分別在不同的幀中進(jìn)行渲染。例如,數(shù)據(jù) a 在第一幀中渲染完成后,通過調(diào)用宏觀指令讓其進(jìn)入下一階段,然后在下一幀中更新數(shù)據(jù) b,依此類推。

           

          在小紅書的圖文筆記場景中,分幀方案得到了應(yīng)用。當(dāng)用戶在首頁的雙列場景中點(diǎn)擊一篇筆記進(jìn)入筆記詳情頁時(shí),這個(gè)過程涉及到許多組件的加載。我們可以將這些組件拆分成不同的幀,例如幀 a、幀 b 和幀 c。對(duì)于用戶而言,他們通常希望在第一時(shí)間看到整個(gè)大屏的畫面,因此我們會(huì)優(yōu)先在幀 a 中展示大圖。而在幀 b 和幀 c 中,我們?cè)偬幚眄敳繉?dǎo)航欄或底部交互區(qū)等內(nèi)容。通過這種分幀策略,我們能夠確保用戶在第一時(shí)間看到最關(guān)鍵的內(nèi)容,同時(shí)避免了因?yàn)橐淮涡约虞d過多組件而導(dǎo)致的性能問題。

          10、鴻蒙NEXT調(diào)優(yōu)工具

          傳統(tǒng)的主觀工具對(duì)于鴻蒙 OS 的性能分析仍然適用。例如,抖音和小紅書都通過競品分析來進(jìn)行主觀測評(píng)。這種能力主要是通過錄屏來展示整個(gè)流程的耗時(shí)和時(shí)長,特別適合評(píng)估冷啟動(dòng)完成時(shí)延和轉(zhuǎn)場過程的性能。通過錄屏,我們可以逐幀查看用戶從點(diǎn)擊開始到結(jié)束的幀數(shù)和真實(shí)時(shí)長,以此來衡量整個(gè)過程的持續(xù)時(shí)間。

          10.1 鴻蒙性能分析工具:IDE Profiler

          除了主觀工具,我們還可以使用 IDE 提供的性能分析工具,如 Profiler,來分析慢函數(shù)。由于 ArkTS 編程語言框架主要通過 RTS 和 NAPI(原生應(yīng)用接口)進(jìn)行關(guān)聯(lián),因此需要能夠查看 ArkTS 和 NAPI 的整個(gè)堆棧層級(jí)。這與安卓有所不同,因?yàn)楫?dāng) Java 通過 Java Native API 與原生代碼交互時(shí),堆棧并不那么容易查看。

          在小紅書的性能分析中,我們展示了一個(gè)整體線程分析的例子。在左側(cè),可以看到小紅書的主線程(如 com 點(diǎn)開頭的線程)、Daemon 線程、Worker 線程以及 FFRT 線程。FFRT 是一種運(yùn)行函數(shù)流的線程,可以執(zhí)行 TaskPool 上的函數(shù)。在下圖右側(cè),我們可以看到在 RTS 環(huán)境下的分析結(jié)果,其中頂部顯示了 NAPI 調(diào)用,底部則是一些 C++ 函數(shù)。整個(gè)調(diào)用棧和它們的執(zhí)行時(shí)長是通過一種自上而下的視圖來展示的。利用這種視圖,我們可以精確地識(shí)別出哪些慢函數(shù)是造成界面卡頓的原因。

          10.2 性能場景測試工具:DevEco Testing

          DevEco Testing 是一個(gè)性能測試工具,它的功能非常全面,性能測試只是其中的一部分。除了性能測試,它還支持多種測試場景,包括 debug testing。在 debug testing 場景中,用戶可以自定義業(yè)務(wù)場景,監(jiān)測 CPU 的耗時(shí)和負(fù)載、GPU 的耗時(shí)和負(fù)載、設(shè)備發(fā)熱情況以及功耗等問題。

          使用 DevEco Testing 進(jìn)行性能測試的過程如下:首先定義測試場景,然后捕獲主幀數(shù)據(jù)。一旦開始捕獲,就可以觀測到 FPS(幀率)、GPU 負(fù)載以及整體功耗等數(shù)據(jù)。完成性能數(shù)據(jù)捕獲后,工具會(huì)生成一份報(bào)告,為用戶提供了一個(gè)完整的場景分析。不過,目前場景定義還缺乏腳本化能力,需要人工操作輔助。未來,我們期望能夠?qū)崿F(xiàn)場景定義的腳本化配置,類似于自動(dòng)化測試。這樣,就可以通過自動(dòng)化工具,實(shí)現(xiàn)更高效的測試流程。

          11、小結(jié)與展望

          在對(duì)性能場景進(jìn)行優(yōu)化后,我們可以看到顯著的收益。在實(shí)驗(yàn)室環(huán)境下的測試顯示,冷啟動(dòng)時(shí)間可以降低 50%,響應(yīng)時(shí)延可以低于 100 毫秒,完成時(shí)延則保持與雙端持平或更優(yōu)。在流暢性方面,在多場景和重載場景下均實(shí)現(xiàn)了 0 丟幀的成果。需要注意的是,這里的測試是在非重載模式下進(jìn)行的,即沒有同時(shí)運(yùn)行多個(gè)資源密集型應(yīng)用,如《王者榮耀》或《和平精英》等。在這種條件下,我們的核心場景,如冷啟動(dòng)、搜索和個(gè)人頁等,都能夠與雙端完全對(duì)齊。

          展望未來,有幾個(gè)方向:

          1)首先:我們希望能夠在全場景下實(shí)現(xiàn)組件復(fù)用,以最大程度地實(shí)現(xiàn) UI 復(fù)用。這樣可以在多個(gè)業(yè)務(wù)之間的轉(zhuǎn)場或 UI 創(chuàng)建過程中,將不必要的 UI 創(chuàng)建和消耗降到最低。

          2)其次:我們正在考慮代碼延遲加載的 lazy 機(jī)制。華為內(nèi)部可能將其作為通用的解決方案,但在實(shí)施過程中我們發(fā)現(xiàn)了許多問題,例如全 lazy 加載可能會(huì)影響第三方 SDK,如支付寶等,因?yàn)樗鼈兛赡苓M(jìn)行了額外的二進(jìn)制優(yōu)化,導(dǎo)致加載失敗或無法響應(yīng)。因此,我們期望通過代碼延遲加載來實(shí)現(xiàn)持續(xù)治理,但目前它可能還不適合全場景的 lazy import。

          3)最后:我們關(guān)注防劣化問題,即在每個(gè)版本發(fā)布時(shí),我們不希望性能指標(biāo)出現(xiàn)劣化。我們希望能夠在開發(fā)階段就定義劣化指標(biāo)和具體數(shù)據(jù),以防止應(yīng)用劣化。這部分可能需要借助 DevEco Testing 和主觀測評(píng)的方式來實(shí)現(xiàn)。包括我們關(guān)注的指標(biāo),例如冷啟動(dòng)和流暢性等,未來可能會(huì)納入防劣化場景。目前,我們的 CI 環(huán)節(jié)或 RC 環(huán)節(jié),包括流水線的性能管控和代碼 CR 機(jī)制,都能夠規(guī)避這類問題。

          12、相關(guān)資料

          [1] 鴻蒙NEXT官方開發(fā)指南

          [2] 一年擼完百萬行代碼,企業(yè)微信的全新鴻蒙NEXT客戶端架構(gòu)演進(jìn)之路

          [3] 鴻蒙NEXT如何保證應(yīng)用安全:詳解鴻蒙NEXT數(shù)字簽名和證書機(jī)制

          [4] 開源IM聊天程序HarmonyChat:基于鴻蒙NEXT的WebSocket協(xié)議

          [5] 微信純血鴻蒙版正式發(fā)布,295天走完微信14年技術(shù)之路!

          [6] 即時(shí)通訊框架MobileIMSDK的鴻蒙NEXT端詳細(xì)介紹

          [7] 即時(shí)通訊框架MobileIMSDK的鴻蒙NEXT端開發(fā)者手冊(cè)

          [8] 擁抱國產(chǎn)化:轉(zhuǎn)轉(zhuǎn)APP的鴻蒙NEXT端開發(fā)嘗鮮之旅

          [9] 微信Windows端IM消息數(shù)據(jù)庫的優(yōu)化實(shí)踐:查詢慢、體積大、文件損壞等

          [10] 微信技術(shù)分享:揭秘微信后臺(tái)安全特征數(shù)據(jù)倉庫的架構(gòu)設(shè)計(jì)

          [11] IM跨平臺(tái)技術(shù)學(xué)習(xí)(九):全面解密新QQ桌面版的Electron內(nèi)存優(yōu)化實(shí)踐

          [12] 企業(yè)微信針對(duì)百萬級(jí)組織架構(gòu)的客戶端性能優(yōu)化實(shí)踐

          [13] 揭秘企業(yè)微信是如何支持超大規(guī)模IM組織架構(gòu)的——技術(shù)解讀四維關(guān)系鏈

          [14] 微信團(tuán)隊(duì)分享:詳解iOS版微信視頻號(hào)直播中因幀率異常導(dǎo)致的功耗問題

          [15] 微信團(tuán)隊(duì)分享:微信后端海量數(shù)據(jù)查詢從1000ms降到100ms的技術(shù)實(shí)踐

          [16] 大型IM工程重構(gòu)實(shí)踐:企業(yè)微信Android端的重構(gòu)之路

          [17] IM技術(shù)干貨:假如你來設(shè)計(jì)微信的群聊,你該怎么設(shè)計(jì)?

          [18] 微信團(tuán)隊(duì)分享:來看看微信十年前的IM消息收發(fā)架構(gòu),你做到了嗎

          [19] 總是被低估,從未被超越,揭秘QQ極致絲滑背后的硬核IM技術(shù)優(yōu)化

          [20] 首次公開,最新手機(jī)QQ客戶端架構(gòu)的技術(shù)演進(jìn)實(shí)踐

          [21] 大型IM穩(wěn)定性監(jiān)測實(shí)踐:手Q客戶端性能防劣化系統(tǒng)的建設(shè)之路


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

          posted @ 2025-05-19 11:24 Jack Jiang 閱讀(25) | 評(píng)論 (0)編輯 收藏

          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 云霄县| 临朐县| 双城市| 武夷山市| 长白| 平阳县| 余干县| 乌兰县| 甘谷县| 滦南县| 深水埗区| 遵义市| 简阳市| 仁化县| 临邑县| 宝坻区| 东乡族自治县| 阿荣旗| 苍溪县| 河津市| 申扎县| 安达市| 巴塘县| 新巴尔虎左旗| 三穗县| 南通市| 南溪县| 共和县| 东台市| 霍山县| 德保县| 策勒县| 乌鲁木齐县| 陆河县| 耒阳市| 黎平县| 嘉鱼县| 云浮市| 新田县| 湖口县| 安溪县|