第1页
Node.js⾼高并发聊天 服务实战
⺩王⽂文明 Github: wangwenming
2015-03-28
第2页
⼤大纲
背景 技术选型&极简架构 性能优化⼯工具
第3页
背景
产品:
• http://www.haosou.com/s?q=exo&src=node • http://t.haosou.com/chat/tantanmobile?topic=exo • http://xiaohua.hao.360.cn/daojie 点进去再滚到底部 • http://tantan.360.news.ifeng.com/news?nid=54d82f5ca15903ec558b4568#_zbs_360_tantan • 世界杯期间 cntv 直播⻚页⾯面
数据:
• 同时在线约 100万 • 每秒接⼊入连接数 5000 • 最⼤大的⼀一个Topic有10万⼈人 (m) • 每秒⼲⼴广播消息 20条 (n) • 每秒⼲⼴广播消息数 200万条 (m * n)
第4页
技术选型
⻓长连接
Q1: ⻓长连接、轮询?
• 举个例⼦子:微博PC版,有2个: 1. 30S⼀一次的轮询(push_count) 2. im的WebSocket
Q2: ⻓长连接⽅方案
• Flash (双向通信) • .WWeebbSSocket (双双向向通通信信))rfrcfc6644555(2(021011.11.21)2,),⼿手⼿机手机上上混合混开合发开⽆发无法⽆无跨法域跨 域
fayyee--wweebbssoocckkeet@t@00.7.7.2.2(w(webesboscokcekt-edtr-idvreirv@er0@.50.3.5) .3) 66445555在在⼿⼿手手机机上上的的⽀⽀支持支持AAndnrdoriodi>d=>4=.44.M4 oMboilbeiSleafSaarif>a=ri6>.=06.0 • .LLoonnggPPuullll xhr stream•ing (rexshprosntrseeaTemxitn⾮g非⼀(r一e次sp返on回se,Teoxntre⾮a非d⼀y一s次ta返tec回ha,ngoen,rexahdr.yrestaadtyeScthaaten=g3e),Cxhhror.mreeadFiyrSeftoaxte=3) Chrome Firefox Forever F•rame(ifFraomreeve/ rHFTrTamP 1e(.1ifrCamhuenk/ eHdTETnPco1d.1inCg)hIuEn,k但ed是E会nc⼀o一d直inLgo)aIdEi,ng但是会⼀一直Loading HTMLFile•(ActivHeXTOMbLjFeiclet对(A象c)tiveXObject对象) JSONP,•Old IE下JSO要N跨P域,Old IE下要跨域 • 兼容性⼀一栏 • “Even Faster Web Sites: Performance Best Practices for Web Developers”
第5页
技术选型
⻓长连接框架
https://github.com/sockjs/sockjs-node Star: 900 @0.3.15
https://github.com/Automattic/socket.io/ Star: 16, 134 @1.3.2
1. #438 2011-08-01提出,作者rauch在2014-08-19关闭了这个 issue,也没有解决,有301个讨论 2. socket.io 的封装功能更多,包括Redis,消息的封装等 on(‘任意’) emit(‘任意消息’),SockJS有且只有1个 on(‘message’) 3. IP地址获取: x-forwarded-for sockjs/lib/transport.js:159
$ mocha test/echo-server.js
第6页
服务架构
尽量简单的架构
Master
T SlaveT
T1 T2 AB
C SlaveC
C1 C2 CD
第7页
服务架构
再简单⼀一点
http://en.wikipedia.org/wiki/Publish %E2%80%93subscribe_pattern
RedisManager.js
hmdel ping retry
数据结构 Hash - hmget hdel Set - sadd srem publish psubscribe 使⽤用O(N)复杂度的操作 ⼤大数据操作使⽤用cursor
第8页
LVS:80
服务架构
部署
Nginx:x.x.x.1-2
Node:900[1-3]
Redis
第9页
$ mocha test/chat-server.js
http://localhost:8080/tantan/chat-client.html?ui
> socket.post(new Date()); > setInterval(function() {socket.post(new Date());}, 2000);
第10页
性能优化
Chrome DevTools
第11页
性能优化
v8
$ d8 —prof --log-timer-events script.js # ⽣生成 v8.log $ mac-tick-processor v8.log $ plot-timer-events v8.log # 需要 Linux with gnuplot 4.6 来绘图
$ npm install -g tick $ node-tick-processor v8.log
http://v8.googlecode.com/svn/branches/bleeding_edge/tools/profviz/profviz.html
第12页
性能优化
v8-profiler
$ npm install v8-profiler $ npm install -g node-inspector $ node --prof --prof_lazy --log index.js 9011 /profile # 会⽴立即⽣生成⼀一个没有真实数据的 v8.log $ node-debug --web-port 8888 index.js 9011 /profile
语句上的优化: http://s3.mrale.ph/nodecamp.eu/#12
第13页
性能优化
压缩数据包
JSON是⽐比较冗余的,可从⽂文本上压缩
$ mocha test/unserialize.js 匿名压缩⽐比: 30.8%, 253B ==> 78B 登录压缩⽐比: 40.3%, 258B ==> 104B
GZIP压缩
Gzip有收益的建议最⼩小值是150-1000字节,150字节左右压缩了反⽽而会变⼤大
如果不考虑旧浏览器,可以直接使⽤用ArrayBuffer
Redis操作: O(m,n) => O(n)
strace(DTrace) -> $ sudo dtruss -cnp 29663 strace发现80%操作在 epoll_wait (只有1个线程)