深入了解Nodejs Buffer的使用

JavaScript 起初为浏览器而设计,没有读取或操作二进制数据流的机制。Buffer类的引入,则让NodeJS拥有操作文件流或网络二进制流的能力。

Buffer基本概念

Buffer 对象的内存分配不是在V8的堆内存中,而是Node在C++层面进行内存申请,可以理解为在内存中单独开辟了一部分空间,但是使用时分配内存则是由Node层面完成的,释放也是由Node中v8的gc机制自动控制。Buffer基本操作,这里不在赘述,官方文档很详细。

Buffer性能对比

通常,网络传输中,都需要将数据转换为Buffer。下面做一个性能对比实验。

1.使用纯字符串返回给客户端

const http = require('http');

let hello = ''
for (var i = 0; i < 10240; i++) {
  hello += "a";
}

console.log(`Hello:${hello.length}`)
// hello = Buffer.from(hello);

http.createServer((req, res) => {
  res.writeHead(200);
  res.end(hello);
}).listen(8001);

使用ab -c 200 -t 100 http://127.0.0.1:8001/命令来进行性能测试,发起200个并发客户端

1.png

使用字符串,QPS可以达到4019.70,传输率为40491.45KB每秒。

2.使用Buffer。将字符串转换为Buffer对象,再发给客户端。

const http = require('http');

let hello = ''
for (var i = 0; i < 10240; i++) {
  hello += "a";
}

console.log(`Hello:${hello.length}`)
hello = Buffer.from(hello);

http.createServer((req, res) => {
  res.writeHead(200);
  res.end(hello);
}).listen(8001);

取消Buffer转换的注释,同样使用ab -c 200 -t 100 http://127.0.0.1:8001/测试,同样发起200个并发客户端

2.png

使用Buffer,QPS达到7130.05,传输率为71822.74KB每秒。
性能是原来的177%,极大的节省了服务器资源。
上面这个对比示例参考于《深入浅出Node JS》。

那么问题来了,为什么会有这么大的性能提升呢?

道理其实很简单,在NodeJS中,进行http传输时,若返回的类型为string,则会将string类型的参数,转换为Buffer,通过NodeJS中的Stream流,一点点的返回给客户端。如果我们直接返回Buffer类型,就没有了转换操作,直接返回,减少了CPU的重复使用率。这一部分逻辑见Node源码https://github.com/nodejs/node/blob/v10.9.0/lib/_http_outgoing.js#L612

在上面性能对比示例中,返回string时,每次请求都需要将string装换成Buffer返回;而直接返回Buffer时,这个Buffer是我们启动服务时就存放在内存中的,每次请求直接返回内存中的Buffer即可,因此Buffer使用前后QPS提升了很多。

因此,我们在写业务代码时,部分资源可以预先转换为Buffer类型(如js、css等静态资源文件),直接返回buffer给客户端,再比如一些文件转发的场景,将获取到的内容储存为Buffer直接转发,避免额外的转换操作。

参考资料:

本文转载自:https://segmentfault.com/a/1190000016056466

更多web前端开发知识,请查阅 HTML中文网 !!

Image placeholder
前端答疑
未设置
  17人点赞

没有讨论,发表一下自己的看法吧

推荐文章
了解Node.js中的流(Stream)

Node.js中的流(Stream)是出了名的难用甚至是难以理解。用DominicTarr的话来说:“流是Node中最好的,也是最容易被误解的想法。”即使是Redux的创建者和React.js的核心团

Cache 和 Buffer 的区别在哪里?

Cache和Buffer是两个不同的概念,简单的说,Cache是加速“读”,而buffer是缓冲“写”,前者解决读的问题,保存从磁盘上读出的数据,后者是解决写的问题,保存即将要写入到磁盘上的数据。在很

来福州,深入了解华为的“数字平台”

   数字化转型已成为几乎所有企业的必经之路,然而在相关战略的制定与真正落地的过程中,企业总是不可避免地会遇到一些困惑与挑战。  企业数字化转型的挑战——尤其对于许多传统行业的企业而言,主要体现在:A

深入了解JavaScript async/await !

Asyncfunctions让我们以async这个关键字开始。它可以被放置在任何函数前面,像下面这样:asyncfunctionf(){ return1; }在函数前面的「async」这个单词表达了一

pymysql fetchone () , fetchall () , fetchmany ()

最近在用python操作mysql数据库时,碰到了下面这两个函数,标记一下: 1.定义 1.1fetchone(): 返回单个的元组,也就是一条记录(row),如果没有结果则返回None 1.2fet

nodejs为什么叫node?

nodejs为什么叫node?最开始NodeJs作者Dahl取的名字叫web.js,仅仅是一个web服务器,是Apache和其他“阻塞”服务器的替代方案。但是该项目很快就超出了他最初的Web服务器库的

学习 nodejs+mongodb+koa2 写接口(一) 环境布置

一.环境准备最近在学用Nodejs写后端接口,了解到koa2是Nodejs的一个框架。可以快速开发后端接口,同时也能更快熟悉Nodejs以下是所需的环境node  v7.6+,可以用nvm或者n安装指

学习 nodejs+mongodb+koa2 写接口(二) koa2教程入门

一.hellokoa安装koa2#初始化package.json npminit #安装koa2 npminstallkoahelloworld代码constKoa=require('koa') c

angular的注入器是什么?

在依赖注入和依赖查找的时候注入器和提供器就需要使用。接下来就简单介绍一下注入器和提供器。注入器Angular提供的类,一般不需调用,会自动通过组件的构造函数注入。1.当一个提供器提供在模块中时,他是对

leveldb源代码分析系列1.1:memtable中comparator的实现

leveldb中memtable封装了一个skiplist用来存储真正的数据,跳跃列表的实现一定需要定义存储项的序关系,而在leveldb中这个序关系通过comparator相关类来实现。leveld

Disruptor的简单介绍与应用

前言最近工作比较忙,在工作项目中,看了很多人都自己实现了一套数据任务处理机制,个人感觉有点乱,且也方便他人的后续维护,所以想到了一种数据处理模式,即生产者、缓冲队列、消费者的模式来统一大家的实现逻辑。

怎么查看nodejs是否安装?

查看nodejs是否安装的方法:1、cmd执行命令开始菜单搜索框输入cmd,点击第一个结果,打开cmd命令行。在cmd命令行中,输入node-v并执行,显示node版本,证明安装成功。例如我的版本是1

如何查看nodejs版本号?

在windows上查看nodejs的版本号想要在电脑上查node版本号,可以打开cmd命令行,使用命令来查看。1、在开始菜单的搜索框中输入cmd,点击cmd.exe打开cmd命令窗口。2、使用命令查看

nodejs都能做什么?

Node对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好。V8引擎执行Javascript的速度非常快,性能非常好。Node是一个基于ChromeJavaScript运行时

nodejs怎么解析less?

nodejs怎么解析less?在cmd中使用npm中的less模块来解析less。npm(全称NodePackageManager,即“node包管理器”)是以JavaScript编写的软件包管理系统

nodejs怎么运行项目?

nodejs怎么运行项目?想要运行nodeJS项目,只需要安装好node的环境就可以了,不需要其他的配置。使用cmd命令,打开window窗口,输入node-v,如果运行的结果是nodeJS的一个版本

nodejs调用外部接口

前言在日让的工作开发中,我们不仅仅要使用node来封装提供一些http接口,也会在node服务中调用一些第三方的HTTP接口,那么如何操作?request安装依赖npminstallrequest-S

AI赌神升级!无惧bluff,6人局德扑完胜世界冠军,训练只用了8天

大数据文摘出品作者:曹培信、宁静2017年年初,BrainvsAI的德州扑克人机大战在卡耐基梅隆大学(CMU)落幕,由4名人类职业玩家组成的人类大脑不敌人工智能程序Libratus。获胜后人类还遭到了

《Effective Go》中文翻译召集

《EffectiveGo》是学习Go编程必读的官方文档,内容包含对Go语法、技巧、编码风格等说明。文档永久地址:《高效的Go编程》欢迎正在学习Go的同学参与。如何参与?进入文档页面《高效的Go编程》

[憨读记 之 Effective Java] 01-用静态工厂方法代替构造器

书的第一章是创建和销毁对象,接下来的几篇也都是围绕这个展开。本篇对应书中的第一条:用静态工厂方法代替构造器。什么是静态工厂方法先看一个例子,Boolean类中有如下构造器publicBoolean(b

在 Golang 中使用 Protobuf

本教程使用proto3版本的protocolbuffer语言,提供了一个基本的在Go程序中使用protocolbuffer的介绍。通过创建一个简单的示例应用程序,向你展示如何在.proto文件中定义消

Go语言高级编程_4.2 Protobuf

4.2Protobuf Protobuf是ProtocolBuffers的简称,它是Google公司开发的一种数据描述语言,并于2008年对外开源。Protobuf刚开源时的定位类似于XML、JSON

Go语言高级编程_4.6 gRPC和Protobuf扩展

4.6gRPC和Protobuf扩展 目前开源社区已经围绕Protobuf和gRPC开发出众多扩展,形成了庞大的生态。本节我们将简单介绍验证器和REST接口扩展。 4.6.1验证器 到目前为止,我们接

Go语言高级编程_4.7 pbgo: 基于Protobuf的框架

4.7pbgo:基于Protobuf的框架 pbgo是我们专门针对本节内容设计的较为完整的迷你框架,它基于Protobuf的扩展语法,通过插件自动生成rpc和rest相关代码。在本章第二节我们已经展示

Protobuf 生成 Go 代码指南

这个教程中将会描述protocolbuffer编译器通过给定的.proto会编译生成什么Go代码。教程针对的是proto3版本的protobuf。在阅读之前确保你已经阅读过Protobuf语言指南。编