27
Node在淘宝的应用实践 这些年,我们起开发过的Node.js By @朴灵 1

D2_node在淘宝的应用实践_pdf版

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: D2_node在淘宝的应用实践_pdf版

Node在淘宝的应用实践这些年,我们⼀一起开发过的Node.jsBy @朴灵

1

Page 2: D2_node在淘宝的应用实践_pdf版

关于我

• CNode社区

• 前端 at SAP for Mobile Web

• 前端 at 淘宝数据产品部

连IE6都能兼容的男人

2

Page 3: D2_node在淘宝的应用实践_pdf版

议程• 我为什么要做Node开发

• 准备工作与作品• Node.js带来的新问题与如何逆袭

• 异步编程

• 缓存与内存

• Buffer

• Node.js在淘宝产品中的⼀一点实践

3

Page 4: D2_node在淘宝的应用实践_pdf版

长达半天的欢乐

4

前端屌丝的坎坷路

icons powered by morcha design

Page 5: D2_node在淘宝的应用实践_pdf版

Node与前端的亲缘

5

Page 6: D2_node在淘宝的应用实践_pdf版

Node与前端的亲缘

6

Page 7: D2_node在淘宝的应用实践_pdf版

左手HTML5右手Node.js

• 熟知的JavaScript执行原理/事件循环

• 熟悉的API、事件、单线程、回调

• Ajax/异步

• 相比HTML5,Node将开启更多的可能性

7

Page 8: D2_node在淘宝的应用实践_pdf版

好奇心 & 满足感• HTTP协议栈:深入后端,反哺前端

• Status code

• Cookie & Session

• Request & Response

• Web Framework

• 高性能JavaScript平台

• 拓宽视野8

Page 9: D2_node在淘宝的应用实践_pdf版

Go, go, go!!!

9

var http = require('http');http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n');}).listen(1337, '127.0.0.1');console.log('Server running at http://127.0.0.1:1337/');

% node example.jsServer running at http://127.0.0.1:1337/

Page 10: D2_node在淘宝的应用实践_pdf版

作品

10

Page 11: D2_node在淘宝的应用实践_pdf版

全JavaScript堆栈的产品

WebGhost

Should

WebGhost

MongoSkin

ITier

Redis & MRedis

Connect

11

Page 12: D2_node在淘宝的应用实践_pdf版

前端工程师到Web工程师

12

结果重了10斤

如何摆脱前端屌丝的身份让女神青睐

Page 13: D2_node在淘宝的应用实践_pdf版

$.get("template", function (template) { // something $.get("data", function (data) { // something $.get("l10n", function (l10n) { // something render(template, data); }); });});

问题:异步协作• 嵌套还是并行?

13

var proxy = new EventProxy();proxy.all("template", "data", "l10n", render);$.get("template", function (template) { // something proxy.trigger("template", template);});$.get("data", function (data) { // something proxy.trigger("data", data);});$.get("l10n", function (l10n) { // something proxy.trigger("l10n", l10n);});

Page 14: D2_node在淘宝的应用实践_pdf版

问题:异步还是同步• 复杂的异步编程

var proxy = new EventProxy();var status = "ready";var _getFile = function (callback) { proxy.once("template", callback); if (status === "ready") { fs.readFile("views/index.html", function (err, file) { status = "pending"; proxy.fire("template", err, file); }); }};

var _template;var getTemplate = function (callback) { if (_template) { callback(null, _template); } else { _getFile(function (err, file) { if (!err && !_template) { _template = file.toString(); } callback(null, _template); }); }};

同步 + 缓存,妥妥滴

var view = fs.readFileSync("../views/index.html", "utf8");

14

Page 15: D2_node在淘宝的应用实践_pdf版

问题:缓存的使用var map = {};var get = function (key) { return map[key];};var set = function (key, value) { map[key] = value;};// 检查缓存if (!get(key)) { // 从数据库或别的地方获取了对象后,放进缓存中 set(key, value);}

var LimitableMap = require('limitablemap');var map = new LimitableMap(1000);map.set("key1", "key1");map.get("key1");

15

Page 16: D2_node在淘宝的应用实践_pdf版

问题:Session

• V8内存堆栈限制

• 分布式中,Session需要共享(Redis)

• 重启应用不丢失session

• 多点Redis,备份容灾

16

Page 17: D2_node在淘宝的应用实践_pdf版

问题:Buffer对象var data = ""; res.on('data', function (chunk) { // chunk是⼀一个Buffer对象 data += chunk;// 隐藏的toString()}) .on("end", function () { //对data转码 });

17

// 正确的方法var chunks = []; var size = 0; res.on('data', function (chunk) { chunks.push(chunk); size += chunk.length; }); res.on('end', function () { var data = null; switch(chunks.length) { case 0: data = new Buffer(0); break; case 1: data = chunks[0]; break; default: data = new Buffer(size); for (var i = 0, pos = 0, l = chunks.length; i < l; i++) { var chunk = chunks[i]; chunk.copy(data, pos); pos += chunk.length; } break; } });

// 简单且正确的方法var bufferHelper = new BufferHelper();req.on("data", function (chunk) { bufferHelper.concat(chunk);}).on('end', function () { var html = bufferHelper.toBuffer().toString();});

Page 18: D2_node在淘宝的应用实践_pdf版

问题:String传输的性能

• 7k大小的静态文件,需做替换

• String ➛ Buffer

• 缓存Buffer,4倍性能提升

18

Page 19: D2_node在淘宝的应用实践_pdf版

问题:多核CPU的利用• 单线程与多核CPU

• 单线程因为异常退出?• 仿若熟悉的Web Worker: child_process

• 进程与消息

var cluster = require('node-cluster');

var master = new cluster.Master();master.register(8080, 'app.js');master.dispatch();

var http = require('http');var cluster = require('node-cluster');

var worker = new cluster.Worker();var server = http.createServer(function (req, res) { // server});

worker.ready(function (socket) { server.emit('connection', socket);}); 19

负载均衡多核利用提升稳定

Page 20: D2_node在淘宝的应用实践_pdf版

小结

• 异步编程问题?EventProxy、JScex等

• 内存限制问题?第三方存储Redis

• CPU消耗问题?缓存中间结果

• 单线程CPU利用不足问题?多进程

• 单线程稳定性问题?Node-Cluster

20

Page 21: D2_node在淘宝的应用实践_pdf版

实践:运维• 异常• 日志• 监控• 部署• 备份容灾

21

// 异步方法中try catch是不靠谱滴// 异步方法的异常async(function (err, data) { if (err) { logger.error(err); return; // TODO } // TODO});

进程数量CPU内存Load磁盘IO流量

双机房双Redis MRedis模块双MongoDB MongoSkin数据源集群

Page 22: D2_node在淘宝的应用实践_pdf版

实践:测试• 测试

• 单元测试• 自动化测试• 性能测试

• 持续集成 WebGhost

Should.js

22

Page 23: D2_node在淘宝的应用实践_pdf版

实践:CommonJS & Node & NPM

CommonJS

Node

NPM

23

Page 24: D2_node在淘宝的应用实践_pdf版

实践:公司范围内共享代码

• 如何保护隐私代码• 如何重用散乱代码• 如何告别复制粘贴

24

Page 25: D2_node在淘宝的应用实践_pdf版

实践:公司范围内共享代码

25

本地NPM 官方NPM

项目

单向同步

私有模块 公有模块

Page 26: D2_node在淘宝的应用实践_pdf版

展望• 深度发掘前端开发和用户体验• 无需与开发沟通,节省成本• 知晓细节,更易改进产品体验• 感谢伟大的github

• 感谢伟大的NPM促成的生态圈

• 感谢Node这件美妙的礼物26

Page 27: D2_node在淘宝的应用实践_pdf版

Q&A

屌丝のぎゃくしゅう

27