Synology Photos 致力于为用户提供流畅可靠的照片管理体验。对于拥有大量照片库的用户来说,初始加载速度至关重要。本文将介绍 Synology Photos 如何应对动态数据库中的同步挑战,并通过从偏移分页演进到游标分页,显著提升性能与稳定性。

问题:大型照片库加载延迟

当用户首次加载大型照片库(如数十万张图片)时,可能会遇到加载时间过长的问题。此前采用的偏移分页机制在某些情况下可能需要数分钟才能完全加载,其根本原因在于该同步方法的设计。

该方法依赖数值型偏移量和批量大小来分批请求数据。应用程序会向存储所有照片的 NAS 服务器发送一系列请求。在静态、不变的照片库中,这种机制表现良好:

  • 请求一:应用程序请求:“跳过 0 张照片,然后给我接下来的 100 张。” 服务器返回照片 1–100。
  • 请求二:应用程序请求:“跳过前 100 张照片,然后给我接下来的 100 张。” 服务器返回照片 101–200。

以此类推,直到所有照片加载完成。

偏移分页的优点在于其简单且直观的实现。应用程序可以直接从特定页码请求数据(例如跳转到第 10 页),无需依赖前一页的信息——这是一种常见且有效的标准做法。

然而,该系统存在一个核心缺陷:它假设数据库中每张照片的位置都是固定的。现实中的照片库是动态的——家庭成员可能随时通过不同设备上传新照片或删除旧照片,这些操作会立即改变数据库的排序。如果系统未能处理这些变动,用户可能会看到照片顺序错误或照片缺失。以下示例说明了数据库变动时偏移分页如何导致数据不完整。

  1. 初始状态:服务器上的照片库为:[Photo A, Photo B, Photo C, Photo D, Photo E, Photo F, Photo G]。
  2. 应用程序的第一次请求(offset=0, limit=3):应用程序请求前三张照片,服务器返回 [Photo A, Photo B, Photo C]。
  3. 外部变动:在应用准备下一个请求时,另一位用户通过网页界面删除了 Photo B。
  4. 服务器上的新状态:数据库立即更新为:[Photo A, Photo C, Photo D, Photo E, Photo F]。原本位于第 4 位的 Photo D 现在移动到了第 3 位。
  5. 应用程序的第二次请求(offset=3, limit=3):应用程序完全未察觉数据库的变动,仍然跳过前 3 个位置后请求照片。
  6. 严重错误——照片被跳过:服务器收到请求后,查看当前列表 [Photo A, Photo C, Photo D ...],跳过前三项(Photo A, Photo C, Photo D),返回 [Photo E, Photo F, Photo G]。

Photo D 虽然未被删除,却被应用请求完全跳过。为确保数据完整性并避免此类遗漏,应用程序内置了安全检查。一旦检测到序列不一致,唯一安全的做法就是丢弃当前已加载的所有项目,并从头重新同步。这正是导致“反复重载”现象、影响用户体验的根本原因。

解决方案:游标分页

为解决偏移分页的局限性,Synology Photos 引入了游标分页。该方法不再依赖可变的数值排序,而是为每次请求使用一个稳定且唯一的“游标”作为锚点。

“游标”是指应用程序每批成功加载的最后一张照片的 ID。应用的请求方式也从“基于数量”的命令转变为“基于锚点”的命令:

  • 旧请求:给我前 100 张之后的 100 张照片。
  • 新请求:请在具有此特定 ID 的照片之后,返回 100 张照片。

如果说偏移分页就像阅读带有页码的书籍,可以随时翻到任意一页,那么游标分页则像是在阅读没有页码的长卷轴,只能从上次放下“书签”(游标)的位置继续阅读。对于 Synology Photos 的连续滚动时间线界面来说,后者显然更加稳定可靠。

由于请求基于照片的唯一 ID,而不是其临时位置,因此该系统不会受到数据库中其他项目新增或删除的影响。在相同场景下,游标分页的处理方式如下:

  1. 初始状态:服务器上的照片库为:[Photo A, Photo B, Photo C, Photo D ...]。
  2. 应用程序的第一次请求:请求前三张照片。服务器返回:[Photo A, Photo B, Photo C]。
  3. 关键区别——建立游标:应用程序将本批次最后一项 Photo C 的唯一标识符 ID_C 作为下次请求的游标。
  4. 外部变更:Photo B 被删除。服务器列表更新为 [Photo A, Photo C (ID_C), Photo D ...]。
  5. 应用程序的第二次智能请求:应用程序向服务器请求:“请在 ID 为 ID_C 的照片之后,返回三张照片。”
  6. 服务器的精确处理:服务器通过 ID_C 立即定位到 Photo C,并返回下一批照片:[Photo D, Photo E, Photo F]。

结果:Photo D 没有被跳过。同步过程无缝衔接,不受外部变更影响。

如何处理意外错误

一个健壮的系统必须能够处理边缘情况。例如:如果作为游标的照片在同步过程中被删除,会发生什么?

该系统的容错能力基于数据库的有序索引机制——所有照片都拥有独立且递增的 ID。

当服务器收到指向已不存在游标(例如 ID 31139)的请求时,并不会失败。相反,服务器会以原游标 ID 作为参考点,发出类似命令:“返回所有 ID 小于 31139 的照片,按值从大到小排序,最多返回 100 条记录。”这样可以找到靠近原游标的照片,并从序列中的下一个可用项继续处理,确保同步过程不中断。

结论:用户受益

从偏移分页到游标分页的演进为 Synology Photos 用户带来了切实的好处:

  • 加载速度大幅提升:首次完成全量同步后,打开应用时照片库几乎可以瞬间显示。
  • 体验稳定可靠:消除了因数据库变更导致的照片闪烁或重复加载问题,使同步过程更加流畅。
  • 照片管理更自由:用户可随时在任意设备上添加或删除照片,无需担心影响移动端应用的性能。

这不仅仅是性能提升,更确保用户在访问珍贵回忆时拥有流畅、可靠且不中断的体验。