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

太长不看:

  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 报错。

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

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

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

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

  • 思源笔记

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

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

    23257 引用 • 93816 回帖 • 1 关注

相关帖子

优质回帖
  • tianzhongs 1 赞同

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

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

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

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

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

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

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

    image.png

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • 思源其实比 ob 官方同步快多了,尤其是在墨水平板等低性能设备上,我个人认为还是没有一个比较好的冲突解决机制,导致不管干啥都得等同步。

  • 其他回帖
  • 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]

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

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

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

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

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

    2 回复
  • # 设置文件夹根目录
    $rootDir = "C:\Users\Administrator\Documents\1"
    
    # 创建根目录
    if (!(Test-Path $rootDir)) {
        New-Item -ItemType Directory -Path $rootDir
    }
    
    # 设置文件数量和大小
    $fileCount = 10000
    $pageSize = 1024
    
    # 设置文件夹数量
    $folderCount = 10
    
    # 计算每个文件夹中的文件数量
    $filesPerFolder = $fileCount / $folderCount
    
    # 生成文件
    for ($i = 0; $i -lt $folderCount; $i++) {
        # 创建文件夹
        $folderPath = Join-Path -Path $rootDir -ChildPath "Folder_$i"
        if (!(Test-Path $folderPath)) {
            New-Item -ItemType Directory -Path $folderPath
        }
    
        # 生成文件
        for ($j = 0; $j -lt $filesPerFolder; $j++) {
            $filePath = Join-Path -Path $folderPath -ChildPath "File_$($i*$filesPerFolder+$j).txt"
            $content = [char[]]::new($pageSize)
            for ($k = 0; $k -lt $pageSize; $k++) {
                $content[$k] = 'a'
            }
            Set-Content -Path $filePath -Value ($content -join '')
        }
    }
    
    

    然后用 mc mirror ./ cloudflare/temp --overwrite 就可以测试了,目测 大概 100 左右.

  • 查看全部回帖

推荐标签 标签

  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    143 引用 • 442 回帖
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    20 引用 • 7 回帖 • 3 关注
  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 561 关注
  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖
  • Laravel

    Laravel 是一套简洁、优雅的 PHP Web 开发框架。它采用 MVC 设计,是一款崇尚开发效率的全栈框架。

    20 引用 • 23 回帖 • 724 关注
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 6 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖 • 1 关注
  • Mobi.css

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

    1 引用 • 6 回帖 • 750 关注
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 220 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 333 关注
  • Latke

    Latke 是一款以 JSON 为主的 Java Web 框架。

    71 引用 • 535 回帖 • 791 关注
  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖 • 2 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖
  • OAuth

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

    36 引用 • 103 回帖 • 17 关注
  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    107 引用 • 295 回帖 • 1 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    943 引用 • 1460 回帖 • 1 关注
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 75 关注
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖 • 1 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 772 关注
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    6 引用 • 63 回帖 • 2 关注
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    5 引用 • 7 回帖 • 5 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    497 引用 • 1388 回帖 • 277 关注
  • WebClipper

    Web Clipper 是一款浏览器剪藏扩展,它可以帮助你把网页内容剪藏到本地。

    3 引用 • 9 回帖 • 2 关注
  • 知乎

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

    10 引用 • 66 回帖
  • Hprose

    Hprose 是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。你无需专门学习,只需看上几眼,就能用它轻松构建分布式应用系统。

    9 引用 • 17 回帖 • 617 关注
  • 域名

    域名(Domain Name),简称域名、网域,是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。

    43 引用 • 208 回帖