NodeJs超長字符串問題處理的詳細分析
問題:對于超大的 string V8不能支持
問題背景
在 Nodejs 計算服務(wù)中,對端上上報的內(nèi)存信息二進制數(shù)據(jù)進行預(yù)處理+緩存時,遇到了一個奇怪的報錯:RangeError: Invalid string length 。根據(jù)該報錯信息,查找得知是字符串長度超過了 node.js 的限制,即 2^29-1 (約 5 億+)個字符。整體流程如圖所示。
關(guān)于 node.js string 的長度上限,主要和 V8 引擎「壓縮指針」技術(shù)有關(guān)。按個人理解,其通過壓縮指向變量的地址(64 位)中固定的 32 位的方式,從而減少引擎的內(nèi)存占用。

代碼細節(jié)
由于需要快速訪問某地址,因此緩存的數(shù)據(jù)結(jié)構(gòu)必須是個對象,即 INodeGraph。具體結(jié)構(gòu)如下:
type IAddr = string;
// 內(nèi)存圖譜
declare interface INodeGraph {
[addr: IAddr]: IParsedNode;
}
// 內(nèi)存節(jié)點信息
declare interface IParsedNode {
addr: IAddr;
// size, nodeType 等輔助信息
parentNodeAddr: IAddr[]; // addr
childNodeAddr: string[]; // addr
edgeMap: {
[addr: IAddr]: {
// 當(dāng)前節(jié)點與父子節(jié)點之間的邊(關(guān)系)的信息
};
};
}我們目的很明確,就是實現(xiàn)這樣一個 js 大對象的持久化存儲,并且能夠方便快速的轉(zhuǎn)回 js object。為解決此問題,首先想到的能否利用 protobuf 替代 JSON 實現(xiàn)持久化??上У氖?protobuf 并不適用于動態(tài) key 的場景,它適用于處理數(shù)組中存儲多個相似結(jié)構(gòu)對象的數(shù)據(jù)結(jié)構(gòu)。
隨后嘗試了減少對象中不必要的信息,即縮短對象的固定 key,例如用「pNode」取代冗長的「parentNodeAddr」。對于一個百萬個鍵值對的 object 而言,雖然犧牲了代碼的可讀性,但在實際的 case 中,能承載的鍵值對數(shù)量大約多了 20%。
事實上回過頭來看,更好的處理方式或許是用另外的 Map 存儲對象的 key。例如 : 將nodeGraph.parentNodeAddr這個 key 最大程度縮短為nodeGraph.p
聲明 const GraphKey = { parentNodeAddr: 'p' } 保存一個 key 的映射,需要訪問某屬性時,使用nodeGraph[GraphKey.parentNodeAddr]
更進一步
上述手段只是治標(biāo)不治本,對于 key 更多的大對象并不能徹底解決問題。因此在不改變項目整體架構(gòu)的前提下(如使用圖數(shù)據(jù)庫/改用 go 開發(fā)等),提出以下兩個最終方案:
方案 1:借助 Node.js C++ Addons 的能力,繞開 js string 的限制,將相關(guān)序列化邏輯交給 C++ 處理,并直接將處理好的引用樹 js object 進行后續(xù)處理。
- 優(yōu)勢:如果能實現(xiàn),性能會獲得優(yōu)先提升;擴展了 Node.js 的能力
- 劣勢:實現(xiàn)難度大;維護可能是個問題
方案 2:生成引用樹緩存時,拆分為多個較小的對象,分別進行序列化和存儲,使用時再合并為一個大對象。
- 優(yōu)勢:無需 C++ 側(cè)開發(fā),難度更??;維護方便
- 劣勢:合并對象需要額外的時間,這一步驟可能會讓未命中緩存時的首次請求更慢

總結(jié)
到此這篇關(guān)于NodeJs超長字符串問題處理的文章就介紹到這了,更多相關(guān)NodeJs字符串問題處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
node.js中的events.EventEmitter.listenerCount方法使用說明
這篇文章主要介紹了node.js中的events.EventEmitter.listenerCount方法使用說明,本文介紹了events.EventEmitter.listenerCount的方法說明、語法、使用實例和實現(xiàn)源碼,需要的朋友可以參考下2014-12-12
Node.js+Express.js+TS實現(xiàn)簡單圖床腳本
在這篇博客文章中,我將介紹如何使用 TypeScript 和 Express 框架來編寫一個簡單的圖床腳本,可以將本地圖片上傳到服務(wù)器,并返回圖片的 URL,這樣,你就可以在 Markdown 文檔中方便地引用圖片,而不用擔(dān)心圖片的存儲和管理問題2023-10-10
node.js實現(xiàn)逐行讀取文件內(nèi)容的代碼
這篇文章主要介紹了node.js實現(xiàn)逐行讀取文件內(nèi)容的代碼,本文還介紹了一個node.js的按行讀取內(nèi)容開源項目,需要的朋友可以參考下2014-06-06
Node.js使用第三方插件nodemailer實現(xiàn)郵件發(fā)送示例
這篇文章主要為大家介紹了Node.js使用第三方插件nodemailer實現(xiàn)郵件發(fā)送示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
NodeJs實現(xiàn)跨域WebSocket即時通訊加強版
這篇文章主要為大家介紹了NodeJs實現(xiàn)跨域WebSocket即時通訊加強版示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11
深入理解nodejs搭建靜態(tài)服務(wù)器(實現(xiàn)命令行)
這篇文章主要介紹了深入理解nodejs搭建靜態(tài)服務(wù)器(實現(xiàn)命令行),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-02-02
node.js中的events.emitter.listeners方法使用說明
這篇文章主要介紹了node.js中的events.emitter.listeners方法使用說明,本文介紹了events.emitter.listeners 的方法說明、語法、接收參數(shù)、使用實例和實現(xiàn)源碼,需要的朋友可以參考下2014-12-12

