如何搞定前后端一体的状态管理
背景
最近在写 一个消息系统的进化史 ,写的过程也是不断思考的过程,于是,我自然而然地会去思考: 消息的触发机制往往是一个外部状态的变动,然后在消息系统的分发中枢做分发,那么,是否存在内部的状态变动而触发消息的需求呢?
探索
在前端体系下,这是一个非常常见的需求,例如在浏览器中,维护一个 global 状态,其他各处的组件都可以监听这个状态的变动,由此触发一系列的连锁变动。在现代前端框架中,vue 下的 vuex,react 下的 redux 都是在做这件事。 即使是最原始的 OBM,监听元素变动事件也是这样的机制。
然而在服务端,这个场景不是特别典型。在当前流行的后端架构下,应用的分布式部署 和 无状态化 成为主流,状态
都是由中央数据库(中间件)维护的,即使要实现消息的分发,也几乎是位处中央的中间件去实现,例如 mysql、monogo、redis 等等。
而实际上,确实非常多的中央数据库都实现了 watcher 接口,例如 mongodb、redis、rocketMQ、zookeeper、etcd 等等。
价值
虽然主流的场景下直接使用中央数据库的 watcher 就可以了,但仍然也存在单机下,通过内存维护状态,并且有监听需求的场景,因此,决定写一个简单的可监听 map 变动的工具。
在消息系统的场景中,目前能想到的应用是:
单机上的 room 存在一些公共状态,在这个 room 中的很多成员都有修改这些状态的能力,例如 房间名称
、房间描述
、是否允许自由加入
等等,如果把这些变成一个个的接口,则会有不少冗余的开发,如果把这些变成每个连接监听的状态,状态发生变动时,自动推送变动通知,则相当于客户端和服务端存在一个共同的状态管理了。
示例
1 |
|
实现
由于是在写 消息系统进化史-零号机 的过程中想到要实现该能力的,因此代码就先放在同一个仓库中了,详情见 bigmess/pkg/responsivemap
在写完这个项目后,发现了另外两个项目,和我这个实现的理念不谋而合:
- vue-socket-io 以及其相同能力的实现 socket.io-extended
- redux-socket.io
实际上,状态的同步,如果以 中心化
的理念去设计,就需要在服务端有一个同样的数据模型,并且所有的触发操作以中心节点的变更为准。 如果是以 去中心化
的理念来设计,服务端只要有一个消息转发机制就行了。
去中心化的理念,在一些协同场景中,就会结合到 CRDT 之类的方案; 而中心化的理念,协同场景中就会有 OT 之类的方案。
甚至你会发现,上面这类 vue-socket.io 的能力,如果把基于 vuex 的部分变成基于 yjs 这类,就成了一个分布式的、拥有 CRDT 能力的协同操作场景了。
后续
- 看情况考虑实现数组的监听
- 将库进行分层组装,暴露该暴露的
- 使用 eventhub 找到更好的实现监听机制的写法
- 写一些 redis、zk、etcd、rocketMQ、mongodb 的监听机制的 demo #important
- 在消息系统一号机中,使用该库形成前后一体状态管理
- 考虑分布式状态管理的实现
True happiness arises, in the first place, from the enjoyment of oneself, and in the next, from the friendship and conversation of a few select companions.
— Joseph Addison
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!