Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

Sosoc 架构

  最近纠结了一坨 Web 架构的东西,最终也没能找到一个完美解决 Web 上 API 调用的东西。无论是 RESTful 还是 SOA 甚至 RPC,单独使用都有大堆的坑存在。虽然这些坑都可以填掉,但是面对这发展如此迅速的 Web,感觉还是有点力不从心。
  纠结到最后,感觉还是自己两年前造的这个轮子比较适合解决 Web 上 API 调用的问题。这个博客程序目前是使用基于长连接(使用 WebSocket 实现)的有状态对象共享架构,不过由于当时很多技术还不成熟,我的实现是非常渣的。另外由于这个概念描述起来太繁琐,于是我造了个词 Sosoc [ˈsɑsɑ:k] (stateful objects sharing on connection)。

基本概念

  Sosoc 是一个架构思想,其基本理念是客户端和服务器都同时维护一个对象的上下文环境,通过长连接来维持更新。

为什么需要这样的东西?

  也许有人会好奇,如今大家都在推行无状态、RESTful 之类的东西,为什么我却偏偏搞了一套有状态的东西出来?我觉得,旧时代的 Web(基于 HTTP 请求和响应)确实可以无状态实现,甚至非常适合无状态实现。但是我相信将来的 Web 会基于实时通信。一旦数据有了实时性的需求,它的实现就应该是有状态的。
  经常有人问这个博客里的「即时聊天」系统如何实现?我很难回答这个问题,因为我根本就没刻意去实现过它,「即时聊天」只是这个架构下的必然产物。

建立连接

  连接可以基于任何形式任何协议的长连接。当连接建立后,服务器端会生成一个实例(下文中的「实例」就特指这个实例)。这个实例会序列化后传到客户端,客户端可以访问这个实例上的属性、调用实例上的方法,甚至给这个实例添加事件。但是建议将这个实例设计为不可扩展的,因为扩展的属性或方法同步起来会非常痛苦而且很容易出错。

属性同步

  实例必须通过一套机制来同步客户端和服务器端的属性。比如客户端手动改变属性的值时会发一个请求到服务器通知对方也做相应的改变,反过来也一样。另外建议给属性变化添加事件(或者让对象自己支持属性变化的监听),这样可以更及时地让程序处理变化后的属性。

方法调用

  方法调用基于一套 RPC 来实现,其返回的结果总是无状态的结构体。我也曾考虑过让方法调用支持有状态对象,但发现实现起来会变得非常复杂。游离于实例的对象还得考虑远程 GC 的同步。虽然可以实现,但总感觉使用不当很容易造成内存泄露。所以放弃了这个做法。
  程序上可能使用一套异步机制(比如基于 Promise/A+ 实现异步方法)来处理调用。当在实例上调用方法时会向对方发送一个调用请求,并把相应参数传过去,服务器响应后再执行预先设置好的回调。
  此外,由于前面定义了「实例由服务器返回」、「不允扩展实例」,所以实例上的所有方法都由服务器提供,那么这里的 RPC 则是单向的,只有客户端调用服务器的方法,服务器没有机会调用客户端定义的方法(因为客户端不能添加方法)。这个奇怪的限制是因为客户端的不确定性太高,如果存在「直接调用」这种程度的耦合就很容易出错。如果服务器端有主动调用客户端的需求可以通过事件实现。

事件机制

  事件机制其实是一个库级别的东西,任何对象只要引入一个事件模型都可以实现事件。比如一个对象继承于某个事件模型后就拥有了 on、off、emit 等方法。然后只要通过方法调用就可以实现事件的绑定了。
  但是通过 RPC 操作这些方法并不太容易,因为通常 RPC 只定义了值类型,而事件操作需要传递的是一个函数指针。这时候就需要维护一个 Map,将所有回调函数添加一个可序列化的唯一标识符来传输。

Sosoc 的优势

  1. 将 API 调用变得像对象方法调用一样方便。
  2. 事件机制可以把复杂的手动数据同步简化掉。
  3. 对实时通信非常友好。

Sosoc 的缺陷

  1. 服务器端需要维护长连接和对象上下文,产生巨大的内存开销。
  2. 长连接在某些浏览器上的支持并不好。

现状

  目前还没有提供一套开源的封装,不过我应该会去造的。因为目前我使用的这套太古老了,而且实现也烂得拿不出手,正打算重新造一套开源的。

网名:
34.203.245.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^