Fluid Framework 简探 (一)

1,907 阅读6分钟

(萌新第一次写文章 可能写的不够深入或者有理解不到位的地方...还请大家轻喷😰)

学习自Fluid Framwork官方文档 Fluid Framework Documentation

简介

Fluid Framework 是微软开源的一个 前端框架无关 的用于分发和同步共享状态的框架.说人话大概就是...一个能实现多端共享数据实时同步的框架

使用Fluid所提供的数据结构和接口,可以像使用本地数据一样使用共享数据,同时数据会自动保持的多端同步,并且延迟低服务器负载也小(至少他们自己是这么说的).

把同步逻辑和业务逻辑开发本身分离,使用低延时的框架,能更好的专注于客户端开发本身.

目前微软自己基于Fluid开发的应用有: 

  • Mircosoft Whiteboard (支持多人协同的画板)
  • Mircosoft Loop (尚未发布,看上去像是notion一类的多人协同双链笔记)等

架构

使用Fluid Framework进行开发的话,客户端之间的架构大致是这样的:

Fluid 0.png 在Client端有一个类似于桩的东西 (官方没有提到Stub哈 是我自己这样认为的)负责共享状态的维护和与Server端交互,屏蔽底层的实现逻辑.

作为用户则可以通过Fluid提供的接口绑定事件,实现事件监听,数据修改等功能,当一个端的数据被修改,其他端的Fluid就会触发相应事件,从而实现数据的多端同步.

为了尽量的低开销和高效,Fluid在设计时尽可能地简化server端的逻辑,让client端的更多的参与对状态的维护:

image.png (图来自Fluid官方文档)

Fluid将数据的修改删除等维护表示为对数据结构一个一个的数据操作(data ops), 而server端只做一些简单的处理,并不亲自执行数据的合并操作,比如:收到的数据操作之后拿个号排上队就可以广播出去了(当然它自己也会留一份作存储什么的).这样每个client端在接收到发过来的数据操作队列之后,由client端自己进行merge操作,既能自己独立准确的复现其他端对数据的操作,同时也降低了Server端的开销,从而降低了延时.

客户端

image.png (图来自Fluid官方文档)

这幅图很清楚的呈现了Fluid Client端的大致结构.

Client端分为两大部分 分别是管理状态的Fluid Container 和 负责连接Sercive和拉起/创建Container的Fluid Loader

Container

先来说Container, Container中包含了app对数据操作的逻辑和数据本身.

一个Container中至少有一个Shared Object来存储逻辑,必要时也可以有多个Object.SharedObject可以拥有state,由DDS(Distributed data structures)负责存储和管理共享.当调用数据相关的逻辑的时候,DDS就联系Server自动共享至其他Client端,触发与之相同的操作,从而实现数据的同步.

DDS支持不同类型的数据类型,除了常规的key-value型,Sequences型(大致可以理解为数组),Strings型等类型之外,还有一些特别的类型,比如,而且后面一些实验性的数据类型还在添加中.

Loader

Loader负责与Fluid Service连接,并创建和加载Container

这里为什么需要Loader呢

第一是当Client加入一个协作环境中时,线上可能已经有数据了,这时候就不需要再另起炉灶新建Container了,而是需要Loader从Service上把已经存在的Container"加载"过来;

还有比较特殊的就是,在图中可以看到Fluid Loader里还有一个"Code Loader",官方文档里对这个Code Loader是这样解释的:

Code loader
If your app is bundled separately from your container code, Fluid can use a code loader to download and load the container code bundle dynamically.

凭借我多年的经验(bushi)和拙劣的英语,妄加猜测一下这段话的意思:在程序运行期间,对面的Client端还可能给Container会增加新的处理逻辑,这些函数操作啊什么的也要同步加载过来,否则就不认识对面发过来的data operations了

服务端

Fluid官网他们说,现在还没有成熟的Server端实现,目前要么上微软自家Azure去搞一个 Azure Fluid Relay,要么 这里有两个不够生产级别质量的Server端还在开发中

Tinylicious

如其名所言,这是一个很小的只是用来开发阶段测试用的小server,数据也是放在内存中的,待会儿跑quickstart的时候会用到

Routerlicious

这个才是正儿八经的Server实现 我在他们的GitHub页面找到了这样一张架构图

image.png (图片来自Fluid 官方Github页面)

一张典型的微服务架构图

Alfred

与用户交互的入口,客户端通过连接到Alfred来连接到相应的流,也就是加入协作啦,然后再进行提交修改,检索历史,或者创建新组之类的.旁边的Redis里放着的是用于推送的数据操作,如果有的话也随时从Alfred这里推给用户.

当Alfred收到用户的操作之后,放入Kafka的队列里,等待Deli消费.经整理后进行广播或是交由Scribe和Scriptorium作进一步的处理和存储.

Deli

Deli接收一堆没被编号也没被排队的数据操作过来,然后Deli挑拣一下,看看他们各自都是对应哪个组的,然后按照各自的分组给他们自增编号.做完这些交给Boradcaster,让它去操作Redis好让Alfred发回给用户.而另一手也把编号的操作序列放入Kafka给下一级消费.

Scriptorium

就是把序列存到数据库里 这里用的数据库是MonogoDB

Scribe

Scribe负责写一下入站摘要啥的,然后放到Historian那里方便历史追溯

Historian

Historian负责存储快照.本身基于Git的REST API来实现的,所以理论上也可以接入自己的git仓库或者github仓库等等.

大致总结一下吧 Alfred负责与用户的交互和收发推送,收到之后交给背后Kafka里,同时留意着Redis里是否有待发的消息.处理的核心是Deli,主要负责编号和整理.Scriptorium负责把Deli整理好的东西持久化,而Scibe和Historian合力负责把快照存到git中去,同时也管理历史树.

END

Talk is cheap, show me the code. 下一篇文章,我们来跑起来代码试试