NoSQL架构实践
怎么样把NoSQL引入到我们的系统架构设计中,需要根据我们系统的业务场景来分析,什么样类型的数据适合存储在NoSQL数据库中,什么样类型的数据必须使用关系数据库存储。明确引入的NoSQL数据库带给系统的作用,它能解决什么问题,以及可能带来的新的问题。下面我们分析几种常见的NoSQL架构。
(一)NoSQL作为镜像 不改变原有的以MySQL作为存储的架构,使用NoSQL作为辅助镜像存储,用NoSQL的优势辅助提升性能。 图 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的高性能来抵挡这些查询。 图 2 -NoSQL为镜像(同步模式) 这种不通过程序代码,而是通过MySQL把数据同步到NoSQL中,这种模式是上面一种的变体,是一种对写入透明但是具有更高技术难度一种模式。这种模式适用于现有的比较复杂的老系统,通过修改代码不易实现,可能引起新的问题。同时也适用于需要把数据同步到多种类型的存储中。 图 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中存储1对多/多对多的映射关系,然后根据关系查询出主键,再查nosql。或者在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架构的系统目前正出现相关的瓶颈,希望本文可以为你带来帮助。 第一种镜像方式,一份数据在RDBMS和NoSQL中都有存储,主要是使用NoSQL中的高效查询,例如当缓存用的那种key-value,查询时显然性能要高很多。第二种组合使用方式,RDBMS存储映射关系,NoSQL存储数据,以发挥两者的优势。 接下来我们继续深入下去,换另外一个角度,“以NoSQL为主”来架构系统。 图 4-纯NoSQL架构 在一些数据结构、查询关系非常简单的系统中,我们可以只使用NoSQL即可以解决存储问题。这样不但可以提高性能,还非常易于扩展。手机凤凰网的前端展示系统就使用了这种方案。 <?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,"name" => "lisi","age" => 25,"email" => "lisi@126.com","lastvisit" => strtotime( "2011-3-3 14:40:44" ),"name" => "laowang","age" => 37,"email" => "laowang@yahoo.com","lastvisit" =>strtotime ( "2011-3-5 08:30:12" ),"area" => "成都" ) ); $id = $tt->genUid (); $tt->put ( $id,"name" => "tom","age" => 21,"email" => "tom@hotmail.com","lastvisit" =>strtotime ( "2010-12-10 13:12:13" ),"area" => "天津" ) ); $id = $tt->genUid (); $tt->put ( $id,"name" => "jack","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同步协议复制到其他存储。根据应用的逻辑来决定去相应的存储获取数据。 图 5 -以NoSQL为数据源的架构 纯NoSQL的架构虽然结构简单,易于开发,但是在应付需求的变更、稳定性和可靠性上,总是给开发人员一种风险难于控制的感觉。为了降低风险,系统的功能不局限在NoSQL的简单功能上,我们可以使用以NoSQL为数据源的架构。 1. 严格不能延迟的,读取操作路由到主库进行。 在这种以NoSQL为数据源的架构中,最核心的就是NoSQL数据库的复制功能的实现。而当前的几乎所有的NoSQL都没有提供比较易于使用的复制接口来完成这种架构,对NoSQL进行复制协议的二次开发,需要更高的技术水平,所以这种架构看起来很好,但是却不是非常容易实现的。我的开源项目PHPBuffer中有个实现TokyoTyrant复制的例子,虽然是PHP版本的,但是很容易就可以翻译成其他语言。通过这个例子的代码,可以实现从Tokyo Tyrant实时的复制数据到其他系统中。 第三种纯NoSQL架构是把NoSQL当普通的数据库来用,存储和查询在一起,即包含NoSQL的优点,也包含NoSQL的缺点。适用于数据不是非常地结构化,查询关系简单的应用系统。第四种以NoSQL为数据源的构架相当于把NoSQL作为数据库集群的前端,简化系统的数据存储和读写,提高性能和系统的扩展性,后台数据到各个RDBMS的复制可以异步进行。 (五)以NoSQL作为缓存的架构 由于NoSQL数据库天生具有高性能、易扩展的特点,所以我们常常结合关系数据库,存储一些高性能的、海量的数据。从另外一个角度看,根据NoSQL的高性能特点,它同样适合用于缓存数据。用NoSQL缓存数据可以分为内存模式和磁盘持久化模式。 1、内存模式
Memcached提供了相当高的读写性能,一般情况下,都足够应付应用的性能要求。但是基于内存的Memcached缓存的总数据大小受限于内存的大小。
我把上面代码演示的缓存使用方式称为基于版本的缓存。这种方式同样适用于基于内存的Memcached。它能实现缓存数据的实时性,让用户感觉不到延迟。只要用户一发表评论,该新闻的评论缓存就会失效。用户很少去评论一些过时的新闻,那么缓存就一直存在于NoSQL中,避免了爬虫访问过时新闻的评论数据而冲击数据库。 本文整理自:http://www.cnblogs.com/sunli/category/250681.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 这些SQLite与SQL差异问题,你遇到过吗
- Actionscript 3 vs haXe:为新的Flash项目选择哪个?
- Extjs用ajax提交表单四种方式
- ruby-on-rails – ActionMailer的电子邮件“发送”在develo
- postgresql – Postgres序列不同步
- c# – 禁用内置语音识别命令?
- c# – 为Windows phone Silverlight Pages实现Dispose和Fin
- 几个常见正则
- ruby-on-rails – 构建Rails和Backbone.js模型之间的多对多
- Ruby中的MySQL SQL / DDL解析器/验证器(在Rails上)