Upload
jacksontian
View
2.913
Download
3
Embed Size (px)
DESCRIPTION
Citation preview
Node在淘宝的应用实践这些年,我们⼀一起开发过的Node.jsBy @朴灵
1
关于我
• CNode社区
• 前端 at SAP for Mobile Web
• 前端 at 淘宝数据产品部
连IE6都能兼容的男人
2
议程• 我为什么要做Node开发
• 准备工作与作品• Node.js带来的新问题与如何逆袭
• 异步编程
• 缓存与内存
• Buffer
• Node.js在淘宝产品中的⼀一点实践
3
长达半天的欢乐
4
前端屌丝的坎坷路
icons powered by morcha design
Node与前端的亲缘
5
Node与前端的亲缘
6
左手HTML5右手Node.js
• 熟知的JavaScript执行原理/事件循环
• 熟悉的API、事件、单线程、回调
• Ajax/异步
• 相比HTML5,Node将开启更多的可能性
7
好奇心 & 满足感• HTTP协议栈:深入后端,反哺前端
• Status code
• Cookie & Session
• Request & Response
• Web Framework
• 高性能JavaScript平台
• 拓宽视野8
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/
作品
10
全JavaScript堆栈的产品
WebGhost
Should
WebGhost
MongoSkin
ITier
Redis & MRedis
Connect
11
前端工程师到Web工程师
12
结果重了10斤
如何摆脱前端屌丝的身份让女神青睐
$.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);});
问题:异步还是同步• 复杂的异步编程
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
问题:缓存的使用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
问题:Session
• V8内存堆栈限制
• 分布式中,Session需要共享(Redis)
• 重启应用不丢失session
• 多点Redis,备份容灾
16
问题: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();});
问题:String传输的性能
• 7k大小的静态文件,需做替换
• String ➛ Buffer
• 缓存Buffer,4倍性能提升
18
问题:多核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
负载均衡多核利用提升稳定
小结
• 异步编程问题?EventProxy、JScex等
• 内存限制问题?第三方存储Redis
• CPU消耗问题?缓存中间结果
• 单线程CPU利用不足问题?多进程
• 单线程稳定性问题?Node-Cluster
20
实践:运维• 异常• 日志• 监控• 部署• 备份容灾
21
// 异步方法中try catch是不靠谱滴// 异步方法的异常async(function (err, data) { if (err) { logger.error(err); return; // TODO } // TODO});
进程数量CPU内存Load磁盘IO流量
双机房双Redis MRedis模块双MongoDB MongoSkin数据源集群
实践:测试• 测试
• 单元测试• 自动化测试• 性能测试
• 持续集成 WebGhost
Should.js
22
实践:CommonJS & Node & NPM
CommonJS
Node
NPM
23
实践:公司范围内共享代码
• 如何保护隐私代码• 如何重用散乱代码• 如何告别复制粘贴
24
实践:公司范围内共享代码
25
本地NPM 官方NPM
项目
单向同步
私有模块 公有模块
展望• 深度发掘前端开发和用户体验• 无需与开发沟通,节省成本• 知晓细节,更易改进产品体验• 感谢伟大的github
• 感谢伟大的NPM促成的生态圈
• 感谢Node这件美妙的礼物26
Q&A
屌丝のぎゃくしゅう
27