Evernote架构探析:为什么不用NoSQL?

来源:互联网 发布:免费附近约会软件 编辑:程序博客网 时间:2024/05/17 06:33

http://cloud.csdn.net/a/20120224/312377.html


导读:Evernote是非常著名的在线记事本应用。下面我们来一起探析它的后台架构,看看Evernote为什么没有选择流行的NoSQL。

当为大家描述我们的整体服务架构时,最常见的两个问题是:

  • 为什么采用结构化方式将数据存储在SQL数据库中,而不使用NoSQL平台?
  • 为什么自己维护数据中心,而不将Evernote托管到云服务提供商?

这两个问题都很有趣,我们先来探讨第一个。

对特定的应用而言,相比一个单一的SQL实例,一个现代的键值存储引擎具备显著的性能优势和可扩展性。

  1. CREATE TABLE notebooks (  
  2.   id int UNSIGNED NOT NULL PRIMARY KEY,  
  3.   guid binary(16) NOT NULL,  
  4.   user_id int UNSIGNED NOT NULL,  
  5.   name varchar(100) COLLATE utf8_bin NOT NULL,  
  6.   ...  
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;   
  8.  
  9. CREATE TABLE notes (  
  10.   id int UNSIGNED NOT NULL PRIMARY KEY,  
  11.   guid binary(16) NOT NULL,  
  12.   user_id int UNSIGNED NOT NULL,  
  13.   notebook_id int UNSIGNED NOT NULL,  
  14.   title varchar(255) NOT NULL,  
  15.   ...  
  16.   FOREIGN KEY (notebook_id) REFERENCES notebooks(id)  
  17. ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

如果你在Windows客户端上创建了一个名为“Cooking”的记事本,并立即在其中粘贴了一个名为“Quick Tomato Sauce”的食谱,客户端会立刻进行如下同步:

  • 调用NoteStore.createNotebook() 请求服务器创建记事本,并返回以创建记事本的GUID。
  • 通过指定记事本的GUID,调用NoteStore.createNote()在记事本中创建笔记。

每次API调用都通过SQL事物予以实现,可以让客户端完全信任服务器的任何提示。ACID兼容的数据库可以做到这些:

  • 原子性(Atomicity):如果API调用成功,那么所有的改动都会保存;如果API调用失败,所有的改动都不会提交。
  • 一致性(Consistency): 在API调用完成后,所有的账户都可用,并能保证内部状态的一致性。每篇笔记都与记事本相关联,以避免出现孤立项。数据库不允许删除关联有记事的记事本,这得感谢FOREIGN KEY约束。
  • 持久性(Durability):当服务器发送记事本已创建完毕的回执后,客户端会认为它的存在具有持久性,以便进行后续的操作。变更的持久性,可以让客户端知道在任何时刻对服务状态的影响都能保持一致性。

对我们的同步协议而言,持久性最为重要。如果客户端不能确定服务器端的变更具有持久性,那么协议将会变得复杂而低效。

“大数据”问题

得益于事务处理的数据库的ACID属性,同样使得数据集非常难以扩展,以超出单台服务器的范围。数据库集群和多主复制技术并不理想,键值存储为实现可扩展性提供了一条捷径。

所幸,Evernote暂时不需要考虑这个问题。即便是我们有近10亿的笔记,和近20亿的资源文件,这也并不能称得上是一个大数据集。通过按用户分区,它被划分成了2千万个独立的数据集。

我们尚未遇到所谓“大数据”引发的问题,倒是遇到了许多“中数据”的存储问题,这就是通过规整分区形成的分片存储架构。

也许以后……

我们对新的存储系统非常感兴趣,非常乐意应用在哪些对ACID要求不强,但确实需要横向扩展的新项目中。例如,我们的报告分析系统已经逐渐超出了MySQL平台的承受力,需要被更快、更先进的系统所取代。

我们现在对以Evernote用户元数据为基础的MySQL分片存储颇为满意,尽管这不会引起那些IT弄潮儿的兴趣。(张志平/编译)