第22章 其他产品的选择
本章将为读者介绍其他的数据库产品,主要是NoSQL产品的选择。
读者在熟悉MySQL之外,也应该了解其他的数据库产品。
本章的目的是给读者一个引导,如何选择一些NoSQL产品,而不是推介或否定某些NoSQL产品,
读者应该自己研究最新的稳定版本的NoSQL产品,确定是否符合生产环境的需要。
在介绍NoSQL产品 之前,有必要先了解一下列式数据库产品。

22.1 列式数据库产品
数据的存储可以简单地理解为,行式数据库,即把每行的数据串起来存储在数据库内,而列式数据库则是把每列的数据串起来存储在数据库内,
行式数据库一般是不压缩的,而列式数据库,由于同一个列的数据被存储在一起,因此往往有重复值,数据可以大大压缩。
随着数据规模的扩大,MySQL在存储和分析海量数据方面变得越来越力不从心,
虽然我们可以把数据切分到多个MySQL节点,但并不是每个业务的数据都适合分布式的MySQL存储的。
本质上,存储的方式应该是有利于查询和分析的。
传统的关系数据库产品一般是以行的方式来存储数据,更适合于处理小批量的数据;而列式数据库则是以列 的方式来存储数据的,更适合大批量的数据处理和查询。
也就是说,侧重于OLTP的系统更适合使用行式数据库,对于OLTP联机事务处理系统来说,一般是随机读写,一次读取一小部分的数据,数据块一般比较小,几KB到十几KB不等,
MySQL的一个块是16KB,容易一次I/O读取出来。
由于行式数据库数据是按行存储的,每列数据分布在多块内,所以如果你要统计某列或修改某列,则需要把整行数据读取出来,读取磁盘的次数会比列式数据库多得多,
因为列式数据库把一个列的数据都压缩存储在相邻的数据块之内,所以,侧重于OLAP的系统更适合于列式数据库。
选择使用行式数据库还是列式数据库,你需要在这中间寻求一个平衡,由于成熟的列式数据库产品一般是商业产品,比如SybaseIQ,价格比较昂贵。
互联网公司很少使用列式数据库产品,更多的是依赖大规模的分布式数据处理和分析系统。
目前常用的基于MySQL的开源列式数据库产品为Infobright,Infobright是业界领先的成熟产品,
其免费版本不能修改数据,只能使用“LOAD DATA INFILE”的方式导入数据,不支持INSERT、UPDATE和DELETE。
收费版本比较昂贵,如果成本可以接受,作为OLAP系统的后端数据库将是一个很好的选择。

22.2 NoSQL产品的选择
22.2.1 概述
NoSQL产品发展得很快,这些年又不断有新的产品出现,但往往是昙花一现,一些上线的NoSQL产品由于不成熟,经常难于维护,甚至数据丢失,
究其原因,往往是选择的NoSQL产品未充分考虑到运维的成本,由于工作性质的不同,程序开发者往往会更加重视功能需要,而忽视了数据库产品的一些基本指标,
作为一个合格的软件架构师也应该关注产品的运维指标和总体拥有成本,能够从系统资源和应用访问的双重视角去考虑问题,以选择合适的数据库产品。
本节将主要阐述选择NoSQL产品的一些思路和方法学,并不会进行各种数据库产品的详细对比,
大家可以按照自己的理解和侧重点编写程序或使用开源工具进行对比,对于NoSQL产品自带的性能评测工具,建议大家保持警惕,
一般我们会假定软件厂商提供的性能监控工具是正确可靠的,但实际上,这些工具的输出可能是不准确的、不可信的。
选择NoSQL数据库产品需要考虑到许多因素,需要权衡取舍,但无论出于何种考虑,大规模的部署必然要求满足运维的一些基本指标,比如稳定性和可维护性。
一些有发展前景的NoSQL产品改进很快,所以可能会随着时间的演变,性能和稳定性都得到长足的发展,一些指标会得到很大的改善,
你应该保持对市场上应用最广泛的一些产品的关注,了解其最新的发展。
本节将主要以最流行的MongoDB和Redis为例,讲述如何选择NoSQL产品,MongoDB和Redis都有良好的发展势头,各种功能特性得到不断完善,
本书所讲述的MongoDB和Redis主要是基于2013年~2014年的版本,由于MongoDB和Redis发展得很快,因此一些论据、论点必然会过时,希望读者留意最新的版本,
希望读者把本书对于这两个产品的说明仅仅作为了解NoSQL产品的方式,而不是真实产品的表现。
许多NoSQL产品是为了存取特定的数据而设计的,将它们都列在一起进行对比,没有多大意义,
如果你需要选择和对比NoSQL产品,实际的比对建议限制在2种(或者最多3种)产品的对比上,如果同时进行对比的产品有很多,那么自身的结论也难有说服力。
选择NoSQL产品需要重点考虑的因素如下:
1.灾难恢复性
灾难恢复性,即故障后数据的恢复性,我们可以通过模拟程序崩溃或主机宕机来验证灾难恢复性。
可考虑如下三种场景:进程崩溃、操作系统崩溃和存储故障。
在崩溃后,测试验证能否正常启动数据库服务、数据文件是否损坏、数据是否完整、数据丢失了多少等?
在存储异常的情况下,验证服务的稳定性,验证是否能及时发现硬件异常。
2.可维护性
可维护性,顾名思义,是指对产品维护的难易程度。
3.可靠性
衡量数据库系统操作的成功性。我们需确保操作结果符合系统设计的预期。
4.高可用性
高可用性可以定义为系统保持正常运行时间的百分比。即, Ao=up time/totaltime或 Ao=(totaltime-down time)/totaltime。
确定可容忍的停机时间是可行的。从这一点上来看,所需的可用性可以很容易地计算出来。
高可用往往不是单个数据库产品就可以决定的,这更多的是一个架构问题。
对于MySQL和诸多其他开源数据库产品,都没有很通行的开源的高可用解决方案。
各大公司在发展到一定规模之后,都采用了一些高可用的技术,目前数据库的高可用技术主要是从两个方向着手,
一个方向是开发中间层,代理所有访问;另一个方向是应用程序框架/客户端实现高可用。
5.高性能
我们衡量的高性能,应该是高访问压力下的高性能。性能一般可用响应时间来度量。
6.可扩展性
可扩展性一般是指我们可以用更多的节点来提高吞吐率,同时性能不会下降到不可接受的范围,这更多地属于架构的范畴。
7.资源利用
对于数据库来说,我们主要关注对I/O资源、CPU资源和内存资源的利用。
8.功能特性实现
这里将简单列举一些示例,包括但不限于以下的一些功能和特性。
(1)dynamic schema
动态schema,也就是NoSQL产品的schema-less特性。
MySQL在这方面不太具有优势,MariaDB在这方面有一些改进,据说MariaDB10会有更多的改进。
NoSQL产品在这方面往往更具优势。现实生产中,MySQL往往通过将记录存储为Key-Value类型来实现dynamic schema。
(2)automatic sharding
一些NoSQL数据库或多或少都实现了此类特性,传统关系型数据库不太容易实现。
但NoSQL产品的auto-sharding特性,仍有待于大规模生产的测试验证。
(3)锁的实现
不同的数据库产品对于锁的实现也不尽相同,锁的设计对于数据库的并发访问有很大影响,
在这方面,传统数据库对于锁的实现较为复杂和高效,而NoSQL锁的实现往往比较简单,且粒度更大。
(4)文件管理
本节主要关注数据文件的空间分配。
(5)支持JOIN等复杂查询的能力
一般NoSQL产品实现了简单的Key-Value或一些改进的数据结构,但一般不会实现传统数据库“表”之间的“JOIN”。
9.数据结构
一般传统的关系型数据库更适合存储一些结构化的数据,而NoSQL产品更适合存储一些非结构化的数据。
在数据量小的时候,一般使用传统数据库就够用了, 传统数据库往往比较通用,但在数据规模很大的时候,许多公司都采用了SQL和NoSQL数据库并存的策略。
各种功能特性的选择,往往不可兼得,所以需要权衡取舍,
比如,如果QPS或延时都很稳定,基本上没有变化,那么我们可以不用太关注使用资源的少许差异。
如果数据安全性要求不高,允许丢失数据,那么我们可以采取最大性能的模式。
以下将详述上面的各个因素。

22.2.2 灾难恢复性
下面我们来对比下MySQL和一些NoSQL产品的灾难恢复机制。以MySQL和MongoDB为例。
(1)MySQL的数据库灾难恢复机制。
1)靠预写日志(Write-ahead logging)来保障持久性。 也就是说,数据文件不会马上写入脏数据,而是先写日志,以后再批量刷新脏数据到数据文件以提高吞吐率。
我们把这个日志叫作事务日志,数据库崩溃之后,可以找到事务日志的某个时间点,把这个时间点之后的日志运行一遍,然后回滚那些没有提交的日志。
事务日志都是顺序写入的,可以设置参数来调整写日志的频率。
2)MySQL还有一个数据结构double write buffer(双写缓冲),可用于增强灾难恢复性。
数据文件随机读写,InnoDB最小的写入单元是16KB,如果由于故障或Bug只写了部分块,那么可能会导致坏块(datacorruption)。
InnoDB使用double write buffer来确保数据安全,避免块损坏。
double write buffer是InnoDB表空间的一个特殊的区域,顺序写入。
当InnoDB刷新数据时(从InnoDB缓冲区到磁盘),首先写入double write buffer,然后写入实际的数据文件。
这样便可确保所有写操作的原子性和持久性。
崩溃重启后,InnoDB将检查每个块(page)的校验和,判断是否坏块,
如果写入 double write buffer的是坏块,那么显然没有写入实际的数据文件,那么就用实际数据文件的块来恢复double write buffer,
如果写入了double write buffer,但是数据文件写的是坏块,那么就用double write buffer的块来重写数据文件。
(2)NoSQL产品的灾难恢复机制。
常见的NoSQL产品的存储引擎有两类实现。一种是Memory-Mapped存储引擎,另一种是日志型的存储模型。
1)许多NoSQL产品都采用了Memory-Mapped存储引擎,如Tokyo Tyrant、BDB、MongoDB等,
MMAP方式是靠操作系统将数据刷新到磁盘的,用的是操作系统的虚拟内存管理策略。
在某些场合可以提高吞吐率,毕竟写内存比写磁盘要快。
主要弊端是数据库无法控制数据写入磁盘的顺序,这样就不可能使用预写日志(Write-ahead logging)来保障持久性。
发生崩溃的情况下,数据文件可能被破坏,需要进行修复。
数据被破坏的过程大致如下:
Linux操作系统有定时刷新数据的机制,一般是几秒的间隔,I/O瓶颈严重时,还会自动调整。
操作系统还有一个30秒的数据过期限制。具体的机制比较复杂,有兴趣的读者可以自己研究下。
生产环境中的大部分业务都有写入数据的场景,在宕机时刻,数据正在刷新的概率很高,此时的后果往往就是损坏数据。
这种情况无法避免,它是由其实现机制决定的,宕机时刻,可能只刷新了部分数据,而刷新的这部分数据并不是按照数据库所期望的顺序写入的,这将破坏数据。
如果每次写入数据时都强制刷新到磁盘,那样将是比较安全的,但这样做不是设计这类产品的本意,会严重影响效率。
我们还可以用昂贵的小机来尽量确保不宕机,但这样做成本比较高,也不符合互联网公司采用相对廉价的PC集群这样一个趋势。
由以上可知,MMAP方式的数据库从理论上就注定了其灾难恢复性不佳。
10gen公司宣称其增加了记录日志的功能,但只是改善了其原来比较差的灾难恢复性,
按照传统数据库的标准,离真正的灾难恢复性还有比较远的距离,因为日志最多是把最近的操作重放一遍,但操作系统把数据库写坏的可能性一直存在。
10gen公司选择这种方式也是有它的考虑的,官方认为单机可靠性并不是很重要,虽然对这点还存在争议。
官方建议的是用复制和复制集(replication set)来保证持久性,意思是如果主库崩溃,就马上切换到正常的节点。
如果主库宕机,重启会不成功,那么必须先进行修复,才能启动,修复的过程相当于把所有的数据全部导出来(跳过损坏的数据)再导进去,
如果用户认为自己可以忍受数据损失,那么就没有关系。
这是一种极度追求可用性的方案,缺点是难以保证数据安全。
目前存在争议的地方是,MongoDB在现实中要求许多冗余来保障安全,而实际上大部分的应用,单机就可以支撑了,单机的可靠性还是很重要的。
不太可能使用3~4个节点的复制集来确保一个普通应用,且复制集并不是很成熟(2.4版本的投票机制存在问题)。
笔者所在的生产环境中曾出现过宕机破坏数据文件的情况(2013年),然后主机重启后MongoDB可以起来,但是数据文件里的部分块已经被破坏,
由于MongoDB并没有做数据块的校验,因此不能及时发现这种数据破坏,很可能在运行一段时间后突然崩溃。
所以宕机对于MongoDB来说还是很致命的,如果是重要的数据,为了以防万一,在宕机后,建议重建整个数据库。
10gen公司对此似乎一直保持着回避的态度,宣称的是“无单点故障”,其实也有“无奈”的成分,存储系统虽然在商业领域很成熟,但要通过一个开源公司来实现,其实是非常困难的。
为了尽快适应市场需要,拿到风险投资,放弃灾难恢复性可能就成了必然选择,但这并不代表他们的做法是对的,新的稳健的存储引擎是必需的,这只是个成本问题。
2)另一种是日志型的存储模型,数据文件是顺序添加的,如bigtable、couchdb。其他如HBASE、leveldb也是类似的实现。
这种存储实现,可以保证在系统掉电后,数据文件尽量不被破坏,需要考虑的是灾难恢复后如何进行恢复,且不丢失数据。
目前许多公司都是基于Google的bigtable模型来设计的,既保持了单机的持久性,又有优良的伸缩性。
3)目前Redis的实现,有些特别,主流的快照持久化方式,是把内存中的数据定期dump到磁盘上(先dump到临时文件,然后mv,可以保证整个过程是原子性的安全操作),
对于实例崩溃,电源掉电之类的故障,也能表现良好,只是会有数据丢失。
Redis另有一种AOF的方式,通过回放日志来进行灾难恢复,它可以尽量减少数据丢失,但由于I/O资源消耗比较大,因此用的并不是很多。

22.2.3 可维护性
可维护性与维护服务的运作及在出现服务中断时尽快恢复等活动相关。
许多NoSQL产品让人诟病的地方就是维护性比较差。缺少文档、缺少监控工具、诊断困难,这些都影响了维护性,运维人员显然没有积极性去使用维护性比较差的产品。
MySQL发展了很多年,相关文档都已经比较完善,IT人员一般都学习过关系数据库的理论和SQL,比较容易上手。
而理解NoSQL产品则不一定容易,也许会比较容易上手,但碰到问题后,很可能会一知半解,没有足够的文档或示例加以阐释。
可维护性在很大程度上取决于内部维护人员的技能,
对于MySQL等常用的数据库,已经有许多人在学习和研究它,它有成熟的解决方案,合理的运维方案,出了问题后一般能够快速解决。
可是NoSQL产品灾难恢复的解决方案可能还不成熟,也缺乏人去熟悉它的机制,出问题的概率更高。
一些软件架构师选择NoSQL产品的理由是其强大的特性,但要让产品稳定运行于生产环境中,是需要有相关运维人员支持的,
如果运维人员认为这个产品的使用者少、社区不活跃、太复杂,可能自身也没有积极性去研究和学习这个产品,这反过来会让这个产品的维护性变得更差。
习惯的力量是很强大的,如果新的产品不够易用、难以理解、难以处理问题,这种情况下非要上某个产品,那么你可能是在和趋势作对。
NoSQL产品如果崩溃了,往往还需要Debug代码,而这对于不熟悉源码的运维人员来说这将是一件很头痛的事情,所以,应该提供快速恢复或屏蔽错误的手段。

22.2.4 可靠性
对于用户的操作,数据库产品应按照约定成功执行。
比如用户可能会犯错,存储介质可能会有异常,各种各样的系统错误都可能会发生,在这些情况下,我们的数据库系统仍然要保持功能的正常和完整。
因此我们需要各种措施和手段来确保数据库产品的可靠性。
我们可以模拟各种用户错误,模拟各种底层硬件、操作系统的异常情况,来验证数据库系统的可靠性。
一般有两种级别的可靠性。
应用依赖的可靠性,比如参考完整性。
应用无关的可靠性,比如ACID特性。
许多数据库产品都支持ACID特性,但支持的程度可能不一样,MySQL InnoDB支持复杂的事务,事务操作可以同时修改多个表的数据,支持多语句操作,
而MongoDB并不支持多文档事务,它仅支持单个文档的原子性操作,官方的解释是:一般情况下,这些就足够了,因为你可以把相关的数据都放到一个文档内,然后写这个文档。
可靠性,可以用如下两个指标来衡量。
1)正确性:正确性指的是系统能够按照约定成功运行。
对于复杂的数据库系统,可能很难用工具去校验系统的正确性,往往需要线上大规模用户的长期验证。
关于正确性这方面,MySQL等传统数据库往往已经经历了10年以上的大量用户验证,因此相对来说它们更具正确性。
2)可用性:系统能够正常工作的时间。
我们可以统计一个系统能正常满足用户操作的时间比例,来衡量一个系统的可用性。
一般以上两者不可兼得,为了追求正确性,可能会降低可用性,比如银行、证券交易系统就需要很高的正确性,为了确保数据准确,宁可降低可用性、暂时停止服务。
而提高可用性可能就会无法保证正确性,比如一些信息发布系统,虽然数据可能不是很准确,但并没有什么大不了的,用户更在乎的是系统可用。
在做架构设计的时候,就需要权衡二者,确定合适的可靠性。

22.2.5 高可用性
本节内容更多考虑的是单机产品。
对于只有少量机器的公司,单机虽然可能失效,但一般还在容忍的范围内,重要的是维护人员能够迅速地处理故障。
设计体验良好的应用程序对于处理数据库的异常宕机会更好,给予用户友好提示,或者临时切换为只读,等待DBA干预是一般中小型公司推荐的做法。
而对于拥有大量机器的公司,如Facebook、Twitter,包括国内的许多公司都有各种数据库中间层(中间件)的方案,
在一定的规模级别下,宕机的概率可能会导致运维工程师根本处理不过来,自然而然就催生了数据库单点切换,数据库中间层的一些方案。
MongoDB(2.4版本)可以配置为复制集(replication set),但生产实践证明它的自动冗余切换的特性并没有宣传得那么好,
官方的投票算法不够完善,难以解决复杂的网络硬件故障异常所导致的切换,所以其高可用性得打个折扣。

22.2.6 高性能
NoSQL产品的官方说明都是说它们具有高性能,对于许多人来说,这是一个好的卖点,对此我们应该有一个清楚的认识。
官方的评测数据更多的是出于市场的需要,它属于产品生命周期的一个正常部分,是公司的一种宣传手段,
公司需要一份评测数据来验证产品的先进性,证明比市场上另外一些产品更好,这样才会有源源不断的新用户加入,但如果将评测太当回事,就没有必要了。
现实的情况是,商家发布的产品评测报告,本质上并不是一份基准测试报告,但它们却常常伪装成基准测试报告。
商家的报告往往为了证明其比同类产品更优秀,但缺少上下文环境,这可能会导致用户产生误解。
我们衡量的高性能,应该是高访问压力下的高性能。
各种测试报告往往专注于峰值吞吐数据,
但是在现实世界中,我们是希望在合理的成本下达到期望值,同时还要求不降低服务质量,我们更关注峰值效率,显然基准测试报告很难满足此点。
如果我们使用缓存(如Memcached),那么我们就不用太担心读的压力。
一些NoSQL产品和传统数据库产品都有缓存热点数据的功能,只是实现效率和成熟度的差别,但基于磁盘的数据库和基于内存的数据库有本质的区别。
这里我们仅讨论基于磁盘的数据库系统,在海量数据高并发读的情况下,我们仍然需要缓存产品。 因为单机的内存有限,无法缓存所有数据。
对于数据写入,起决定作用的是物理磁盘(存储),磁盘技术在其发展的几十年以来,一直是计算机的瓶颈所在,相对于CPU和内存技术的快速发展,磁盘技术一直没有太大的改观。
所以不要期待换了数据库产品,就可能有什么特别的改善。
实践证明,单机的Key-Value产品性能并没有像传说中的那么高。为什么生产环境和网上的官方性能数据会出现那么大的差异呢?
原因是部分的NoSQL产品是MMAP存储引擎的方式,因为写入数据时并不需要实时刷新到磁盘,而是操作系统批量地将数据刷新到磁盘,通过这种方式可以极大地提高吞吐率。
这对于小的数据小的系统会很有效,但对于大量数据的场合,缓存一般都会耗尽,真正的性能将严重受制于磁盘的性能。
如果做基于Key-Value的单机性能测试,传统的产品和NoSQL产品并没有什么区别,而且传统产品还会更胜一筹,因为毕竟传统数据库发展了很多年,各种优化、索引的技术更完备。
实际生产验证中,当数据库数据远远大于内存时,此时缓存已经不能存放所有的热点数据,
那么数据库可能不得不去磁盘进行读取,miss rate(缓存未命中比率)指标可以用来衡量Cache(缓存)的效率,
如果数据库能够尽可能地把热点数据放到缓存中(操作系统Cache或数据库Buffer),那么就可以减少miss rate,
否则miss rate会上升,将可能导致磁盘I/O瓶颈,你的系统将受制于I/O瓶颈,MongoDB依赖于操作系统缓存数据,操作系统是不太可能知道数据的冷热情况的,
所以其miss rate会表现得比MySQL差。
注意,我们一般不关注数据库的缓存命中率,我们应该关注的是缓存未命中的比率。
生产实践还表明,MongoDB的INSERT速率会比InnoDB慢5倍以上,主要原因在于MongoDB写入了比其他数据库多得多的大数据(包括日志和数据文件)。
对比MongoDB,传统的数据库对于数据的处理往往做了更多的优化,比如InnoDB的insert buffer,数据文件也更紧凑,支持行锁,所以其有更高的性能,这点并不稀奇。
所以,如果我们测试NoSQL产品,发现其和传统产品有很大的区别时,应该检查下,是否有其他因素的影响(如OS、缓存、数据结构等)。
以上所说的是单机的基于磁盘的产品,如果是一个集群,从应用层sharding(分片),那么NoSQL集群的性能一般也会弱于传统数据库产品的集群。
以上并不是说NoSQL的性能就必然比传统的数据库产品差,因为有许多其他因素还没有考虑进去,数据结构及程序对于数据的操作方式也深刻地影响着性能。
希望大家明白,衡量一个产品要考虑实际的物理限制。
在底层硬件技术没有太大改变的情况下不要期待太高,性能大致差不多是更符合现实物理法则的。
任何产品在自己的官方页面上,都可能会加上“高性能”几个字。
要提高I/O性能,更多的是其他设计层面上要考虑的,如:转换随机读写为顺序读写、进行压缩、访问存储方式(可参考http://en.wikipedia.org/wiki/Locality_of_reference )。
例如,TokuMX对于数据页的写入是顺序I/O,顺序I/O的代价更小,从而TokuMX有更多的余量可用来处理读请求。
高性能还有一个潜台词,可以充分挖掘出硬件的能力,以及充分利用硬件的能力。
如,在一台CPU资源很充足的机器上,支持压缩的数据库产品,往往可以获得比较好的性能。
因为CPU不怎么饱和,而经过压缩写入更少的字节就意味着I/O写入的代价更小,性能可以得到提高,在大数据的情况下,数据能够被压缩不仅可以提高性能,也可以大大减少成本。
本质上,这是把I/O瓶颈转换为CPU瓶颈。
其实高性能,并不是我们关注的重点,我们应该重点关注的是NoSQL产品的伸缩性(可扩展性)。

22.2.7 可扩展性
可扩展性,一般是指可以用更多的节点来提高吞吐率,性能不会下降到不可接受的范围。我们也称之为伸缩性。
注意,伸缩性不等于性能,伸缩性更多的是满足吞吐率的要求。
按照维基百科的定义:伸缩性指的是系统、网络、程序处理不断增长的负荷的能力。它能够满足不断增长的负荷,而自身的性能仍然尚可这样一 种能力。
1)一般的传统数据库,可能有些人会觉得可扩展性比较差,
但对于海量数据,MySQL分库分表在目前来说仍然是最成熟的办法,从应用层分片不存在任何问题,前提是你需要有合理的数据规划。
业内有各种分库分表的算法,一般可以预留几倍到10多倍的扩展,拆分起来的难度一般在可以容忍的范围内。
对于绝大部分应用,简单的分库算法可以满足需求。
如果真的有爆炸性的应用,可能需要百倍乃至千倍的扩展,那么在前端实现虚拟数据库就是一种可行的办法,
虚拟数据库可以理解为前端有很多逻辑的数据库,后端是可变的一些物理数据库,虚拟数据库实现逻辑数据库到物理数据库的映射。
这样的方式就像一个数据库代理软件,可以让应用更透明。典型的实现是在数据库中存储一个路由表。
大家可以参考下Facebook、Twitter的架构,它们都是把MySQL当作一个分布式的Key-Value存储,充分利用了MySQL的可靠、稳定和安全的特性。
2)NoSQL产品从理论上说,其可扩展性比传统数据库产品更好,但在现实生产环境中,NoSQL产品的可扩展性可能并没有那么好。
大部分NoSQL产品并不是可扩展的,它们一般是属于单机的产品,有部分产品支持扩展,如Amazon的S3、Google的bigtable等。
一些可扩展的技术目前仍然没有经过大规模的验证,尚不成熟,比如MongoDB的自动分片,所以和MySQL一样,从应用层分片往往是更值得考虑的、更稳健的方式。
在前期的架构设计中,应该充分理解自己的业务,分片数据,尽量避免在后期又需要进行一些自动或手动的扩展。
需要注意的是:节点增多,宕机的可能性就会比较高。
现实生产中,NoSQL产品的节点是需要具备单机可靠性的,
或者如MongoDB,虽然不具备单机可靠性,但是会有一个复制集(replication set),保证自动故障冗余切换,否则,维护的成本会很高。
3)一般情况下,我们不需要考虑读压力,也不用考虑读写分离,缓存产品(如Memcached)可以极大地缓解读的压力,我们主要担心的是写的I/O瓶颈。
对于简单查询,一般MySQL普通主机的QPS为几千,Key-Value的存储也是很稳健的,性能不会比NoSQL产品的差。
这种能力,已经足够支持大部分应用了,所以我们在做架构设计的时候,要考虑清楚,我们的应用是否有这么高的并发访问量。
如果一台机器能够满足1~2年的几倍增长需求,就不需要过度设计,不需要考虑到以后几十倍的可扩展性。
过度设计将使得架构变得复杂,浪费资源。
而且,即使碰到主机不能满足负荷的情况,我们也仍然可以通过向上扩展(scale up)的方式增加内存、CPU,
使用SSD(SSD对比传统硬盘,随机读写有一个数量级别的I/O性能提升)来提升性能,能用硬件的方式解决就优先选用硬件的方式解决是更具实践性的方案。
4)现实中的场景,有时是一些混合性的方案,同时使用了NoSQL产品和MySQL产品。
比如新浪微博的Redis加MySQL技术方案,MySQL支持海量数据,Redis支持高性能及一些其他的特性。对于海量数据高性能的方案来说,这是更现实的选择。
一般来说,同时支持海量数据和高性能的数据库,其实现代价会很大,或者说费力不讨好。
在架构上,同时使用传统数据库和NoSQL数据库产品,是更值得采纳的方案。
5)关于MySQLCluster的方案,具体如下。
还有一种Oracle官方公布的伸缩性比较好的方案,MySQL Cluster,但很少有人精通,没有已知的大规模使用的案例。
MySQL Cluster是share nothing的架构,把数据分布在各个节点的内存中。据说现在的新版本也能容许将部分数据放到磁盘上。
这个产品所受的限制比较多,很复杂,除非你是这方面的专家,很熟悉它的特性和优化,否则不建议使用。
这种技术架构,可以有一定的扩展性,但实际上它可能对付不了不断增长的扩展性需求,
因为一旦节点增多,各个节点需要互相通信,并保持同步,代价就会越来越大,节点会是有限的,这点和Oracle的RAC有点相似。
而海量应用,其节点可能就会非常的多。
从成本上来说,内存也比较贵。把热点数据加载到内存是更经济的方法,用不着把所有数据都加载到内存里。
基于磁盘的Key-Value海量存储仍然是性价比最佳的方式,如果纯粹想用内存数据库实现所有需求,可能性能很好,但成本将会是惊人的。

以上5点的说明,目的是澄清一些对于NoSQL产品可扩展性的误解。
现实中,NoSQL产品往往没有宣传得那么好,但是,NoSQL产品毕竟代表了一个趋势,它突破了一些关系数据库产品的限制。
DBA有必要利用NoSQL产品来增强整体系统的可扩展性。
可扩展性还可以理解为,随着数据规模的增大、机器设备的增多,业务规模的增大,我们的人手不用增加太多,我们的服务管理性仍然优良。
不同阶段考虑的问题不太一样,当机器设备很少时,这个时候的维护成本主要是人的成本,当机器数目很大时,就有必要减少硬件、网络的成本了,
这个时候,一个高性能、高可靠、高效的数据库产品就更值得看重了。
随着数据的增加,数据库主机的增多,大规模运维必然会摆上日程,这方面,MySQL有比较成熟的解决方案,
但对于一些开源产品来说,大规模的部署和自动化运维会有不少挑战,综合运维的成本会比较高。

22.2.8 资源利用
对于大规模服务的运维,需要考虑资源的利用效果。
传统数据库产品已经发展了很多年,往往有了比较成熟的分配资源和控制资源的方式。
而开源数据库产品,往往前期着重在功能实现上,可能会忽略对系统资源的使用。
对于资源的消耗,我们可以做一些数据库产品的测试,然后记录一些相关的数据指标,加以对比。
例如,每秒的读/写次数、平均每个查询的物理读、每秒写入的数据、每秒读取的数据等。
如下列出了一些指标,可供参考:
DB-size:一轮测试后数据库的大小。
Bytes-per-doc:平均每条记录/每个文档的长度。DB-size除以行数(文档数)。
Write-rate:使用iostat统计的平均每秒写入存储的字节数。
Bytes-written:本轮测试总计写入存储的字节数。
Test-secs:本轮测试所耗时间。
TPS:本轮测试的平均事务吞吐,各个数据库产品的事务应该类似,比如插入1000条记录/文档。
Server:所测试的数据库产品配置(比如是否启用了压缩,是否开启了日志,日志的刷新策略如何等)。
下面我们以MongoDB为例,说明其资源利用的不足之处。
1)MongoDB对于内存资源的利用。
MongoDB采用了MMAP的方式来操作数据文件,这将导致我们无法限制MongoDB进程所使用的内存容量,
它会尽可能地申请所有空闲内存作为自己的缓存,虽然理论上在其他进程需要内存的时候,MongoDB可以释放出部分内存,
但这样的资源管理方式并不太友好,可能会导致部署在同一台机器上的其他服务出现内存瓶颈。
而且用操作系统来管理缓存,效率也比较差。
目前最好的部署办法只能是将其单独部署在一台服务器(虚拟机)上。MongoDB数据文件会比传统数据库存储大得多,会导致存储成本大大增加。
而在文件比MySQL大得多的情况下,缓存数据的效果也会更差,因为缓存同样的数据,MongoDB所需要的内存要大得多。
2)MongoDB对于I/O资源的利用。
采用MMAP的方式其I/O效率比较差,容易导致主机达到I/O瓶颈,产生许多毛刺。
MongoDB使用的是缓冲后批量刷新数据的方式,由于靠操作系统缓存来刷新数据,因此短时间内可能需要将大量数据写回到存储系统中。
Linux并没有针对这种负载进行专门优化,写回期间,其他的I/O请求,比如数据读取或写日志,可能会受到影响,因为此时的I/O资源已经趋向饱和,资源竞争的现象也会加剧。
根本问题是,页面读取和日志写请求应该优先于脏页面的写回。
传统的数据库存储引擎有专门的优化,能够尽可能地减少写数据对其他操作的影响,但MongoDB仅依赖于操作系统,难以避免资源的争用对自身的影响。
如果查看MongoDB的性能曲线,可以观察到,在被修改的数据回写期间,数据库延时会有比较大的上升,
对于InnoDB引擎,如果应用的写操作很频繁,那么也会存在因为检查点等操作导致短时间延时升高、吞吐率下降的问题,但绝大部分情况下会比MongoDB表现得更加稳定。
生产实践可证明,MongoDB写入的字节是InnoDB的4倍,TokuMx的20倍。这对于flash设备的寿命很不利。
由于MongoDB的数据文件比InnoDB、TokuMX大得多,因为执行各种文件操作也会消耗更多的资源,缓存的命中率随着文件的增大可能也会下降,你将需要更多的物理读。
生产环境中,有些人会选择禁用journal日志,或者把日志放到内存文件系统(tmpfs)上,这样做性能往往会得到提高,但这是以牺牲安全性为代价的。
数据库往往是I/O密集型的负荷,所以衡量一些常规的负载/查询消耗的磁盘读写次数可以大致评估这个产品的I/O效率。
由于MongoDB自身并没有一个缓冲池,其主要是靠文件系统来实现读写数据的,因此MongoDB对比InnoDB,查询需要更多的物理读。
MongoDB有一个类似LRU的算法用于预测哪些块在内存中,这可能会消耗过多的CPU。
由于MongoDB主要靠文件系统来实现读写数据,所以需要重视对文件系统的调优,比如文件系统的预读参数。
3)资源的利用效率也和负荷有关,
由于InnoDB和TokuMX的表是聚簇索引(cluster index)组织数据的方式,数据是按照主键来排列的,那么如果基于主键查找或是主键的小范围查找,效率会最高。
而MongoDB的表不是按聚簇索引的方式存储数据的,因此基于主键的查找显然需要更多的物理读。
4)大规模运维的资源考虑。
一般来说MongoDB必须独占整个主机的资源,会影响到上面的其他实例,无法充分利用资源。
大规模部署MongoDB,可能意味着硬件资源的极大浪费,磁盘空间、内存资源可能都存在巨大的浪费。
许多人的生产实践都证明了MongoDB存储效率的不理想,有过多的写入。
对于硬件成本,我们还是要关注下,尤其是对于有大量机器,使用固态硬盘的公司,存储成本很高。
如果你能写入更少的字节,你就能购买更便宜的设备,你的设备就能够获得更长的寿命,你的备份预算也可以更少。

22.2.9 功能特性实现
如下叙述的是一些功能特性的实现,仅仅是一部分子集,读者可以考虑自己所需要评估的功能特性。
(1)索引结构
B树: 传统的数据库一般使用B树或B树变种的索引结构,比如MySQL使用的是B+树,SQL Server使用的是标准的B-tree。
从原理上来说,B系列树在查询过程中 应该是不会很慢的,其主要问题出现在插入过程。
B-Tree在插入的时候,如果是最后一个node(节点),那么速度将会非常快,因为是顺序写。
但如果数据插入比较无序、离散的时候,那么可能需要大量的随机I/O。
MySQL和MongoDB使用的都是B树。在查询数据时可以获得比较良好的性能,但更新和插入数据的索引的开销会比较大。
fractal树: TokuDB实现了这种索引结构。这种索引结构极大地减少了随机写,一般情况下,更新、插入、查询数据均可获得良好的性能。但在顺序插入的时候性能不佳。
(2)dynamic schema
dynamic schema,也就是NoSQL产品的schema-less特性。MySQL在这方面不太具有优势,MariaDB在这方面有一些改进,NoSQL产品在这方面往往比较有优势。
现实生产中,MySQL往往将记录存储为Key-Value类型来实现dynamic schema。Facebook就是这样做的。
(3)锁
锁的实现,不同的数据库产品对于锁的实现不尽相同,在这方面,传统数据库对于锁的实现较为复杂和高效,而NoSQL对锁的实现一般比较简单,粒度也更大。
如MongoDB对于并发写入的锁的粒度很粗,最开始是数据库级别的,后来,据官方介绍,MongoDB 2.8可支持文档级别的锁。
MongoDB(2.4版本)使用的是数据库级的reader-writer锁,不支持行锁,这个per-database RW-lock粒度太大,会导致并发性大降,
如果所有文档(documents)都在一个数据库(database)里,那么并发的更新操作都需要申请数据库锁(database lock),
很显然,这演化成了一个串行的操作,那么写操作次数的最高峰值将和单个线程操作设备的极限次数相近,即使磁盘设备有余量,也利用不上。
也就是说,如果100个线程同时操作MySQL的某个表的某些数据,那么会产生竞争,如果把这些数据分离到多个表,则可以提高性能,
而对于MongoDB,即使你把数据分离到了多个文档(如果仍然在同一个数据库里),也无助于性能的改善。
你可以选择每个集合(collection)一个数据库,这样可以减少互相等待,大大提高并发性能,但这种做法很奇怪,不符合正常的使用情况。
就目前的生产实践而言,MongoDB仍然有较大的性能提升空间,锁的实现显然是MongoDB的重要瓶颈根源之一。
(4)事务
MongoDB不能严格地支持事务,可以理解为其支持单个文档的事务,它并不支持修改多个文档的原子性操作,
官方的解释是,MongoDB的Documents模型可以嵌套,也许一个文档已经包含了所有需要原子性操作的数据了,
这个还不能确定,对于数据库来说,如果不能支持多个对象的原子性操作,很难说得上其对事务的支持。
对于海量数据来说,多个分片中,保证对事务的支持是很难的,往往不需要进行考虑,但是对于单个分片,仍然有一定的实现ACID特性的必要。
MongoDB的事务级别类似于我们所说的read uncommitted,read uncommitted是数据库理论中隔离级别最低的一种,
这样做可以允许客户端在写操作还没有返回或还没有实际提交之前就看到,这样可能会出现数据显示和实际数据存储不一致的情况。
比如我们刚查询到一批数据,但马上就宕机了,重启之后我们再查询,可能这部分数据已经丢失了。
(5)文件管理
我们看下MongoDB的空间分配。
据笔者的生产实践,MongoDB占据的磁盘空间比MySQL大得多,可以理解为文档数据,如JSON这种格式,存在许多冗余数据,
但空间占用大得有些不正常,甚至是传统数据库的三到四倍,不太契合工程实践,应该还有改善的余地。
1)MongoDB的每个库逻辑上包含许多集合(collection),物理上存储为多个数据文件,数据文件的分配是预先分配的,预分配的方式可以减少碎片,
程序申请磁盘空间的时候将更高效,但MongoDB预分配的策略可能会导致空间的浪费。
默认的分配空间的策略是:随着数据库数据的增加,MongoDB会不断分配更多的数据文件。
每个新数据文件的大小都是上一个已分配文件的两倍(64MB、128MB、256MB、512MB、1GB、2GB、2GB、2GB),直到达到预分配文件大小的上限2GB。
虽然2GB的阈值是可以调整的,但一般运维的时候往往不会进行调整,就这点来说,可能会导致大量空间的浪费。
对于磁盘空间的分配效率,笔者一直报以怀疑的态度,如果本身有I/O瓶颈,那么预分配一个2GB的文件,将可能导致服务出现严重的性能问题。
预分配文件, 可以减少碎片,提高程序申请空间的效率,但是否有必要一次分配和初始化一个巨大的文件,这点还有待商榷。
虽然对于预分配的机制,官方文档的说明是可以关闭的,
但一般使用NoSQL产品时都会使用默认的配置,也建议使用默认的配置,因为默认配置往往经历了长久的考验,没有那么多Bug。
2)MongoDB的文档在数据文件中是连续存储的,这点不同于一些关系数据库的做法(它们会把长记录拆分为两部分,将溢出的那部分单独存放在另一处),
如果没有预留足够的空间,那么更新可能会导致原有空间放不下新的文档。
当更新迫使引擎在BSON存储中移动文档时,存储碎片将会导致意外的延迟。
对此MongoDB 官方给出了如下的解释:
“如果有足够的空间,在MongoDB中更新文档时,数据会在原地更新。
如果更新后的文档大小大于已经分配的空间,那么文档会在一个新位置被重写。
MongoDB 最终会重用原来的空间,但这可能需要时间,而且空间可能会过度分配。
在MongoDB 2.6中,默认的空间分配策略将是powerOf2Sizes,这个选项从MongoDB 2.2开始就已经提供了。
该设置会将MongoDB分配的空间大小向上取整为2的幂 (比如,2、4、8、16、32、64,等等)。
该设置会降低需要移动的文档的几率,并使空间可以得到更高效的重用,结果是更少的空间过度分配和更可预测的性能。
用户仍然可以使用精确匹配的分配策略,如果不增加文档的大小,那么该策略将会更节省空间。”
以上是MongoDB官方的解释。
显然,这种策略将导致空间的浪费,特别是对于导入只读类型的数据。
3)MongoDB不支持数据文件的压缩,也不能回收空间。
它所使用的碎片整理的策略,可能是在一个新的地方重写,而不是对旧的碎片进行整理和合并。
4)不支持校验数据页。
页面校验对于数据库是非常重要的,有助于识别存储设备异常、数据块异常。
就这点来说,MongoDB存储的数据可能会不安全,也许某 一天会导致实例崩溃。
(6)支持JOIN等复杂查询的能力
一般的NoSQL产品都实现了简单的查询,一般不会实现传统数据库的“JOIN”。
这点对于未来的商业需求来说可能会导致存在隐患。因为如果数据是有关系的,那么就可能存在一些JOIN的需求。
(7)auto-sharding
一些NoSQL数据库或多或少地实现了此类特性,传统关系型数据库不太容易实现。
但NoSQL产品的auto-sharding特性,仍然需要大规模生产的测试验证。
sharding一般是指,把数据分片分布到不同的节点(实例)。
当内存、磁盘、网络、CPU等资源受限制了,我们可能需要分片,以获得持续稳定的服务能力。
NoSQL产品的auto-sharding往往是一个卖点。我们需要了解分片的一些常识和限制。
分片的一些要点具体如下:
1)避免单个节点资源超过限制:比如Redis的内存超过了物理内存,性能急剧下降。比如,数据库的内存严重不够将导致索引需要频繁访问磁盘。
2)NoSQL一般不能JOIN,而MySQL JOIN则比较难。
3)各分片数据可能不均衡。
4)热点数据可能导致性能问题,可能需要调整sharding key或算法,切割为更小的分片,如果对于延时的要求不高,也可以利用从节点扩展读取的能力。
5)节点的快速恢复。比如Redis在使用AOF持久化方式时,加载磁盘数据到内存时可能会慢到无法接受,MongoDB修复数据的速度可能会很慢。
6)单点故障:可以自动路由到正常的节点,或者提供开关降级服务,或者可以提供一个只读的节点,保障部分功能可用。
7)对于数据的容量规划还不是很清晰,有时这是现实,确实不清楚需求,需要不断调整。
8)尽量模拟真实环境进行压力测试。
需要说明的一点是:分片可以让失效的数据控制在某个范围内,但同时分片将导致更多的硬件错误。
MongoDB(2.4版本)已知的问题是auto-sharding不太可靠,可能出现CPU瓶颈。即使NoSQL产品有auto-sharding功能,仍然建议软件架构师预先分片。
我们往往需要数据库产品能够通用,这样它才能适应未来不断增长的业务需求。
MySQL是一个比较通用的数据库,而开源产品,比如MongoDB、Redis都比较特殊,更适合于特定的场景。
我们评判一个产品功能是否完善,除了要满足数据操作的需求,还有其他的运维需要,比如,是否有完善的备份支持和监控支持,是否方便迁移和故障切换。
开源产品在这方面功能一般不够完善,一些开源产品,
比如LevelDB只是实现了数据库底层的一些功能,并不是一个完善的数据库产品,但可以作为其他数据库产品的一个基础,比如RocksDB就是基于LevelDB实现的。
PostgreSQL作为一个功能强大的数据库产品,其功能丰富性还超过了MySQL,其更像是Oracle的开源版本,
但在市场的流行程度都远不如MySQL,如果你要选择它,你要确认是否真的需要它的某些特性,有没有其他更好的替代方案。

22.2.10 数据结构
一般传统的关系型数据库更适合存储一些结构化的数据,而NoSQL产品更适合存储一些非结构化的数据。
有些NoSQL的狂热支持者认为数据应该普遍使用NoSQL产品,移除关系型数据库的种种约束,比如不需要ACID,
而一些传统数据库的拥趸者往往认为数据就应该整整齐齐地存放在数据表内。
这两种极端都不可取。
在数据量小的时候,使用传统数据库一般就够用了,传统数据库往往比较通用,但在数据规模很大的时候,许多公司都采用了SQL和NoSQL数据库并存的策略。
对于大规模的业务,我们需要在开发的便捷和运维的成本之间找到平衡点,选择合适的数据结构和合适的数据库产品。
比如Redis里就存在一些适合开发人员“拿来就用”的数据结构,它们适合程序员的编程思维,因此用起来更舒服。

22.2.11 选择数据库产品的建议
如下是笔者对于数据库产品选择的一些建议。
1)应该随着大流走。
我们先看一些业内公司的选择,比如Facebook、Twitter,大部分的应用使用的仍然是MySQL加Memcached。
Facebook的MySQL主要用来存储Key-Value数据,在2008年,就已经有了1800台MySQL。
Twitter曾经说要迁移到NoSQL上,但也只是说说,为什么许多公司仍然选择MySQL存储海量数据,是因为目前仍然缺少稳健的方案,谁也不愿意当小白鼠。
所以,我们应该跟着大流走,多研究NoSQL产品,在业内已经有了比较成功的应用之后,再考虑使用NoSQL产品。
比如,新浪微博大规模使用Redis,其运维能力很强,就是一个值得借鉴的案例。
一些公司,如Facebook、Yahoo、Baidu大规模使用Hadoop就是一个趋势。
但是,某个数据库产品是否适用于自己的应用,仍然要仔细检查需求,看是否真正满足你的需要。
如果有许多大公司选择使用某个数据库产品,那么随着时间的发展,这个产品必将变得更好、更完善,
如果大公司也倾向于放弃这个产品,那么我们就需要审慎考虑,是否要继续跟进,是否会碰到一些产品限制或功能缺陷。
2)选择产品有两个决定性的因素:是否有稳定的团队维护,开源社区是否活跃。
目前的现实是大部分的NoSQL产品都是昙花一现。而那些趋势较好的产品大都满足这两个条件,比如Redis、MongoDB、HBase。
MongoDB的迅猛发展就和10gen公司不遗余力地推广和响应社区有很大关系。
Redis后面有VMware的支持,而HBase作为Apache的顶级项目,许多大公司都在使用和贡献patch。
研究这些业内比较知名的产品,用更低的成本支撑应用才是正确的选择,而不是花费过多的精力研究不断出现的眼花缭乱的产品。
对于开源产品,内部有熟悉源码的团队也是必需的,即使社区再活跃也很难帮你马上定位到问题所在,有时候,你不能等待官方发布补丁,你必须自己解决问题,
现实中,许多公司的解决方案往往比官方的解决方案还要早了好几年,这是因为大规模使用的公司往往会比官方更早发现和提出问题,从而更快地拥有解决方案。
比如Facebook和Google就对MySQL贡献了许多补丁。
3)NoSQL主要是为了满足扩展性而出现的,为了海量数据出现的,它不是一种通用的数据库产品。
4)对于应用场景的界定,应该回到数据的本身上,看看我们的数据是否方便查询、管理和维护,一般来说目前的NoSQL产品在这点上比较薄弱,容易被滥用,
如果数据本身是存在关系的,比如基于用户的数据,那么关系数据库仍然是更合适的选择,可以不断满足后面的商业需求,而不需要刻意使用NoSQL产品,
许多情况下,其实我们并不清楚自己的需求和数据。
5)关注基础运维指标。
NoSQL产品的部分初衷也许是认为这些数据存储起来很方便,再也不需要什么维护人员了,再也不用面对MySQL修改表结构的痛苦过程了,但事与愿违。
许多人在谈论CAP,但是,如果稳定性、可靠性、可维护性等关键运维指标无法满足,CAP更多的只是纸上谈兵。
如果底层存储实现、资源控制没有大的改进,那么某些NoSQL产品将会难以走远,运维这类产品就不是经验就可以解决的问题了。
6)NoSQL产品的安全也是一个因素,很多时候,我们必须相信内网是可靠的。
如果这个产品暴露于外网,风险会更大,软件防火墙的防攻击能力欠佳。
如果你碰到对安全不做考虑的一些NoSQL产品,则意味着数据的风险,你可能需要修改源码,增强安全机制。
7)不要轻信宣传,许多信息,往往出于公司的广告宣传,或者编辑的博取“眼球效应”,往往不能代表实际的使用情况。
一些产品,对外声称有许多公司在用,但也许只是某个公司的一个很小的项目在使用,而且现在也不一定还在使用,
我们要知道,一个互联网公司,也许有成百上千个项目,某个项目使用了某个NoSQL产品一点也不稀奇。
你应该多看一些业内人士的介绍,留意竞争对手的批评,考察其实际市场占用率,尽可能地从各种渠道获取信息。
总之,NoSQL产品是为了特定的问题而出现的,
虽然有各种NoSQL产品可以支持单机使用,Oracle也发布了memcache plugin响应需求,但如果在项目中普遍使用,成本是会大大增加的。
目前的NoSQL产品,可靠性、可维护性大都欠佳,后期的升级、Debug、二次开发、维护成本都不容忽视。
如果不能承受数据丢失的风险,那么你在选择的时候需要更慎重。
现实的场景是,许多公司的应用,即使架构再烂,也不会成为性能问题,也可以在后期解决,
但如果你使用了处于测试阶段的NoSQL产品,可能一开始就会让你感到痛苦,你还得时刻面临未知的风险,
软件人员认为有了问题可以Debug,通过更改代码来解决,而从运维的角度来看,这是一种很不好的倾向,
如果是核心的关键数据,则意味着存在巨大的商业风险。
现实的问题是,我们有没有海量的数据,我们有没有可能碰到伸缩性的问题,我们的数据是否真的易于管理和维护?
为什么许多应用NoSQL产品的公司绝大部分的应用仍然运行在传统的MySQL加Memcached架构下,这些都值得我们冷静思考。
小结 :
NoSQL产品往往作为MySQL的补充,在许多项目中被使用,甚至在一些项目中作为主要存储。
MySQLDBA不应该局限于MySQL,也应该熟悉其他的数据库产品。
本章为读者介绍了选择NoSQL产品需要考虑的一些因素,现实中,选择某个产品可能有许多非技术的因素,但这不是本书所能涵盖的。
由于NoSQL数据库产品发展得很快,本章中介绍的一些NoSQL数据库产品的数据和行为很可能已经不再准确,请读者参考最新的资讯。

22-MySQL DBA笔记-其他产品的选择的更多相关文章

  1. 读书笔记——《MySQL DBA 工作笔记》

    关于前言 作者在前言中提出的一些观点很具有参考价值, 梳理完整的知识体系 这是每一个技术流都应该追逐的,完整的知识体系能够使我们对知识的掌握更加全面,而不仅仅局限于点 建立技术连接的思维,面对需求,永 ...

  2. 《高性能MySQL》笔记——MySQL建表数据类型的选择

    前段时间看了<高性能MySQL>中的选择优化的数据类型,这里主要是做一下笔记. 首先数据选择有几个简单原则: 更小的通常更好.一般情况下,应该尽量使用可以正确存储数据的最小数据类型.例如只 ...

  3. MySQL入门笔记

    MySQL入门笔记 版本选择: 5.x.20 以上版本比较稳定 一.MySQL的三种安装方式: 安装MySQL的方式常见的有三种: ·          rpm包形式 ·          通用二进制 ...

  4. 4-MySQL DBA笔记-开发进阶

    第4章 开发进阶 本章将介绍一些重中之重的数据库开发知识.在数据库表设计中,范式设计是非常重要的基础理论,因此本章把它放在最前面进行讲解,而这其中又会涉及另一个重要的概念——反范式设计.接下来会讲述M ...

  5. 我心中的MySQL DBA

    原文网址链接:http://wangwei007.blog.51cto.com/68019/1718311 MySQL是一个跨平台的开源关系型数据库管理系统,目前MySQL被广泛地应用在Interne ...

  6. MySQL DBA面试全揭秘

    来源:http://ourmysql.com/archives/1426 本文起源于有同学留言回复说想了解下MySQL DBA面试时可能涉及到的知识要点,那我们今天就来大概谈谈吧. MySQL DBA ...

  7. Mysql DBA 20天速成教程,DBA大纲

    Mysql DBA 20天速成教程 基本知识1.mysql的编译安装2.mysql 第3方存储引擎安装配置方法3.mysql 主流存储引擎(MyISAM/innodb/MEMORY)的特点4.字符串编 ...

  8. MySQL常用存储引擎及如何选择

    一.MySQL的存储引擎 完整的引擎说明还是看官方文档:http://dev.mysql.com/doc/refman/5.6/en/storage-engines.html 这里介绍一些主要的引擎 ...

  9. 阿里巴巴MySQL DBA面试题答案[转]

    无意中看到阿里巴巴的面试题,,借此回首DBMS时刻趁热打铁巩固一下基础 拿到题目大概浏览了一遍难度大概在中上游水平,自己跪了接近35%的题目 自己答题如下,欢迎大家讨论分析题 1 2 3 4 5 6 ...

随机推荐

  1. python pip settools 安装基于源码 gdal安装需要c++相关库

  2. OpenJudge计算概论-取石子游戏

    OpenJudge计算概论-取石子游戏[函数递归练习] /*====================================================================== ...

  3. MSVCRTD.lib(crtexew.obj) : error LNK2019: 无法解析的外部符号 _WinMain@16

    1.问题描述做开源项目时,碰到VS2010报错如下:MSVCRTD.lib(crtexew.obj) : error LNK2019: 无法解析的外部符号 _WinMain@16,该符号在函数 ___ ...

  4. mysql查看被锁住的表

    转: mysql查看被锁住的表 2019年05月14日 11:58:59 hlvy 阅读数 1068更多 分类专栏: mysql mysql   转:https://blog.51cto.com/mo ...

  5. 阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_11-课程详情页面静态化-课程信息模板设计

    测试模板 页面的模板已经做好了 直接那来用 测试模板,把这个模板copy到这个测试freemarker的resources目录 远程调用 获取数据 返回模板的文件名 tomcat不支持ssr.ngin ...

  6. 清空表且id为0

    sql命令: 用于清空某表的数据 且让自增的id重新从0开始 truncate table

  7. python面向对象之类属性,实例属性

    python中的属性分为类属性和实例属性,之前已经说过一些,这里主要是对类属性与实例属性的增删改查 首先是对类属性的增删改查,下面这个是对类属性的修改,在书写类时,已经对类属性occupation进行 ...

  8. react Link标签 火狐失效怎么解决

    这个问题其实找了好多资料都没有具体的解决方法: 今天突然想到可能是层级嵌套出问题了,刚好有个bug也是关于这个的,已经亲测解决了 代码如下:火狐和谷歌都能正常的跳转 <Link to=" ...

  9. 如何去除PATH里的重复项并排序

    注意sed的用法,linux和Mac os不同,linux是Gnu的,Mac是BSD的 PATH排序去掉重复内容 mac和linux的换行符替换方法不一样,如下是Mac下的操作 export PATH ...

  10. golang web框架 beego 学习 (七)json转数组

    Modules type User struct { Id int64 `json:"id"` Name string `json:"name"` Email ...