关于思源同步为啥这么慢的探究

太长不看:

  1. 扫盘建立快照不够高效,占比 10%
  2. 网络条件拉跨,占比 10-100%(假如你家网速正常就 10%,不正常直接断了,影响算 100% 是没问题吧trollface
  3. 同步有锁,必须交替进行,占比 30%
  4. web 上传对小文件极不友好,占比 50%

关于一些前置的讨论可以看看 Issue #12246 · siyuan-note/siyuan ,我在这里研究了下 obsidian 的 livesync 插件与思源同步机制的差异,试图搞清楚,为啥都能使用 S3 作为同步中介,livesync 可以做到实时同步,而思源则有明显的卡顿感。

一个反直觉的观点是,思源的快照机制并不慢,至少不是同步慢的最主要问题。以下是测试出来的快照建立时间于同步时间之间的差异:

  • 日记编辑 0.75s,未同步
  • 主题更新(22 个文件,2m 数据量)0.86s,同步时间 3s
  • 安装插件(650 个文件,20m 数据量)3.36s,同步时间 94s
  • 删除插件(删除 650 个文件,20mb 数据)0.86s,同步时间 14s

以上都是先建立快照,再进行同步的操作,换而言之,同步的时间已经是去除快照建立的时间了,但是还是可以看出相对于快照操作是很慢的。

因此同步慢的的最大根源就是同步加锁……而已吗?

直到今天之前,我都是这个观点,但我忽然想到,同步加锁只是会影响到另一端同步并下载云端内容的速度,理论上不会影响到我这一端上传的速度,或许还要严格评估一下 web io 对于同步速度的影响。因此我直接在本地搭建了一个 docker minio,新开了一个库作为测试。我同时把我主笔记库的数据复制过来了,总共是 800m 的大小,6500 个文件。

我阅读了 dejavu 的代码,发现它里面有对同时上传文件数的限制。我合理的怀疑这就是问题的根源。于是,我拉到本地,进行修改,将同时上传、下载文件数的限制,也是 NewPoolWithFunc 的 poolSize 全拉高了 10 倍,重新打包思源的 kernel,进行测试。以上所有操作都是基于思源是个开源软件,所有,哎,就是能改着玩!

在我进行修改之前,使用本地的 minio 进行全库上传的耗时是 440s,那么,你觉得我修改后的耗时是多少呢?

还是 436s!

这少掉的 4s,完全可以被认为就是一个误差而已,因此可以说,dejavu 里对同时上传文件大小的限制,根本就不是同步慢的原因。

我尝试绕过思源,直接通过 minio 的 webui 上传,时间相差无几。

接着,我做了另一种尝试,使用 restic 进行备份,然后直接通过 webui 上传。备份同样的内容,思源的同步机制总共生成了 13,062 个文件,259 个文件夹,而 restic 则是 48 个文件,261 个文件夹。

最后,restic 的上传时间为 10s。

在查看日志中发现,minio 的同时上传速度哪怕在本地也只能做到每秒 40 左右的文件。

作为测试,我尝试使用官方的上传机制,这次就更慢了,每秒只能上传 16 个文件。而且甚至因为同时上传等待时间过长,还给我返回了 time out 报错。

因此,问题的根源似乎很清楚了:思源扫盘建立快照当然可以进步,但进步空间不大。改善云端同步协作机制、实现无锁同步,以及改变思源的快照分片机制,才是根本解决方案。

那么,古尔丹,代价是什么呢?

代价就是,从此思源的增量下载能力可能大大减弱,可能你下载一个快照,就得把整个库下载回来,因为现在一个数据分块对应了多个实际的文件,你只能一起下载回来再拆分。

这里,我就不得不感慨,省空间换时间,还是省时间换空间,依然、并且永远,是一个值得考虑的问题啊。

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    22382 引用 • 89613 回帖

相关帖子

优质回帖
  • tianzhongs 1 赞同

    目前的优化的话,我能想到的就是类似于 Duplicati(某备份工具),他也是增量备份,他的逻辑是

    1. 第一个文件:把元数据的一些映射关系做了信息映射;
    2. 别的文件就是加密后的元数据,同样也是进行了分片,但是他多了一个步骤,就是

    压缩,我觉得这个压缩很有搞头

    1. 每次增量备份,只多备份新的修改的元数据对照和压缩的元数据

    他这个备份工具也支持加密,也是一样的,我个人体验同步速度算快的,毕竟他压缩的大小能指定,比如说 650MB(CD 大小),元数据足够大的话,就会有很多的 650MB 的压缩包,上传起来比思源现在的上传小文件肯定会快很多;

    然后就是映射关系,他本地也有一个数据库,保存的是映射关系和日志,相当于是缓存,可以删因为云端也有,这种同步的话,除了第一次同步这个日志数据库慢点,其余时间都比思源快很多。

    加密上传后的的目录:能看到精简了很多

    image.png

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • winds

    trollface 看到最后释怀了,慢就慢点吧,至少增量同步还行。

  • 其实在电脑端,差个十几秒也算不得什么,主要是手机端每次打开哪怕是 5 秒都感觉慢了,基本告别「闪念速记」这一用途

    1 回复
  • 本地一份全量明文,还有一份大量的分块,空间也没省下来

    1 回复
  • zxhd86

    目前是可以删除快照,清理删除未引用的分块的,但 restic 的版本可能就没法简单的清理未引用分块了,因为可能虽然只有最新的快照,但全是被引用的分块……要做复杂的操作来重新分块。

    当然,这只是最差的情况,对于大多数人来说,其实 restic 的方案应该不会有太大区别,比如我,因为我就没有清理过快照 😋 这种情况下 restic 方案就是纯优点了。

    1 回复
  • 可能应该采用 AOL append only log 的方式来同步,先同步 log,再同步一个个快照。快照可以实时依据 log 生成。

  • 即便没有快照,只保存一个版本,这一堆文件在本地也是多存了一份的分块数据。

    如果能另做一份,本地直接加密存储的 data 目录的就好了,简单一点,当然按思源的原理可能还会出问题

    1 回复
  • 能搞好冲突处理的话,速记就不用等同步完了。感觉和同步速度的关系不是特别大

  • uniqueink

    没有很强烈的插件需求的话,感觉 docker 部署还比较香的,随时随地开箱即用 😄

  • zxhd86

    这倒是,这样就绝对不用担心文件被外部占用了trollface

  • tianzhongs

    随便说两点,第一,你拿 ob 的 livesync 实时同步来比较,并不恰当,因为 livesync 的同步是挂在服务器上,其本质就跟你部署在 docker 上,访问网页应用类似;

    当然,这并不是思源同步慢的真正原因,真正的原因是:

    1. 可能存在线程或者文件并行同步的数量限制;
    2. 加密,你应该考虑思源是加密了的,也就是说存在类似于 Cryptomator 那样的加密措施,导致文件和文件夹众多,可以直接在对象存储平台查看加密后的文件夹就会发现非常多image.png
    3. 文件和文件夹的深度和数量都会极其影响同步、复制等速度,这个使用过 npm 以及复制 jar 包的同学应该都深有体会

    我目前每次同步的速度大概在 3s 左右,如果有重大改变,可能会在十几秒左右,但是我觉得这个同步速度其实还好,因为有个 30s 自动同步的机制,所以我平时也很少手动同步,但是每次启动的时候的加载才是让我头痛的,每次都要等待封面,这个有点无语。

    你如果非要对比的话,应该对标是 ob 的 remotely save 插件,记得加上加密,其次,ob 的该插件似乎不会分割文件,所以还是有一定的区别,但是会比你说的 livesync 更接近对比效果。

    如果说解决的话,你要么就不用思源的官方同步,直接用三方同步工具同步 data 文件夹,这个也是可以的,我尝试过,只是不优雅。或者说用 docker 部署,这个优雅,但是只能用浏览器访问。

    1 回复
  • suhe98 1 评论

    image.png

    我的 assets 文件夹。不过话说回来,是 s3 同步快点还是 webdav 快呢。有没有测试过的,个人一直用 s3

    不用想,铁定 s3,webdav 的响应更慢,并行更少,对于思源是相当不友好的
    zxhd86
  • zxhd86

    同学,读题不认真啊,livesync 有一个 couchdb 部署版本,这应该就是你说的服务器吧?但是他后面又出了一个只需要 S3 进行同步的,我就好奇的是这一个。经过代码的研究后,我确定他跟思源一样是使用加密和分块的方案。

    你说的真正原因有部分是对的,也就是文件并行数这一块,至于文件和文件夹的深度和数量……我感觉你说的不是同步的 repo 文件夹,而是思源 data 的目录?这个倒是影响不大的,因为思源的深度和数量还没到会影响快照生成的等级。转成快照之后,文件数量是多了,但是深度是小了很多。

    另外,快照生成的文件数多,这是我确定出来的原因,也是我认为同步慢最主要的原因。

    至于加密,在生成快照这一块就已经进行加密了,如我文章所说,他并不慢。

    最后,在这里必须明确一下,livesync、restic、siyuan,都是使用的分块、加密的方案,加密上可能算法上存在一些差异,主要的区别是在分块以及上传上。

    livesync 的粒度是最大的,他会把更新的内容打包成一个文件,直接上传上去。restic 中等,他同样会进行打包,但打包之后还会分块。思源的粒度最小,一个文件最少会生成一个分块,大的文件,会生成多个分块。因此,思源的上传下载量、本地占用储存空间最少,但是速度最慢,livesync 速度理论上是最快的,但是上传下载量、本地储存空间占用最大。

    总体来说,正如我文章最后所言,省时间换空间还是省空间换时间?这是一个永恒的问题。

    3 回复
  • 这种基于文件的冷备份同步性能基本就这个样儿了,到头了已经,对象储存带宽不高吗?很高了,对象储存高并发支持得不好吗?也仅次于数据库服务器了,除非要研发出来什么新鲜的东西,查阅国内外也没有人在这种基础上做的性能更加卓越,在这个机制上探讨意义并不大,可能花尽心思搞一堆东西,也就优化个一两秒,同步目前最简单粗暴的增本增效的方法就是,直接在服务器上给每个订阅用户运行自己的思源内核实例,在使用官方同步的情况下,客户端后端直接与云端内核通信,离线状态下客户端自己记录距离上一次同步的离线时间戳,每当与云端内核连接,就开始对比数据新鲜度,而冲突解调在云端内核进行,但是说实话,就做一个最简单的同步,单纯从打开窗口或者后端 api 请求判断哪个 sy 文件发送了改变,上传了哪些文件,删除了哪些文件,禁止 fs,真正的按需同步,也比现在快,大家当然想要如果修改了 3 个字,就只做同步 3 个字的操作,但现在恐怕连修改了 3 个字就只同步这个文档的操作都没做到,从去年讨论到现在,关于同步已经讨论了无数多个先进方案了。我的评价是,别自嗨,主要看 D 怎么说

    1 回复
  • 另外说一句,同步慢就是会发生冲突这么多的元凶,只要你同步的足够快,用户根本来不及做自己的骚操作,慢就是同步出冲突的最终元凶,你不能指望本身是一个轻型文档编辑器,用户还要等你个五六秒才开始下一步的操作,PC 端尚要等这么久,移动端这种退出往往不由客户端本身决定的情况,冲突只会更严重

    1 回复
  • 我在做同步感知插件的时候,还有一个特别脑溢血的操作,就是无论你在外部,通过多好的决策,多好的时机来选择触发让思源开始同步,他最后直接会给你一个 Windows reload, 刷新整个界面,直接让你的暂存修改全部丢失

    1 回复
  • zxhd86

    对象储存高并发支持得不好吗?

    可悲的是,确实不高,我自己手动修改了并发数后运行的效果确实如果。可能 minio 的性能有限,可能官方同步在控制台对于并发数做了限制,但是事实就是,大量小文件的并发上传和下载速度并不好。

    可能花尽心思搞一堆东西,也就优化个一两秒

    这倒不能这么说,只使用 s3 的 obsidian livesync 算是为我们揭示冷备份方案的上限了,他确实没有在云端运行一个实例的。就算算上思源跟 livesync 建立同步上的差异,对于 20mb、650 个文件的同步,那也能从 90s 砍到 4(建立快照) + 3s,这是极大的提升了。

    就做一个最简单的同步,单纯从打开窗口或者后端 api 请求判断哪个 sy 文件发送了改变,上传了哪些文件,删除了哪些文件,禁止 fs,真正的按需同步,也比现在快

    不太行,因为有外部修改的因素,不考虑这个就确实可以。

    obsidian 使用了 node 的 fs.watch 来递归监听文件夹变化,它也不是靠监听窗口和自身的修改动作实现文件修改事件的监听的。livesync 归根结底也是调用了 obsidian 的这个接口。可惜,golang 没有这么方便的东西,有归有,但是 windows、linux、mac 各有各的接口,头都大了。目前最有希望的还是使用轮询机制动态监听,而不是在同步时才扫描文档、建立快照。

    但现在恐怕连修改了 3 个字就只同步这个文档的操作都没做到

    这个据我所知应该是实现了?不过每次同步最少是要上传、下载一份索引,这个索引体积依照 data 而定,我的 data 大概需要 134kb 的索引,emmm……

    1 回复
  • zxhd86

    这我倒是赞同的,livesync 也没做多好的同步合并,但是同步的够快,所以就看不出问题了。

    2 回复
  • zxhd86

    啊,这我倒是不了解了,你是用什么方法触发同步的?

    1 回复
  • 自己搭建的 minio 吗?个人服务器性能一般都是丐中丐,如果是海外的对象存储,也比较拉跨,可以用腾讯云的对象存储试一下,运营商无带宽上限,只要不怕花钱,只要自己带宽够高,一天跑一套房子没问题

    你说的外部修改因素我当然是有提及,不然也不会说禁止用户和插件通过思源调用 fs,我的评价是锁都锁了,直接禁止 fs 模块或者其他三方修改,被改了就报错,为什么要承担用户自己外部修改的责任?想要自由度又想要稳定性,哪里来的这么多好事,一切操作最多只通过 api 进行就是最合理的方法,或者直接打乱目录,防止本地有人直接修改本地明文

    你说的只是对比索引然后增量同步而已,我很明确的指出了是只进行同步单个文档的操作,目前就和扫盘然后看一下哪里变了然后同步没什么区别

    然后是上限问题,live 我是真真正正用过一段时间的,无论是服务器版本还是对象存储版本,我不认同你说的它是传统意义上的《冷备份》,甚至可以作为冷备份的上限,冷备份不是指云端没有实例可以实时通信,靠对象存储就是冷备份了,在运维系统里,冷备份通常是在系统离线的情况下进行的,通常需要停止应用程序或系统,然后对整个数据集进行备份。这种情况下,数据通常会被重新打包成一个一致性的备份文件或快照。这可以包括复制整个数据库、文件系统或其他存储介质。我概率中的同步,是指允许系统在运行时进行保持数据一致性,需要在系统运行时处理数据的一致性问题,同步通常比冷备份更复杂,同步需要和改动一样是结构化的,可传递的,可解析的,而不是单向发送的数据文件,应该属于系统的一个操作,思源就把它当做了独立与系统操作的另一个冷备份操作,自己多设备都要打架,再谈第三方有什么意义呢?而 live 并不存在这种情况,虽然没有实时通信的实例,但是它在本地运行了一个可以做到改动与同步同时进行的程序,没错,随着同步和改动一起进行,没有实例可以实时通信,那随着改动发生的结构化同步应该放到哪里呢?它从头造轮子,把同步操作缓存到了本地,而不只是一个简单的触发索引对比器,一切依旧具有结构化,从头造轮子把文件变动打包成了接近于 api 转发,结构化的请求,在我看来,它虽然没有做到真正的改动与同步同时进行,但是在改动发生时做到了实时存储改动信息,不需要在《每一次同步的时候》频繁扫盘索引,所以它的同步不管什么时候开始,同步携带的信息都是具有时效性的,数据切片也是和结构化数据一样最小的。

    2 回复
  • 另外,live 也就 md 同步快,在同步附件的时候还没有思源性能好,对于这种大 chunk 的东西,他貌似没有单独做数据上传流,也没有做数据切片

  • 然后我还想说一句,Anytype 的后端存储也是对象存储,冷备份热备份根本就和你用不用云端实例没有半毛钱关系,就看你有没有那个心思,有那个精力去做可以和系统运行时操作耦合良好的中间件,难道把 anysync 搬到我内网里边,它冲突解调就做不好了吗?一样可以的,它存储就不是用的对象存储了吗?也是用的对象存储

    所以,真的别再说什么第三方修改了,思源的同步和自己的系统操作都耦合不好,省了事,就应该好好承担这些后果,别再做什么幻想了

    1 回复
  • 现在 ipv6 都开放了,如果只是 vps 同步,还要必要?还要什么服务器?我一般快照这些都是关闭的,写个批处理每天增量备份一下 data 目录就是.

  • zxhd86

    自己搭建的 minio 吗?个人服务器性能一般都是丐中丐,如果是海外的对象存储

    我不是用个人服务器,我是直接在我自己的电脑上,用 docker 运行 minio,minio 跟思源甚至没经过外网网络交互,全部都是在一台电脑上进行。在 40 并发上传时,minio 的 cpu 占用已经飙升到 40% 了。在我没上传前,它的占用是 0.2%。我觉得 minio 作为这方面最流行的个人 s3 项目,它的代码不至于拉跨商业主流技术好几代,而我给他分配的资源,我个人觉得也应该远胜大部分公有云给你分配的量级。

    你说的外部修改因素我当然是有提及,不然也不会说禁止用户和插件通过思源调用 fs,我的评价是锁都锁了,直接禁止 fs 模块或者其他三方修改,被改了就报错,为什么要承担用户自己外部修改的责任?想要自由度又想要稳定性,哪里来的这么多好事,一切操作最多只通过 api 进行就是最合理的方法,或者直接打乱目录,防止本地有人直接修改本地明文

    如果能这样当然最好,但是确实是有需要放 word,然后外部修改的例子,这方面的应用数不胜数,甚至都需要 D 专门放行,方便内核运行时不会报错,全封了不太对吧……

    你说的只是对比索引然后增量同步而已,我很明确的指出了是只进行同步单个文档的操作,目前就和扫盘然后看一下哪里变了然后同步没什么区别

    因为有上述前提,所以不扫描就是不行的。而且,还是那句话,扫描一遍还真就不花什么时间,它不是制约同步速度的主要因素。

    而 live 并不存在这种情况,虽然没有实时通信的实例,但是它在本地运行了一个可以做到改动与同步同时进行的程序,没错,随着同步和改动一起进行

    我研究过它的代码了,实际上他就是在文件改动的时候动态的把内容加入快照库,然后触发同步,把更新的块打包,和索引一起上传上去。它并没有做所谓的同步操作缓存,至于结构化,我不太理解你的意思。你的意思难道是它会准确的识别操作具体的内容,比如说 md 文本里最后插入了”this is sync“,它就能发送一个{insert:"this is sync"}之类的东西?那你可能要失望了,你可以看看这部分的代码:

    https://github.com/vrtmrz/obsidian-livesync/blob/630889680e6da80a58c55f44ca764eb265758f4c/src/storages/StorageEventManager.ts#L78

    https://github.com/vrtmrz/obsidian-livesync/blob/630889680e6da80a58c55f44ca764eb265758f4c/src/main.ts#L1586

    https://github.com/vrtmrz/obsidian-livesync/blob/630889680e6da80a58c55f44ca764eb265758f4c/src/main.ts#L3092

    https://github.com/vrtmrz/obsidian-livesync/blob/630889680e6da80a58c55f44ca764eb265758f4c/src/storages/SerializedFileAccess.ts#L87

    以上代码的逻辑就是获取文件更改,然后直接视为 string 或二进制,创建快照分片而已,在我的标准里,属实算不上什么结构化。思源要进行这种操作也能做到的,无非就是动态获取修改内容,然后新建指定快照罢了。之前是扫盘获取需要建立快照的文件,现在是你给定路径确定建立快照的文件,区别不大,思源的性能可能还高一点。

    2 回复
  • zxhd86

    Anytype 的后端存储也是对象存储,冷备份热备份根本就和你用不用云端实例没有半毛钱关系

    可我记得 anytype 没法只用对象储存吧……它总得有个对接的服务器。我是从来不在意用的是不是对象储存、webdav 的,我考虑的只是需不需要云端需要一个服务后端进行对接。

  • zxhd86 2 评论

    刚刚用腾讯云测试了下,以下是测试结果:

    I 2024/08/17 00:06:11 s3.go:94: uploaded object [repo/objects/95/4cc61e297a67c163cb1e3ae0f66353c8b2178f]
    I 2024/08/17 00:06:11 sync.go:1265: uploaded chunk [objects/95/4cc61e297a67c163cb1e3ae0f66353c8b2178f, 82/6604]

    I 2024/08/17 00:06:32 s3.go:94: uploaded object [repo/objects/28/551765ccb476243d2d9deae94d52c16fb301c1]
    I 2024/08/17 00:06:32 sync.go:1265: uploaded chunk [objects/28/551765ccb476243d2d9deae94d52c16fb301c1, 521/6604]

    每秒 20 个,还行吧,比七牛稍微好点,但也不多。目前尝试的 s3 对于批量小文件的支持都挺一般的。

    2 回复
    我用 powershell 生成了 1W 个 1Kb 小文件,用 cloudflare 试了下,每秒 100 个左右,没你那么慢..
    sunk926
    @sunk926 想问一下具体的代码可以吗?我测试下这里的速度,但我对 powershell 不熟悉
    zxhd86
  • 第一,我觉得你可能对对象存储有什么误解,对象存储的意义就是为了解决个人服务器带宽或者性能不够,然后提供一种按量计费的套餐,它的带宽是直接和腾讯从三大运营商拉过来的专线对等的,我再说的通俗一点,如果你家里宽带有 10000 兆的带宽,那么你下载腾讯 s3 的速度就是一万兆,你个人就算是硬盘提供得了这么大的速度吗?详情见这里,https://doc.fincloud.tencent.cn/tcloud/Storage/COS/845813/uploaddownloadfaq
    对象存储的性能和带宽不上限,只按量,远超你自己局域网运行一个 docker 的性能

    第二,我说了没有那么好的事情,即自由又稳定,况且,又不是没有解决方案,只需要把附件这种不会频繁变动的内容单独走另一个单独的上传信息通道就好了,而不是放到高频索引里面再扫一遍

    第三,你也看了片段了,可以看到,它不是一个简单的索引触发器,更改的内容是由操作写入的,而不是索引对比文件,索引本身没有问题,问题是只有利用操作来写入索引才能让索引具有足够的时效性,这样做,同步的内容是和操作耦合的,而不是只和扫盘索引耦合,“数据分片”这个概念我也提到了,至少 ob 可以直接知道该同步哪一个 md 文件,思源可以在操作后马上知道该同步哪一个 sy 文件吗?倘若能,为什么要去扫盘?难道是因为我改了一个 sy 文件,每一次都要扫库看看我有没有改其他文件吗?那为什么不一直扫,万一我改了其他的文件但是没该文档,岂不是没有办法了,只能等我改文档的时候再帮我检测一下?这个思路倒是可以理解了。我是真的觉得,和用户的操作一块进行,监听哪些文件发生更改,然后没有中间服务商直接同步哪些文件,都比现在快。

    第四,我知道你不停的强调建立一个快照或者索引有多快,但是,在我用的过程中,建立快照并不是卡我的原因,原因是这个快照索引本身就是没有时效性的,不可靠的,所以它不是建立完就没事了,他需要下载下来,然后解析,然后一个个核对,我的同步大部分时间就是花在这个核对索引上,一直在校验索引,少则校验 5-6s,多则半分钟,3.10 版本有时候校验索引都会卡死,扫盘建立的索引,终究还是要扫盘去核对

    第五,我想表达的意思是,对象存储作为储存器并不是问题,问题是,没有一个很好的《中间件》来作为和对象存储的桥梁,anytype 的中间件,节点原理,即使塞到本体里面一样可以用(它也确实塞进去了),断网后,局域网内客户端是可以互相沟通同步的,每个客户端都具有与储存器之间的完整的中间件,而不是把储存器

    同步应该与实时操作耦合,不然,我只能叫他频繁地扫盘备份,第三方备份这样做完全合理,甚至本应该就这么做,大家为了节省流量,或者因为没有同步感知,都会以较为低频的方式用,和 remotely-safe 基本上完全一个原理,但是官方同步,如果只是一个频繁地备份,我觉得至少不能作为一个优势,不说是缺点已经很不错了

  • 我们先假设,你这个测试是有意义的,思源是因为批量小文件拉慢了速度。那么,批量小文件不应该只在第一次下拉数据的时候吗?为什么要对批量小文件是对象存储应该考虑的问题?或者说,思源为什么每次同步都产生这么多批量小文件?我平常手写一秒只在一篇文档里写几个字,上传两三个附件,我真的修改了这么多的文件?人不是机器,很多人做不到无影手一下子修改那么多东西,哪怕是插件,也没有几个会平常一下子修改几十个文件,如果是因为自己的机制,每次一定要产生这么多校验文件,还真就是机制没做好

    2 回复
  • zxhd86

    我再说的通俗一点,如果你家里宽带有 10000 兆的带宽,那么你下载腾讯 s3 的速度就是一万兆,你个人就算是硬盘提供得了这么大的速度吗?详情见这里,https://doc.fincloud.tencent.cn/tcloud/Storage/COS/845813/uploaddownloadfaq
    对象存储的性能和带宽不上限,只按量,远超你自己局域网运行一个 docker 的性能

    对象储存对于少量大文件的带宽确实能跑满,但是大量小文件就不太行了。这个我已经在腾讯云上尝试过了,参照上面的记录,golang 并发上传数设为 640,但是每秒上传文件数他就是有上限的,腾讯云也只能达到每秒 20 个,目前看来,对于小文件,还是 minio 在本地是比较快。

    如果你测试出更好的数据,可以跟我说一下怎么写,我也可以改进下 siyuan 这方面的代码。

    我说了没有那么好的事情,即自由又稳定,况且,又不是没有解决方案,只需要把附件这种不会频繁变动的内容单独走另一个单独的上传信息通道就好了,而不是放到高频索引里面再扫一遍

    可是实际上外部变动主要就是改附件啊,单纯思源本身的笔记文件反而不太会被改,因为其他软件读不懂……

    至少 ob 可以直接知道该同步哪一个 md 文件,思源可以在操作后马上知道该同步哪一个 sy 文件吗?倘若能,为什么要去扫盘?难道是因为我改了一个 sy 文件,每一次都要扫库看看我有没有改其他文件吗?那为什么不一直扫,万一我改了其他的文件但是没该文档,岂不是没有办法了,只能等我改文档的时候再帮我检测一下?这个思路倒是可以理解了。我是真的觉得,和用户的操作一块进行,监听哪些文件发生更改,然后没有中间服务商直接同步哪些文件,都比现在快。

    我倒是没有否认 ob livesync 建立快照速度更快,更有优越性,只不过 golang 上没有太好可用的包。

    我知道你不停的强调建立一个快照或者索引有多快,但是,在我用的过程中,建立快照并不是卡我的原因,原因是这个快照索引本身就是没有时效性的,不可靠的,所以它不是建立完就没事了,他需要下载下来,然后解析,然后一个个核对,我的同步大部分时间就是花在这个核对索引上,一直在校验索引,少则校验 5-6s,多则半分钟,3.10 版本有时候校验索引都会卡死,扫盘建立的索引,终究还是要扫盘去核对

    此索引非彼索引啊,这里有两个概念的索引,siyuan sqlite 里的索引和快照 dejavu 使用的文档索引。思源懒得判断文档变化情况选择全部校验一遍来重建 sqlite 确实是懒政情况了,但是这跟同步的索引和快照完全是两回事啊。解决问题终究还是要一个个来的。

    局域网内客户端是可以互相沟通同步的,每个客户端都具有与储存器之间的完整的中间件

    我觉得对等点本身就是一个服务端了吧……硬要这么说,思源也可以内部塞一个 webdav 或 s3 实现,然后直接通过局域网发现协议互相找到端口,进行同步。但是这种情况下思源自己就成为服务端了,这跟思源作为伺服的区别有多大呢?

    1 回复
  • 然后就是关于你提供的代码定位,我当然可以跟着你看代码,可以看到,光是监听就写了

            plugin.registerEvent(plugin.app.vault.on("modify", this.watchVaultChange));
            plugin.registerEvent(plugin.app.vault.on("delete", this.watchVaultDelete));
            plugin.registerEvent(plugin.app.vault.on("rename", this.watchVaultRename));
            plugin.registerEvent(plugin.app.vault.on("create", this.watchVaultCreate));
            //@ts-ignore : Internal API
            plugin.registerEvent(plugin.app.vault.on("raw", this.watchVaultRawEvents));
    

    五个,每一个事件不只是一个触发器来触发进行扫盘索引,而是拥有具体的返回对象,例如

       watchVaultChange(file: TAbstractFile, ctx?: any) {
            this.appendQueue([{ type: "CHANGED", file }], ctx);
        }
    
    

    通过将文件的修改事件封装成一个对象,这个方法能够为后续的处理提供结构化的数据,这至少是一种基本的处理,至少是和操作挂钩了,返回校验也不需要重新牵一发而动全身

    其他的我就不细看了,要休息

    1 回复
  • 我觉得对等点本身就是一个服务端了吧……硬要这么说,思源也可以内部塞一个 webdav 或 s3 实现,然后直接通过局域网发现协议互相找到端口,进行同步。但是这种情况下思源自己就成为服务端了,这跟思源作为伺服的区别有多大呢?

    区别就是思源只是现在的思源,而不是你口中的“要是怎么怎么样就行了”“思源也可以怎么怎么样”

    1 回复
  • zxhd86

    所有你看到我的结论归纳分 4 个了,因为它们确实都有影响。

    对于少量更新,思源需要带锁同步,这时候没碰到小文件上传的并发上限,那么就会有 0.5(扫盘)+0.3(少量修改产生新快照)+1(云端尝试锁定)+0.5(文件上传完成)+1(云端解除锁定)总计 3.3s,也就是那一端最少需要等待 3s 才能进入同步状态。因此,整个交替同步流程最少是需要 6s 的时间,这与打开同步感知后进行同步的体验大致相同。

    至于插件,插件确实会产生很多新文件的,特别是你进行了批量更新。一个插件最少带有 5 个文件,以我这里的例子来说平均是 29 个(49 个插件 1454 个文件),一次批量更新我们假设是 10 个插件,那么就会产生 300 个文件变动,假设每个插件只实际更新 50% 的文件内容,那么会实际产生个 150 文件变动。150 个变动文件假设大小都不大,每个产生一个分片,那么就总计 150 个分片、150 个文档索引、一个最新索引,在我的设备上,这个数据量意味着 300/20 = 15s+4s 总共 19s 的同步时间。当然,这是最好的情况下。

    1 回复
  • zxhd86

    所以你是觉得这样就算结构化了嘛。那这个要求和难度都不算太高,改善也不大就是了。

    这个实现无论是轮询还是系统监听都能做到,但是还是如上面所说,这方面再怎么改善也是提高了在快照上传到云端前的快照建立速度,但无论什么情况下,基本快照建立都不是主要时间。oss 的并发上传限制、思源保守的云端锁、快照分片数量、本地索引校验机制,无论哪一个的改善都远远比这个显著。

    1 回复
  • 至于插件,插件确实会产生很多新文件的,特别是你进行了批量更新。一个插件最少带有 5 个文件,以我这里的例子来说平均是 29 个(49 个插件 1454 个文件),一次批量更新我们假设是 10 个插件,那么就会产生 300 个文件变动,假设每个插件只实际更新 50% 的文件内容,那么会实际产生个 150 文件变动。150 个变动文件假设大小都不大,每个产生一个分片,那么就总计 150 个分片、150 个文档索引、一个最新索引,在我的设备上,这个数据量意味着 300/20 = 15s+4s 总共 19s 的同步时间。当然,这是最好的情况下

    有一点跑分测试的嫌疑了,实时上,批量更新插件,拉库这些,我相信大部分人都是主动点击之后在《等》的,也不是天天在点击,并不是影响平常同步体验的关键因素,ob 之前拉库更慢,一个小时都有,耐不住平常同步就是快啊,平常我按照十几个插件,他们也不会突然就产生或者修改几十个文件,一般涉及到这些操作,大部分用户都是主动点击然后《等》,反而不是最关键的因素,关键是因素是平常我就打几个字同步都这么慢

    1 回复
  • 所以你是觉得这样就算结构化了嘛。那这个要求和难度都不算太高,改善也不大就是了。这个实现无论是轮询还是系统监听都能做到,但是还是如上面所说,这方面再怎么改善也是提高了在快照上传到云端前的快照建立速度,但无论什么情况下,基本快照建立都不是主要时间。oss 的并发上传限制、思源保守的云端锁、快照分片数量、本地索引校验机制,无论哪一个的改善都远远比这个显著。

    我个人觉得恰恰相反,这个不是为了减少本来就不慢的建立快照的时间,而可以解决我同步的时候,我直接知道我应该同步哪几个文件,而不用还要携带本来就应该是中间件写入储存器之前,供中间件自己建立同步流程用的零零碎碎的小文件,以及可以在让客户端拿到数据时尽量目标明确的去校验特定的文件

    1 回复
  • zxhd86

    主要是我没理解你提出中间件干啥,你的描述已经完全不是只使用 s3 了,而是一个 anytype 作为一个服务端调用储存后端,那我想象出来的对等情况就是思源里面绑着一个 s3……然后忽然反应过来这不如直接伺服得了。

  • zxhd86

    这个可能不是你觉得自己打几个字就真的是几个字了,你得看看实际数据块的数量。实际上真正的打几个字的场景就是开了同步感知进行交替同步,目前我测试的延迟就是 6s 左右。你可能得看看内核日志,确定到底主要在干啥了。

    2 回复
  • zxhd86

    你的意思是另一端直接知道要校验那几个文件的索引?这个……其实 livesync 不管这个的。obsidian 也不管 livesync 的,更别说 dataview 之类插件的索引了。它们都是使用文件系统的事件来更新的。确定是那几个文件需要校验确实有帮助,不过目前快照直接进行索引对比也能找出更改文件。这方面的主要问题还是 D 偷懒!没有利用这个信息!

    1 回复
  • 我想向你描述的很清楚了,包括你现在又说伺服,我一开头表达的很清楚

    同步目前最简单粗暴的增本增效的方法就是,直接在服务器上给每个订阅用户运行自己的思源内核实例,在使用官方同步的情况下,客户端后端直接与云端内核通信,离线状态下客户端自己记录距离上一次同步的离线时间戳,每当与云端内核连接,就开始对比数据新鲜度,而冲突解调在云端内核进行

    代表我不是不知道伺服可以最快解决,但是你不能作为一个官方订阅,让用户自己伺服吧,所以我直接说了云内核,增本增效。

    但是说实话,就做一个最简单的同步,单纯从打开窗口或者后端 api 请求判断哪个 sy 文件发送了改变,上传了哪些文件,删除了哪些文件,禁止 fs,真正的按需同步,也比现在快,大家当然想要如果修改了 3 个字,就只做同步 3 个字的操作,但现在恐怕连修改了 3 个字就只同步这个文档的操作都没做到

    这个是想表达,储存器性能根本不是原因,是自己没做足够复杂的中间件处理,最为全世界广泛应用的技术,对象存储已经是最好的云端存储方案了,就好像是,能不能让博尔特再快 5s,这样我看他跑步时间就更短了,有没有可能是自己阈值太高?

    然后就是,我也没有把 live 看成是什么标杆,它也是早轮子而已

    说白了,你觉得很简单的东西,像 live 做的监听对象,思源加了没有?最后我说这么多,我觉得最核心的还是这个

    从去年讨论到现在,关于同步已经讨论了无数多个先进方案了。我的评价是,别自嗨,主要看 D 怎么说

    1 回复
  • 我不明白你提到“块”这个概念是为什么,首先,索引不会校验“块”而是文件,根本没深入到这个数据结构,“块”的改动只是触发扫盘索引而已,我自己 win 下用 bat 写个监听,日常使用中,根本没有几个文件会发生改变,而是几个文件在“高频”改变,这些文件本来就是运行时文件,而思源不通过中间件处理对接,反而放在了同步里面,内核我也看,很多数据发生了改变=很多文件发生了改变?

    1 回复
  • 而且假设你说的也对,我打几个字就是会产生很多小碎片,如果说,用户打了几个字,只动了一个思源文档,但是思源产生了一堆数据块,这个作为一个个人使用的本地软件,不是一种冗余吗?要怪在用户不了解的头上吗?

    1 回复
  • zxhd86

    那我的意思也并没有说思源目前同步的机制在速度上是好的,不然这个标题也不会是”这么慢的探究“了……

    我想指出的只是,速度慢的原因与大多数人想的情况并不一样,使用思源这种快照、分块、加密的形式也能达到一个比较好的速度,举了 restic 和 livesync 作为例子。

    但是,我最后也得到了另一方面的结论,思源对速度不友好,但是对于空间占用、上下传流量是最友好的。这在另一种层面上,就是要时间还是要空间的考虑,思源的同步机制并不是一无是处的。

  • zxhd86

    在这里的语境中,我指的是建立快照时,产生的数据分块,也就是把文件变动后加入快照,产生的加密小文件。跟思源文档中的块是不同的概念。

    这些文件本来就是运行时文件,而思源不通过中间件处理对接,反而放在了同步里面,内核我也看,很多数据发生了改变=很多文件发生了改变?

    所以你的运行时文件是指什么,中间件处理对接又是什么,很多数据发生了改变是什么情况?

    2 回复
  • 运行时文件是指与文档本身无关的数据库和索引
    中间件处理对接是指监听 api 和文件变动对象
    很多数据发生了改变是指你说的我打几个字 net 里会有一堆调用内核 api 的情况

    1 回复
  • zxhd86

    我打几个字就是会产生很多小碎片,如果说,用户打了几个字,只动了一个思源文档,但是思源产生了一堆数据块,这个作为一个个人使用的本地软件,不是一种冗余吗?要怪在用户不了解的头上吗?

    我并没有说”用户打了几个字,只动了一个思源文档,但是思源产生了一堆数据块“是合理的,只是我觉得实际上并不只是修改了那一个文档,而是不知不觉中修改了多个文件。这些文件的修改当然是要改进的问题,但是这不是同步机制的问题。

    2 回复
  • 在这里的语境中,我指的是建立快照时,产生的数据分块,

    那我是理解错了,我以为是 sy 里面的块结构,但是好在,你说的很多数据库会产生,我也做了假设

  • 但是这不是同步机制的问题。

    可能我觉得数据结构和同步机制也有关系?话说这种结构不就是为了同步而生的吗?本地使用,软件读取明文,备份也是直接 copy 目录或者导出 sy.zip,我可能理解不到,客户端读取数据是基于这种数据结构的?

  • 或者说,到底什么情况下,需要打这么多的块文件?数据回滚吗?

    1 回复
  • zxhd86

    数据库和索引是不经过同步的,它们放在 temp 目录下。

    调用一堆内核 api 跟很多数据发生变化无关,我指的是打开 siyuan.log,看这一堆东西的上下文:

    I 2024/08/17 00:06:34 s3.go:94: uploaded object [repo/objects/c4/0294c4d4c1c85d1d3c85d9ad8527c8988d4121]
    I 2024/08/17 00:06:34 sync.go:1265: uploaded chunk [objects/c4/0294c4d4c1c85d1d3c85d9ad8527c8988d4121, 561/6604]
    I 2024/08/17 00:06:34 s3.go:94: uploaded object [repo/objects/cf/5e4f6bad5e4a80d2e2e596b5bb084eb1447915]
    I 2024/08/17 00:06:34 sync.go:1265: uploaded chunk [objects/cf/5e4f6bad5e4a80d2e2e596b5bb084eb1447915, 562/6604]
    I 2024/08/17 00:06:34 s3.go:94: uploaded object [repo/objects/89/24958a3954bd9c8bad705e0f6a03a8d33f6273]
    I 2024/08/17 00:06:34 sync.go:1265: uploaded chunk [objects/89/24958a3954bd9c8bad705e0f6a03a8d33f6273, 563/6604]
    I 2024/08/17 00:06:34 s3.go:94: uploaded object [repo/objects/d9/2c22093eaa028952d2a912f5af45c8a24d0328]
    I 2024/08/17 00:06:34 sync.go:1265: uploaded chunk [objects/d9/2c22093eaa028952d2a912f5af45c8a24d0328, 564/6604]
    I 2024/08/17 00:06:34 s3.go:94: uploaded object [repo/objects/60/3ddb05be9c7b26b7b962eb6bd4948c50a78915]
    I 2024/08/17 00:06:34 sync.go:1265: uploaded chunk [objects/60/3ddb05be9c7b26b7b962eb6bd4948c50a78915, 565/6604]

    它们就是实际上传下载的数据分块,如果数量小,时间短,那就说明并不是在这一步阻塞的。

  • zxhd86

    答案就是:节省空间,并且在大文件上传下载时加速。由于每个块只对应一个文件,所以能下载最少的内容到本地快照。由于一个大文件被拆成多个分块,所以能很好利用 s3 在少量大文件批量上传的速度。

    2 回复
请输入回帖内容 ...

推荐标签 标签

  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 9 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 49 关注
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 232 回帖 • 4 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 4 关注
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖
  • 博客

    记录并分享人生的经历。

    273 引用 • 2388 回帖
  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 26 关注
  • 创造

    你创造的作品可能会帮助到很多人,如果是开源项目的话就更赞了!

    179 引用 • 995 回帖 • 1 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖 • 1 关注
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    88 引用 • 1235 回帖 • 411 关注
  • Bootstrap

    Bootstrap 是 Twitter 推出的一个用于前端开发的开源工具包。它由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 合作开发,是一个 CSS / HTML 框架。

    18 引用 • 33 回帖 • 659 关注
  • Flutter

    Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作,它正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

    39 引用 • 92 回帖 • 3 关注
  • abitmean

    有点意思就行了

    30 关注
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖
  • 分享

    有什么新发现就分享给大家吧!

    248 引用 • 1794 回帖
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖 • 2 关注
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4601 回帖 • 699 关注
  • gRpc
    11 引用 • 9 回帖 • 74 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 733 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 168 关注
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 52 关注
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 61 关注
  • 禅道

    禅道是一款国产的开源项目管理软件,她的核心管理思想基于敏捷方法 scrum,内置了产品管理和项目管理,同时又根据国内研发现状补充了测试管理、计划管理、发布管理、文档管理、事务管理等功能,在一个软件中就可以将软件研发中的需求、任务、bug、用例、计划、发布等要素有序的跟踪管理起来,完整地覆盖了项目管理的核心流程。

    6 引用 • 15 回帖 • 113 关注
  • 生活

    生活是指人类生存过程中的各项活动的总和,范畴较广,一般指为幸福的意义而存在。生活实际上是对人生的一种诠释。生活包括人类在社会中与自己息息相关的日常活动和心理影射。

    230 引用 • 1454 回帖
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 212 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖