第1页
14年11⽉月27⽇日 星期四
第2页
Nodejs框架设计与实践
14年11⽉月27⽇日 星期四
⺩王骕 2014.11 百度 移动云平台
第3页
About Me & RapidJS
14年11⽉月27⽇日 星期四
第4页
About Me & RapidJS
14年11⽉月27⽇日 星期四
第5页
About Me & RapidJS
14年11⽉月27⽇日 星期四
第6页
About Me & RapidJS
......
...... 2011
14年11⽉月27⽇日 星期四
第7页
About Me & RapidJS
......
ScreenX
...... 2011
14年11⽉月27⽇日 星期四
第8页
About Me & RapidJS
......
ScreenX
...... Sumeru 2011
14年11⽉月27⽇日 星期四
第9页
About Me & RapidJS
ScreenX
Clouda
...... Sumeru 2011
14年11⽉月27⽇日 星期四
......
第10页
About Me & RapidJS
Clouda+ & RapidJS Clouda
ScreenX
......
...... Sumeru 2011
14年11⽉月27⽇日 星期四
第11页
About Me & RapidJS
Clouda+ & RapidJS Clouda
ScreenX
......
...... Sumeru 2011
14年11⽉月27⽇日 星期四
第12页
About Me & RapidJS
Clouda+ & RapidJS Clouda
ScreenX
......
...... Sumeru 2011
14年11⽉月27⽇日 星期四
NodeJS
第13页
About Me & RapidJS
Clouda+ & RapidJS
Clouda
ScreenX
...... Sumeru 2011
14年11⽉月27⽇日 星期四
填别⼈人的坑
NodeJS
......
第14页
14年11⽉月27⽇日 星期四
第15页
• 为什么写框架?
14年11⽉月27⽇日 星期四
第16页
• 为什么写框架? • 写什么样的框架?
14年11⽉月27⽇日 星期四
第17页
• 为什么写框架? • 写什么样的框架?
- RapidJS是怎么做的?
14年11⽉月27⽇日 星期四
第18页
为什么写框架?
14年11⽉月27⽇日 星期四
第19页
为什么写框架?
14年11⽉月27⽇日 星期四
第20页
为什么写框架?
产品成熟度
14年11⽉月27⽇日 星期四
时间
第21页
为什么写框架?
产品成熟度
14年11⽉月27⽇日 星期四
时间
第22页
为什么写框架?
产品成熟度
14年11⽉月27⽇日 星期四
初始
成⻓长
成熟
迭代扩张
时间
第23页
为什么写框架?
产品成熟度
通⽤用框架
初始
成⻓长
成熟
迭代扩张
时间
14年11⽉月27⽇日 星期四
第24页
为什么写框架?
产品成熟度
包装&堆叠
通⽤用框架
成⻓长
初始
成熟
迭代扩张
时间
14年11⽉月27⽇日 星期四
第25页
为什么写框架?
产品成熟度
沉积&迭代
通⽤用框架
包装&堆叠
成⻓长
成熟
初始
迭代扩张 时间
14年11⽉月27⽇日 星期四
第26页
为什么写框架?
产品成熟度
定制&剥离&独⽴立
通⽤用框架
沉积&迭代
包装&堆叠
成⻓长
成熟
迭代扩张
初始
时间
14年11⽉月27⽇日 星期四
第27页
为什么写框架?
产品成熟度
?!
定制&剥离&独⽴立
通⽤用框架
沉积&迭代
包装&堆叠
成⻓长
成熟
迭代扩张
初始
时间
14年11⽉月27⽇日 星期四
第28页
为什么写框架?
产品成熟度
?!
定制&剥离&独⽴立
通⽤用框架
沉积&迭代
包装&堆叠
成⻓长
成熟
迭代扩张
初始
时间
框架⼀一定会产⽣生出来,⽆无论你是否愿意!
14年11⽉月27⽇日 星期四
第29页
写什么样的框架?
14年11⽉月27⽇日 星期四
第30页
写什么样的框架?
业务复杂度
14年11⽉月27⽇日 星期四
框架复杂度
第31页
写什么样的框架?
业务复杂度
简单
14年11⽉月27⽇日 星期四
框架复杂度
复杂
第32页
写什么样的框架?
业务复杂度
简单
14年11⽉月27⽇日 星期四
复杂(重)
简单(轻) 框架复杂度
复杂
第33页
写什么样的框架?
复杂(重)
业务复杂度
简单
常⽤用封装
简单(轻) 框架复杂度
14年11⽉月27⽇日 星期四
复杂
第34页
写什么样的框架?
业务复杂度
简单
常⽤用封装
复杂(重) 更⾼高包装程度, 更多贴合业务, 复⽤用成熟模式.解决特定场景内问题,
复杂
简单(轻) 框架复杂度
14年11⽉月27⽇日 星期四
第35页
写什么样的框架?
业务复杂度
复杂(重)
更⾼高包装程度, 更多贴合业务, 复⽤用成熟模式.解决特定场景内问题,
简单
常⽤用封装
复杂
留给开发⼈人员有更多⾃自由空间 容易在其它场景复⽤用. ⾄至少解决⼀一类问题.
简单(轻)
框架复杂度
14年11⽉月27⽇日 星期四
第36页
写什么样的框架?
业务复杂度
想出HelloWorld的1024种 写法. 然后挑出最复杂的⼀一 种!! 抽像成框架!
复杂(重)
更⾼高包装程度, 更多贴合业务, 复⽤用成熟模式.解决特定场景内问题,
简单
常⽤用封装
复杂
留给开发⼈人员有更多⾃自由空间 容易在其它场景复⽤用. ⾄至少解决⼀一类问题.
简单(轻)
框架复杂度
14年11⽉月27⽇日 星期四
第37页
写什么样的框架?
业务复杂度
想出HelloWorld的1024种 写法. 然后挑出最复杂的⼀一 种!! 抽像成框架!
复杂(重)
更⾼高包装程度, 更多贴合业务, 复⽤用成熟模式.解决特定场景内问题,
简单
常⽤用封装
复杂
留给开发⼈人员有更多⾃自由空间 容易在其它场景复⽤用. ⾄至少解决⼀一类问题.
简单(轻)
框架复杂度
14年11⽉月27⽇日 星期四
第38页
写什么样的框架?
业务复杂度
想出HelloWorld的1024种 写法. 然后挑出最复杂的⼀一 种!! 抽像成框架!
复杂(重)
更⾼高包装程度, 更多贴合业务, 复⽤用成熟模式.解决特定场景内问题,
简单
常⽤用封装
复杂
留给开发⼈人员有更多⾃自由空间 容易在其它场景复⽤用. ⾄至少解决⼀一类问题.
简单(轻)
框架复杂度
14年11⽉月27⽇日 星期四
第39页
• RapidJS是怎么做的?
14年11⽉月27⽇日 星期四
第40页
拆分主题, 避免以⼀一概全
14年11⽉月27⽇日 星期四
第41页
拆分主题, 避免以⼀一概全
// Rapid框架组成
14年11⽉月27⽇日 星期四
第42页
拆分主题, 避免以⼀一概全
// Rapid框架组成
Question
⼯工程组织 运⾏行时资源管理
启动控制 开发,部属环境与执⾏行
http业务提供 数据&业务访问
插 件 系 统
其它
......
Solution
Rapid-core
Rapid-tank rapid-httpserver
rapid-express rapid-access rapid-mysql rapid-simplem-ongo
......
Remarks
基于AMD规范的资源管 理能⼒力
执⾏行容器, ⾃自动化测试等
各类通⽤用业务能⼒力
......
14年11⽉月27⽇日 星期四
第43页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
……
filters
pcs
extensions
bcs
……
14年11⽉月27⽇日 星期四
第44页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
……
filters
pcs
extensions
bcs
……
14年11⽉月27⽇日 星期四
第45页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
……
filters
pcs
extensions
bcs
……
14年11⽉月27⽇日 星期四
第46页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
……
filters
pcs
extensions
bcs
……
14年11⽉月27⽇日 星期四
第47页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
Resource,Config, 执⾏行⽆无差别,仅语义不同
……
filters extensions
pcs bcs
……
14年11⽉月27⽇日 星期四
第48页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
Resource,Config, 执⾏行⽆无差别,仅语义不同
……
filters extensions
pcs bcs
……
14年11⽉月27⽇日 星期四
第49页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
Resource,Config, 执⾏行⽆无差别,仅语义不同
……
filters extensions
pcs bcs
……
14年11⽉月27⽇日 星期四
第50页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin 插件式附加⼆二级API,提供业务能⼒力
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
Resource,Config, 执⾏行⽆无差别,仅语义不同
……
filters extensions
pcs bcs
……
14年11⽉月27⽇日 星期四
第51页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin 插件式附加⼆二级API,提供业务能⼒力
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
Resource,Config, 执⾏行⽆无差别,仅语义不同
……
filters extensions
pcs bcs
……
14年11⽉月27⽇日 星期四
第52页
Rapid&core
Rapid 运⾏行时架构
Resource
Config
Plugin 插件式附加⼆二级API,提供业务能⼒力
{any}
http.conf httpserver access
mysql
{any}…
…. log.conf
services
mysql
{any}
actions mongodb
Resource,Config, 执⾏行⽆无差别,仅语义不同
……
filters extensions
pcs bcs
插件内扩展, 提供三级API
……
14年11⽉月27⽇日 星期四
第53页
保持通⽤用性 , 少即是多
14年11⽉月27⽇日 星期四
第54页
保持通⽤用性 , 少即是多
// rapid-core 执⾏行过程
14年11⽉月27⽇日 星期四
第55页
保持通⽤用性 , 少即是多
// rapid-core 执⾏行过程
(Start)
•
require
•
scan
•
•
watching
runing.
•
, core', log ,
,' & , ..'
14年11⽉月27⽇日 星期四
,
第56页
保持通⽤用性 , 少即是多
// rapid-core 执⾏行过程
(Start)
•
require
•
scan
•
•
watching
runing.
•
, core', log ,
,' & , ..'
14年11⽉月27⽇日 星期四
,
第57页
控制灵活,限制合理, 适度包装
14年11⽉月27⽇日 星期四
第58页
控制灵活,限制合理, 适度包装
// rapid-httpserver 调度过程
14年11⽉月27⽇日 星期四
第59页
控制灵活,限制合理, 适度包装
// rapid-httpserver 调度过程
Services0 ispath
Services if(match(url))0{0execute0&0next0}0else{0next0}
FilterChain filter01 filte0r2 …… filter0n
action0n
Extension01
Extension02
Extension0n
…… action02 action01 ActionChain
Main outer
if(match(url))0{0execute0&0end0}0else{0next0}
Sub0Router
14年11⽉月27⽇日 星期四
第60页
绕过已知的坑,留意细节
14年11⽉月27⽇日 星期四
第61页
绕过已知的坑,留意细节
1.执⾏行效率低
14年11⽉月27⽇日 星期四
第62页
绕过已知的坑,留意细节
1.执⾏行效率低 2.callback层级过多代码难读
14年11⽉月27⽇日 星期四
第63页
绕过已知的坑,留意细节
1.执⾏行效率低 2.callback层级过多代码难读 3.稳定性差,异常控制困难.易crash
14年11⽉月27⽇日 星期四
第64页
绕过已知的坑,留意细节
14年11⽉月27⽇日 星期四
第65页
绕过已知的坑,留意细节
1.优化执⾏行效率:
14年11⽉月27⽇日 星期四
第66页
绕过已知的坑,留意细节
1.优化执⾏行效率:
i.留意js语⾔言本⾝身性能, (http://jsperf.com/)
14年11⽉月27⽇日 星期四
第67页
绕过已知的坑,留意细节
1.优化执⾏行效率:
i.留意js语⾔言本⾝身性能, (http://jsperf.com/) ii.能并⾏行尽量不要串⾏行, 减少同步操作. (发挥优势)
14年11⽉月27⽇日 星期四
第68页
绕过已知的坑,留意细节
1.优化执⾏行效率:
i.留意js语⾔言本⾝身性能, (http://jsperf.com/) ii.能并⾏行尽量不要串⾏行, 减少同步操作. (发挥优势) iii.回避⾼高CPU计算量操作业务 (回避劣势)
14年11⽉月27⽇日 星期四
第69页
绕过已知的坑,留意细节
1.优化执⾏行效率:
i.留意js语⾔言本⾝身性能, (http://jsperf.com/) ii.能并⾏行尽量不要串⾏行, 减少同步操作. (发挥优势) iii.回避⾼高CPU计算量操作业务 (回避劣势) iv.稀释事件触发 (类似浏览器事件稀释)
14年11⽉月27⽇日 星期四
第70页
绕过已知的坑,留意细节
14年11⽉月27⽇日 星期四
第71页
绕过已知的坑,留意细节
2.callback层级过多代码难读:
14年11⽉月27⽇日 星期四
第72页
绕过已知的坑,留意细节
2.callback层级过多代码难读:
i.参⻅见1.2的前半句
14年11⽉月27⽇日 星期四
第73页
绕过已知的坑,留意细节
2.callback层级过多代码难读:
i.参⻅见1.2的前半句 ii.尽量使⽤用事件类
14年11⽉月27⽇日 星期四
第74页
绕过已知的坑,留意细节
2.callback层级过多代码难读:
i.参⻅见1.2的前半句 ii.尽量使⽤用事件类 iii.使⽤用控制库,如 : Q, async, promise等
14年11⽉月27⽇日 星期四
第75页
绕过已知的坑,留意细节
14年11⽉月27⽇日 星期四
第76页
绕过已知的坑,留意细节
3.稳定性差,异常控制困难.易crash
14年11⽉月27⽇日 星期四
第77页
绕过已知的坑,留意细节
3.稳定性差,异常控制困难.易crash
i.多进程 + 守护进程 (最低保障)
14年11⽉月27⽇日 星期四
第78页
绕过已知的坑,留意细节
3.稳定性差,异常控制困难.易crash
i.多进程 + 守护进程 (最低保障) ii.减少全局对像(内容隔离,利于异常后状态恢复)
14年11⽉月27⽇日 星期四
第79页
绕过已知的坑,留意细节
3.稳定性差,异常控制困难.易crash
i.多进程 + 守护进程 (最低保障) ii.减少全局对像(内容隔离,利于异常后状态恢复) iii.使⽤用Domain
14年11⽉月27⽇日 星期四
第80页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
14年11⽉月27⽇日 星期四
第81页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
14年11⽉月27⽇日 星期四
第82页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
domain.enter() user
handle()
//
if
throw domain.exit()
14年11⽉月27⽇日 星期四
第83页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
domain.enter() user
handle()
//
if
throw domain.exit()
14年11⽉月27⽇日 星期四
第84页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
domain.enter() user
handle()
//
if
throw domain.exit()
14年11⽉月27⽇日 星期四
第85页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
if(process.domain){
domain.emit(“error”,err) }else
if(uncaughtException){
process.emit(“uncaughtException”,err) }else{
crash…. }
domain.enter() user
handle()
//
if
throw domain.exit()
14年11⽉月27⽇日 星期四
第86页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
if(process.domain){
domain.emit(“error”,err) }else
if(uncaughtException){
process.emit(“uncaughtException”,err) }else{
crash…. }
domain.enter() user
handle()
//
if
throw domain.exit()
14年11⽉月27⽇日 星期四
第87页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
if(process.domain){
domain.emit(“error”,err) }else
if(uncaughtException){
process.emit(“uncaughtException”,err) }else{
crash…. }
domain.enter() user
handle()
//
if
throw domain.exit()
14年11⽉月27⽇日 星期四
第88页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
if(process.domain){
domain.emit(“error”,err) }else
if(uncaughtException){
process.emit(“uncaughtException”,err) }else{
crash…. }
14年11⽉月27⽇日 星期四
domain.enter() user
handle()
//
if
throw domain.exit() if(this.onerror){
onerror(err); }else{
if(
this.domain){
this.domain.emit(“error”,err);
//
Unhandled
}else{
//
throw
Uncaught
error
} }
第89页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
if(process.domain){
domain.emit(“error”,err) }else
if(uncaughtException){
process.emit(“uncaughtException”,err) }else{
crash…. }
14年11⽉月27⽇日 星期四
domain.enter() user
handle()
//
if
throw domain.exit() if(this.onerror){
onerror(err); }else{
if(
this.domain){
this.domain.emit(“error”,err);
//
Unhandled
}else{
//
throw
Uncaught
error
} }
第90页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
if(process.domain){
domain.emit(“error”,err) }else
if(uncaughtException){
process.emit(“uncaughtException”,err) }else{
crash…. }
14年11⽉月27⽇日 星期四
domain.enter() user
handle()
//
if
throw domain.exit() if(this.onerror){
onerror(err); }else{
if(
this.domain){
this.domain.emit(“error”,err);
//
Unhandled
}else{
//
throw
Uncaught
error
} }
第91页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
if(process.domain){
domain.emit(“error”,err) }else
if(uncaughtException){
process.emit(“uncaughtException”,err) }else{
crash…. }
14年11⽉月27⽇日 星期四
domain.enter() user
handle()
//
if
throw domain.exit() if(this.onerror){
onerror(err); }else{
if(
this.domain){
this.domain.emit(“error”,err);
//
Unhandled
}else{
//
throw
Uncaught
error
} }
第92页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
if(process.domain){
domain.emit(“error”,err) }else
if(uncaughtException){
process.emit(“uncaughtException”,err) }else{
crash…. }
new
EventEmitter(){
if(domain.action){
this.domain
=
domain.action
} } domain.enter() user
handle()
//
if
throw domain.exit()
if(this.onerror){
onerror(err); }else{
if(
this.domain){
this.domain.emit(“error”,err);
//
Unhandled
}else{
//
throw
Uncaught
error
} }
14年11⽉月27⽇日 星期四
第93页
About the “Domain”
EventEmitter
//
I/O
Events
{ }Timer
if(process.domain){
domain.emit(“error”,err) }else
if(uncaughtException){
process.emit(“uncaughtException”,err) }else{
crash…. }
new
EventEmitter(){
if(domain.action){
this.domain
=
domain.action
} } domain.enter() user
handle()
//
if
throw domain.exit()
if(this.onerror){
onerror(err); }else{
if(
this.domain){
this.domain.emit(“error”,err);
//
Unhandled
}else{
//
throw
Uncaught
error
} }
14年11⽉月27⽇日 星期四
第94页
⼩小⼼心domain的陷阱
14年11⽉月27⽇日 星期四
第95页
⼩小⼼心domain的陷阱
• 抓不到的异常
14年11⽉月27⽇日 星期四
第96页
⼩小⼼心domain的陷阱
• 抓不到的异常
Demo
14年11⽉月27⽇日 星期四
第97页
⼩小⼼心domain的陷阱
• 抓不到的异常
Demo
• 尝试解决
14年11⽉月27⽇日 星期四
第98页
⼩小⼼心domain的陷阱
• 抓不到的异常
Demo
• 尝试解决
Demo_fix
14年11⽉月27⽇日 星期四
第99页
⼩小⼼心domain的陷阱
• 抓不到的异常
Demo
• 尝试解决
Demo_fix
• WARN :
14年11⽉月27⽇日 星期四
第100页
⼩小⼼心domain的陷阱
• 抓不到的异常
Demo
• 尝试解决
Demo_fix
• WARN :
没有绝对的万全之策. RD多想,QA多测.
14年11⽉月27⽇日 星期四
第101页
回顾⼀一下
14年11⽉月27⽇日 星期四
第102页
回顾⼀一下
• 框架⼀一定会有,不论是否愿意.
14年11⽉月27⽇日 星期四
第103页
回顾⼀一下
• 框架⼀一定会有,不论是否愿意. • 框架的迭代过程,就是在简单与复杂中博弈的过
程.
14年11⽉月27⽇日 星期四
第104页
回顾⼀一下
• 框架⼀一定会有,不论是否愿意. • 框架的迭代过程,就是在简单与复杂中博弈的过
程.
• 不要试着⼀一起解决所有问题.问题永远⽐比你想的 多.只解决必须关注的就好.
14年11⽉月27⽇日 星期四
第105页
回顾⼀一下
• 框架⼀一定会有,不论是否愿意. • 框架的迭代过程,就是在简单与复杂中博弈的过
程.
• 不要试着⼀一起解决所有问题.问题永远⽐比你想的 多.只解决必须关注的就好.
• 选择有通⽤用性的问题解决.
14年11⽉月27⽇日 星期四
第106页
回顾⼀一下
• 框架⼀一定会有,不论是否愿意. • 框架的迭代过程,就是在简单与复杂中博弈的过
程.
• 不要试着⼀一起解决所有问题.问题永远⽐比你想的 多.只解决必须关注的就好.
• 选择有通⽤用性的问题解决. • 适可⽽而⽌止,让最少的建议发挥最⼤大的价值.
14年11⽉月27⽇日 星期四
第107页
回顾⼀一下
• 框架⼀一定会有,不论是否愿意. • 框架的迭代过程,就是在简单与复杂中博弈的过
程.
• 不要试着⼀一起解决所有问题.问题永远⽐比你想的 多.只解决必须关注的就好.
• 选择有通⽤用性的问题解决. • 适可⽽而⽌止,让最少的建议发挥最⼤大的价值. • 所有细节都很重要,即便是只有 0.1%的影响.
14年11⽉月27⽇日 星期四
第108页
Thanks!
• GitHub : https://github.com/clouda-team • 官 ⺴⽹网: http://clouda.com/ • Q Q 群 : 53732724
14年11⽉月27⽇日 星期四
Email : wangsu01@baidu.com Hi: wangsu1944