-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
增强多进程研发模式 #322
Comments
最后这个 SDKClient 能给个具体的例子吗? const client = cluster(RealClient, SDKClient) |
没看懂为啥不能 delegate 普通函数? |
是因为在调用 sub 时如果是 follower 直接走了 cluster 的逻辑而没走 realclient 的逻辑么? 这里就是我之前提出的问题,cluster-client 在这里切的太早了,我认为应该是由 realclient 自行转调。
|
如果是同步的 API,根本没法代理的,因为我们是通过 tcp 连接做 invoke,所以势必只能是异步的 API 才能 work。 |
上面那个 SDKClient 的 class 就是例子。当然还可以进一步精简,例如提供一个基类,转调 subscribe 和 publish 可以自动完成。 |
所以归根到底的问题还是 follower 做 sub 没法缓存数据,get 就取不到了
Shawn <[email protected]>于2017年2月6日 周一21:53写道:
… 没看懂为啥不能 delegate 普通函数?
如果是同步的 API,根本没法代理的,因为我们是通过 tcp 连接做 invoke,所以势必只能是异步的 API 才能 work。
@popomore <https://github.com/popomore>
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#322 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAWA1ZtxvVg247bOAeMyHvHApq5Geuvuks5rZyXkgaJpZM4L4EqW>
.
|
是的 |
不仅仅有函数的问题,还有一些需求,我们想提供事件、以及某些public 属性,只通过现在的 ClusterClient 还是挺难做到的。 |
感觉我说的方式才能真正解决问题
Shawn <[email protected]>于2017年2月6日 周一21:57写道:
… 不仅仅有函数的问题,还有一些需求,我们想提供事件、以及某些public 属性,只通过现在的 ClusterClient 还是挺难做到的。
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#322 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAWA1cW_DJQm_FBeX32MAGG61BJnjkfJks5rZya5gaJpZM4L4EqW>
.
|
这样另外一个好处是,agent 和 app worker 中 client 的 API 真正达到了完全的一致,因为访问的都是 SDKClient。
内部的 antvip 实际上用的是这个模式做到 API 完全抹平(主要是这个模块的同步 API 计算逻辑太多,不是简单在两个进程里都搞一些就搞的定的),当时因为没有广泛使用的概念抽象,理解起来反而复杂了。所以想试试结合现在的 cluster-client,如果能推广开就更好了。 |
@popomore 你说的那个方式其实和我的比较类似,你是想暴露的是 realclient 给用户使用,内部转调 clusterClient,或者 extend。但是这样有个问题,realclient 里的实现不好做,需要考虑当前跑在哪里,sub 和 pub 这块以及 invoke 的函数设计都不好做了。或者你可以举个例子,写写伪代码看看。 |
@shaoshuai0102 你的这个例子,ClusterClient 貌似不需要修改什么,就是外边再做一次封装 class APIClient extends Base {
constructor(options) {
super(options);
this._client = cluster(RealClient).create({});
this._client.ready(() => this.ready(true));
this._cache = {};
// config.subMap:
// {
// foo: reg1,
// bar: reg2,
// }
for (const key in config.subMap) {
this.subscribe(onfig.subMap[key], value => {
this._cache[key] = value;
});
}
}
subscribe(reg, listener) {
this._client.subscribe(reg, listener);
}
publish(reg) {
this._client.publish(reg);
}
get(key) {
return this._cache[key];
}
} |
是的。cluster-client 主体不修改的,但定位变了,本来是用来解决全部问题,包括抹平 API,现在变成只解决数据同步方面的 API。最终的用的是 APIClient(内部转调 ClusterClient)。整体方案可以内置到 cluster-client 模块中,以 |
是不是可以约定 cluster-client 封装的都是纯接口的 client (不带业务逻辑,不包含缓存等等),然后外边再对其进行业务封装 |
是的。也可以说只做数据操作。 |
举个简单的例子,比如 configclient,以前我们会对订阅到的数据进行处理后再吐给业务,现在我们就将它拆分成两部分,一部分就是纯粹的订阅、发布 api 实现,这部分可以很容易的被 cluster-client 封装,另外一份就是对它的进一步封装 |
是的是的 |
有点 meteorjs 同步数据的感觉? worker 是前端调用,agent 是后端 rpc 代理 。 |
我的想法是 cluster 基类的 API 和 net 的一致,比如调用 sub 时 cluster 来判断是否调用远程 server 还是自己实现。如果难实现可以开放一个函数让客户端来实现自己的 sub |
@popomore 写一下例子解释下你的想法吧 没 get 到。 |
明天写个,不在电脑旁 |
实例代码 @shaoshuai0102 @gxcsoccer const { BaseClient, SUBSCRIBE } = require('cluster-client');
class Client extends BaseClient {
get() {
// 获取缓存
}
subscribe(...args) {
// 做些 hack,缓存订阅代码
// 父类判断是否为 leader
// leader 调用 client 端的实现
// follower 转调 leader 的客户端的实现。
super.subscribe(...args);
}
// 实现本客户端的 sub
// 这里我不是很清楚能否抽象,最差就是客户端自己实现
[SUBSCRIBE]() {
}
}
|
做一下 bind 就可以了吧 app.client = new APIClient(Object.assign({}, config, { cluster: app.cluster.bind(app) }); |
反正意思差不多,最好是插件只需要传递一个 |
我改一下 |
根据 @dead-horse 的建议做了简化,更新到上面的回复了 |
|
updated |
ZookeeperClient 就是一个开源的例子 |
仓库在那里 没找到 |
有时间我包一下 |
@fengmk2 zk 基于哪个你上面说的模块还是基于 https://github.com/dannycoates/zkjs ? 我看 zkjs 最后一个mr 是你的 |
@shaoshuai0102 请问"由于 clusterClient 的 API 已经被抹平了多进程差异"这句话中 “被抹平了多进程差异”具体指的什么? |
@gxcsoccer 可以帮解释下 |
@shaoshuai0102 这句话的意应该就是说 clusterclient 帮你封装了进程间交互的问题,让你感知不到多进程模式的存在 |
我写了几次,都没法测出多进程。 |
definition worker
use |
可以考虑在框架层面抹平多进程差异,比如在Service层面抹平多进程差异,所有Service都在一个独立Worker中运行 |
几年后回头再看这个模式,还是挺厉害的。 |
这个设计挺好的,但是存在一个问题,对于 保留两层结构设计,使得用户无需感知多进程实现的 |-----------------------------|
| ClusterClient |
|-----------------------------|
| | RealClient |
|------|----------------------| |
讨论结论
1. 开发 DataClient
2. 包装出 clusterClient
cluster-client 模块保持不变,通过
cluster(DataClient).create()
生成支持多进程的 ClusterClient3. 开发 APIClient
例如增加带缓存的 get 同步方法:
4. 模块向外暴露 API
5. plugin 开发
附:
issue 原始内容如下
cluster-client 模块给我们提供了强大的功能,在 sub/pub 模式下使得我们能够只开发一个客户端,在不同的进程中运行同样的 API,且复用同一个远端连接。
一个最简单的例子:
这段代码运行于多个进程,我们在每个进程都可以使用:
brilliant!
但 ClusterClient 同时带来了一些约束,如果想在各进程暴露同样的方法,那么只能是 subscribe publish 和 generator 函数。
假设我要实现一个同步的 get 方法,sub 过的数据直接放入内存,使用 get 方法时直接返回。要怎么实现呢?
cluster-client 提供了 override 方法,你可能会想:
这时你会发现不可行,因为还没有 create 之前,我们无法拿到实例进行提前 subscribe,进行缓存。
所以这里建议一种模式,再包一个 API class:
这样我们就可以:
当然这个例子太简单,看起来收益并不大。但是有些功能不仅仅是 sub 到数据就可以了,还需要做出复杂的处理,这种方式就变得有意义了。
好处还有提供一种统一的拓展模式,否则只要是同步的 API,开发者都需要实现一种 patch 的方式,写法太灵活了。
总结一下:
这种增强可以进一步固化到 cluster-client 中。
通过这种方式一键返回最后需要使用的客户端。当然,对于只需要 pub/sub 的简单客户端,直接
cluster(RealClient)
即可,和原来是一样的。The text was updated successfully, but these errors were encountered: