Node.js 分布式架构
发布于 4 年前 作者 lonelyclick 18032 次浏览 最后一次编辑是 3 年前 来自 分享

1.单台服务器上,如何让 Node.js 充分利用多核心 cpu

可以使用 Node.js 的 Cluster 功能

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  // In this case it is an HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);
}

PM2 内置

pm2 start app.js -i max // 支持最多 cpu 核心数运行
pm2 start app.js -i 2 // 支持最多 2 个 cpu 核心运行

另外,使用 docker 容器,能更好的解决该问题,可以考虑弃用 pm2

2.多台服务器上,负载均衡怎么部署

负载均衡实现选型比较:balancerbattle

比较的结论:nginx 和 haproxy 更加成熟,速度更快

3.多个 Node Web Server 之间,如何进行状态共享

  • 对事务要求较高 - 数据库存储 - mysql
  • session,配置项 - 缓存 - redis
  • 图片,二进制文件等 - 文件系统

如果只做一个 Node.js 中间层,后台服务还是 Java 的话,Node.js 最好做成无状态的

PS:首发与 Node.js 分布式架构,欢迎捧场~

8 回复

无状态什么意思

@blackjack 就是多个 server 之间没有共享数据

@lonelyclick stateless是这个意思吗?下面是PM2官方的解释:

We recommend (and you must) write stateless NodeJS apps. Apps that don’t retain any form of local variables or local instances or whatever local. Every data, states, websocket session, session data, must be shared via any kind of database.

http://pm2.keymetrics.io/docs/usage/knowledge/#stateless-apps

无状态,深有体会。 有时候程序越离散,却越稳定。

分享的东西都很不错。 Rest Style API + JWT基本上可以实现无状态的API。

关于无状态: 举一个例子。 情景1:往常我们的设计是一个用户登陆成功就会在服务器上给这个用户创建一个Session文件,记录用户的登录状态,那么下次用户调用一个API的时候我们需要到众多的Session里面找这个用户的Session,判断这个用户当前是否是登陆状态,如果是的话就允许执行,不是就让用户登陆。 情景2:用户访问量变大了,一台服务器撑不住了,那么我部署两台,但是问题来了,用户在A服务器上登陆成功就只会在服务器A上创建Session文件,如果负载均衡将用户的下一个请求发到了服务器B上,那么服务器B发现自己并没有这个用户登陆成功的Session,于是就让用户滚去登陆了,然后用户就开始骂娘~所以为了解决这个问题,以前的方案通常有这几种:一、让两台服务器实时同步Session文件,这样时刻保证两台服务器上都有一份所有Session的Copy;二、把Session存在一个两台服务器共用的数据库中,每个服务器接收到请求都去数据库中查询Session;三、让负载均衡系统按照用户的Session来分配是哪个服务器来处理,用户在A服务器上登陆成功了,负载均衡就永远把这个用户的请求发给A服务器,而不是B。 情景3:想象一下你是淘宝双11的总架构师,大量的、高频的用户请求不亚于DDOS,这样你如果再用情景2的方法你会发现由于API是有状态的,每个API请求都需要查询Session状态信息,Session的查询就成为了及其恐怖的服务短板,以至于你发现500台服务器和1000台服务器的效果一样,甚至还不如500台服务器的性能好(因为短板不在这),当然你也可以继续死抠架构壕堆硬件,但其实使用无状态的设计可以彻底解决这个问题(暂时忽略其他问题)。 所以我们现在有一个愿景,干掉Session,程序中的Session是API的状态,干掉Session就是干掉了API的状态;当然业务是有状态的,我们不可能不验证用户登录状态就允许他操作,那有没有啥方法可以保留业务状态、干掉API状态? 可以呀,把Session放到浏览器上不就好了,但是有问题:Session信息大多是敏感度很高的,存在浏览器上不安全。我们可以把信息加密呀! 我暂时没想到其他的问题,大牛们都考虑过这个,具体可以搜索一下大牛们的分析。 情景4:用户在一台服务器上成功登录,服务器将状态信息压缩加密生成Token放到Response头中返回,浏览器端拿到Token存在Web Storage中,每次请求API都在Request头中携带这个Token,任意一个服务器收到这个请求直接将Token解密还原成状态信息,验证权限和处理请求,把更新后的状态信息重新压缩加密成Token返回给浏览器端。。。

除了能解决情景3的问题,无状态设计还有一个很爽的地方,就是服务的性能是随着服务器的数量的增加而倍数增加的,500台服务器就是500倍性能,1000台服务器就是1000倍性能,再有性能问题就肯定是公共资源的性能问题了,比如业务数据库的性能、Cache的性能、底层公共服务的性能、网速等等。。。

当然服务器架构是个很复杂的问题,包括特别多其他问题,无状态设计只是解决了其中一个或几个。但你没遇到这些问题也没必要用无状态设计,因为毕竟多一些设计就要多一些开发成本,而且对Token的加密和解密的操作也比较消耗CPU资源。。。没有最完美的设计,只有最合适的设计。

我们就在用无状态设计,用的是云服务器,经过多次的实验和压测表明,云服务器的CPU真TM慢,对于我们的服务来说,8台1核的服务器每台跑单个服务,比2台4核的服务器分别跑4个Cluster(或就是4个独立Node进程独立端口)的性能要好,可能是多种因素影响的结果吧,但是用了弹性策略后根据压力动态买和释放服务器让我们省下了一半的钱。。。 另外鄙人不才,云服务器上各种搞Nginx做负载均衡压测数据很烂,可能配置有问题?不费那个劲了,用了第三方负载均衡服务,别人搞了那么多年总比自己搞得好,压测结果很好看~

回到顶部