-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat:add sticky cluster mode #14
Conversation
@ngot, thanks for your PR! By analyzing the history of the files in this pull request, we identified @dead-horse, @popomore and @atian25 to be potential reviewers. |
Codecov Report@@ Coverage Diff @@
## master #14 +/- ##
==========================================
+ Coverage 96.25% 96.58% +0.33%
==========================================
Files 7 7
Lines 267 293 +26
==========================================
+ Hits 257 283 +26
Misses 10 10
Continue to review full report at Codecov.
|
参考来源? |
@popomore @fengmk2 @dead-horse 同志们帮忙review下 |
改动有点大,需要点时间去消耗一下什么是 sticky |
@@ -34,7 +34,22 @@ function startServer() { | |||
// emit `server` event in app | |||
app.emit('server', server); | |||
|
|||
server.listen(options.port); | |||
if (options.sticky) { | |||
server.listen(0, '127.0.0.1'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这一步 listen 有什么作用?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
原来的cluster模式完全没有改变。每个worker内的http的hander,依然需要存在,用来接受master转发过来的socket对象,来进行下一步的处理。这里listen 0只是为了启动http handler,而不暴露出去。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
去掉这个 listen 应该也是可以的。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
需要listen,不然逻辑走不下去
lib/master.js
Outdated
}).listen(this.options.port); | ||
} | ||
|
||
stickyWorker(ip) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
要写一个测试,看看 stickyWorker 这个算法是否分配均匀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个算法,是根据用户的IP和进程数量做的一个hash匹配。能够保证,某个固定ip映射到某个固定Worker。但是其实,并不能完全保证平均分配。如果,实际访问的样本IP是平均分布的,那么问题不大,如果是集中某几个固定IP,那么就会导致非常不均衡。昨天,想到公司内部做过代理,导致来源IP被篡改为公司固定的出口IP,是有问题的。
lib/master.js
Outdated
@@ -309,6 +343,11 @@ class Master extends EventEmitter { | |||
} | |||
|
|||
this.isAllAppWorkerStarted = true; | |||
|
|||
if (this.options.sticky) { | |||
this.startMasterSocketServer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
startMasterSocketServer 也是一个异步过程,它成功了才能 ready 成功
return this.startMasterSocketServer(err => {
if (err) return this.ready(err);
this.ready(true);
});
test/master.test.js
Outdated
app.ready(done); | ||
}); | ||
|
||
after(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
app.close() 返回的是 promise,需要 return 才会生效,写成 after(() => app.close())
吧
test/master.test.js
Outdated
describe('--sticky', () => { | ||
before(done => { | ||
app = utils.cluster('apps/cluster_mod_sticky', { sticky: true }); | ||
app.ready(done); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return app.ready() 即可,不需要 done 了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
if (options.sticky) { | ||
server.listen(0, '127.0.0.1'); | ||
// Listen to messages sent from the master. Ignore everything else. | ||
process.on('message', (message, connection) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
忽略其他消息这个会不会影响到 messeger 那边?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
应该不会,这个只是新增一个listenser,只限定在这个逻辑,不会影响其他的。
lib/master.js
Outdated
@@ -58,8 +58,12 @@ class Master extends EventEmitter { | |||
|
|||
this.ready(() => { | |||
this.isStarted = true; | |||
this.logger.info('[master] %s started on %s://127.0.0.1:%s (%sms)', | |||
frameworkPkg.name, this.options.https ? 'https' : 'http', this.options.port, Date.now() - startTime); | |||
let stickyMsg = ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const stickMsg = this.options.sticky ? ' with STICKY MODE!' : '';
lib/master.js
Outdated
const wsd = ws.map(w => w % workerNumbers); | ||
|
||
let s = ''; | ||
for (let i = 0, _len = ip.length; i < _len; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i < ip.length
就可以了
lib/master.js
Outdated
s += ip[i]; | ||
} | ||
} | ||
s = +s; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s = Number(s)
吧
lib/master.js
Outdated
|
||
let s = ''; | ||
for (let i = 0, _len = ip.length; i < _len; i++) { | ||
if (!isNaN(ip[i])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里是不是用一些 hash 算法会比较好一点?不然很容易就造出一系列 ip 地址全部都连接到一个 worker 上了。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
嗯,是的,我也有这个担忧
Codecov Report@@ Coverage Diff @@
## master #14 +/- ##
==========================================
+ Coverage 96.25% 96.58% +0.33%
==========================================
Files 7 7
Lines 267 293 +26
==========================================
+ Hits 257 283 +26
Misses 10 10
Continue to review full report at Codecov.
|
s += ip[i]; | ||
} | ||
} | ||
s = Number(s); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
那直接改成 hash(ip) % workerNumbers
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我研究看看,有没有更好些的算法
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
框架本身的话,没有找到很好的算法。大多数做法,还是在集群前面架设负载设备来做。目前,就这样其实就已经够了。
LGTM, need @dead-horse one more +1 |
+1, 先这样,到时候文档里面说清楚这个模式下的一些弊端和怎样配合反向代理使用好了。cluster 的文档里面都可以不介绍这个功能,只在 socket.io 的文档里面说明好了? |
1.4.0 |
就只在 |
Checklist
npm test
passesAffected core subsystem(s)
Description of change
增加sticky模式,用于websocket服务模式