自动保存技术的实现思路

自动保存技术的实现思路
  • 功能需求:
    刷知乎时,在编辑答案的时候,知乎会对编辑的答案进行自动保存。这样有效的避免了因为各种意外情况导致编辑的内容意外丢失。作为提供长文章博客服务的网站,我认为自动保存的功能是十分必要的。
  • 初步方案:
    目前网站基于Node.js+Express构建,后台数据库为Mongodb运行在独立的Container上。用于暂存的技术方案考虑过两种:
    1. 基于Redis做高速缓存,随后将暂存数据异步持久化到Mongodb中。
    2. 基于Mongodb直接进行持久化保存
  • 技术选型:
    两种方案各有其优点与劣势:
    • 方案1:
      • pros:
        性能相对更好,即使在高负载下也不会因为磁盘性能不足而导致瓶颈。目前作为工业界常用的缓存机制使用。
      • cons:
        目前网站基于Docker运作,使用Redis缓存意味着需要另外一个Docker container,对于并不充裕的服务器存储空间与内存空间都是很大的压力。并且目前开发用机器都是Windows,开发调试使用Redis的应用都较为不方便
    • 方案2:
      • pros:
        不需要调整目前站点结构,技术上实现容易。能更快速的进行开发。不需要额外运行Redis服务器,能够节省服务器的硬件资源。
      • cons:
        性能差,在高负载下非常容易出现磁盘性能瓶颈。
  • 分析使用环境:
    站点部署在Digital Ocean 的Docker Droplet上。使用的是高速SSD存储,随机读的IOPS在30K以上,随机写入也能达到10K以上(来源:Dzone-IOPS: Benchmarking Disk I/O – AWS vs DigitalOcean)。
    自动保存的频率为60秒一次,每篇文章在提交时会自动删除该文章的自动保存副本。
    需要对自动保存数据库进行CRUD操作的有以下一些情况:
    • 每分钟一次的自动保存。进行创建/更新操作。
    • 提交新文章/编辑完成旧文章。进行删除操作。
    • 打开编辑器时。进行查找操作。
  • 确定技术方案:
    由上文可以看出,对于每个用户,自动保存功能所开销的资源并不多。并且由于本身服务器磁盘性能较高,因此可以直接使用Mongodb作为暂存存储。

辣么,已经确定了使用的技术,应该如何实现自动保存的功能呢?

  • 业务逻辑:
    在打开编辑器时,如果有对应文档的自动保存,则载入自动保存(新建文档同样作为文档处理),否则从文档数据库中调出文档进行编辑。在编辑过程中,每分钟进行一次自动保存。在提交编辑后,应当下次打开编辑器时编辑器中内容为已经提交的内容而不是可能与已经提交内容不同的自动保存内容。
  • 分析:
    1. 如果有对应文档的自动保存,则载入自动保存:
      实现这一功能,需要在暂存文章的数据结构中保存其所对应的文档。因此暂存文章的数据结构与普通文章相比,在Header中增加了derivedFrom字段以指示其对应的文章
    2. 在编辑过程中,每分钟进行一次自动保存:
      实现这一功能,在编辑器的Template中使用定时器定时调用autoSave接口。为防止接口被恶意攻击,在调用接口后,服务器将会检查上次调用接口的时间,设置了50秒的内部超时,在50秒内重复调用autoSave接口,服务器将直接返回403 Unauthorized错误
    3. 下次打开编辑器时编辑器中内容为已经提交的内容而不是自动保存内容。:
      因为自动保存为定时保存,因此在提交后,最后录入的内容可能并未进行保存。此时有两种方法,一是提交时将自动保存的数据与提交数据进行同步,二是提交时直接删除自动保存数据。出于减小数据库体积的考虑,提交时自动删除保存数据是更好的做法,并且第一种做法除了逻辑上更为简明以外并没有任何优势。因此在提交编辑时将暂存数据直接删除即可又快又好的完成这一需求。
  • 实现:
    参见GitHub Repo中提交2cd350b4267820