NodeJs 实践之他说

作为前端,我们知道 node 在构建方面是成功的,我们也听说过全栈,那么 node 是否能应用在企业级的后端?一起来看一下腾讯视频的 NodeJs 改造

Tip: 故事大概是 2018 年,主角杨浩,来源于:

背景

腾讯视频是一个内容型的网页。

在 2014 年以前使用的是 C++ 动态生成页面。有两个问题:

  • 前端不太会维护 C++ 的那套东西
  • C++ 定时生成网页。有多少个视频,它就会生成多少个网页,然后推送到对应的服务器中。如果更改了某个视频的信息,得等到下次生成网页才会更新

于是打算使用 NodeJs 来对其进行改造。

第一只怪 - 打通 NodeJs

由于腾讯视频是内容型的网页,当时有 30% 的流量来自搜索引擎,所以需要更好的 SEO,于是选用 SSR(服务器渲染)。

Tip: Vue_SSR中也提到服务端渲染的优势:更快的首屏加载、更好的 SEO

NodeJs 扮演的角色如下:

请求经过 cdn,经过 nginx 通过负载均衡访问 NodeJs 服务,NodeJs 从各个后台服务拉取数据,渲染好了在返回给前端。

Tip:相当于以前用 c++ 生成页面,现在由 NodeJs 生成页面。

打通 RPC 调用

rpc(作用类似 http 协议) 就是远端资源调用,因为 node 需要从各个后台服务拉取数据。这里涉及4个方面的事情:

  • 负载均衡。node 和后台服务之间有一层负载均衡,用的是一种类DNS负载均衡,所以得和负载均衡服务交互,拿到每次需要访问服务器的ip
  • Mongo/mysql/redis(redis - 基于键值对的内存数据库) 存储的打通。比较简单,就是对应 npm 包的使用
  • 后台私有协议。例如二进制的协议某场景下比http协议好一些
  • 监控系统/日志系统

Tip: DNS除了能解析域名之外还具有负载均衡的功能

高并发下进程管理

node 是单线程,使用 cluster 模块创建多个 Nodejs 进程,实现高并发和高可用性。但 cluster 还有点缺陷,做了以下几点优化:

  • 心跳 - master 定时给 cluster 发信息,如果有回复说明它还活着,否则就是僵死,就 kill 它
  • 内存检测 - 监控 cluster 内存,如果内存过高,可能就是内存泄漏,也杀死它
  • 重启 - cluster kill 后,有的应用可能不能用,就需要将其重启

Tip:在 Node.js 中,cluster 模块提供了一种简单的方式来创建多个 Node.js 进程,以实现高并发和高可用性。通过集群模块,开发者可以使用现有的单线程程序代码,并将其自动拆分到多个子进程中执行,从而充分利用 CPU 和内存资源,提高应用的效率和稳定性。

第二只怪 - 维护 NodeJs

终于把 Node 打通了,现在可以用 node 写点东西了。

要用 node 写一个稳定的服务,也不是那么简单。node 很容易挂掉,比如一点语法问题。

Node 人员不足

懂前端的人很多,但懂 node 的就相对要少。写后端需要懂后端那套东西,要会服务器调优,还要懂运维。

为了解决 Node 人员不足,决定使用框架来平滑 node 曲线。

之前要用 node 写项目难度大,是因为需要经历这4步:业务逻辑 -> 会写 NodeJs -> 熟悉 rpc 调用 -> 熟悉运维(性能调优)

现在用框架,只需要写业务逻辑就能开干。

这里框架主要使用配置化,屏蔽底层复杂的实现,对外暴露友好的配置。就像 webpack,让前端构建生态非常繁荣。

要做配置化,就得分析 ssr 本质:从各个后台领取数据,简单处理后进行渲染。

ssr抽象表示:请求参数 -> 后端数据 + 模板 -> 页面文本

ssr 公式:内容=f(数据源,模板)

只要将数据源模板配置化,就可以通过一个函数解决 ssr 的问题。

模板引擎的选型

研究了如下几种模板:

  1. art-template 国内有名的开源模板引擎
  2. es6 template string + vm.runInNewContext(编译和运行代码,作用类似 new Function('console.log("1")'))
  3. vue ssr、react ssr

art-template 中的 forEach 可以使用预编译语法来实现,由于交互较少,所以无需使用 vue和react。而且 es6 模板速度测试比 vue-server-render 快很多。

所以最终选取第二种方案:es6 template

数据源

数据源的配置用如下一个 json 表示:

module.exports = {
video: {
url: "http://...."
},
vidviewcount: {
dependencies: ['video'],
url: "protobuf://union.video.qq.com/...."
},
rank: {
url: "redis://admin:admin@135246:65535/get?key=haha"
}
}

这个 json 表示 ssr 过程中数据获取逻辑,其中 vidviewcount 通过 dependencies 字段指明依赖 video。

这里用 http、protobuf、redis三种协议(方式)获取数据。一个协议对应一个请求器,不在框架中的协议可以注册即可。就像这样:

factory.registerRequestor('http', requestor);
function requestor(){
...
}

为了增加配置的灵活性,这里增加了几个 hook:

{
...
fixBefore: function(param){
// 检测参数合法性
return param
},
fixAfter: function(data){
// 检测返回数据合法性
if(!data.vid){
throw Error('xxx')
}
return data
},
onError: function(e){
return err;
}
}

写配置就是写 SSR 逻辑

只要学会写配置就能搞定 ssr 逻辑。

公式:内容=f(数据源,模板)(参数)

ssr 外部用 koa(nodejs 的web框架) 封装一下就是一个服务:

let app = koa()
let ssr = pigfarm(data, template)
app.use(async ctx => {
ctx.body = await ssr(ctx.query)
})

第三只怪 - 抢后端饭碗的问题

后台有后台擅长的地方(逻辑、计算密集),前端有前端擅长的地方(前端网页优化)。

寻找一个合作共赢的方式。这里做了如下几个有特色的前端服务:

热更新

每次业务逻辑的改动需要经历长时间的发布重启

前面已经将数据源模板做到了配置化,现在修改逻辑,只需要更改数据库中的数据源和模板即可,做到热更新。

首页调优

v.qq.com 首页包含27个模块

  • 富含个性化内容,无法缓存
  • 页面庞大,速度慢
  • 全网页超过40个rpc
  • 个性化接口调用慢

利用 transfer-encoding:chunked 快速返回首屏数据,后面再加载2、3、4...屏的数据

Tip:BigPipe 是一个前端性能优化技术,采用分块渲染的方式。transfer-encoding:chunked 是一种 HTTP协议中定义的传输编码方式之一。运行服务器在不知道响应体大小的情况下,将响应分成若干个固定大小的快进行传输。

容灾

前端容灾是指在前端应用中,为了保障可靠性和稳定性而采用的一系列技术和策略,以确保即使在系统出现部分异常或错误的情况下,仍然可以正常提供服务。比如网络问题、服务器故障等

这里可以做整页备份

js 中用高阶函数非常容易实现缓存。请看示例:

function memoize(func) {
// 用于缓存
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
// 如果缓存中有值,直接返回
if (cache[key]) {
return cache[key];
} const result = func.apply(this, args);
cache[key] = result;
return result;
};
}

NodeJs 实践之他说的更多相关文章

  1. nodejs实践-MongoDB

    nodejs实践-MongoDB laiqun@msn.cn Contents 1. 特点: 2. 开始使用 3. 使用Mongoose操作MongoDB 4. 在express中使用,组织数据库相关 ...

  2. nodejs实践-代码组织

    nodejs实践-代码组织 laiqun@msn.cn Contents 1. 代码组织 1. 代码组织 更新版本 npm install -g n n latest 项目文件组织 MVC 前后端代码 ...

  3. nodejs 实践:express 最佳实践(四) express-session 解析

    nodejs 实践:express 最佳实践(四) express-session 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs ...

  4. nodejs 实践:express 最佳实践系列

    nodejs 实践:express 最佳实践系列 nodejs 实践:express 最佳实践(一) 项目结构 nodejs 实践:express 最佳实践(二) 中间件 nodejs 实践:expr ...

  5. nodejs 实践:express 最佳实践(三) express 解析

    nodejs 实践:express 最佳实践(三) express 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固, ...

  6. nodejs 实践:express 最佳实践(五) connect解析

    nodejs 实践:express 最佳实践(五) connect解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需 ...

  7. nodejs 实践:express 最佳实践(六) express 自省获得所有的路由

    nodejs 实践:express 最佳实践(六) express 自省获得所有的路由 某些情况下,你需要知道你的应用有多少路由,这在 express 中没有方法可以.因此我这边曲线了一下,做成了一个 ...

  8. nodejs 实践:express 最佳实践(七) 改造模块 connect2 解析

    nodejs 实践:express 最佳实践(七) 改造模块 connect2 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的 ...

  9. nodejs 实践:express 最佳实践(八) egg.js 框架的优缺点

    nodejs 实践:express 最佳实践(八) egg.js 框架的优缺点 优点 所有的 web开发的点都考虑到了 agent 很有特色 文件夹规划到位 扩展能力优秀 缺点 最大的问题在于: 使用 ...

  10. nodejs 实践:express 最佳实践 (一)

    express 最佳实践 (一) 最近,一直在使用 nodejs 做项目,对 nodejs 开发可以说深有体会. 先说说 nodejs 在业务中的脚色,, 在 web同构 方面, nodejs 的优势 ...

随机推荐

  1. 制作可以显示GIF动图的activeX 控件

    因为工作需要,我需要一个可以显示gif 动图的控件,用来在VBS中显示动图,结果找了半天发现根本没有这样的控件,所以只能搜集资料自己来制作一个. 下面记录一下步骤: 1. 下载 PictureEx.h ...

  2. 除select外查询数据的另一种姿势

    1.24 1.[GYCTF2020]Blacklist buuctf上的题目 1.解题过程 输入1会返回一个数组,加上单引号就报错了,说明存在注入 以前做过类似的估计是堆叠注入,尝试一下 注入成功 正 ...

  3. leader epoch

    更多内容,前往 IT-BLOG leader epoch 代表 Leader 的纪元信息(epoch),初始值为0.每当 Leader 变更一次,leader epoch 的值就会加1,相当于为 Le ...

  4. Seata锁等待超时问题排查

    问题描述 生产环境,一个简单的事务方法,提交失败,报 Global lock wait timeout 伪代码如下: @GlobalTransactional(rollbackFor = Except ...

  5. UnrealEngine - 反射系统分析

    1. 反射 什么是反射?或者说反射能做什么,简单来说,反射可以提供一种能力,能够在运行时动态获取对象的成员信息,如成员函数,成员变量. UE 在其反射系统上支持了许多功能,如: 编辑器中可供编辑的属性 ...

  6. [issues] webrtc 接入SRS丢包率不正确问题

    目录 [issues] webrtc 接入SRS丢包率不正确问题 原因和解决方法 srs增加rtx SDP协商 构建RTX包 [issues] webrtc 接入SRS丢包率不正确问题 原因和解决方法 ...

  7. hdfs集群的扩容和缩容

    目录 1.背景 2.集群黑白名单 3.准备一台新的机器并配置好hadoop环境 3.1 我们现有的集群规划 3.2 准备一台新的机器 3.2.1 查看新机器的ip 3.2.2 修改主机名和host映射 ...

  8. 【前端黑魔法】浏览器打开任意可执行exe文件方法

    思路:通过注册表注册自定义URL协议执行bat脚本,将文件路径作为参数传入 环境:win10 前置问题与条件 问题1:可以从浏览器直接打开可执行文件吗? 答:不能.其实可以通过 ActiveXObje ...

  9. python注册热键方式

    #!/usr/bin/env python3   import win32con import ctypes import ctypes.wintypes from threading import  ...

  10. 如何在Java中做基准测试?JMH使用初体验

    大家好,我是王有志,欢迎和我聊技术,聊漂泊在外的生活.快来加入我们的Java提桶跑路群:共同富裕的Java人. 最近公司在搞新项目,由于是实验性质,且不会直接面对客户的项目,这次的技术选型非常激进,如 ...