
## 将分布式延伸到用户端

为了支持用户自部署以及将数据存储在本地，我们做了一个大胆的尝试，将分布式服务延伸到用户端

![distribute-flex](docimgs/distribute-flex.png)

传统的 B/S，和一般的微服务架构，对用户而言，依然是 “中央” 式服务。kstore 将分布式延伸到用户端后，也具有了一些明显的优势：

- 可就近为用户提供服务。在任一网络，用户总可以直接访问本地或局域网的 kstore 服务，用户体验极佳
- 断网依然可用。断网后只是导致不能和其他网络中的设备进行同步，但本地或者局域网的 kstore 依然可用；网络恢复后再次同步
- 真正意义上做到了用户对服务可控

当然，这种架构也面临着一些极具挑战性的问题或限制，例如：

- 数据的存储，不能像一般的微服务分布式架构那样，直接做分块分片处理。这方面 kstore 使用了自己的[存储策略](/store_strage)
- 用户自部署的 kstore 服务可能没有启动，分布式环境下如何保证数据的一致性（该问题见下面小节）
- **限制：**当请求一个文件时，至少要保证有一个在线节点拥有该文件

## 网络通讯

分布式环境下，一个 kstore 服务在其[所属子网](/admin_self_network)中，会通过种子节点尝试与该子网中的其他设备建立连接，还有通过局域网中的自动发现服务查找更多的同一子网中的设备。

另外，kstore 在运行过程中，也会周期性地检查已经建立的连接的健康状况并重新查找更多的设备。当然也有连接数限制，目前是 100 个。

!> kstore 服务同时扮演了两种重要的角色：一个是提供存储服务，另一个则是提供中继通讯服务

在发起传输文件时，kstore 会在子网网络中查找可达的传输路由，并在文件提供方与传输目标设备之间尝试建立 P2P 连接，尽可能地利用多种传输路径以提高传输的速率以及成功率。

## 最终一致性：CRDT

由上面得知，我们采用的是将分布式延伸到用户端的架构。由于用户自部署的 kstore 服务是否启动我们不可控，因此不能采用**强一致性**的处理方式。

kstore 的处理方案中，选择了**最终一致性**的处理方式，即允许分布式环境中一些节点在某个时刻数据可以是不一致的，只要系统一直运行（关闭服务的后续再启动），各个节点的数据最终可达到一致。

!> 注意：这里说的数据一致性，是指元数据方面（文件名称等属性还有文件列表等），而不是文件的实际存储数据

`CRDT`(Conflict-Free Replicated Data Type，直译“无冲突可复制数据类型”)，是各种基础数据结构最终一致算法的理论总结，能根据一定的规则自动合并，解决冲突，达到最终一致的效果。想了解更多的请自行搜索更多相关资料。

我们实现了符合 CRDT 要求的数据结构，例如 `G-Set`, `LWW-Set` 还有 `Treedoc` 等，这为达到**最终一致性**给予了有力保证。同时也给用户自部署 kstore 服务的控制上有非常自由的空间。例如下面的使用场景都是可以的：

> 用户在家里的两台机子(分别为A，B)上都部署了 kstore 服务
1. A 启动服务，B 退出服务。在 A 机子上执行一系列操作：上传文件，重命名，移动和删除文件等
2. A 退出服务，B 启动服务。在 B 机子上也执行一系列操作
3. A，B 都启动服务，一段时间后（很快），在两台机子上浏览到的数据就是一致性的了