欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Node綁定全局TraceID的實現(xiàn)方法

 更新時間:2019年11月14日 08:33:50   作者:Jiahonzheng  
這篇文章主要介紹了Node 綁定全局 TraceID的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

問題描述

由于Node.js的 單線程模型 的限制,我們無法設(shè)置全局 traceid 來聚合請求,即 實現(xiàn)輸出日志與請求的綁定 。如果不實現(xiàn)日志和請求的綁定,我們難以判斷日志輸出與對應(yīng)用戶請求的對應(yīng)關(guān)系,這對 線上問題排查 帶來了困難。

例如,在用戶訪問 retrieveOne API 時,其會調(diào)用 retrieveOneSub 函數(shù),如果我們想在 retrieveOneSub 函數(shù)中輸出當(dāng)前請求對應(yīng)的學(xué)生信息,是繁瑣的。在 course-se 現(xiàn)有實現(xiàn)下,我們針對此問題的解決方法是:

  1. 方案1:在調(diào)用 retrieveOneSub 函數(shù)的父函數(shù),即 retrieveOne 內(nèi),對 paramData 進(jìn)行 解構(gòu) ,輸出學(xué)生相關(guān)信息,但該方案 無法細(xì)化日志輸出粒度 。
  2. 方案2:修改 retrieveOneSub 函數(shù)簽名,接收 paramData 為其參數(shù),該方案 能確保日志輸出粒度 ,但 在調(diào)用鏈很深的情況下,需要給各函數(shù)修改函數(shù)簽名 ,使其接收 paramData ,頗具工作量,并不太可行。
/**
 * 返回獲取一份提交的函數(shù)
 * @param {ParamData}  paramData
 * @param {Context}   ctx
 * @param {string}   id
 */
export async function retrieveOne(paramData, ctx, id) {
 const { subModel } = paramData.ce;
 const sub_asgn_id = Number(id);

 // 通過 paramData.user 獲取 user 相關(guān)信息,如 user_id ,
 // 但無法細(xì)化日志輸出粒度,除非修改 retrieveOneSub 的簽名,
 // 添加 paramData 為其參數(shù)。
 const { user_id } = paramData.user;
 console.log(`${user_id} is trying to retreive one submission.`);
 // 調(diào)用了 retrieveOneSub 函數(shù)。
 const sub = await retrieveOneSub(sub_asgn_id, subModel);
 const submission = sub;
 assign(sub, { sub_asgn_id });
 assign(paramData, { submission, sub });
 return sub;
}

/**
 * 從數(shù)據(jù)庫獲取一份提交
 * @param {number}   sub_asgn_id
 * @param {SubModel}   model
 */
async function retrieveOneSub(sub_asgn_id, model) {
 const [sub] = await model.findById(sub_asgn_id);
 if (!sub) {
  throw new ME.SoftError(ME.NOT_FOUND, '找不到該提交');
 }
 return sub;
}

Async Hooks

其實,針對以上的問題,我們還可以從 Node 的 Async Hooks 實驗性 API 方面入手。在 Node.js v8.x 后,官方提供了可用于 監(jiān)聽異步行為 的 Async Hooks(異步鉤子)API 的支持。

Async Scope

Async Hooks 對每一個(同步或異步)函數(shù)提供了一個 Async Scope ,我們可調(diào)用 executionAsyncId 方法獲取當(dāng)前函數(shù)的 Async ID ,調(diào)用 triggerAsyncId 獲取當(dāng)前函數(shù)調(diào)用者的 Async ID。

const asyncHooks = require("async_hooks");
const { executionAsyncId, triggerAsyncId } = asyncHooks;

console.log(`top level: ${executionAsyncId()} ${triggerAsyncId()}`);

const f = () => {
 console.log(`f: ${executionAsyncId()} ${triggerAsyncId()}`);
};

f();

const g = () => {
 console.log(`setTimeout: ${executionAsyncId()} ${triggerAsyncId()}`);
 setTimeout(() => {
  console.log(`inner setTimeout: ${executionAsyncId()} ${triggerAsyncId()}`);
 }, 0);
};

setTimeout(g, 0);
setTimeout(g, 0);

在上述代碼中,我們使用 setTimeout 模擬一個異步調(diào)用過程,且在該異步過程中我們調(diào)用了 handler 同步函數(shù),我們在每個函數(shù)內(nèi)都輸出其對應(yīng)的 Async ID 和 Trigger Async ID 。執(zhí)行上述代碼后,其運行結(jié)果如下。

top level: 1 0
f: 1 0
setTimeout: 7 1    
setTimeout: 9 1    
inner setTimeout: 11 7
inner setTimeout: 13 9

通過上述日志輸出,我們得出以下信息:

  • 調(diào)用同步函數(shù),不會改變其 Async ID ,如函數(shù) f 內(nèi)的 Async ID 和其調(diào)用者的 Async ID 相同。
  • 同一個函數(shù),被不同時刻進(jìn)行異步調(diào)用,會分配至不同的 Async ID ,如上述代碼中的 g 函數(shù)。

追蹤異步資源

正如我們前面所說的,Async Hooks 可用于追蹤異步資源。為了實現(xiàn)此目的,我們需要了解 Async Hooks 的相關(guān) API ,具體說明參照以下代碼中的注釋。

const asyncHooks = require("async_hooks");

// 創(chuàng)建一個 AsyncHooks 實例。
const hooks = asyncHooks.createHook({
 // 對象構(gòu)造時會觸發(fā) init 事件。
 init: function(asyncId, type, triggerId, resource) {},
 // 在執(zhí)行回調(diào)前會觸發(fā) before 事件。
 before: function(asyncId) {},
 // 在執(zhí)行回調(diào)后會觸發(fā) after 事件。
 after: function(asyncId) {},
 // 在銷毀對象后會觸發(fā) destroy 事件。
 destroy: function(asyncId) {}
});

// 允許該實例中對異步函數(shù)啟用 hooks 。
hooks.enable();

// 關(guān)閉對異步資源的追蹤。
hooks.disable();

我們在調(diào)用 createHook 時,可注入 init 、 before 、 after 和 destroy 函數(shù),用于 追蹤異步資源的不同生命周期 。

全新解決方案

基于 Async Hooks API ,我們即可設(shè)計以下解決方案,實現(xiàn)日志與請求記錄的綁定,即 Trace ID 的全局綁定。

const asyncHooks = require("async_hooks");
const { executionAsyncId } = asyncHooks;

// 保存異步調(diào)用的上下文。
const contexts = {};

const hooks = asyncHooks.createHook({
 // 對象構(gòu)造時會觸發(fā) init 事件。
 init: function(asyncId, type, triggerId, resource) {
  // triggerId 即為當(dāng)前函數(shù)的調(diào)用者的 asyncId 。
  if (contexts[triggerId]) {
   // 設(shè)置當(dāng)前函數(shù)的異步上下文與調(diào)用者的異步上下文一致。
   contexts[asyncId] = contexts[triggerId];
  }
 },
 // 在銷毀對象后會觸發(fā) destroy 事件。
 destroy: function(asyncId) {
  if (!contexts[asyncId]) return;
  // 銷毀當(dāng)前異步上下文。
  delete contexts[asyncId];
 }
});

// 關(guān)鍵!允許該實例中對異步函數(shù)啟用 hooks 。
hooks.enable();

// 模擬業(yè)務(wù)處理函數(shù)。
function handler(params) {
 // 設(shè)置 context ,可在中間件中完成此操作(如 Logger Middleware)。
 contexts[executionAsyncId()] = params;
 
 // 以下是業(yè)務(wù)邏輯。
 console.log(`handler ${JSON.stringify(params)}`);
 f();
}

function f() {
 setTimeout(() => {
  // 輸出所屬異步過程的 params 。
  console.log(`setTimeout ${JSON.stringify(contexts[executionAsyncId()])}`);
 });
}

// 模擬兩個異步過程(兩個請求)。
setTimeout(handler, 0, { id: 0 });
setTimeout(handler, 0, { id: 1 });

在上述代碼中,我們先聲明了 contexts 用于存儲每個異步過程中的上下文數(shù)據(jù)(如 Trace ID),隨后我們創(chuàng)建了一個 Async Hooks 實例。我們在異步資源初始化時,設(shè)置當(dāng)前 Async ID 對應(yīng)的上下文數(shù)據(jù),使得其數(shù)據(jù)為調(diào)用者的上下文數(shù)據(jù);我們在異步資源被銷毀時,刪除其對應(yīng)的上下文數(shù)據(jù)。

通過這種方式,我們只需在一開始設(shè)置上下文數(shù)據(jù),即可在其引發(fā)的各個過程(同步和異步過程)中,獲得上下文數(shù)據(jù),從而解決了問題。

執(zhí)行上述代碼,其運行結(jié)果如下。根據(jù)輸出日志可知,我們的解決方案是可行的。

handler {"id":0}
handler {"id":1}
setTimeout {"id":0}
setTimeout {"id":1}

不過需要注意的是,Async Hooks 是 實驗性 API , 存在一定的性能損耗 ,但 Node 官方正努力將其變得生產(chǎn)可用。因此, 在機(jī)器資源足夠的情況下,使用本解決方案,犧牲部分性能,換取開發(fā)體驗。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • PHP和NodeJs開發(fā)的應(yīng)用如何共用Session

    PHP和NodeJs開發(fā)的應(yīng)用如何共用Session

    這篇文章主要介紹了PHP和NodeJs開發(fā)的應(yīng)用如何共用Session的相關(guān)資料及思路,需要的朋友可以參考下
    2015-04-04
  • express結(jié)合nodejs開啟服務(wù)示例模版

    express結(jié)合nodejs開啟服務(wù)示例模版

    這篇文章主要為大家展現(xiàn)了express結(jié)合nodejs開啟服務(wù)的代碼示例模版,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • 在Nodejs中實現(xiàn)一個緩存系統(tǒng)的方法詳解

    在Nodejs中實現(xiàn)一個緩存系統(tǒng)的方法詳解

    在數(shù)據(jù)庫查詢遇到瓶頸時,我們通??梢圆捎镁彺鎭硖嵘樵兯俣?同時緩解數(shù)據(jù)庫壓力,在一些簡單場景中,我們也可以自己實現(xiàn)一個緩存系統(tǒng),避免使用額外的緩存中間件,這篇文章將帶你一步步實現(xiàn)一個完善的緩存系統(tǒng),需要的朋友可以參考下
    2024-03-03
  • Nodejs sublime text 3安裝與配置

    Nodejs sublime text 3安裝與配置

    Sublime Text是一個輕量、簡潔、高效、跨平臺的編輯器,方便的配色以及兼容vim快捷鍵等各種優(yōu)點博得了很多前端開發(fā)人員的喜愛!Sublime Text這款程序員必備代碼編輯器,幾乎每位程序員提到Sublime Text都是贊不絕口!它體積小巧,無需安裝,綠色便攜
    2014-06-06
  • 分享五個Node.js開發(fā)的優(yōu)秀實踐?

    分享五個Node.js開發(fā)的優(yōu)秀實踐?

    這篇文章主要介紹了分享五個Node.js開發(fā)的優(yōu)秀實踐,文章圍繞主題展開詳細(xì)的分享內(nèi)容,需要的小伙伴可以參考一下,希望對你的工作有所幫助
    2022-04-04
  • nodejs文件操作模塊FS(File System)常用函數(shù)簡明總結(jié)

    nodejs文件操作模塊FS(File System)常用函數(shù)簡明總結(jié)

    這篇文章主要介紹了nodejs文件操作模塊FS(File System)常用函數(shù)簡明總結(jié),對FS模塊的大部份異步函數(shù)做了介紹,而且用中文注釋,這下用起來方便了,需要的朋友可以參考下
    2014-06-06
  • Nodejs 獲取時間加手機(jī)標(biāo)識的32位標(biāo)識實現(xiàn)代碼

    Nodejs 獲取時間加手機(jī)標(biāo)識的32位標(biāo)識實現(xiàn)代碼

    本文給大家分享nodejs獲取時間加手機(jī)標(biāo)識的32位標(biāo)識實現(xiàn)代碼,非常不錯,具有參考借鑒價值,需要的朋友參考下
    2017-03-03
  • Node.js 使用 cors 中間件解決跨域問題小結(jié)

    Node.js 使用 cors 中間件解決跨域問題小結(jié)

    cors 是 Express 的一個第三方中間件,通過安裝和配置 cors 中間件,可以很方便地解決跨域問題,本文介紹Node.js 使用 cors 中間件解決跨域問題,感興趣的朋友一起看看吧
    2024-01-01
  • Node.js API詳解之 os模塊用法實例分析

    Node.js API詳解之 os模塊用法實例分析

    這篇文章主要介紹了Node.js API詳解之 os模塊用法,結(jié)合實例形式分析了Node.js API中os模塊基本功能、原理、用法及操作注意事項,需要的朋友可以參考下
    2020-05-05
  • Nodejs學(xué)習(xí)筆記之Global Objects全局對象

    Nodejs學(xué)習(xí)筆記之Global Objects全局對象

    本文是NodeJS學(xué)習(xí)筆記系列文章的第二篇,從這篇開始我們就根據(jù)官方文檔來逐個學(xué)習(xí)下NodeJS的各個模塊,首先我們來學(xué)習(xí)下Global
    2015-01-01

最新評論