从源码分析Node的Cluster模块

前段时间,公司的洋彬哥老哥遇到一个问题,大概就是本机有个node的http服务器,但是每次请求这个服务器的端口返回的数据都报错,一看返回的数据根本不是http的报文格式,然后经过一番排查发现是另外一个服务器同时监听了http服务器的这个端口。这个时候洋彬老哥就很奇怪,为啥我这个端口明明使用了,却还是可以启动呢?这个时候我根据以前看libuv源码的经验解释了这个问题,因为uv__tcp_bind中,对socket会设置SO_REUSEADDR选项,使得端口可以复用,但是tcp中地址不能复用,因为那两个监听虽然是同一个端口,但是地址不同,所以可以同时存在。这个问题让我不禁想到了之前看一篇文章里有人留言说这个选项是cluster内部复用端口的原因,当时没有细细研究以为说的是SO_REUSEPORT也就没有细想,但是这次因为这个问题仔细看了下结果是设置的SO_REUSEADDR选项,这个选项虽然能复用端口,但是前提是每个ip地址不同,比如可以同时监听'0.0.0.0'和'192.168.0.

  • pagecao
9 min read

对Node.js中Buffer的简单理解

背景 二进制数据 字符集 字符编码 Stream流 Buffer Buffer的一些API 背景 Node.js中有一些我们平常很少直接用到的核心模块,比如Buffer、Stream等。记得我来公司面试的时候,洋彬大佬问我关于这些核心模块的问题,我只能在一边瑟瑟发抖。什么Buffer、Stream、二进制数据之类的概念对于我们这些非计算机专业毕业的同学来说就是——这TM是啥。大多数的教程都是教我们怎么开发WEB应用,讲到这些概念时就直接跳过了,然后告诉你“没事,你用不上的,呵呵”,为了让自己遇到这类问题心里不那么慌,我觉得还是非常有必要了解一下。 这篇文章不会讲很底层的东西(主要原因还是我不懂),如果要了解底层的话,可以看下Page大佬这篇关于Buffer的内存分配、回收的文章(Node中Buffer的初始化及回收)

  • Zhu Kang
8 min read

Node中Buffer的初始化及回收

node中的buffer相信大家都不会陌生,毕竟这个东西是node的核心之一,我们读写文件,网络请求都会用到它。不过,之前我虽然一直在用这个东西,却没关心过他的实现,只知道通过buffer分配的内存占用的不是v8的heap上的内存,存在于newSpace和oldSpace之外,所以可以用它来进行一些大段内存的操作,但是却从没关心过它是如何分配内存,又是什么时候被回收这些问题。在一次有幸跟我神交已久的一位老哥的交流中,提起了这个问题才意识到自己这一块上确实存在盲区,于是专程去node源码(v8.1.4)中去寻找了一番,也算是颇有所得,所以专门写一篇文章记录和分享一下。 buffer的初始化 首先,我们可以从lib/buffer.js中,我们可以通过Buffer函数的代码往下追溯,发现Buffer的生成都是通过new FastBuffer来生成的,而FastBuffer我们可以看到代码中是这样实现的: class FastBuffer extends

  • pagecao
4 min read

Node子进程async/await方法不正常执行的思考和解决

前段时间,我做了一个node模块node-multi-worker ,希望通过这个模块让node能够脱离单线程的限制,具体的使用可以看一下上面的链接。其思路就是注册任务后,分出子进程,然后在主进程需要执行任务时,向reactor子进程发送命令,而reactor收到命令后分配到worker子进程在执行完成后返回结果到主进程。这篇文章主要是为了跟大家分享一下我在开发过程中,遇到的一个问题,如何解决以及对相关知识的一个挖掘。 不执行的async/await 在第一次完成了该工程后,我做了一些简单的测试,比如在子进程执行的方法中做一些加减乘除或者字符运算,当然都是没问题的。而对于一些异步的情况,我通过bluebird的处理也能够处理,于是我开始尝试起了aysnc/await的情况,结果发现这个的执行只要遇到await,await后面的语句能够执行,但是在下面的语句就再也不能执行了。这个情况顿时让我摸不着了头脑,我一度以为是v8内核中对于这种子进程的情况不支持(确实v8对你fork出子进程的支持是有问题的,不过跟这个问题没关,具体在模块的Readme中提到了),于是看了v8内部对async/await的实现,并没有什么发现有跟子进程有什么关系,

  • pagecao
8 min read

Node中console.log的同步实现

console.log相信使用过js的朋友都不会陌生,对于我这种前端转过来的node开发者,用起这个函数更是毫不手软,使用它把需要的信息打印到标准输出,觉得就是1+1=2那么正常,但是有天在网上看到一个问题console.log到底是异步还是同步?我觉得很诧异,这还是个问题么?当然是同步啦。但是问题的答案出乎我的意料,上面告诉我是要分情况的,根据process.stdout的情况可能会出现异步的情况。我当时眉头一皱,才发现问题确实不是我想的那么简单,于是在Node的文档中发现了这一段提示: Writes may be synchronous depending on what the stream is connected to and

  • pagecao
6 min read

深入node stream

要说node最令人印象深刻的模块,第一肯定是events,而第二肯定就是stream模块了,今天这篇文章就来跟大家聊聊stream的实现,主要是以stream_readable为例来讲解,并以fs模块中的createReadStream为例来说明node内部是如何使用stream的。 Stream.Readable 从lib/stream.js中我们可以看到node的stream主要分为了四种,读流,写流以及读写兼具的全双工流,还有可以修改和变换数据的 Transform流 ,不过读流和写流的实现逻辑和思路在大架构上是类似的,至于双全工流我们可以通过文件lib/_stream_duplex.js看到他其实就是通过: function Duplex(options) { ... Readable.call(this, options); Writable.call(this, options); ... } 使函数拥有了读流和写流所有的方法和属性而成,

  • pagecao
8 min read

Node中异步和同步的实现

使用过node的朋友都知道,它最重要的也是最值得称道的就是使用了异步事件驱动的框架libuv,这个框架使得被称为玩具语言的JavaScript也在后端语言中占了一席之地(当然V8的高性能也是功不可没,而且libuv的代码非常优雅,很值得大家的学习。不过libuv整个框架很大,我们不可能只通过一篇文章就能了解到它所有的东西,所以我挑选了node中最简单fs模块同步读和异步读文件的过程讲解来对libuv的一个大概过程有所了解。 fs.readSync fs.readSync这个方法我相信没有人会陌生,在node中同步读取文件,不过再很多文章中都不推荐使用这个方法,因为会造成node单线程的阻塞,对于一些比较繁忙的node实例来说是非常不友好的,不过今天我们不讨论这些,只讨论其中的实现。实现我们在node工程的lib目录中找到fs.js可以看到它的代码: function(fd, buffer, offset, length, position) { if (length === 0) { return 0; } return

  • pagecao
17 min read

记一次node协程模块开发

记一次node协程模块开发 开始 早前通过swoole了解到了协程的概念,正值当时看到了JS的GeneratorFunction,于是激动的心颤抖的手,敲着代码往前走,就用js写下了一个协程模块node-coroutine-js.当然这个模块比较简单,基本就是利用node本身的能力实现的,其中为了避免主线的阻塞所以使用了setImmediate的方法来执行方法。后来在了解协程方面信息的时候,了解到了libco以后,又产生了通过libco的方式来做node协程模块,因为libco这个库真的太厉害了,我接下来为大家分析一下其中我用到的swap相关的核心逻辑。至于libco的loop,在node的libuv面前却显得不太出众。 libco核心逻辑 libco是通过一个stCoRoutine_t结构体来管理一个协程单元的,这个结构中主要包括了该协程单元的被交换时的寄存器值,以及stack的空间,以及协程执行的方法和传入的参数值,通过co_create方法来初始化,初始化的过程也不算复杂,有兴趣的可以自己了解一下。然后在初始化了stCoRoutine_t以后,通过co_resume方法将协程方法调用起来,其具体代码如下所示: void

  • pagecao
17 min read
V8内存分配过程浅谈

V8内存分配过程浅谈

前言 本文会通过V8中对String对象的内存分配开始分析,对中间出现的源码进行解读。对heap内存的新生代分配和老生代内存分配的过程解读。首先,我们来看一张流程图,该流程图给出整个分配过程中的前期流程图,其中省略了一些步骤,只给出了关键的步骤。 从String::NewFromUtf8开始 我们从String::NewFromUtf8这个函数开始,首先我们来看一下使用,从samples/hello-world.cc中我们可以看到 Local<String> source = String::NewFromUtf8(isolate, "'Hello' + ', World!'", NewStringType::kNormal)

  • pagecao
28 min read

Mycat下的数据库读写分离以及分库分表

读写分离 读写分离解决的问题 1.可以使读操作分布到多个服务器,实现对读密集型应用的优化,并且使对数据库的负载均衡更加简单。 2.对备份来说,复制是一项很有意义的技术补充,不过复制不能取代备份。 3.可以实现高可用性,在发生故障需要切换的时候,读机器可以更快的切换到数据使系统能够显著的缩短宕机时间。 4.也可以用来做一些功能的升级的时候拿来做测试。 读写分离的原理 那么复制是如何工作的呢,主要是通过以下三个步骤: 1.在主库把数据更改记录到二进制日志(俗称 bin-log)中。 2.备库将主库上的日志复制到自己的中继日志(relay-log)中。 3.备库读取中继日志中的时间,并将其重放到备库的数据库上。 流程如下图: 读写分离的数据库配置

  • pagecao
12 min read

Linux上编译V8

Linux上编译V8 好吧~~看到这篇文章你也许会问: 编译一个有详细文档的V8有什么难的,你还写个东西?当翻译么? 嗯。。。如果你真的这样认为,那我只能告诉你:朋友你太天真了。v8的文档是个梗好吧。。我都没想到google这么大的公司开源个项目,文档写得如此粗糙,你要是想通过V8的文档来做v8的编译或者embed开发,我只能说 兄弟,你会被坑得错过大年三十的。为什么呢?因为开发者光顾着升级代码,不更新文档了,文档里大量老旧错误信息,网上这方面的信息上也有很多问题。 好了,多的不说了。我直接贴出这个编译的过程,中间遇到的坑以及编译samples中hello-world.cc的方法: 步骤一 google 在v8这个的编译上面用了一个极其蛋疼的工具(推广需要)。以前可以直接通过git拉下来,然后通过

  • pagecao
9 min read
Mysql-高性能索引

Mysql-高性能索引

索引一种数据结构,其目的是为了更快的查询数据,在数据量很大的表中,建立良好的索引能够提升极大的性能。 磁盘io与预读 因为数据库存储数据量大,是不可能存储在内存中以供查询的,所以对于数据的查询必然会跟磁盘打交道,所以只有了解了磁盘io和预读的基本知识,我们才能真正的理解索引的原理。 磁盘读取数据靠的是机械运动,每次读取数据花费的时间可 以分为寻道时间、旋转延迟、传输时间三个部分,寻道时间指的是磁臂移动到指定磁道所需要的时间,主流磁盘一般在5ms以下;旋转延迟就是我们经常听说的磁 盘转速,比如一个磁盘7200转,表示每分钟能转7200次,也就是说1秒钟能转120次,旋转延迟就是1/120/2 = 4.17ms;传输时间指的是从磁盘读出或将数据写入磁盘的时间,一般在零点几毫秒,相对于前两个时间可以忽略不计。那么访问一次磁盘的时间,即一次磁盘 IO的时间约等于5+

  • pagecao
17 min read
docker

MAC使用docker、VScode开发调试NODE.JS

本文的目的: 更快的搭建Node.js开发调试环境 保持开发环境和测试、生产环境一致,避免因环境不同造成的问题 准备本地环境 目录结构如下所示,其中/data/src/config为配置文件目录,/data/src/web为工程代码目录(前后端代码在同一层级): /data └── src ├── config │   ├── config.json │   ├── interfaceConf.json │   └── update_config └── web ├── ams-pc ├── ams-pc-node ├── community-pc ├── community-pc-node ├── community-pos-api ├── login-android-node ├── login-node

  • Zhu Kang
7 min read
JavaScript

React 学习笔记 - 4

前言 前边几节中学习了组件和路由控制,已经能够做一个静态的SPA了。但是对于一个富应用来说,我们只学习了View,接下来我们将要学习数据处理模块,在正式开始学习之前,先来介绍下这位新朋友。 Redux Redux 是 JavaScript 状态容器,提供可预测化的状态管理。可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。Redux 由 Flux 演变而来,但受 Elm 的启发,避开了 Flux 的复杂性。 Redux 规定,将模型的更新逻辑全部集中于

  • Gavin
    Gavin
8 min read
React 学习笔记 - 1
JavaScript

React 学习笔记 - 1

简介 React SPA 开发,需要引入React-router控制路由,这里选择了Redux管理数据层,构建工具选择Webpack。 本节中包含React SPA 开发的相关配置和一个React的简单示例。 Tips :文章中所有示例代码使用ES6。 文档 React Document React-router Document Redux Document Webpack Document 目录结构 . ├──app | ├──js | | ├──action | | ├──components | | ├──containers | | ├──reducer | | ├──store | | └──app.js | └──index.html

  • Gavin
    Gavin
4 min read

Subscribe to Magicare