关于海量数据的数据模型
http://my.oschina.net/chenzuoping/blog/37747
sharding恶梦
国内的很多大型的网站应该都有过sharding的经验。sharding貌似是使用mysql的网站进行性能升级的最重要的手段。weibo.com,youku.com,douban.com,这此网站都是用sharding作为其性能升级的手段。sharding看起来不错,而且从weibo youku douban的用户体验来说sharding确实给发挥了作用。
sharding一般都是通过把一个数据集非常巨大的表,按主键切割成多个数据表,甚至是把一个数据库分割成多个数据库。这样数据的读写压力就分散到了多个表或多台机器上,这样性能自然而然的会提高了。
虽然sharding带来了性能的重大提升,但其带来的问题也十分明显 。程序逻辑会改变,会带来程序编写上的困难。一个表被sharding成多个子表后,程序要确定到哪个子表找数据。当要进行多表连接查询时,这几乎成了一个不可完成的任务,因为要连接的子表可能会在另一台机器上。解决的办法是编写一个专门的数据访问层,但随着一次又一次的sharding,数据访问层本身也变得十分复杂。sharding本身也非常的复杂,做sharding操作的时候要考虑很多问题,要保证Sharding后业务需要的数据操作依然能够完成,不正确的sharding会给系统带来灾难性的后果,因为其复杂性,所以很容易导致意料不到的错误出现。
新思路
mysql在sharding中出现的问题也使得业界寻找新更好解决方案。google和amazon分别给出了他们的解决方案,分别是bigtable,和dynamo。bigtable和dynamo有很多区别,但其有一个重要的共同点是它们两者都放弃了关系模型,由上面的分析可以看出关系模型在海量数据的情形下会出现扩展困难的问题。
它们都采用了一种实体(entity)[1]模型,实体可以理解为一组相互关联的属性的集合,或一个可以任意添加属性但却没有方法的对象。实体的作用在于把紧密相关系的数据连接在一起,同时区隔开不相关联的数据。实体是最小的分割单位,当数据量变大时数据会被分割到不同的机器上,不同的实体可能会被分割到不同的机器上,但同一个实体的不同属性必须保存在同一个机器上。
例如可以把一个用户a建模成一个实体,而人的名字(name)、年纪(age)、身高(height)、体重(weight)等一系列信息都可以表示成该实体的属性。如果a写了一篇文章则可以该文章仍然应该表示成该实体的一个属性(article1),因为该文章是a写的,因此article1和a之间紧密相联,如果它写了第二篇文章则新建一个article2的属性,如果a发布了一张照片,则该照片也要用a的一个属性photo1来表示,第二个照片则用属性photo2来表示。
这样做的好处在于,所有相关联的数据都捆绑在一了起。当用户数量大到一定程度一个服务无法存储所有数据,或一台服务器无法负载海量的数据请求时,则可以把实体分散到不同的服务器上。因为实体之间几乎是完全不关联的,所以实体被分散到不同的服务器上不会给程序带来太大的影响。
上面的这个模型的优点在于模型非常简单,非常适合于分布式存储。还可以实现自动的sharding,因为sharding的时候根本不需要考虑实体关的关系,只需要以实体为单位将实体分布到不同的机器上即可。
上面这些思考的内容来自于一篇论文life beyond distributed transactions。里面还讲到了消息传递,状态机等问题。非常值得一读。