网易智慧企业 Node.js 实践(2)| 平滑发布和前端代码

健康检查

前文提到咱们经过网关把流量转发到Node 应用,那网关是如何肯定 Node 应用的可用性呢?css

若是Node 应用在发布的过程当中也把流量转发过来,就会致使请求失败,因此咱们的网关会对Node 应用作一个健康检查,要首先肯定 Node 应用是健康的,也就是能够对外服务的。具体来讲就是网关会每隔30秒调一下 Node 应用的健康检查的 HTTP 接口,若是接口返回的 code 是200,那就表示 Node 应用是可用的,用户的请求在下次检查以前都会转发过来,若是返回其余 code,表示应用不可用,请求就不会转发过来。过30秒再重复这个过程。html

图片3.png

                                                                    【示意图】前端

这个方案实现起来很是简单,只要再Node 添加个能正常请求的 HTTP 接口便可,好比咱们用的接口 `/health/check`它的 controller 内就 `this.ctx.body = 'OK'`就能够了。若是 Node 应用正常启动,能够接受用户请求,那么这个接口返回 code 就会是200,若是这个接口不能正常访问,返回的code不是200,那么也意味着整个应用是不能访问的。webpack

那上面这个方案就没有问题了吗?确定是有的,好比咱们在发布时候,首先要让Node 应用下线,若是刚好 Node 应用刚被健康检查经过后就下线了,那么就会致使后面30秒内转发到 Node 应用的流量访问失败,因此咱们有了升级方案-平滑发布。web

平滑发布

平滑发布就要跟发布系统进行配合了,就是咱们在发布应用的时候发布系统会自动调用Node 应用的下线接口,发布完成以后会调用 Node 应用的上线接口,这样就能够经过一个全局变量控制应用的状态,而这个状态是和应用的真实状态没有关系的。调用下线接口后,应用状态置为下线,而后等待一段时间才真正让应用下线,因此若是这时有流量进来应用依然能够正常服务。json

图片4.png

                                                                    【示意图】 安全

逻辑很简单,可是实现的时候要考虑到Egg.js 的多进程模型,Egg.js  通常根据服务器的 CPU 核数来定启动相应数量的 Worker 进程,这样就能够完美利用多核资源。每一个进程里都跑的是同一份源代码,这些进程同时监听一个端口,因此当发布系统调用下线接口时,只有其中一个进程会收到请求,若是只是把收到请求的这个进程的全局变量置为下线的话,其它的进程在收到健康检查的时候依然返回的是在线状态,这样就不对了,因此要使用进程间通讯,告诉全部进程下线。服务器

基于这些分析咱们实现了Egg.js 插件 `pp-ndp` ,另外因为 Egg.js 插件中不容许有路由,因此咱们经过中间件的形式实现,主要代码以下:app

```工具

const { request } = ctx;

const { path, hostname } = request;

if (path === online) {

    app.messenger.sendToApp(ONLINE, '');

    ctx.body = 'NDP: Nodejs Is Online';

} else if (path === offline) {

    app.messenger.sendToApp(OFFLINE, '');

    ctx.body = 'NDP: Nodejs Is Offline';

} else if (path === check) {

  ctx.body = 'NDP: Nodejs Start Success';

} else if (path === status) {

  if (app[ISONLINE]) {

    ctx.body = 'NDP: Nodejs Is Online';

  } else {

    ctx.status = 500;

  }

} else {

  await next();

}

```

固然这个方案的前提是有多台Node 服务机器,并按分组进行发布。若是只有一台机器就不必这么麻烦了,反正发布必定会致使停服。

插件`pp-ndp` 为了知足不一样业务需求,online、offline、check、status 这四个 URL 是支持自定义配置的。

这个方案不只解决了咱们平滑发布的问题,让发布再也不那么恐怖,并且还能够利用这个方案让应用上线后可以更好的服务,好比:能够在应用获取配置以后再把应用置为上线状态,或者能够在应用成功注册或链接某服务以后再把应用置为上线状态。让应用保证最健康的状态对外服务。

代码上CDN 和 代码发现

看到CDN 可能会奇怪, Node 应用为何要 CDN,实际上是由于咱们为了方便使用同构渲染,而把前端代码和 Node 代码放在了一个应用里面,虽然这样解决了服务端渲染代码访问问题,可是客户端代码仍是走 CDN 比较合理。关于 webpack 使用 CDN 网上有不少文章能够参考,我主要介绍下如何发现前端代码的,包括代码上 CDN 和模版中插入前端代码 URL。

主要是使用`webpack-manifest-plugin` 这个 webpack 插件,它会生成一个文件,好比咱们用的 `manifest.json`,里面包括前端代码资源名称和对应路径,相似:

```

{

  "vendor.js": "/static/f5e0281b/js/vendor.chunk.js",

  "vendor.js.map": "/static/f5e0281b/js/vendor.chunk.js.map",

  "Page.css": "/static/f2065164/css/Page.chunk.css",

  "Page.js": "/static/f2065164/js/Page.chunk.js",

  "Page.js.map": "/static/f2065164/js/Page.chunk.js.map",

}

```

只须要把这个文件内列的文件上传到CDN 便可,不需本身手动去打包目录一个一个找。在上传 CDN 的时候给每一个文件保持一样路径。使用咱们实现的工具 `pp-cdn` 在发布过程当中的代码编译完成以后进行上传。在 Node 模版中引用代码时,使用咱们开发的 Egg.js 插件 `pp-just`,使用方式:

```html

<script src='{{ctx.just.use("Page.js")}}'></script>

```

插件内部也是读取`manifest.json` 文件,输出加上 CDN 域名以后的 URL,好比上面的代码就转变为:

```html

<script src='https://qiyukf.nosdn.127.net/huke/static/f2065164/js/Page.chunk.js'></script>

```

其实之因此这么作,是为了利用前端代码多版本带来的好处,咱们是使用文件hash 做为文件路径的一部分做为多版本控制的,这样每次发布后编译后会把新生成的文件路径写入 `manifest.json`,而后经过上面讲的方式就能够获取到最新版本的代码。

固然目前Node 和 前端代码在一块儿是不合理的,可能会致使没必要要的发布,后续应该会彻底分离,可是使用`manifest.json`也能够做为咱们后续代码分离后的方案之一。

总结

技术方案的选择通常要结合团队已有的技术方案和业务需求,本文介绍的平滑发布方案在咱们业务前期,确实解决了咱们的发布问题,让发布变得更安全。

可是随着业务发展咱们须要灰度环境,来更好的确保应用的健康状态,提早发现应用中的问题。另外咱们还须要知道咱们的应用的运行状态,因此在下一讲内容中,咱们会分享关于灰度发布和应用监控相关的内容。

相关文章
相关标签/搜索