node. js and Threadlocal

Source: Internet
Author: User
Tags node server

The argument for the threadlocal variable comes from Java, a solution for concurrency problems in multithreaded models.
The threadlocal variable, as a local variable within a thread, can remain independent under multiple threads, and it exists in
During the life cycle of a thread, data can be shared between multiple modules during the threads run phase. So, the threadlocal variable
And how does it relate to node. js?

Node model

Node's running model does not need to be said: " event loop + asynchronous execution ", but node development engineers are more interested in points
Mostly concentrated on the "coding mode", that is, asynchronous code synchronous writing, thereby proposing a number of solutions to solve the callback hell:

    • Yield
    • Thunk
    • Promise
    • Await

But if you leap from the microscopic perspective of the code execution process, the macro view of the node server processing each HTTP request will
Found that this is actually a multi-threaded Web server another embodiment , although the design is not as intuitive as the multithreaded model. In a single-core CPU
The node server can handle only one request at a time, but when node executes the asynchronous call in the current request, it will "break" into the next
The event loop processes another request until the last requested asynchronous task event triggers the execution of the corresponding callback, continuing with the subsequent logic of the request.
This is somewhat similar to the CPU's time-slice preemption mechanism, the micro-order execution, macro-synchronous execution.

Node "simulates" the common multithreading logic in a single-process single-threaded (JS thread of execution), although it is not available in a single node process
Leverages CPU multi-core and Hyper-threading features, but avoids critical resource synchronization and threading contexts in multithreaded models
Switching issues, while memory resource overhead is relatively small, so use node to develop Web services under I/O intensive business
There are often unexpected benefits.

In node development, however, you need to track the call link for each request, by getting the Traceid field of the request header at each level
Call link, including "HTTP requests, Dubbo calls, DAO operations, Redis, and log management."
By tracing the Traceid, we can analyze all the intermediate links through the request, evaluate the delay and bottleneck of each link,
Easier performance tuning and troubleshooting.

So, how to get the relevant traceid in the business code without intrusion? This leads to the threadlocal variable of this article.

Traditional log-tracking mode

Manual delivery of Traceid to the log middleware is required:

var koa = require('koa');var app =  new koa();var Logger = {    info(msg,traceId){        console.log(msg,traceId);    }};let business = async function(ctx){    let v = await new Promise((res)=>{        setTimeout(()=>{            Logger.info('service执行结束',ctx.request.headers['traceId'])            res(123);        },1000);    });    ctx.body = 'hello world';    Logger.info('请求返回',ctx.request.headers['traceId'])};app.use(async(ctx,next)=>{    ctx.request.headers['traceId'] = Date.now() + Math.random();    await next();});app.use(async(ctx,next)=>{    await business(ctx);});app.listen(8080);

In the business transaction function, log management is performed at the end of service execution and after the body returns, while manually
The transfer request header Traceid to the log module, which facilitates the tracking of the link in the relevant system.

At present, the code can not normalize the log interface, but also caused great trouble to the developers. For business developers, they
Should not care about the link tracking, and the current code is directly into the business code, this function should be by the log module
Logger, but how does the logger module, which has no connection to the request context, get the traceid of each request?

This relies on the threadlocal variable in node. js. The article begins by mentioning that the threadlocal variable under multithreading is associated with
Each thread's life cycle corresponds, if implemented under the "single-threaded + asynchronous call + Event loop" feature of node. js
Similar to the threadlocal variable, it is not possible to get the corresponding threadlocal variable when the asynchronous callback is executed for each request.
Get contextual information about it?

Node implementation of Threadlocal

It is not complicated to implement the intermediate link request tracing of the Web server simply, using global variable map and unique identity through each request
Stores the context information and, when executed to the next asynchronous call to the request, obtains the threadlocal bound to the request by the global map
variables, but this is a speculative behavior at the application level, and is a simple implementation of tight coupling with requests.

The most thorough solution is to implement a stack frame at the node application layer, rewrite all asynchronous functions within the stack frame, and add individual
Hooks perform in each life cycle of an asynchronous function, implementing the mapping of the asynchronous function execution context to the stack frame, which is the most
Thorough threadlocal implementations, rather than just staying in the mapping process with HTTP requests.

At present, the Zone.js Library realizes the controllable encoding of node application layer stack frame, and can be bound at the stage of the stack frame survival.
Related data, we can use this feature to implement threadlocal variables similar to multithreading.

Our goal is to achieve non-intrusive writing of business code with link tracking, as follows:

app.use(async(ctx,next)=>{    let v = await new Promise((res)=>{        setTimeout(()=>{            Logger.info('service执行结束')            res(123);        },1000);    });    ctx.body = 'hello world';    Logger.info('请求返回')});

In comparison, Logger.info does not need to pass the Traceid variable manually, which is obtained by the log module by accessing the threadlocal variable.

With the Create zone (corresponding to stack frame) feature provided by Zone.js, we can not only get the current request (similar to a single thread under multithreading).
Threadlocal variable, you can also get information about the previous request.

Require (' zone.js '), var koa = require (' KOA '), var app = new Koa (), var Logger = {info (msg) {Console.log (msg,zone.    Current.get (' Traceid ')); }};var koazoneproperties = {Requestcontext:null};var Koazone = Zone.current.fork ({name: ' KOA ', Properties:koa            Zoneproperties}); let business = Async function (CTX) {Let V = await new Promise (res) =>{setTimeout (() =>{        Logger.info (' Service execution end ') res (123);    },1000);    });    Ctx.body = ' Hello World '; Logger.info (' request return ')};koazone.run (() =>{app.use (Async (Ctx,next) =>{console.log (koazone.get (' RequestContext ')        )) ctx.request.headers[' traceid '] = Date.now ();    await next ();        });                App.use (Async (Ctx,next) =>{await new Promise ((resolve) =>{Let Koamidzone = Koazone.fork ({                Name: ' Koamidware ', properties: {traceid:ctx.request.headers[' traceid '] }}). Run (Async () =&Gt                {//Save request context to Parent zone Koazoneproperties.requestcontext = CTX;                Await business (CTX);            Resolve ();        });    });        }); App.listen (8080);});

Created two zones (stack frames) with inheritance, Koazone's RequestContext property stores the context information for the previous request;
The Traceid property of Koamidzone stores the Traceid variable, which is a threadlocal variable.
Zone.current.get (' Traceid ') in the Logger.info to get the current "thread"
Threadlocal variable without the developer manually passing the Traceid variable.

With regard to other uses of zone.js, readers are interested in self-study. This paper mainly uses Zone.js to save an execution stack frame
The execution context of multiple asynchronous functions within a map of the specific data (that is, the threadlocal variable).

Description

At present, this model has been used online to track all levels of links, middleware including Dubbo client, Dubbo provider,
The configuration center relies on the threadlocal variable for data transmission and invocation, so it can be used with confidence.

node. js and Threadlocal

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.