分布式Node.js--01-为什么选择分布式

164 阅读3分钟

Node.js是独立的运行时,为了JavaScript代码运行在服务器上,提供了JavaScript语言引擎和一系列API,其中许多允许应用与底层操作系统和外部世界进行通信。

JavaScript的单线程特性

JavaScript与大多数语言类似,是重函数的,一个一个组成功能模块,调用,放入函数栈中,如果不小心写了个无限递归调用,会出现超过最大调用栈的问题。

注意:

通常情况下,不需要担心会出现超过调用栈的问题,V8引擎的可容纳数是15000个

与其它语言不同,JavaScript在应用的生命周期中不会限制自己使用单一的函数调用栈

JavaScript的并发处理:通过Node.js的事件循环处理。

大多数情况下JavaScript应用中不允许在同一时刻出现两个函数调用栈,这意味着应用程序如果需要同时运行多个副本,需要进行应用程序扩展。

在node.js中,方法在将来新的调用中被调用称为异步调用,一个方法调用另一个方法在同一个调用栈中被调用称为同步调用。

node.js底层由C++编写,node.js可以使用多线程运行,其中包括第三方工具libuv,可以处理系统操作、I/O操作和一些第三方模块,只有最上层是用JavaScript编写的。

Node.js事件循环

JavaScript运行在浏览器和JavaScript运行在Node.js这二者都需要实现事件循环,它们的相似之处是都在独立的调用栈中异步执行,不同之处是前者一般用在浏览器单页面应用,后者是运行在服务端。

理解基本的事件循环有利于对整个程序的调度,错误的理解事件循环会非常损耗性能。

事件循环

运行后不会终止,循环的运行,可以控制一系列事件的回调方法何时触发,推动应用程序队列的执行,事件循环相关API提供了JavaScript访问底层C++相关控制。

事件循环的几个阶段

1、轮询(Poll)

轮询阶段会执行I/O回调方法,当主程序启动,这阶段便启动

2、检查(Check)

在这个阶段回调方法会被setImmediate()方法触发执行

3、关闭(Close)

这个阶段通过执行EventEmitter触发关闭的回调方法,例如关闭TCP服务,发送关闭事件,运行关闭这个回调方法

4、定时器(Timers)

这个阶段可以使用setTimeout() 和 setInterval()调整回调时序

5、挂起(Pending)

特殊的系统运行阶段,出现错误情况下会挂起,比如TCP出现连接错误比如解决连接,

小贴士

搭建Node.js应用时,不用在意事件循环的细节,许多情况下都只是工作而已。

不用担心回调方法是否在第一时间被执行

不要在单一栈里面执行过多代码,会导致事件循环的停滞,影响其他方法的调用

Demo--食谱

两部分,第一部分:recipe-API,不能被外部访问,可以被内部的服务或者应用程序访问。

第二部分:web-API公开的服务,可以通过HTTP请求被第三方访问,这部分可以访问recipe-API。

大致结构如下图

producer_http_basic.js

//fastify创建服务
const server = require('fastify')()

const HOST = process.env.HOST || '127.0.0.1'
const PORT = process.env.PORT || 4000

console.log(`work pid =${process.pid}`);

server.get('/recipe/:id', async(req, reply) => {
  console.log(`work pid =${process.pid}`);
  const id = Number(req.params.id)
  if (id !== 42) {
    reply.statusCode = 404
    return {error: 'not found'}
  } 
  return {
    producer_id:process.pid,
    recipe: {
      id, name: "Chicken Tikka Masala",
      steps: "Throw it in a pot...",
      ingredients: [
        { id: 1, name: "Chicken", quantity: "1 lb", },
        { id: 2, name: "Sauce", quantity: "2 cups", }
      ]
    }
  }
})

server.listen(PORT, HOST, () => {
  console.log(`running at http:${HOST}${PORT}`);
})

consumer-http-basic.js

const server = require('fastify')();
const fetch = require('node-fetch'); //2.6版本
const HOST = process.env.HOST || '127.0.0.1'
const PORT = process.env.PORT || 3000
const TARGET = process.env.TARGET || 'localhost:4000'

server.get('/', async() => {
  const req = await fetch(`http://${TARGET}/recipe/42`)
  const producer_data = await req.json()

  return {
    consumer_pid: process.pid,
    producer_data
  }
})

server.listen(PORT, HOST, () => {
  console.log(`Consumer running at http://${HOST}:${PORT}/`);
})

请求3000端口,内部的根请求会请求4000端口,返回结果如下

一个简单的分布式服务器就搭建完成了。