专栏名称: 程序人生
十年漫漫程序人生,打过各种杂,也做过让我骄傲的软件;管理过数十人的团队,还带领一班兄弟姐妹创过业,目前在硅谷一家创业公司担任 VP。关注程序人生,了解程序猿,学做程序猿,做好程序猿,让我们的程序人生精彩满满。
目录
相关文章推荐
51好读  ›  专栏  ›  程序人生

胖客户端,瘦服务器?

程序人生  · 公众号  · 程序员  · 2021-03-01 08:04

正文

请到「今天看啥」查看全文


  1. 排序好的数据会打包成一个个 block,成为数据分发和获取的基石。这样每个客户端同步数据就变得简单:我现在块高在 9527,你是 9627,所以我需要 9528 - 9627 之间的所有数据。在此期间,新收到的数据我暂时存着,直到我的状态达到最新,再处理。

我们再看 Git:

  1. 客户端拥有全部状态。你可以不联网,依旧可以访问到所有本地的数据并该干嘛干嘛,联网后可以 手动 获取最新的 commits,本地一个 commit 一个 commit 去更新工作目录(working directory),把本地工作目录更新到最新。

  2. 客户端发送 commit 以及这个 commit 里更改过的 blob,「服务端」不自动进行数据的排序,完全依赖于客户端提交的 commit 基于最新的 commit。如果两个 commit 有冲突,客户端需要 手动 解决(区块链通过预置的 consensus 算法解决)。 这样提交到服务端的 commits 自然是排好序的。

  3. 对于 Git 来说,commit 以及和 commit 有关的 blobs 是数据分发和获取的基石。客户端同步数据也很简单:我的 head 是 0b39,你的 head 是 a758,我们中间有 100 个 commits,于是我需要所有这些 commits 以及它们包含的 blobs。如果这个过程中或者过程前本地产生了新的 commit,那需要经历一次 merge。

我们从两者的共通点看看可以学到什么有用的东西:

  1. 客户端产生事件(event),事件经过排序(无论手工还是自动)后被打包储存成方便读取的形式(区块链一般使用 linklist,而 Git 使用 DAG),供其他人访问。

  1. 事件是原子的,不可修改的。客户端按顺序拿到所有有关的事件后,就可以构建一致的状态了。

  1. 客户端告诉服务器自己获取到的最新的事件是什么,就可以很容易从服务器拉取从这点之后的所有事件了。除了第一次拉取数据外,以后的更新,都是增量更新。

  1. 如果客户端的状态被破坏了,只需要重新 replay 一遍所有的事件,就能复原整个状态。

  1. 客户端如果卸载了,全部本地数据丢失,也可以重装后全量 clone 一下服务端的数据,就能恢复整个状态。

循着这个思路,我们可以构造出客户端和瘦服务器间的所有交互:

  • Clone:拉取全量数据

  • Push:提交本地生成的新的事件

  • Pull:拉取从某个事件之后的所有事件

在这个基础上,还可以加上 Subscribe/Unsubscribe 来监听某些感兴趣的服务端得到的新的事件。

这和我们熟悉的 Git 操作非常类似。

当然,这些操作披着 Git 的外衣,但处理方式更贴近区块链。因为我们希望由服务端的共识算法来决定如何排序,而不是靠客户端之间手工同步,这种方式,对用户很不友好。

但是,我们又很不喜欢区块链低效的,全局排序的处理方式(全部数据全局共识)。事件之间是有内在联系的,不相干的事件放在一起排序是没有意义的(这就是我认为 BTC 的全网共识的思路是 ok 的,而 ETH 是别扭的,不 ok 的,每个 contract 的 tx 应该只跟这个 contract 相关的 tx 进行排序做共识)。所以,从 Git 那里,我们可以偷师 repo 的概念:事件的排序发生在 repo 内部;不同 repo 间的数据,可以不需要排序。

所以,我们用 repo 作为事件的防火墙。一个 repo 类似一条区块链。

兵棋推演:瘦服务端的实现

好,我们有了基本的架构思路后,接下来就是怎么实现它。

一般到这个时候,就是数据库的选型了。

等等。 为什么我们需要数据库?

呃。。呃。。因为,好像,我们现在做软件设计不都是从 database schema 开始么?

似乎也对。那么稳妥起见,我们找个 RDBMS,比如 Postgres 开始吧。

我们要存储的主要对象是事件。按照我们刚才的描述,一个事件大概长这个样子:

repo_id:事件属于哪个 repo(这个 repo_id,类似于 partition key)

  • timestamp:服务器端插入事件的 UTC 时间戳

  • signature:事件是由谁签署的(参考区块链),从这个信息我们可以确认事件的作者以及事件的有效性

  • event data:protobuf 或者其他方式序列化的事件数据本身。这里用 protobuf 或者类似的解决方案,是为了数据格式升级后,应用程序依然能够兼容历史数据。注意,这里的 event 不要跟 analytics event 混淆哦。







请到「今天看啥」查看全文