Add New Notes

This commit is contained in:
geekard
2012-08-08 14:26:04 +08:00
commit 5ef7c20052
2374 changed files with 276187 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T21:58:17+08:00
====== CAP原理和BASE思想 ======
Created 星期二 14 六月 2011
分布式领域CAP理论
Consistency(一致性), 数据一致更新,所有数据变动都是同步的
Availability(可用性), 好的响应性能
Partition tolerance(分区容错性) 可靠性
定理:任何分布式系统只可同时满足二点,没法三者兼顾。
忠告:架构师不要将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。
关系数据库的ACID模型拥有 高一致性 + 可靠性 丧失可用性:
Atomicity原子性一个事务中所有操作都必须全部完成要么全部不完成。
Consistency一致性. 在事务开始或结束时,数据库应该在一致状态。
Isolation隔离层. 事务将假定只有它自己在操作数据库,彼此不知晓。
Durability. 一旦事务完成,就不能返回。
跨数据库事务2PC (two-phase commit) 2PC is the anti-scalability pattern (Pat Helland) 是反可伸缩模式的JavaEE中的JTA事务可以支持2PC。因为2PC是反模式尽量不要使用2PC使用BASE来回避。
BASE模型反ACID模型完全不同ACID模型牺牲高一致性获得可用性或可靠性
Basically Available基本可用。支持分区失败(e.g. sharding碎片划分数据库)
Soft state软状态 状态可以有一段时间不同步,异步。
Eventually consistent最终一致最终数据是一致的就可以了而不是时时高一致。
BASE思想的主要实现有
1.按功能划分数据库
2.sharding碎片
BASE思想主要强调基本的可用性如果你需要High 可用性也就是纯粹的高性能那么就要以一致性或容错性为牺牲BASE思想的方案在性能上还是有潜力可挖的。
现在NOSQL运动丰富了拓展了BASE思想可按照具体情况定制特别方案比如忽视一致性获得高可用性等等NOSQL应该有下面两个流派
1. key-value存储如Amaze Dynamo等可根据CAP三原则灵活选择不同倾向的数据库产品。
2. 领域模型 + 分布式缓存 + 存储 Qi4j和NoSql运动可根据CAP三原则结合自己项目定制灵活的分布式方案难度高。
这两者共同点都是关系数据库SQL以外的可选方案逻辑随着数据分布任何模型都可以自己持久化将数据处理和数据存储分离将读和写分离存储可以是异步或同步取决于对一致性的要求程度。
不同点NOSQL之类的key-value存储产品是和关系数据库头碰头的产品BOX可以适合非Java如PHP RUBY等领域是一种可以拿来就用的产品而领域模型 + 分布式缓存 + 存储是一种复杂的架构解决方案,不是产品,但这种方式更灵活,更应该是架构师必须掌握的。

View File

@@ -0,0 +1,72 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T22:10:18+08:00
====== 五大优势五大挑战 ======
Created 星期二 14 六月 2011
关系数据库模型已经流行了几十年了但是一种新类型的数据库——被称为NoSQL正在引起企业的注意。下面是关于它的优势和劣势的一个概述。二十多年以来对数据库管理来说关系数据库(RDBMS)模型一直是一个占统治地位的数据库模型。但是,今天,非关系数据库,“云”数据库,或 “NoSQL”数据库作为关系数据库以外的一些选择正在引起大家的广泛关注。在这篇文章里我们将主要关注那些非关系的NoSQL数据库的十大利弊包括五大优势和五大挑战。
  NoSQL的五大优势
  1.灵活的可扩展性
  多年以来,数据库管理员们都是通过“纵向扩展”的方式(当数据库的负载增加的时候,购买更大型的服务器来承载增加的负载)来进行扩展的,而不是通过“横向扩展”的方式(当数据库负载增加的时候,在多台主机上分配增加的负载)来进行扩展。但是随着交易率和可用性需求的增加数据库也正在迁移到云端或虚拟化环境中“横向扩展”在commodity hardware方面的经济优势变得更加明显了对各大企业来说这种“诱惑”是无法抗拒的。
  在commodity clusters上要对RDBMS做“横向扩展”并不是很容易但是各种新类型的NoSQL数据库主要是为了进行透明的扩展来利用新节点而设计的而且它们通常都是为了低成本的commodity hardware而设计的。
  2.大数据
  在过去的十年里正如交易率发生了翻天覆地的增长一样需要存储的数据量也发生了急剧地膨胀。OReilly把这种现象称为“数据的工业革命”。为了满足数据量增长的需要RDBMS的容量也在日益增加但是对一些企业来说随着交易率的增加单一数据库需要管理的数据约束的数量也变得越来越让人无法忍受了。现在大量的“大数据”可以通过NoSQL系统(例如Hadoop)来处理它们能够处理的数据量远远超出了最大型的RDBMS所能处理的极限。
  3.“永别了”!DBA们!
  在过去的几年里虽然一些RDBMS供应商们声称在可管理性方面做出了很多的改进但是高端的RDBMS系统维护起来仍然十分昂贵而且还需要训练有素的DBA们的协助。DBA们需要亲自参与高端的RDBMS系统的设计安装和调优。
  NoSQL数据库从一开始就是为了降低管理方面的要求而设计的从理论上来说自动修复数据分配和简单的数据模型的确可以让管理和调优方面的要求降低很多。但是DBA的死期将至的谣言未免有些过于夸张了。总是需要有人对关键性的数据库的性能和可用性负责的。
  4.经济
  NoSQL数据库通常使用廉价的commodity servers集群来管理膨胀的数据和事务数量而RDBMS通常需要依靠昂贵的专有服务器和存储系统来做到这一点。使用NoSQL每GB的成本或每秒处理的事务的成本都比使用RDBMS的成本少很多倍这可以让你花费更低的成本存储和处理更多的数据。
  5.灵活的数据模型
  对于大型的生产性的RDBMS来说变更管理是一件很令人头痛的事情。即使只对一个RDBMS的数据模型做了很小的改动也必须要十分小心地管理也许还需要停机或降低服务水平。NoSQL数据库在数据模型约束方面是更加宽松的甚至可以说并不存在数据模型约束。NoSQL的主键值数据库和文档数据库可以让应用程序在一个数据元素里存储任何结构的数据。即使是规定更加严格的基于“大表”的NoSQL数据库(例如Cassandra, HBase)通常也允许创建新列,这并不会造成什么麻烦。
  应用程序变更和数据库模式的变更并不需要作为一个复杂的变更单元来管理。从理论上来说,这可以让应用程序迭代的更快,但是,很明显,如果应用程序无法维护数据的完整性,那么这会带来一些不良的副作用。
  NoSQL的五大挑战
  NoSQL的种种承诺引发了一场热潮但是在它们得到主流的企业的青睐以前它们还有许多困难需要克服。下面是NoSQL需要面对的一些挑战。
  1.成熟度
  RDBMS系统已经发展很长时间了。NoSQL的拥护者们认为RDBMS系统那超长的发展的年限恰恰表示它们已经过时了但是对于大多数的 CIO们来说RDBMS的成熟度更加令它们放心。大多数情况下RDBMS系统更加稳定而且功能也更加丰富。相比之下大多数的NoSQL数据库都是 pre-production版本许多关键性的功能还有待实现。
  对于大多数开发者来说,处于技术的最前沿的确是很令人兴奋的,但是企业应该怀着极端谨慎的态度来处理此事。
  2.支持
  企业都希望能得到这样的保证如果一个关键性的系统出现问题了他们可以获得及时有效的支持。所有的RDBMS供应商都在竭尽全力地提供高水平的企业支持。
  相反大多数的NoSQL系统都是开源项目虽然对于每个NoSQL数据库来说通常也会有一个或多个公司对它们提供支持但是那些公司通常是小型的创业公司在支持的范围支持的资源或可信度方面它们和Oracle, Microsoft或IBM是无法相提并论的。
  3.分析和商业智能化
  NoSQL数据库现在已经可以满足现代的Web2.0应用程序的高度的可扩展性的要求了。这直接导致的结果是它们的大多数功能都是面向这些应用程序而设计的。但是在一个应用程序中具有商业价值的数据早就已经超出了一个标准的Web应用程序需要的“插入-读取-更新-删除”的范畴了。在公司的数据库中进行商业信息的挖掘可以提高企业的效率和竞争力,而且对于所有的中到大型的公司来说,商业智能化(BI)一直是一个至关重要的IT问题。
  NoSQL数据库几乎没有提供什么专用的查询和分析工具。即使是一个简单的查询也要求操作者具有很高超的编程技术而且常用的BI工具是无法连接到NoSQL的。
  像HIVE或PIG那样的新出现的一些解决方案在这方面可以提供一些帮助它们可以让访问Hadoop集群中的数据变得更加容易最后也许还会支持其他的NoSQL数据库。Quest软件已经开发了一个产品——Toad for Cloud Databases——它给各种NoSQL数据库提供了专用的查询功能。
  4.管理
  NoSQL的设计目标是提供一个“零管理”的解决方案但是目前来说还远远没有达到这个目标。安装NoSQL还是需要很多技巧的同时维护它也需要付出很多的努力。
  5.专业知识
  毫不夸张地说全世界有数百万的开发者他们都对RDBMS的概念和编程方法很熟悉在每个业务部门中都有这样的开发者。相反几乎每一个 NoSQL开发者都正处于学习状态中。虽然这种情况会随着时间的推移而改变但是现在找到一些有经验的RDBMS程序员或管理员要比找到一个NoSQL 专家容易的多。
  结论
  NoSQL数据库正在逐渐地成为数据库领域中不可或缺的一部分如果使用方法得当的话能获得很多的好处。但是企业应该谨慎行事要充分地认识到这些数据库的一些限制和问题。

View File

@@ -0,0 +1,96 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T21:05:19+08:00
====== NoSQL架构实践(1) ======
Created 星期二 14 六月 2011
怎么样把NoSQL引入到系统架构设计中需要根据我们**系统的业务场景来分析**什么样类型的数据适合存储在NoSQL数据库中什么样类型的数据必须使用关系数据库存储。明确引入的NoSQL数据库带给系统的作用它能解决什么问题以及可能带来的新的问题。下面我们分析几种常见的NoSQL架构。
===== NoSQL作为镜像 =====
不改变原有的以MySQL作为存储的架构使用NoSQL作为辅助镜像存储用NoSQL的优势辅助提升性能。
{{./image1.JPG}}
图 1 -NoSQL为镜像代码完成模式
//写入数据的示例伪代码
//data为我们要存储的数据对象
data.title=”title”;
data.name=”name”;
data.time=”2009-12-01 10:10:01”;
data.from=”1”;
id=DB.Insert(data);//写入MySQL数据库
NoSQL.Add(id,data);//以写入MySQL产生的自增id为主键写入NoSQL数据库
如果有数据一致性要求,可以像如下的方式使用
//写入数据的示例伪代码
//data为我们要存储的数据对象
bool status=false;
DB.startTransaction();//开始事务
id=DB.Insert(data);//写入MySQL数据库
if(id>0){
status=NoSQL.Add(id,data);//以写入MySQL产生的自增id为主键写入NoSQL数据库
}
if(id>0 && status==true){
DB.commit();//提交事务
}else{
DB.rollback();//不成功,进行回滚
}
上面的代码看起来可能觉得有点麻烦但是只需要在DB类或者ORM层做一个统一的封装就能实现重用了其他代码都不用做任何的修改。
这种架构**在原有基于MySQL数据库的架构上增加了一层辅助的NoSQL存储**代码量不大技术难度小却在可扩展性和性能上起到了非常大的作用。只需要程序在写入MySQL数据库后同时写入到NoSQL数据库让MySQL和NoSQL拥有相同的镜像数据在某些可以根据主键查询的地方使用高效的NoSQL数据库查询这样就节省了MySQL的查询用NoSQL的高性能来抵挡这些查询。
{{./image2.JPG}}
图 2 -NoSQL为镜像同步模式
这种不通过程序代码而是通过MySQL**把数据同步到NoSQL**中,这种模式是上面一种的变体,是一种对**写入透明**但是具有更高技术难度一种模式。这种模式适用于现有的比较复杂的老系统,通过修改代码不易实现,可能引起新的问题。同时也适用于需要把数据同步到多种类型的存储中。
MySQL到NoSQL同步的实现可以使用**MySQL UDF**函数MySQL binlog的解析来实现。可以利用现有的开源项目来实现比如
MySQL memcached UDFs从通过UDF操作Memcached协议。
国内张宴开源的mysql-udf-http通过UDF操作http协议。
有了这两个MySQL UDF函数库我们就能通过MySQL透明的处理Memcached或者Http协议这样只要有兼容Memcached或者Http协议的NoSQL数据库那么我们就能通过MySQL去操作以进行同步数据。再结合lib_mysqludf_json通过UDF和MySQL触发器功能的结合就可以实现数据的自动同步。
===== MySQL和NoSQL组合 =====
MySQL中只存储需要查询的**小字段**NoSQL存储所有数据。
{{./image3.JPG}}
图 3 -MySQL和NoSQL组合
//写入数据的示例伪代码
//data为我们要存储的数据对象
data.title=”title”;
data.name=”name”;
data.time=”2009-12-01 10:10:01”;
data.from=”1”;
bool status=false;
DB.startTransaction();//开始事务
id=DB.Insert(“INSERT INTO table (from) VALUES(data.from)”);//写入MySQL数据库,只写from需要where查询的字段
if(id>0){
status=NoSQL.Add(id,data);//以写入MySQL产生的自增id为主键写入NoSQL数据库
}
if(id>0 && status==true){
DB.commit();//提交事务
}else{
DB.rollback();//不成功,进行回滚
}
把需要查询的字段,一般都是数字,时间等类型的**小字段存储于MySQL中**根据查询建立相应的索引其他不需要的字段包括大文本字段都存储在NoSQL中。在查询的时候我们先从MySQL中查询出数据的主键然后从NoSQL中直接取出对应的数据即可。
这种架构模式把MySQL和NoSQL的作用进行了融合各司其职让MySQL专门负责处理擅长的关系存储NoSQL作为数据的存储。它有以下优点
* 节省MySQL的IO开销。由于MySQL只存储需要查询的小字段不再负责存储大文本字段这样就可以节省MySQL存储的空间开销从而节省MySQL的磁盘IO。我们曾经通过这种优化把MySQL一个40G的表缩减到几百M。
* 提高MySQl Query Cache缓存命中率。我们知道query cache缓存失效是**表级**的在MySQL表一旦被更新就会失效经过这种字段的分离更新的字段如果不是存储在MySQL中那么对query cache就没有任何影响。而NoSQL的Cache往往都是行级别的只对更新的记录的缓存失效。
* 提升MySQL主从同步效率。由于MySQL存储空间的减小同步的数据记录也减小了而部分数据的更新落在NoSQL而不是MySQL这样也减少了MySQL数据需要同步的次数。
* 提高MySQL数据备份和恢复的速度。由于MySQL数据库存储的数据的减小很容易看到数据备份和恢复的速度也将极大的提高。
* 比以前更容易扩展。NoSQL天生就容易扩展。经过这种优化MySQL性能也得到提高。
比如手机凤凰网就是这种架构 http://www.cnblogs.com/sunli/archive/2010/12/20/imcp.html
===== 总结 =====
以NoSQL为辅的架构还是以MySQL架构的思想为中心只是在以前的架构上辅助增加了NoSQL来提高其性能和可扩展性。这种架构实现起来比较容易却能取得不错的效果。如果正想在项目中引入NoSQL或者你的以MySQL架构的系统目前正出现相关的瓶颈希望本文可以为你带来帮助。

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,98 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T21:05:19+08:00
====== NoSQL架构实践 ======
Created 星期二 14 六月 2011
前面《为什么要使用NoSQL》和《关系数据库还是NoSQL数据库》两篇从大体上介绍了为什么要用NoSQL何时该用NoSQL。经常有朋友遇到困惑看到NoSQL的介绍觉得很好但是却不知道如何正式用到自己的项目中。很大的原因就是思维固定在MySQL中了他们问得最多的问题就是用了NoSQL我如何做关系查询。那么接下来我们看下怎么样在我们的系统中使用NoSQL。
怎么样把NoSQL引入到我们的系统架构设计中需要根据我们**系统的业务场景来分析**什么样类型的数据适合存储在NoSQL数据库中什么样类型的数据必须使用关系数据库存储。明确引入的NoSQL数据库带给系统的作用它能解决什么问题以及可能带来的新的问题。下面我们分析几种常见的NoSQL架构。
===== NoSQL作为镜像 =====
不改变原有的以MySQL作为存储的架构使用NoSQL作为辅助镜像存储用NoSQL的优势辅助提升性能。
{{./image1.JPG}}
图 1 -NoSQL为镜像代码完成模式
//写入数据的示例伪代码
//data为我们要存储的数据对象
data.title=”title”;
data.name=”name”;
data.time=”2009-12-01 10:10:01”;
data.from=”1”;
id=DB.Insert(data);//写入MySQL数据库
NoSQL.Add(id,data);//以写入MySQL产生的自增id为主键写入NoSQL数据库
如果有数据一致性要求,可以像如下的方式使用
//写入数据的示例伪代码
//data为我们要存储的数据对象
bool status=false;
DB.startTransaction();//开始事务
id=DB.Insert(data);//写入MySQL数据库
if(id>0){
status=NoSQL.Add(id,data);//以写入MySQL产生的自增id为主键写入NoSQL数据库
}
if(id>0 && status==true){
DB.commit();//提交事务
}else{
DB.rollback();//不成功,进行回滚
}
上面的代码看起来可能觉得有点麻烦但是只需要在DB类或者ORM层做一个统一的封装就能实现重用了其他代码都不用做任何的修改。
这种架构**在原有基于MySQL数据库的架构上增加了一层辅助的NoSQL存储**代码量不大技术难度小却在可扩展性和性能上起到了非常大的作用。只需要程序在写入MySQL数据库后同时写入到NoSQL数据库让MySQL和NoSQL拥有相同的镜像数据在某些可以根据主键查询的地方使用高效的NoSQL数据库查询这样就节省了MySQL的查询用NoSQL的高性能来抵挡这些查询。
{{./image2.JPG}}
图 2 -NoSQL为镜像同步模式
这种不通过程序代码而是通过MySQL**把数据同步到NoSQL**中,这种模式是上面一种的变体,是一种对**写入透明**但是具有更高技术难度一种模式。这种模式适用于现有的比较复杂的老系统,通过修改代码不易实现,可能引起新的问题。同时也适用于需要把数据同步到多种类型的存储中。
MySQL到NoSQL同步的实现可以使用**MySQL UDF**函数MySQL binlog的解析来实现。可以利用现有的开源项目来实现比如
MySQL memcached UDFs从通过UDF操作Memcached协议。
国内张宴开源的mysql-udf-http通过UDF操作http协议。
有了这两个MySQL UDF函数库我们就能通过MySQL透明的处理Memcached或者Http协议这样只要有兼容Memcached或者Http协议的NoSQL数据库那么我们就能通过MySQL去操作以进行同步数据。再结合lib_mysqludf_json通过UDF和MySQL触发器功能的结合就可以实现数据的自动同步。
===== MySQL和NoSQL组合 =====
MySQL中只存储需要查询的**小字段**NoSQL存储所有数据。
{{./image3.JPG}}
图 3 -MySQL和NoSQL组合
//写入数据的示例伪代码
//data为我们要存储的数据对象
data.title=”title”;
data.name=”name”;
data.time=”2009-12-01 10:10:01”;
data.from=”1”;
bool status=false;
DB.startTransaction();//开始事务
id=DB.Insert(“INSERT INTO table (from) VALUES(data.from)”);//写入MySQL数据库,只写from需要where查询的字段
if(id>0){
status=NoSQL.Add(id,data);//以写入MySQL产生的自增id为主键写入NoSQL数据库
}
if(id>0 && status==true){
DB.commit();//提交事务
}else{
DB.rollback();//不成功,进行回滚
}
把需要查询的字段,一般都是数字,时间等类型的**小字段存储于MySQL中**根据查询建立相应的索引其他不需要的字段包括大文本字段都存储在NoSQL中。在查询的时候我们先从MySQL中查询出数据的主键然后从NoSQL中直接取出对应的数据即可。
这种架构模式把MySQL和NoSQL的作用进行了融合各司其职让MySQL专门负责处理擅长的关系存储NoSQL作为数据的存储。它有以下优点
* 节省MySQL的IO开销。由于MySQL只存储需要查询的小字段不再负责存储大文本字段这样就可以节省MySQL存储的空间开销从而节省MySQL的磁盘IO。我们曾经通过这种优化把MySQL一个40G的表缩减到几百M。
* 提高MySQl Query Cache缓存命中率。我们知道query cache缓存失效是**表级**的在MySQL表一旦被更新就会失效经过这种字段的分离更新的字段如果不是存储在MySQL中那么对query cache就没有任何影响。而NoSQL的Cache往往都是行级别的只对更新的记录的缓存失效。
* 提升MySQL主从同步效率。由于MySQL存储空间的减小同步的数据记录也减小了而部分数据的更新落在NoSQL而不是MySQL这样也减少了MySQL数据需要同步的次数。
* 提高MySQL数据备份和恢复的速度。由于MySQL数据库存储的数据的减小很容易看到数据备份和恢复的速度也将极大的提高。
* 比以前更容易扩展。NoSQL天生就容易扩展。经过这种优化MySQL性能也得到提高。
比如手机凤凰网就是这种架构 http://www.cnblogs.com/sunli/archive/2010/12/20/imcp.html
===== 总结 =====
以NoSQL为辅的架构还是以MySQL架构的思想为中心只是在以前的架构上辅助增加了NoSQL来提高其性能和可扩展性。这种架构实现起来比较容易却能取得不错的效果。如果正想在项目中引入NoSQL或者你的以MySQL架构的系统目前正出现相关的瓶颈希望本文可以为你带来帮助。

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,76 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T21:43:26+08:00
====== NoSQL架构实践2 ======
Created 星期二 14 六月 2011
===== 纯NoSQL架构 =====
只使用NoSQL作为数据存储。
{{./image1.jpg}}
图 4-纯NoSQL架构
在一些数据结构、查询关系非常简单的系统中我们可以只使用NoSQL即可以解决**存储问题**。这样不但可以**提高性能**,还非常**易于扩展**。手机凤凰网的前端展示系统就使用了这种方案。
__在一些数据库结构经常变化数据结构不定的系统中就非常适合使用NoSQL来存储__。比如监控系统中的监控信息的存储可能每种类型的监控信息都不太一样。这样可以避免经常对MySQL进行表结构调整增加字段带来的性能问题。
这种架构的缺点就是数据直接存储在NoSQL中不能做关系数据库的**复杂查询**,如果由于需求变更,需要进行某些查询,可能无法满足,所以采用这种架构的时候需要确认未来是否会进行复杂关系查询以及如何应对。
非常幸运的是有些NoSQL数据库已经具有部分关系数据库的**关系查询特性**他们的功能介于key-value和关系数据库之间却具有key-value数据库的性能基本能满足绝大部分web 2.0网站的查询需求。比如:
MongoDB就带有关系查询的功能能解决常用的关系查询所以也是一种非常不错的选择。下面是一些MongoDB的资料
《视觉中国的NoSQL之路从MySQL到MongoDB》
《Choosing a non-relational database; why we migrated from MySQL to MongoDB》
最近的一次Mongo Beijing 开发者聚会也有一部分资料。
虽然Foursquare使用MongoDB的宕机事件的出现使人对MongoDB的自动Shard提出了质疑但是毫无疑问MongoDB在NoSQL中是一个优秀的数据库其单机性能和功能确实是非常吸引人的。由于上面的例子有详细的介绍本文就不做MongoDB的使用介绍。
Tokyo Tyrant数据库带有一个名为**table的存储类型**可以对存储的数据进行关系查询和检索。一个table库类似于MySQL中的一个表。下面我们看一个小演示
我们要存储一批用户信息,用户信息包含用户名(name),年龄(age)email最后访问时间(lastvisit),地区(area)。下面为写入的演示代码:
<?php
$tt = new TokyoTyrantTable ( "127.0.0.1", 1978 );
$tt->vanish ();//清空
$id = $tt->genUid ();//获取一个自增id
//put方法提供数据写入。 put ( string $key , array $columns )
$tt->put ( $id, array ("id" => $id, "name" => "zhangsan", "age" => 27, "email" => "zhangsan@gmail.com", "lastvisit" =>strtotime ( "2011-3-5 12:30:00" ), "area" => "北京" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "lisi", "age" => 25, "email" => "lisi@126.com", "lastvisit" => strtotime( "2011-3-3 14:40:44" ), "area" => "北京" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "laowang", "age" => 37, "email" => "laowang@yahoo.com", "lastvisit" =>strtotime ( "2011-3-5 08:30:12" ), "area" => "成都" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "tom", "age" => 21, "email" => "tom@hotmail.com", "lastvisit" =>strtotime ( "2010-12-10 13:12:13" ), "area" => "天津" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "jack", "age" => 21, "email" => "jack@gmail.com", "lastvisit" =>strtotime ( "2011-02-24 20:12:55" ), "area" => "天津" ) );
//循环打印数据库的所有数据库
$it = $tt->getIterator ();
foreach ( $it as $k => $v ) {
print_r ( $v );
}
?>
比如我们需要查询年龄为21岁的所有用户
<?php $tt = new TokyoTyrantTable ( "127.0.0.1", 1978 );
$query = $tt->getQuery (); //查询年龄为21岁的用户
$query->addCond ( “age”, TokyoTyrant::RDBQC_NUMEQ, “21” );
print_r ( $query->search () ); ?>查询所有在2011年3月5日之后登陆的用户
<?php $tt = new TokyoTyrantTable ( "127.0.0.1", 1978 );
$query = $tt->getQuery ();
$query->addCond ( “lastvisit”, TokyoTyrant::RDBQC_NUMGE, strtotime ( "2011-3-5 00:00:00" ) );
print_r ( $query->search () ); ?>
从上面的示例代码可以看出使用起来是非常简单的甚至比SQL语句还要简单。Tokyo Tyrant的表类型存储还提供了给字段建立普通索引和倒排全文索引大大增强了其检索功能和检索的性能。所以完全用NoSQL来构建部分系统是完全可能的。配合部分带有关系查询功能的NoSQL在开发上比MySQL数据库更加快速和高效。
===== 以NoSQL为数据源的架构 =====
数据直接写入NoSQL再通过NoSQL同步协议复制到其他存储。根据应用的逻辑来决定去相应的存储获取数据。
{{./image2.jpg}}
图 5 -以NoSQL为数据源
纯NoSQL的架构虽然结构简单易于开发但是在应付需求的变更、稳定性和可靠性上总是给开发人员一种风险难于控制的感觉。为了降低风险系统的功能不局限在NoSQL的简单功能上我们可以使用以NoSQL为数据源的架构。
在这种架构中应用程序只负责把数据直接写入到NoSQL数据库就OK然后通过NoSQL的复制协议把NoSQL数据的每次写入更新删除操作都**复制到MySQL数据库中**。同 时,也可以通过复制协议把数据同步复制到全文检索实现强大的检索功能。在海量数据下面,我们也可以根据不同的规则,把数据同步复制到设计好的**分表分库**的 MySQL中。这种架构
* 非常灵活。可以非常方便的在线上系统运行过程中进行数据的调整,比如调整分库分表的规则、要添加一种新的存储类型等等。
* 操作简单。只需要写入NoSQL数据库源应用程序就不用管了。需要增加存储类型或者调整存储规则的时候只需要增加同步的数据存储调整同步规则即可无需更改应用程序的代码。
* 性能高。数据的写入和更新直接操作NoSQL实现了**写的高性能**。而通过同步协议,把数据复制到各种适合查询类型的存储中(按照业务逻辑区分不同的存储),能实现**查询的高性能** 不像以前MySQL一种数据库就全包了。或者就一个表负责跟这个表相关的所有的查询现在可以把一个表的数据复制到各种存储让各种存储用自己的长处来对外服务。
* 易扩展。开发人员只需要关心写入NoSQL数据库。数据的扩展可以方便的在后端由复制协议根据规则来完成。
这种架构需要考虑数据复制的延迟问题这跟使用MySQL的master-salve模式的延迟问题是一样的解决方法也一样。
在这种以NoSQL为数据源的架构中最核心的就是NoSQL数据库的复制功能的实现。而当前的几乎所有的NoSQL都没有提供比较易于使用的复制接口来完成这种架构对NoSQL进行复制协议的二次开发需要更高的技术水平所以这种架构看起来很好但是却不是非常容易实现的。我的开源项目PHPBuffer中有个实现TokyoTyrant复制的例子虽然是PHP版本的但是很容易就可以翻译成其他语言。通过这个例子的代码可以实现从Tokyo Tyrant实时的复制数据到其他系统中。
===== 总结 =====
以NoSQL为主的架构应该算是对NoSQL的一种深度应用整个系统的架构以及代码都不是很复杂但是却需要一定的NoSQL使用经验才行。

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,79 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T21:43:26+08:00
====== NoSQL架构实践——以NoSQL为主 ======
Created 星期二 14 六月 2011
http://luanmad2009.s156.eatj.com/thread-988-1-1.html
作者 孙立
前面一篇《NoSQL架构实践——以NoSQL为辅》主要介绍了以NoSQL为辅助的架构这种架构实施起来比较简单易于理解由于其中也使用了传统的关系数据库让开发者更容易控制NoSQL带来的风险。接下来我们继续深入下去换另外一个角度“以NoSQL为主”来架构系统。
===== 纯NoSQL架构 =====
只使用NoSQL作为数据存储。
{{./image1.jpg}}
图 4-纯NoSQL架构
在一些数据结构、查询关系非常简单的系统中我们可以只使用NoSQL即可以解决**存储问题**。这样不但可以**提高性能**,还非常**易于扩展**。手机凤凰网的前端展示系统就使用了这种方案。
__在一些数据库结构经常变化数据结构不定的系统中就非常适合使用NoSQL来存储__。比如监控系统中的监控信息的存储可能每种类型的监控信息都不太一样。这样可以避免经常对MySQL进行表结构调整增加字段带来的性能问题。
这种架构的缺点就是数据直接存储在NoSQL中不能做关系数据库的**复杂查询**,如果由于需求变更,需要进行某些查询,可能无法满足,所以采用这种架构的时候需要确认未来是否会进行复杂关系查询以及如何应对。
非常幸运的是有些NoSQL数据库已经具有部分关系数据库的**关系查询特性**他们的功能介于key-value和关系数据库之间却具有key-value数据库的性能基本能满足绝大部分web 2.0网站的查询需求。比如:
MongoDB就带有关系查询的功能能解决常用的关系查询所以也是一种非常不错的选择。下面是一些MongoDB的资料
《视觉中国的NoSQL之路从MySQL到MongoDB》
《Choosing a non-relational database; why we migrated from MySQL to MongoDB》
最近的一次Mongo Beijing 开发者聚会也有一部分资料。
虽然Foursquare使用MongoDB的宕机事件的出现使人对MongoDB的自动Shard提出了质疑但是毫无疑问MongoDB在NoSQL中是一个优秀的数据库其单机性能和功能确实是非常吸引人的。由于上面的例子有详细的介绍本文就不做MongoDB的使用介绍。
Tokyo Tyrant数据库带有一个名为**table的存储类型**可以对存储的数据进行关系查询和检索。一个table库类似于MySQL中的一个表。下面我们看一个小演示
我们要存储一批用户信息,用户信息包含用户名(name),年龄(age)email最后访问时间(lastvisit),地区(area)。下面为写入的演示代码:
<?php
$tt = new TokyoTyrantTable ( "127.0.0.1", 1978 );
$tt->vanish ();//清空
$id = $tt->genUid ();//获取一个自增id
//put方法提供数据写入。 put ( string $key , array $columns )
$tt->put ( $id, array ("id" => $id, "name" => "zhangsan", "age" => 27, "email" => "zhangsan@gmail.com", "lastvisit" =>strtotime ( "2011-3-5 12:30:00" ), "area" => "北京" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "lisi", "age" => 25, "email" => "lisi@126.com", "lastvisit" => strtotime( "2011-3-3 14:40:44" ), "area" => "北京" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "laowang", "age" => 37, "email" => "laowang@yahoo.com", "lastvisit" =>strtotime ( "2011-3-5 08:30:12" ), "area" => "成都" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "tom", "age" => 21, "email" => "tom@hotmail.com", "lastvisit" =>strtotime ( "2010-12-10 13:12:13" ), "area" => "天津" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "jack", "age" => 21, "email" => "jack@gmail.com", "lastvisit" =>strtotime ( "2011-02-24 20:12:55" ), "area" => "天津" ) );
//循环打印数据库的所有数据库
$it = $tt->getIterator ();
foreach ( $it as $k => $v ) {
print_r ( $v );
}
?>
比如我们需要查询年龄为21岁的所有用户
<?php $tt = new TokyoTyrantTable ( "127.0.0.1", 1978 );
$query = $tt->getQuery (); //查询年龄为21岁的用户
$query->addCond ( “age”, TokyoTyrant::RDBQC_NUMEQ, “21” );
print_r ( $query->search () ); ?>查询所有在2011年3月5日之后登陆的用户
<?php $tt = new TokyoTyrantTable ( "127.0.0.1", 1978 );
$query = $tt->getQuery ();
$query->addCond ( “lastvisit”, TokyoTyrant::RDBQC_NUMGE, strtotime ( "2011-3-5 00:00:00" ) );
print_r ( $query->search () ); ?>
从上面的示例代码可以看出使用起来是非常简单的甚至比SQL语句还要简单。Tokyo Tyrant的表类型存储还提供了给字段建立普通索引和倒排全文索引大大增强了其检索功能和检索的性能。所以完全用NoSQL来构建部分系统是完全可能的。配合部分带有关系查询功能的NoSQL在开发上比MySQL数据库更加快速和高效。
===== 以NoSQL为数据源的架构 =====
数据直接写入NoSQL再通过NoSQL同步协议复制到其他存储。根据应用的逻辑来决定去相应的存储获取数据。
{{./image2.jpg}}
图 5 -以NoSQL为数据源
纯NoSQL的架构虽然结构简单易于开发但是在应付需求的变更、稳定性和可靠性上总是给开发人员一种风险难于控制的感觉。为了降低风险系统的功能不局限在NoSQL的简单功能上我们可以使用以NoSQL为数据源的架构。
在这种架构中应用程序只负责把数据直接写入到NoSQL数据库就OK然后通过NoSQL的复制协议把NoSQL数据的每次写入更新删除操作都**复制到MySQL数据库中**。同 时,也可以通过复制协议把数据同步复制到全文检索实现强大的检索功能。在海量数据下面,我们也可以根据不同的规则,把数据同步复制到设计好的**分表分库**的 MySQL中。这种架构
* 非常灵活。可以非常方便的在线上系统运行过程中进行数据的调整,比如调整分库分表的规则、要添加一种新的存储类型等等。
* 操作简单。只需要写入NoSQL数据库源应用程序就不用管了。需要增加存储类型或者调整存储规则的时候只需要增加同步的数据存储调整同步规则即可无需更改应用程序的代码。
* 性能高。数据的写入和更新直接操作NoSQL实现了**写的高性能**。而通过同步协议,把数据复制到各种适合查询类型的存储中(按照业务逻辑区分不同的存储),能实现**查询的高性能** 不像以前MySQL一种数据库就全包了。或者就一个表负责跟这个表相关的所有的查询现在可以把一个表的数据复制到各种存储让各种存储用自己的长处来对外服务。
* 易扩展。开发人员只需要关心写入NoSQL数据库。数据的扩展可以方便的在后端由复制协议根据规则来完成。
这种架构需要考虑数据复制的延迟问题这跟使用MySQL的master-salve模式的延迟问题是一样的解决方法也一样。
在这种以NoSQL为数据源的架构中最核心的就是NoSQL数据库的复制功能的实现。而当前的几乎所有的NoSQL都没有提供比较易于使用的复制接口来完成这种架构对NoSQL进行复制协议的二次开发需要更高的技术水平所以这种架构看起来很好但是却不是非常容易实现的。我的开源项目PHPBuffer中有个实现TokyoTyrant复制的例子虽然是PHP版本的但是很容易就可以翻译成其他语言。通过这个例子的代码可以实现从Tokyo Tyrant实时的复制数据到其他系统中。
===== 总结 =====
以NoSQL为主的架构应该算是对NoSQL的一种深度应用整个系统的架构以及代码都不是很复杂但是却需要一定的NoSQL使用经验才行。

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,102 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T22:12:10+08:00
====== 为什么要用非关系数据库? ======
Created 星期二 14 六月 2011
随着互联网web2.0网站的兴起非关系型的数据库现在成了一个极其热门的新领域非关系数据库产品的发展非常迅速。而传统的关系数据库在应付web2.0网站特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,例如:
1、High performance - 对数据库高并发读写的需求
web2.0网站要根据用户个性化信息来实时生成动态页面和提供动态信息所以基本上无法使用动态页面静态化技术因此数据库并发负载非常高往往要达到每秒上万次读写请求。关系数据库应付上万次SQL查询还勉强顶得住但是应付上万次SQL写数据请求硬盘IO就已经无法承受了。其实对于普通的BBS网站往往也存在对高并发写请求的需求例如像JavaEye网站的实时统计在线用户状态记录热门帖子的点击次数投票计数等因此这是一个相当普遍的需求。
2、Huge Storage - 对海量数据的高效率存储和访问的需求
类似FacebooktwitterFriendfeed这样的SNS网站每天用户产生海量的用户动态以Friendfeed为例一个月就达到了2.5亿条用户动态对于关系数据库来说在一张2.5亿条记录的表里面进行SQL查询效率是极其低下乃至不可忍受的。再例如大型web网站的用户登录系统例如腾讯盛大动辄数以亿计的帐号关系数据库也很难应付。
3、High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求
在基于web的架构当中数据库是最难进行横向扩展的当一个应用系统的用户量和访问量与日俱增的时候你的数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供24小时不间断服务的网站来说对数据库系统进行升级和扩展是非常痛苦的事情往往需要停机维护和数据迁移为什么数据库不能通过不断的添加服务器节点来实现扩展呢
在上面提到的“三高”需求面前关系数据库遇到了难以克服的障碍而对于web2.0网站来说,关系数据库的很多主要特性却往往无用武之地,例如:
1、数据库事务一致性需求
很多web实时系统并不要求严格的数据库事务对读一致性的要求很低有些场合对写一致性要求也不高。因此数据库事务管理成了数据库高负载下一个沉重的负担。
2、数据库的写实时性和读实时性需求
对关系数据库来说插入一条数据之后立刻查询是肯定可以读出来这条数据的但是对于很多web应用来说并不要求这么高的实时性比方说我JavaEye的robbin发一条消息之后过几秒乃至十几秒之后我的订阅者才看到这条动态是完全可以接受的。
3、对复杂的SQL查询特别是多表关联查询的需求
任何大数据量的web系统都非常忌讳多个大表的关联查询以及复杂的数据分析类型的复杂SQL报表查询特别是SNS类型的网站从需求以及产品设计角度就避免了这种情况的产生。往往更多的只是单表的主键查询以及单表的简单条件分页查询SQL的功能被极大的弱化了。
因此,关系数据库在这些越来越多的应用场景下显得不那么合适了,为了解决这类问题的非关系数据库应运而生,现在这两年,各种各样非关系数据库,特别是键值数据库(Key-Value Store DB)风起云涌多得让人眼花缭乱。前不久国外刚刚举办了NoSQL Conference各路NoSQL数据库纷纷亮相加上未亮相但是名声在外的起码有超过10个开源的NoSQLDB例如
RedisTokyo CabinetCassandraVoldemortMongoDBDynomiteHBaseCouchDBHypertable RiakTin Flare Lightcloud KiokuDBScalaris Kai ThruDB ......
这些NoSQL数据库有的是用C/C++编写的有的是用Java编写的还有的是用Erlang编写的每个都有自己的独到之处看都看不过来了我(robbin)也只能从中挑选一些比较有特色看起来更有前景的产品学习和了解一下。这些NoSQL数据库大致可以分为以下的三类
一、满足极高读写性能需求的Kye-Value数据库RedisTokyo Cabinet Flare
高性能Key-Value数据库的主要特点就是具有极高的并发读写性能RedisTokyo Cabinet Flare这3个Key-Value DB都是用C编写的他们的性能都相当出色但出了出色的性能他们还有自己独特的功能
1、Redis
Redis是一个很新的项目刚刚发布了1.0版本。Redis本质上是一个Key-Value类型的内存数据库很像memcached整个数据库统统加载在内存当中进行操作定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作Redis的性能非常出色每秒可以处理超过10万次读写操作是我知道的性能最快的Key-Value DB。
Redis的出色之处不仅仅是性能Redis最大的魅力是支持保存List链表和Set集合的数据结构而且还支持对List进行各种操作例如从List两端push和pop数据取List区间排序等等对Set支持各种集合的并集交集操作此外单个value的最大限制是1GB不像memcached只能保存1MB的数据因此Redis可以用来实现很多有用的功能比方说用他的List来做FIFO双向链表实现一个轻量级的高性能消息队列服务用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间因此也可以被当作一个功能加强版的memcached来用。
Redis的主要缺点是数据库容量受到物理内存的限制不能用作海量数据的高性能读写并且它没有原生的可扩展机制不具有scale可扩展能力要依赖客户端来实现分布式读写因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。目前使用Redis的网站有githubEngine Yard。
2、Tokyo Cabinet和Tokoy Tyrant
TC和TT的开发者是日本人Mikio Hirabayashi主要被用在日本最大的SNS网站mixi.jp上TC发展的时间最早现在已经是一个非常成熟的项目也是Kye-Value数据库领域最大的热点现在被广泛的应用在很多很多网站上。TC是一个高性能的存储引擎而TT提供了多线程高并发服务器性能也非常出色每秒可以处理4-5万次读写操作。
TC除了支持Key-Value存储之外还支持保存Hashtable数据类型因此很像一个简单的数据库表并且还支持基于column的条件查询分页查询和排序功能基本上相当于支持单表的基础查询功能了所以可以简单的替代关系数据库的很多操作这也是TC受到大家欢迎的主要原因之一有一个Ruby的项目miyazakiresistance将TT的hashtable的操作封装成和ActiveRecord一样的操作用起来非常爽。
TC/TT在mixi的实际应用当中存储了2000万条以上的数据同时支撑了上万个并发连接是一个久经考验的项目。TC在保证了极高的并发读写性能的同时具有可靠的数据持久化机制同时还支持类似关系数据库表结构的hashtable以及简单的条件分页和排序操作是一个很棒的NoSQL数据库。
TC的主要缺点是在数据量达到上亿级别以后并发写数据性能会大幅度下降NoSQL: If Only It Was That Easy提到他们发现在TC里面插入1.6亿条2-20KB数据的时候写入性能开始急剧下降。看来是当数据量上亿条的时候TC性能开始大幅度下降从TC作者自己提供的mixi数据来看至少上千万条数据量的时候还没有遇到这么明显的写入性能瓶颈。
这个是Tim Yang做的一个MemcachedRedis和Tokyo Tyrant的简单的性能评测仅供参考
3、Flare
TC是日本第一大SNS网站mixi开发的而Flare是日本第二大SNS网站green.jp开发的有意思吧。Flare简单的说就是给TC添加了scale功能。他替换掉了TT部分自己另外给TC写了网络服务器Flare的主要特点就是支持scale能力他在网络服务端之前添加了一个node server来管理后端的多个服务器节点因此可以动态添加数据库服务节点删除服务器节点也支持failover。如果你的使用场景必须要让TC可以scale那么可以考虑flare。
flare唯一的缺点就是他只支持memcached协议因此当你使用flare的时候就不能使用TC的table数据结构了只能使用TC的key-value数据结构存储。
二、满足海量存储需求和访问的面向文档的数据库MongoDBCouchDB
面向文档的非关系数据库主要解决的问题不是高性能的并发读写而是保证海量数据存储的同时具有良好的查询性能。MongoDB是用C++开发的而CouchDB则是Erlang开发的
1、MongoDB
MongoDB是一个介于关系数据库和非关系数据库之间的产品是非关系数据库当中功能最丰富最像关系数据库的。他支持的数据结构非常松散是类似json的bjson格式因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大其语法有点类似于面向对象的查询语言几乎可以实现类似关系数据库单表查询的绝大部分功能而且还支持对数据建立索引。
Mongo主要解决的是海量数据的访问效率问题根据官方的文档当数据量达到50GB以上的时候Mongo的数据库访问速度是MySQL的10倍以上。Mongo的并发读写效率不是特别出色根据官方提供的性能测试表明大约每秒可以处理0.5万1.5次读写请求。对于Mongo的并发读写性能robbin也打算有空的时候好好测试一下。
因为Mongo主要是支持海量数据存储的所以Mongo还自带了一个出色的分布式文件系统GridFS可以支持海量的数据存储但我也看到有些评论认为GridFS性能不佳这一点还是有待亲自做点测试来验证了。
最后由于Mongo可以支持复杂的数据结构而且带有强大的数据查询功能因此非常受到欢迎很多项目都考虑用MongoDB来替代MySQL来实现不是特别复杂的Web应用比方说why we migrated from MySQL to MongoDB就是一个真实的从MySQL迁移到MongoDB的案例由于数据量实在太大所以迁移到了Mongo上面数据查询的速度得到了非常显著的提升。
MongoDB也有一个ruby的项目MongoMapper是模仿Merb的DataMapper编写的MongoDB的接口使用起来非常简单几乎和DataMapper一模一样功能非常强大易用。
2、CouchDB
CouchDB现在是一个非常有名气的项目似乎不用多介绍了。但是我却对CouchDB没有什么兴趣主要是因为CouchDB仅仅提供了基于HTTP REST的接口因此CouchDB单纯从并发读写性能来说是非常糟糕的这让我立刻抛弃了对CouchDB的兴趣。
三、满足高可扩展性和可用性的面向分布式计算的数据库CassandraVoldemort
面向scale能力的数据库其实主要解决的问题领域和上述两类数据库还不太一样它首先必须是一个分布式的数据库系统由分布在不同节点上面的数据库共同构成一个数据库服务系统并且根据这种分布式架构来提供online的具有弹性的可扩展能力例如可以不停机的添加更多数据节点删除数据节点等等。因此像Cassandra常常被看成是一个开源版本的Google BigTable的替代品。Cassandra和Voldemort都是用Java开发的
1、Cassandra
Cassandra项目是Facebook在2008年开源出来的随后Facebook自己使用Cassandra的另外一个不开源的分支而开源出来的Cassandra主要被Amazon的Dynamite团队来维护并且Cassandra被认为是Dynamite2.0版本。目前除了Facebook之外twitter和digg.com都在使用Cassandra。
Cassandra的主要特点就是它不是一个数据库而是由一堆数据库节点共同构成的一个分布式网络服务对Cassandra的一个写操作会被复制到其他节点上去对Cassandra的读操作也会被路由到某个节点上面去读取。对于一个Cassandra群集来说扩展性能是比较简单的事情只管在群集里面添加节点就可以了。我看到有文章说Facebook的Cassandra群集有超过100台服务器构成的数据库群集。
Cassandra也支持比较丰富的数据结构和功能强大的查询语言和MongoDB比较类似查询功能比MongoDB稍弱一些twitter的平台架构部门领导Evan Weaver写了一篇文章介绍Cassandrahttp://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/,有非常详细的介绍。
Cassandra以单个节点来衡量其节点的并发读写性能不是特别好有文章说评测下来Cassandra每秒大约不到1万次读写请求我也看到一些对这个问题进行质疑的评论但是评价Cassandra单个节点的性能是没有意义的真实的分布式数据库访问系统必然是n多个节点构成的系统其并发性能取决于整个系统的节点数量路由效率而不仅仅是单节点的并发负载能力。
2、Voldemort
Voldemort是个和Cassandra类似的面向解决scale问题的分布式数据库系统Cassandra来自于Facebook这个SNS网站而Voldemort则来自于Linkedin这个SNS网站。说起来SNS网站为我们贡献了n多的NoSQL数据库例如CassandarVoldemortTokyo CabinetFlare等等。Voldemort的资料不是很多因此我没有特别仔细去钻研Voldemort官方给出Voldemort的并发读写性能也很不错每秒超过了1.5万次读写。
从Facebook开发CassandraLinkedin开发Voldemort我们也可以大致看出国外大型SNS网站对于分布式数据库特别是对数据库的scale能力方面的需求是多么殷切。前面我robbin提到web应用的架构当中web层和app层相对来说都很容易横向扩展唯有数据库是单点的极难scale现在Facebook和Linkedin在非关系型数据库的分布式方面探索了一条很好的方向这也是为什么现在Cassandra这么热门的主要原因。
如今NoSQL数据库是个令人很兴奋的领域总是不断有新的技术新的产品冒出来改变我们已经形成的固有的技术观念我自己robbin稍微了解了一些就感觉自己深深的沉迷进去了可以说NoSQL数据库领域也是博大精深的robbin也只能浅尝辄止robbin写这篇文章既是自己一点点钻研心得也是抛砖引玉希望吸引对这个领域有经验的朋友来讨论和交流。
从我robbin个人的兴趣来说分布式数据库系统不是我能实际用到的技术因此不打算花时间深入而其他两个数据领域高性能NoSQLDB和海量存储NoSQLDB都是我很感兴趣的特别是RedisTT/TC和MongoDB这3个NoSQL数据库因此我接下来将写三篇文章分别详细介绍这3个数据库。
声明ITeye文章版权属于作者受法律保护。没有作者书面许可不得转载。

View File

@@ -0,0 +1,102 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T22:12:10+08:00
====== 主题NoSQL数据库探讨之一 为什么要用非关系数据库? ======
Created 星期二 14 六月 2011
http://www.iteye.com/topic/524977
随着互联网web2.0网站的兴起非关系型的数据库现在成了一个极其热门的新领域非关系数据库产品的发展非常迅速。而传统的关系数据库在应付web2.0网站特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,例如:
1、High performance - 对数据库高并发读写的需求
web2.0网站要根据用户个性化信息来实时生成动态页面和提供动态信息所以基本上无法使用动态页面静态化技术因此数据库并发负载非常高往往要达到每秒上万次读写请求。关系数据库应付上万次SQL查询还勉强顶得住但是应付上万次SQL写数据请求硬盘IO就已经无法承受了。其实对于普通的BBS网站往往也存在对高并发写请求的需求例如像JavaEye网站的实时统计在线用户状态记录热门帖子的点击次数投票计数等因此这是一个相当普遍的需求。
2、Huge Storage - 对海量数据的高效率存储和访问的需求
类似FacebooktwitterFriendfeed这样的SNS网站每天用户产生海量的用户动态以Friendfeed为例一个月就达到了2.5亿条用户动态对于关系数据库来说在一张2.5亿条记录的表里面进行SQL查询效率是极其低下乃至不可忍受的。再例如大型web网站的用户登录系统例如腾讯盛大动辄数以亿计的帐号关系数据库也很难应付。
3、High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求
在基于web的架构当中数据库是最难进行横向扩展的当一个应用系统的用户量和访问量与日俱增的时候你的数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供24小时不间断服务的网站来说对数据库系统进行升级和扩展是非常痛苦的事情往往需要停机维护和数据迁移为什么数据库不能通过不断的添加服务器节点来实现扩展呢
在上面提到的“三高”需求面前关系数据库遇到了难以克服的障碍而对于web2.0网站来说,关系数据库的很多主要特性却往往无用武之地,例如:
1、数据库事务一致性需求
很多web实时系统并不要求严格的数据库事务对读一致性的要求很低有些场合对写一致性要求也不高。因此数据库事务管理成了数据库高负载下一个沉重的负担。
2、数据库的写实时性和读实时性需求
对关系数据库来说插入一条数据之后立刻查询是肯定可以读出来这条数据的但是对于很多web应用来说并不要求这么高的实时性比方说我JavaEye的robbin发一条消息之后过几秒乃至十几秒之后我的订阅者才看到这条动态是完全可以接受的。
3、对复杂的SQL查询特别是多表关联查询的需求
任何大数据量的web系统都非常忌讳多个大表的关联查询以及复杂的数据分析类型的复杂SQL报表查询特别是SNS类型的网站从需求以及产品设计角度就避免了这种情况的产生。往往更多的只是单表的主键查询以及单表的简单条件分页查询SQL的功能被极大的弱化了。
因此,关系数据库在这些越来越多的应用场景下显得不那么合适了,为了解决这类问题的非关系数据库应运而生,现在这两年,各种各样非关系数据库,特别是键值数据库(Key-Value Store DB)风起云涌多得让人眼花缭乱。前不久国外刚刚举办了NoSQL Conference各路NoSQL数据库纷纷亮相加上未亮相但是名声在外的起码有超过10个开源的NoSQLDB例如
RedisTokyo CabinetCassandraVoldemortMongoDBDynomiteHBaseCouchDBHypertable RiakTin Flare Lightcloud KiokuDBScalaris Kai ThruDB ......
这些NoSQL数据库有的是用C/C++编写的有的是用Java编写的还有的是用Erlang编写的每个都有自己的独到之处看都看不过来了我(robbin)也只能从中挑选一些比较有特色看起来更有前景的产品学习和了解一下。这些NoSQL数据库大致可以分为以下的三类
一、满足极高读写性能需求的Kye-Value数据库RedisTokyo Cabinet Flare
高性能Key-Value数据库的主要特点就是具有极高的并发读写性能RedisTokyo Cabinet Flare这3个Key-Value DB都是用C编写的他们的性能都相当出色但出了出色的性能他们还有自己独特的功能
1、Redis
Redis是一个很新的项目刚刚发布了1.0版本。Redis本质上是一个Key-Value类型的内存数据库很像memcached整个数据库统统加载在内存当中进行操作定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作Redis的性能非常出色每秒可以处理超过10万次读写操作是我知道的性能最快的Key-Value DB。
Redis的出色之处不仅仅是性能Redis最大的魅力是支持保存List链表和Set集合的数据结构而且还支持对List进行各种操作例如从List两端push和pop数据取List区间排序等等对Set支持各种集合的并集交集操作此外单个value的最大限制是1GB不像memcached只能保存1MB的数据因此Redis可以用来实现很多有用的功能比方说用他的List来做FIFO双向链表实现一个轻量级的高性能消息队列服务用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间因此也可以被当作一个功能加强版的memcached来用。
Redis的主要缺点是数据库容量受到物理内存的限制不能用作海量数据的高性能读写并且它没有原生的可扩展机制不具有scale可扩展能力要依赖客户端来实现分布式读写因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。目前使用Redis的网站有githubEngine Yard。
2、Tokyo Cabinet和Tokoy Tyrant
TC和TT的开发者是日本人Mikio Hirabayashi主要被用在日本最大的SNS网站mixi.jp上TC发展的时间最早现在已经是一个非常成熟的项目也是Kye-Value数据库领域最大的热点现在被广泛的应用在很多很多网站上。TC是一个高性能的存储引擎而TT提供了多线程高并发服务器性能也非常出色每秒可以处理4-5万次读写操作。
TC除了支持Key-Value存储之外还支持保存Hashtable数据类型因此很像一个简单的数据库表并且还支持基于column的条件查询分页查询和排序功能基本上相当于支持单表的基础查询功能了所以可以简单的替代关系数据库的很多操作这也是TC受到大家欢迎的主要原因之一有一个Ruby的项目miyazakiresistance将TT的hashtable的操作封装成和ActiveRecord一样的操作用起来非常爽。
TC/TT在mixi的实际应用当中存储了2000万条以上的数据同时支撑了上万个并发连接是一个久经考验的项目。TC在保证了极高的并发读写性能的同时具有可靠的数据持久化机制同时还支持类似关系数据库表结构的hashtable以及简单的条件分页和排序操作是一个很棒的NoSQL数据库。
TC的主要缺点是在数据量达到上亿级别以后并发写数据性能会大幅度下降NoSQL: If Only It Was That Easy提到他们发现在TC里面插入1.6亿条2-20KB数据的时候写入性能开始急剧下降。看来是当数据量上亿条的时候TC性能开始大幅度下降从TC作者自己提供的mixi数据来看至少上千万条数据量的时候还没有遇到这么明显的写入性能瓶颈。
这个是Tim Yang做的一个MemcachedRedis和Tokyo Tyrant的简单的性能评测仅供参考
3、Flare
TC是日本第一大SNS网站mixi开发的而Flare是日本第二大SNS网站green.jp开发的有意思吧。Flare简单的说就是给TC添加了scale功能。他替换掉了TT部分自己另外给TC写了网络服务器Flare的主要特点就是支持scale能力他在网络服务端之前添加了一个node server来管理后端的多个服务器节点因此可以动态添加数据库服务节点删除服务器节点也支持failover。如果你的使用场景必须要让TC可以scale那么可以考虑flare。
flare唯一的缺点就是他只支持memcached协议因此当你使用flare的时候就不能使用TC的table数据结构了只能使用TC的key-value数据结构存储。
二、满足海量存储需求和访问的面向文档的数据库MongoDBCouchDB
面向文档的非关系数据库主要解决的问题不是高性能的并发读写而是保证海量数据存储的同时具有良好的查询性能。MongoDB是用C++开发的而CouchDB则是Erlang开发的
1、MongoDB
MongoDB是一个介于关系数据库和非关系数据库之间的产品是非关系数据库当中功能最丰富最像关系数据库的。他支持的数据结构非常松散是类似json的bjson格式因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大其语法有点类似于面向对象的查询语言几乎可以实现类似关系数据库单表查询的绝大部分功能而且还支持对数据建立索引。
Mongo主要解决的是海量数据的访问效率问题根据官方的文档当数据量达到50GB以上的时候Mongo的数据库访问速度是MySQL的10倍以上。Mongo的并发读写效率不是特别出色根据官方提供的性能测试表明大约每秒可以处理0.5万1.5次读写请求。对于Mongo的并发读写性能robbin也打算有空的时候好好测试一下。
因为Mongo主要是支持海量数据存储的所以Mongo还自带了一个出色的分布式文件系统GridFS可以支持海量的数据存储但我也看到有些评论认为GridFS性能不佳这一点还是有待亲自做点测试来验证了。
最后由于Mongo可以支持复杂的数据结构而且带有强大的数据查询功能因此非常受到欢迎很多项目都考虑用MongoDB来替代MySQL来实现不是特别复杂的Web应用比方说why we migrated from MySQL to MongoDB就是一个真实的从MySQL迁移到MongoDB的案例由于数据量实在太大所以迁移到了Mongo上面数据查询的速度得到了非常显著的提升。
MongoDB也有一个ruby的项目MongoMapper是模仿Merb的DataMapper编写的MongoDB的接口使用起来非常简单几乎和DataMapper一模一样功能非常强大易用。
2、CouchDB
CouchDB现在是一个非常有名气的项目似乎不用多介绍了。但是我却对CouchDB没有什么兴趣主要是因为CouchDB仅仅提供了基于HTTP REST的接口因此CouchDB单纯从并发读写性能来说是非常糟糕的这让我立刻抛弃了对CouchDB的兴趣。
三、满足高可扩展性和可用性的面向分布式计算的数据库CassandraVoldemort
面向scale能力的数据库其实主要解决的问题领域和上述两类数据库还不太一样它首先必须是一个分布式的数据库系统由分布在不同节点上面的数据库共同构成一个数据库服务系统并且根据这种分布式架构来提供online的具有弹性的可扩展能力例如可以不停机的添加更多数据节点删除数据节点等等。因此像Cassandra常常被看成是一个开源版本的Google BigTable的替代品。Cassandra和Voldemort都是用Java开发的
1、Cassandra
Cassandra项目是Facebook在2008年开源出来的随后Facebook自己使用Cassandra的另外一个不开源的分支而开源出来的Cassandra主要被Amazon的Dynamite团队来维护并且Cassandra被认为是Dynamite2.0版本。目前除了Facebook之外twitter和digg.com都在使用Cassandra。
Cassandra的主要特点就是它不是一个数据库而是由一堆数据库节点共同构成的一个分布式网络服务对Cassandra的一个写操作会被复制到其他节点上去对Cassandra的读操作也会被路由到某个节点上面去读取。对于一个Cassandra群集来说扩展性能是比较简单的事情只管在群集里面添加节点就可以了。我看到有文章说Facebook的Cassandra群集有超过100台服务器构成的数据库群集。
Cassandra也支持比较丰富的数据结构和功能强大的查询语言和MongoDB比较类似查询功能比MongoDB稍弱一些twitter的平台架构部门领导Evan Weaver写了一篇文章介绍Cassandrahttp://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/,有非常详细的介绍。
Cassandra以单个节点来衡量其节点的并发读写性能不是特别好有文章说评测下来Cassandra每秒大约不到1万次读写请求我也看到一些对这个问题进行质疑的评论但是评价Cassandra单个节点的性能是没有意义的真实的分布式数据库访问系统必然是n多个节点构成的系统其并发性能取决于整个系统的节点数量路由效率而不仅仅是单节点的并发负载能力。
2、Voldemort
Voldemort是个和Cassandra类似的面向解决scale问题的分布式数据库系统Cassandra来自于Facebook这个SNS网站而Voldemort则来自于Linkedin这个SNS网站。说起来SNS网站为我们贡献了n多的NoSQL数据库例如CassandarVoldemortTokyo CabinetFlare等等。Voldemort的资料不是很多因此我没有特别仔细去钻研Voldemort官方给出Voldemort的并发读写性能也很不错每秒超过了1.5万次读写。
从Facebook开发CassandraLinkedin开发Voldemort我们也可以大致看出国外大型SNS网站对于分布式数据库特别是对数据库的scale能力方面的需求是多么殷切。前面我robbin提到web应用的架构当中web层和app层相对来说都很容易横向扩展唯有数据库是单点的极难scale现在Facebook和Linkedin在非关系型数据库的分布式方面探索了一条很好的方向这也是为什么现在Cassandra这么热门的主要原因。
如今NoSQL数据库是个令人很兴奋的领域总是不断有新的技术新的产品冒出来改变我们已经形成的固有的技术观念我自己robbin稍微了解了一些就感觉自己深深的沉迷进去了可以说NoSQL数据库领域也是博大精深的robbin也只能浅尝辄止robbin写这篇文章既是自己一点点钻研心得也是抛砖引玉希望吸引对这个领域有经验的朋友来讨论和交流。
从我robbin个人的兴趣来说分布式数据库系统不是我能实际用到的技术因此不打算花时间深入而其他两个数据领域高性能NoSQLDB和海量存储NoSQLDB都是我很感兴趣的特别是RedisTT/TC和MongoDB这3个NoSQL数据库因此我接下来将写三篇文章分别详细介绍这3个数据库。
声明ITeye文章版权属于作者受法律保护。没有作者书面许可不得转载。

View File

@@ -0,0 +1,118 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T21:05:47+08:00
====== 关系数据库还是NoSQL数据库 ======
Created 星期二 14 六月 2011
在过去我们只需要学习和使用一种数据库技术就能做几乎所有的数据库应用开发。因为成熟稳定的关系数据库产品并不是很多而供你选择的免费版本就更加少了所以互联网领域基本上都选择了免费的MySQL数据库。在高速发展的WEB2.0时代,我们发现关系数据库在性能、扩展性、数据的快速备份和恢复、满足需求的易用性上并不总是能很好的满足我们的需要,我们越来越趋向于**根据业务场景选择合适的数据库**以及进行多种数据库的融合运用。几年前的一篇文章《One Size Fits All - An Idea Whose Time Has Come and Gone》就已经阐述了这个观点。
当我们在讨论是否要使用NoSQL的时候你还需要理解NoSQL也是分很多种类的在NoSQL百花齐放的今天NoSQL的**正确选择**比选择关系数据库还具有挑战性。虽然NoSQL的使用很简单但是选择却是个麻烦事这也正是很多人在观望的一个原因。
NoSQL的分类
NoSQL仅仅是一个概念NoSQL数据库根据数据的存储模型和特点分为很多种类。
类型 部分代表 特点
列存储 Hbase
Cassandra
Hypertable
顾名思义是按列存储数据的。最大的特点是方便存储结构化和半结构化数据方便做数据压缩对针对某一列或者某几列的查询有非常大的IO优势。
文档存储
MongoDB
CouchDB
文档存储一般用类似json的格式存储存储的内容是文档型的。这样也就有有机会对某些字段建立索引实现关系数据库的某些功能。
key-value存储
Tokyo Cabinet / Tyrant
Berkeley DB
MemcacheDB
Redis
可以通过key快速查询到其value。一般来说存储不管value的格式照单全收。Redis包含了其他功能
图存储
Neo4J
FlockDB
图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。
对象存储
db4o
Versant
通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。
xml数据库
Berkeley DB XML
BaseX
高效的存储XML数据并支持XML的内部查询语法比如XQuery,Xpath。
以上NoSQL数据库类型的划分并不是绝对只是从**存储模型**上来进行的大体划分。它们之间没有绝对的分界也有交差的情况比如Tokyo Cabinet / Tyrant的Table类型存储就可以理解为是文档型存储Berkeley DB XML数据库是基于Berkeley DB之上开发的。
===== NoSQL还是关系数据库 =====
虽然09年出现了比较激进的文章《关系数据库已死》但是我们心里都清楚关系数据库其实还活得好好的你还不能不用关系数据库。但是也说明了一个事实关系数据库在处理WEB2.0数据的时候,的确已经出现了瓶颈。
那么我们到底是用NoSQL还是关系数据库呢我想我们没有必要来进行一个绝对的回答。我们需要根据我们的**应用场景来决定我们到底用什么**。
如果关系数据库在你的应用场景中完全能够很好的工作而你又是非常善于使用和维护关系数据库的那么我觉得你完全没有必要迁移到NoSQL上面除非你是个喜欢折腾的人。如果你是在金融电信等以数据为王的关键领域目前使用的是Oracle数据库来提供高可靠性的除非遇到特别大的瓶颈不然也别贸然尝试NoSQL。
然而,在**WEB2.0**的网站中关系数据库大部分都出现了瓶颈。在磁盘IO、数据库可扩展上都花费了开发人员相当多的精力来优化比如做分表分库database sharding、主从复制、异构复制等等然而这些工作需要的技术能力越来越高也越来越具有挑战性。如果你正在经历这些场合那么我觉得你应该尝试一下NoSQL了。
===== 选择合适的NoSQL =====
如此多类型的NoSQL而每种类型的NoSQL又有很多到底选择什么类型的NoSQL来作为我们的存储呢这并不是一个很好回答的问题影响我们选择的因素有很多而选择也可能有多种随着业务场景需求的变更可能选择又会变化。我们常常需要根据如下情况考虑
数据结构特点。包括结构化、半结构化、字段是否可能变更、是否有大文本字段、数据字段是否可能变化。
写入特点。包括insert比例、update比例、是否经常更新数据的某一个小字段、原子更新需求。
查询特点。包括查询的条件、查询热点的范围。比如用户信息的查询,可能就是随机的,而新闻的查询就是按照时间,越新的越频繁。
===== NoSQL和关系数据库结合 =====
其实NoSQL数据库仅仅是关系数据库在某些方面性能扩展的一个弥补单从功能上讲NoSQL的几乎所有的功能在关系数据库上都能够满足所以**选择NoSQL的原因并不在功能上**。
所以我们一般会把NoSQL和关系数据库进行**结合使用**各取所长需要使用关系特性的时候我们使用关系数据库需要使用NoSQL特性的时候我们使用NoSQL数据库各得其所。
举个简单的例子吧比如用户评论的存储评论大概有主键id、评论的对象aid、评论内容content、用户uid等字段。我们能确定的是评论内容content肯定不会在数据库中用where content=’’查询,评论内容也是一个大文本字段。那么我们可以把 主键id、评论对象aid、用户id存储在数据库**评论内容存储在NoSQL**这样数据库就节省了存储content占用的磁盘空间从而节省大量IO对content也更容易做Cache。
//从MySQL中查询出评论主键id列表
commentIds=DB.query("SELECT id FROM comments where aid='评论对象id' LIMIT 0,20");
//根据主键id列表从NoSQL取回评论实体数据
CommentsList=NoSQL.get(commentIds);
===== NoSQL代替MySQL =====
在某些应用场合比如一些配置的关系键值映射存储、用户名和密码的存储、Session会话存储等等用NoSQL完全可以替代MySQL存储。不但具有更高的性能而且开发也更加方便。
===== NoSQL作为缓存服务器 =====
MySQL+Memcached的架构中我们处处都要精心设计我们的缓存包括过期时间的设计、缓存的实时性设计、缓存内存大小评估、缓存命中率等等。
NoSQL数据库一般都具有非常高的性能在大多数场景下面你不必再考虑**在代码层**为NoSQL构建一层Memcached缓存。NoSQL数据本身在Cache上已经做了相当多的优化工作。
Memcached这类内存缓存服务器缓存的数据大小受限于内存大小如果用NoSQL来代替Memcached来缓存数据库的话就可以不再受限于内存大小。虽然可能有少量的磁盘IO读写可能比Memcached慢一点但是完全可以用来缓存数据库的查询操作。
===== 规避风险 =====
由于NoSQL是一个比较新的东西特别是我们选择的NoSQL数据库还不是非常成熟的产品所以我们可能会遇到未知的风险。为了得到NoSQL的好处又要考虑规避风险鱼与熊掌如何兼得
现在业内很多公司的做法就是数据的备份。在往NoSQL里面存储数据的时候还会往MySQL里面存储一份。NoSQL数据库本身也需要进行备份冷备和热备。或者可以考虑使用两种NoSQL数据库出现问题后可以进行切换避免出现digg使用Cassandra的悲剧
===== 总结 =====
本文只是简单的从MySQL和NoSQL的角度分析如何选择以及进行融合使用。其实在选择NoSQL的时候你可能还会碰到关于CAP原则最终一致性BASE思想的考虑。因为使用MySQL架构的时候你也会碰到上面的问题所以这里没有阐述。

View File

@@ -0,0 +1,101 @@
Content-Type: text/x-zim-wiki
Wiki-Format: zim 0.4
Creation-Date: 2011-06-14T21:59:24+08:00
====== 视觉中国的NoSQL之路从MySQL到MongoDB ======
Created 星期二 14 六月 2011
http://www.programmer.com.cn/4199/
===== 起因 =====
视觉中国网站(www.chinavisual.com)是国内最大的创意人群的专业网站。2009年以前同很多公司一样我们的CMS和社区产品都构建于PHP+Nginx+MySQL之上MySQL使用了Master+Master的部署方案前端使用自己的PHP框架进行开发Memcached作为缓存Nginx进行Web服务和负载均衡Gearman进行异步任务处理。在传统的基于静态内容如文章资讯帖子的产品这个体系运行良好。通过分级的缓存数据库端实际负载很轻。2009年初我们进行了新产品的开发。此时我们遇到了如下一些问题。
* 用户数据激增我们的MySQL某个信息表上线1个月的数据就达到千万。我们之前忽略的很多数据在新形势下需要跟踪记录这也导致了数据量的激增
* 用户对于信息的实时性要求更高:对信息的响应速度和更新频度就要求更高。简单通过缓存解决的灵丹妙药不复存在;
* 对于Scale-out的要求更高有些创新产品的增长速度是惊人的。因此要求能够无痛的升级扩展否则一旦停机那么用户流失的速度也是惊人的
* 大量文件的备份工作我们面向的是创意人群产生的内容是以图片为主。需要能够对这些图片及不同尺寸的缩略图进行有效的备份管理。我们之前使用的Linux inotify+rsync的增量备份方案效果不佳
* 需求变化频繁:开发要更加敏捷,开发成本和维护成本要更低,要能够快速地更新进化,新功能要在最短的周期内上线。
最初我们试图完全通过优化现有的技术架构来解决以上问题对数据时效性进一步分级分层缓存减小缓存粒度改进缓存更新机制线上实时和线下异步更新提高缓存命中率尝试对业务数据的特点按照水平和垂直进行分表使用MogileFS进行分布存储进一步优化Mysql的性能同时增加MySQL节点等。但很快发现即便实施了上述方案也很难完全解决存在的问题过度依赖Memcached导致数据表面一致性的维护过于复杂应用程序开发需要很小心很多时候出现Memcached的失效会瞬间导致后端数据库压力过大不同类型数据的特点不同数据量差别也很大分表的机制和方式在效率平衡上很难取舍MogileFS对我们而言是脚小鞋大维护成本远远超过了实际的效益引入更多的MySQL数据库节点增大了我们的维护量如何有效监控和管理这些节点又成了新的问题。虽然虚拟化可以解决部分问题但还是不能令人满意
除了MySQL能否找到一个更为简单、轻便的瑞士军刀呢我们的目光投向了NoSQL的方案。
===== 候选方案 =====
最初对于NoSQL的候选方案我依据关注和熟悉程度并且在甄别和选择合适的方案时特别制定了一些原则是否节省系统资源对于CPU等资源是否消耗过大客户端/API支持这直接影响应用开发的效率文档是否齐全社区是否活跃部署是否简单未来扩展能力。按以上几点经过一段测试后我们候选名单中剩下Redis、MongoDB和Flare。
Redis对丰富数据类型的操作很吸引人可以轻松解决一些应用场景其读写性能也相当高唯一缺点就是**存储能力和内存挂钩**,这样如果存储大量的数据需要消耗太多的内存(最新的版本已经不存在这个问题)。
Flare的集群管理能力令人印象深刻它可以支持节点的动态部署支持节点的基于权重的负载均衡支持数据分区。同时允许存储大的数据其key的长度也不受Memcached的限制。而这些对于客户端是透明的客户端使用Memcached协议链接到Flare的proxy节点就可以了。由于使用集群Flare支持failover当某个数据节点宕掉对于这个节点的访问都会自动被proxy节点forward到对应的后备节点恢复后还可以自动同步。Flare的缺点是实际应用案例较少文档较为简单目前只在Geek使用。
以上方案都打算作为一个优化方案我从未想过完全放弃MySQL。然而用MongoDB做产品的设计原型后我彻底被征服了决定全面从MySQL迁移到MongoDB。
===== 为什么MongoDB可以替代MySQL =====
MongoDB是一个**面向文档**的数据库目前由10gen开发并维护它的功能丰富齐全完全可以替代MySQL。在使用MongoDB做产品原型的过程中我们总结了MonogDB的一些亮点
* 使用JSON风格语法易于掌握和理解MongoDB使用JSON的变种BSON作为内部存储的格式和语法。针对MongoDB的操作都使用JSON风格语法客户端提交或接收的数据都使用JSON形式来展现。相对于SQL来说更加直观容易理解和掌握。
* Schema-less支持嵌入子文档MongoDB是一个Schema-free的文档数据库。一个数据库可以有多个Collection每个Collection是Documents的集合。Collection和Document和传统数据库的Table和Row并不对等。无需事先定义Collection随时可以创建。
* Collection中可以包含具有不同schema的文档记录。 这意味着你上一条记录中的文档有3个属性而下一条记录的文档可以有10个属性属性的类型既可以是基本的数据类型如数字、字符串、日期等也可以是数组或者散列甚至还可以是一个子文档embed document。这样可以实现逆规范化denormalizing的数据模型提高查询的速度。
图1 MongoDB是一个Schema-free的文档数据库
图2是一个例子作品和评论可以设计为一个collection评论作为子文档内嵌在art的comments属性中评论的回复则作为comment子文档的子文档内嵌于replies属性。按照这种设计模式只需要按照作品id检索一次即可获得所有相关的信息了。在MongoDB中不强调一定对数据进行Normalize 很多场合都建议De-normalize开发人员可以扔掉传统关系数据库各种范式的限制不需要把所有的实体都映射为一个Collection只需定义最顶级的class。MongoDB的文档模型可以让我们很轻松就能将自己的Object映射到collection中实现存储。
图2 MongoDB支持嵌入子文档
图2 MongoDB支持嵌入子文档
简单易用的查询方式MongoDB中的查询让人很舒适没有SQL难记的语法直接使用JSON相当的直观。对不同的开发语言你可以使用它最基本的数组或散列格式进行查询。配合附加的operatorMongoDB支持范围查询正则表达式查询对子文档内属性的查询可以取代原来大多数任务的SQL查询。
CRUD更加简单支持in-place update只要定义一个数组然后传递给MongoDB的insert/update方法就可自动插入或更新对于更新模式MongoDB支持一个upsert选项“如果记录存在那么更新否则插入”。MongoDB的update方法还支持Modifier通过Modifier可实现在服务端即时更新省去客户端和服务端的通讯。这些modifer可以让MongoDB具有和Redis、Memcached等KV类似的功能较之MySQLMonoDB更加简单快速。Modifier也是MongoDB可以作为对用户行为跟踪的容器。在实际中使用Modifier来将用户的交互行为快速保存到MongoDB中以便后期进行统计分析和个性化定制。
所有的属性类型都支持索引甚至数组这可以让某些任务实现起来非常的轻松。在MongoDB中“_id”属性是主键默认MongoDB会对_id创建一个唯一索引。
服务端脚本和Map/ReduceMongoDB允许在服务端执行脚本可以用Javascript编写某个函数直接在服务端执行也可以把函数的定义存储在服务端下次直接调用即可。MongoDB不支持事务级别的锁定对于某些需要自定义的“原子性”操作可以使用Server side脚本来实现此时整个MongoDB处于锁定状态。Map/Reduce也是MongoDB中比较吸引人的特性。Map/Reduce可以对大数据量的表进行统计、分类、合并的工作完成原先SQL的GroupBy等聚合函数的功能。并且Mapper和Reducer的定义都是用Javascript来定义服务端脚本。
性能高效,速度快: MongoDB使用c++/boost编写在多数场合其查询速度对比MySQL要快的多对于CPU占用非常小。部署也很简单对大多数系统只需下载后二进制包解压就可以直接运行几乎是零配置。
支持多种复制模式: MongoDB支持不同的服务器间进行复制包括双机互备的容错方案。
Master-Slave是最常见的。通过Master-Slave可以实现数据的备份。在我们的实践中我们使用的是Master-Slave模式Slave只用于后备实际的读写都是从Master节点执行。
Replica Pairs/Replica Sets允许2个MongoDB相互监听实现双机互备的容错。
MongoDB只能支持有限的双主模式Master-Master实际可用性不强可忽略。
内置GridFS支持大容量的存储这个特点是最吸引我眼球的也是让我放弃其他NoSQL的一个原因。GridFS具体实现其实很简单本质仍然是将文件分块后存储到files.file和files.chunk 2个collection中在各个主流的driver实现中都封装了对于GridFS的操作。由于GridFS自身也是一个Collection你可以直接对文件的属性进行定义和管理通过这些属性就可以快速找到所需要的文件轻松管理海量的文件无需费神如何hash才能避免文件系统检索性能问题 结合下面的Auto-shardingGridFS的扩展能力是足够我们使用了。在实践中我们用MongoDB的GridFs存储图片和各种尺寸的缩略图。
图3 MongoDB的Auto-sharding结构
图3 MongoDB的Auto-sharding结构
内置Sharding提供基于Range的Auto Sharding机制一个collection可按照记录的范围分成若干个段切分到不同的Shard上。Shards可以和复制结合配合Replica sets能够实现Sharding+fail-over不同的Shard之间可以负载均衡。查询是对客户端是透明的。客户端执行查询统计MapReduce等操作这些会被MongoDB自动路由到后端的数据节点。这让我们关注于自己的业务适当的时候可以无痛的升级。MongoDB的Sharding设计能力最大可支持约20 petabytes足以支撑一般应用。
第三方支持丰富: MongoDB社区非常活跃很多开发框架都迅速提供了对MongDB的支持。不少知名大公司和网站也在生产环境中使用MongoDB越来越多的创新型企业转而使用MongoDB作为和DjangoRoR来搭配的技术方案。
实施结果
实施MonoDB的过程是令人愉快的。我们对自己的PHP开发框架进行了修改以适应MongoDB。在PHP中对MongoDB的查询、更新都是围绕Array进行的实现代码变得很简洁。由于无需建表MonoDB运行测试单元所需要的时间大大缩短对于TDD敏捷开发的效率也提高了。当然由于MongoDB的文档模型和关系数据库有很大不同在实践中也有很多的困惑幸运的是MongoDB开源社区给了我们很大帮助。最终我们使用了2周就完成了从MySQL到MongoDB的代码移植比预期的开发时间大大缩短。从我们的测试结果看也是非常惊人数据量约2千万数据库300G的情况下读写2000rpsCPU等系统消耗是相当的低我们的数据量还偏小目前陆续有些公司也展示了他们的经典案例MongoDB存储的数据量已超过 50亿>1.5TB。目前我们将MongoDB和其他服务共同部署在一起大大节约了资源。
一些小提示
切实领会MongoDB的Document模型从实际出发扔掉关系数据库的范式思维定义重新设计类在服务端运行的JavaScript代码避免使用遍历记录这种耗时的操作相反要用Map/Reduce来完成这种表数据的处理属性的类型插入和查询时应该保持一致。若插入时是字符串“1”则查询时用数字1是不匹配的优化MongoDB的性能可以从磁盘速度和内存着手MongoDB对每个Document的限制是最大不超过4MB在符合上述条件下多启用Embed Document, 避免使用DatabaseReference内部缓存可以避免N+1次查询问题MongoDB不支持joins
用Capped Collection解决需要高速写入的场合如实时日志大数据量情况下新建同步时要调高oplogSize的大小并且自己预先生成数据文件避免出现客户端超时CollectionIndex合计数量默认不能超过24000当前版本<v1.6删除数据的空间不能被回收如果你频繁删除数据那么需要定期执行repairDatabase释放这些空间。
结束语
MongoDB的里程碑是1.6版本预计今年7月份发布届时MongoDB的Sharding将首次具备在生产环境中使用的条件。作为MongoDB的受益者我们目前也在积极参与MongoDB社区活动改进Perl/PHP对于MongoDB的技术方案。在1.6版本后也将年内推出基于MongoDB的一些开源项目。
对于那些刚刚起步或者正在开发创新型互联网应用的公司来说MongoDB的快速、灵活、轻量和强大扩展性正适合我们快速开发产品快速迭代适应用户迅速变化和更新的种种需求。
总而言之MongoDB是一个最适合替代MySQL的全功能的NoSQL产品使用MongoDBPerl/PHP/Django/RoR的组合将很快成为开发Web2.0、3.0的产品的最佳组合就像当年MySQL替代Oracle/DB2/Informix一样历史总是惊人的相似让我们拭目以待吧
作者简介:
潘凡nightsailerN.S., 视觉中国网站技术总监,联合创始人家有1狗2猫。目前负责网站平台设计和底层产品研发工作。当前关注Apps平台设计、分布式文件存储、NoSQL、高性能后现代的Perl编程。Twitter@nightsailer Bloghttp://nightsailer.com/
本文来自《程序员》杂志10年06期

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB