Quantcast
Channel: CodeSection,代码区,数据库(综合) - CodeSec
Viewing all 6262 articles
Browse latest View live

Hadoop开源启示录

$
0
0
[前言]对中国大数据产业来说,2016年是从垂直领域野蛮生长到爆发全国范围关注热潮的一个转折点。不论是人山人海巨头云集的贵阳数博会,还是首次在华举办的全球顶级大数据会议Strata + Hadoop World,都揭示了中国大数据产业发展的澎湃动力。政府和产业需要转型,互联网公司、新兴的智能硬件公司、传统的生产制造型企业等都希望借力大数据实现更智能更个性化更有竞争力的渴望。然而,我国大数据人才稀缺使得大数据技术发展情况不够理想,这也导致中国在国际社区话语权的缺失。因此,中国需要有更专业更有前瞻性眼光的机构站出来,集合优势资源,对行业现状做出改变,培育优质专业人才。
Hadoop开源启示录

2016年8月,清华大学宣布与Hadoop开发社区的顶级贡献者Cloudera公司联合推进大数据人才教育项目,在大数据开源社区方面开展合作。在Hadoop生态领域,Cloudera是规模最大、知名度最高的企业,也是当前大数据领域最强有力的解决方案服务商之一。带着对中国大数据市场的满满诚意,Cloudera创始人、董事长兼首席战略官Mike Olson以及Hadoop之父、Cloudera首席架构师Doug Cutting来到清华,为三百余位现场听众及两千余名在线直播听众讲述了Hadoop的发展历程,并与清华大学软件学院副院长、党委书记王建民及现场的同学们展开了深刻而有趣的对话。

Doug Cutting口述:

Hadoop十年,撬动未曾料及的魔法时代

10年前我开创Hadoop时,存储企业数据和商业数据系统的使用和现在大不相同。对大多数机构来说,企业数据建立如果不依赖关系型数据库,就完全没可能了解数据。但关系型数据库使用起来很昂贵,也不适用于所有形式的数据。那时人们关注很多数据只是聚焦在关键字、任务、业务等(编者注:可数据库领域的查询条件)。世事变迁,Hadoop是如何带来一些改变的呢?

因兴趣创建Lucene,试水开源社区

在大约18年前,当时我在Excite负责做搜索引擎。事实上,我做过多个搜索引擎,从就职Xerox开始,到苹果再到Excite。我喜欢做搜索引擎并且一直有一个想法,用一个新的方式去写搜索引擎,Excite对这个想法并不感兴趣,于是只能自己钻研。我尝试用一种新的编程语言,并认为它会成为一种通用计算机语言,就是当时并非主流的Java。

1998年我完成了Lucene的第一个版本。当时并没有想好能用它做什么,只是有兴趣尝试并在业余时间完成了。两年后,也就是2000年,我还没想好用Lucene能做什么,但我决定不能就这样冒然地成立一家新公司,因为我不清楚财务、人事、合同等公司常规流程。我真心希望人们能用上这个产品,这也是我开发这个产品的动机,我也希望能让更多人发现它的实用性,并从中发现价值。我决定把它贡献到开源社区。

在把Lucene的代码贡献到开源社区的第二年,它被一些小的社区使用,我也因此被邀请加入Apache软件基金会。Apache专注于开源,集合了一群软件界拥有最强大脑的工程师。它追求开放自由,让人们利用软件变得无所不能。在市场需求推动下,我们合作将软件出版成商业产品,但Apache不强调归属于某个社区,而且所有的社区都开放,欢迎新成员加入。Apache社区上所有功能和提供的信息都及时共享并不断更新。从2001年加入Apache到目前为止,这种模式已经得到了令人惊叹的成果。

其中一点,就是随着越来越多的开发者,这种开放模式让人们可以随时随地的使用开源软件,也可以向其他推荐。当需要向老板汇报却又不在办公室时,可以下载之后在家处理,信息也可以实时同步。这使得人们处理程序、改进程序、理解程序变得容易,能随时和其他开发者沟通。如果从事软件开发,你会发现以往只有机会和公司的同事讨论工作,而做开源项目则可以和全世界讨论,有很多表现的机会,甚至可以和自己在业内的“粉丝”去沟通。这种自我展现的方式有很好的激励作用,为了更好地在观众面前展示自己,人们会更努力地工作,让项目日臻完美。

此外,开发者通过做软件会被很多机构了解并认可,你的软件很可能会富裕一个行业全新的生命力,所以每个方案每次改变都要有普适性。要做到为每一个人服务,还要坚持一段时间,用最好的方法做正确的事。开源并不仅是帮助开发者,它更会孕育出一批高质量的软件,让人们会越来越有动力去把事情做好。

从Lucene进入开源平台感受到的第三点,也是最有意思的一点:这是一条突飞猛进的捷径。Lucene对原有的搜索引擎造成了很大的冲击,因为Lucene使用成本很低,且使用效果大大好于通用的商业产品。经过大量的实践与反复改进,Lucene已经成为世界上最受欢迎的搜索技术之一。这并非是因为它创造了一个软件技术的开端――也许有这个因素――但更重要的是它是开源技术,能让每一个人都能参与进来,学习并改进它,享受这个过程。这种开源的方法很强大,能让技术走近更多人,也促使技术变得更好更快。

此外,就像Mike Olson说的,当人们有选择的时候,在企业专用软件和开源软件之间,人们总是倾向于选择开源软件。一轮又一轮迭代后,你会发现开源软件在任何领域都会胜出。

Nutch、GFS和MapReduce, Hadoop萌芽在即

我开始了另一个名为Nutch的项目。在Lucene的基础上将开源的思想继续深化,我们从网页上收集大量数据,基于这些建立一个全新的开源搜索引擎,就像Google、微软bing或其他搜索引擎,收集特定的网页及链接,提取信息,同时处理数十亿的网页请求。一台PC无法存储如此大量的信息,也无法在合理时间内响应,所以我们尝试用分布式系统,Nutch在5台电脑上运行起来。我们也把Nutch资料总结成文本放入开源社区中。

大约2003年到2004年的时候,Google发布了一些相关的研究报告,介绍了他们基于现有搜索引擎做的改进,吸引了我的关注。这些技术成果对我的研发有着十分直接的指导意义。运用这些技术,我们可以将原本需要手工操作的大量繁琐的数据分配和空间管理等操作步骤实现自动化。这两个平台一个是GFS(Google File System),将不同设备所产生的海量数据统一管理在同一个存储空间内,与所有电脑都自动关联,其中一个设备出现障碍,数据不会丢失,而且程序可以迁移到其他设备继续运行,所有数据资源可以共享。这种具备自动关联能力的数据管理是Google实现的一个核心突破,这使我们的操作能力可以从五台电脑提升到成百数千台。同时,Google发布的另一个研究是有关MapReduce的,内容是关于运行在GFS上时,如何用MapReduce进行大规模数据的处理。

Mike Cafarella和我开始基于这两项技术,在开源平台上校准我们原有的程序Nutch。2005年,我们开始有数据基于20台硬件设备在Nutch上运行,这是当时我们能借调到设备的最大数量。我当时在一个非营利组织工作,Mike还没从大学毕业,20台设备已经是我们能筹备到的极限。以这20台设备所支持的开发和测试情况来看,我们意识到这种数据分配的程序存在太多的bug,自动关联很难实现,测试往往以失败告终。当你交叉验证时,你会发现使用两台机器所产生的测试结果不一样。

雅虎助力,Hadoop潜能释放

我意识到这是一个很好的机会,通过开源平台对世界上所有的主流数据处理模式做出彻底的革新,而且基于低廉的硬件成本。如果靠单枪匹马去实现这个宏伟的计划,它会耗费十年甚至更长时间才能最终替代现有的解决方案。我们需要其他帮助。

2005年底,经过一番筛选我把目光聚焦在雅虎。雅虎对我的研究项目很感兴趣,因为当时在做搜索引擎的过程中他们也有类似的困惑,合作研发也会同时帮他们解决问题。2006年,我们加入雅虎,把Nutch分布式数据管理部分重新命名为Hadoop,名字来源于我儿子的黄色毛绒玩具――一只小象。为了新项目Hadoop的运行,雅虎做了大量投入。从一开始的10人工程师团队迅速增加到20人然后更多;机器数量也从一开始的100台,在6个月后增加到数千台。六个月内我们不断测试、开发、运行,逐渐有了成效。

从2007到2008年,切实改进了数据关联能力的技术,其他人也开始使用,这项技术也开始释放富有魔力的潜能。任何人都能下载这个开源软件,在并不昂贵的设备上运行非常大量的计算。Yahoo、Facebook、eBay、LinkedIn、Twitter等公司都开始以Hadoop为基础搭建他们的业务。

未料及的行业渗透 Hadoop创造历史

曾一度以为Hadoop能做的事情已经完成,一切都在按预期发生。但我没意识到的是,所有的传统行业都在酝酿着变革,硬件设备已遍布如此广泛,可用于计算的硬件已渗透到各行各业中,比如卡车、拖拉机、飞机、汽车等。所有这些传统行业都在做数字化转型,这正在产生更加海量更加有效的数据。运用好这些数据能帮助人们更高效更精准的管理生活。起初我并没有意识到这一点,曾以为只有互联网公司、媒体公司才需要Hadoop技术,但Mike Olson告诉我,这项技术已在更多行业领域释放出更大的能量。所以他在2008年创建了Cloudera――第一家专注特定领域的企业,也是迄今为止特定领域规模最大的企业。

2009年,为了参与这个让人振奋的过程,见证更多的人利用我帮助创建的软件技术发挥更大的潜能,我加入了Cloudera。现在,我们见证预言变成了现实,比如汽车生产商特斯拉,通过实时收集汽车动态数据,了解驾驶者的行为喜好,从而改进他们的下一代汽车;航空公司在飞机上安装了数百个传感器,根据回传的数据,优化航线。这真是令人瞩目的改变!甚至在农业、重型机械、铁路、零售、健康医疗等所有我们能想到的行业,数据都在发挥强大的影响力。

Hadoop切实推动了这些令人瞩目的改变的实施。在今天,Hadoop还在日益强大,但我觉得围绕Hadoop发生的事情将更加有趣。在这个长期的过程中,它已经孵化了更多伟大的技能。从单机项目开始,然后有了分布式的文件系统GFS和信息专家MapReduce,搭建的调度程序让人们能够基于Hadoop分享资源,并开发其他类型的引擎,类似于YARN。越来越多的软件技术基于Hadoop衍生出来,比如在线键值存储;比如面向列的开源数据库技术HBase;超越了MapReduce的Spark,在实时批处理上表现更卓越;Impala能以SQL语义,快速查询PB级大数据,Lucene擅长的搜索也被充分整合。每年都有更多的新技术刷新我们的视野。

试想一下,每一个系统的进化迭代,每一个开源项目的建立,都可能带动一次技术革新。其中一些非常有用的技术,越来越多的人会开始使用。这些技术将会慢慢变成所有人认可的通用标准,还有一些不流行地将慢慢被人们遗忘。时代在急速变化,关系型数据库的世界几乎固化了30年,只有非常细微的改变。在Hadoop诞生的近10年间内,技术界发生了翻天覆地的变化。我们见到了许多新的模型,它们支持实时处理、机器学习的新功能,实现新事件的新方法……很多现在无法想象的事都将在随后几年发生。我认为这就是Hadoop留给世界的最宝贵的财富。它平稳运行10年之后,还将影响到未来的数十年。它不设中心控制的强大软件系统孵化了各种不同的项目,有的失败有的成功,但这种由平台衍生的复杂多样性不可能在一家公司的掌控下实现。

未来,为我们而来

今天,来自世界不同地方的我们通力合作,将决定下一个划时代的平台。时间的推移将证实我们的设想。这个平台将更加强大灵活,适用范围更广,功能更多。我们能用它来应对几乎每一个问题,不仅是关系型问题,还能轻松完成机器学习,能搜索、对大数据实时批处理,将有更多的工具箱,让我们在开源平台以更低的成本更好地探索世界。我相信这是一个光明的未来。同时,硬件也在进步,英特尔发布了让人惊喜的新技术,使硬件可以储存更大量的数据,闪存与读取速度更快,成本和以往差不多。当可以在内存里储存PB级的数据并且访问,甚至通过网络访问时,很多事情也会因此改变。我们很快将看到一个全新的时代,一个进步的框架,一个被充分提升的有价值产品。我们将这种理念运用于Impala、Kudu等新产品研发中,但仍有很多事情是我们尚未想到的。

这是一个令人振奋的时代,但我希望各位不仅仅是观望,而是切身参与,加入到开源社区来,甚至是开创一个新的开源项目。我也看到越来越多的项目从中国出现,比如Apache Kylin(麒麟)。我相信在这个新世界里,改变才是常态,新的技术每年都会出现。这些年中国发生了巨大的变化,有很多机会可以应用这些新技术,大数据开源社区将会在中国落地生根。我会很期待看到,有多少人采用它,中国产生贡献,在接下来的几年衍生出越来越多的机会。

巅峰对话实录:

Hadoop未来,事实将碾压今天所有的质疑

人物简介

Mike Olson:毕业于加利福利亚大学,曾作为Sleepycat软件公司CEO主导开发了全球应用广泛的开源数据库Berkeley DB,后被甲骨文收购,任甲骨文嵌入式技术副总裁。2008年与其他三位合伙人创立Cloudera,将其打造成国际领先的大数据数据管理和分析平台的服务商,2014年12月Cloudera进入中国。

Doug Cutting:毕业于美国斯坦福大学,Lucene、Nutch等开源项目的发起人,打造了目前在云计算和大数据领域里如日中天的Hadoop,让大数据推动业务的数字化转型有了开源的技术平台。他擅于把高深莫测的搜索技术形成产品并贡献于市场及大众,现任Cloudera首席架构师,同时也在Apache软件基金会董事会任职。

王建民:清华大学软件学院副院长、清华大学软件学院大数据中心主任,国家科技部中青年科技领军人才,国家基金委杰出青年基金获得者,国家“核高基”科技重大专项总体组成员,国家863计划先进制造领域专家、国家卫计委信息化专家委专家、我国第一个大数据专项“核高基”-“非结构化数据管理系统”负责人;工信部“中国制造2025”:“操作系统与工业软件”工作组组长。

一、 关于HADOOP与Spark、GPU,及商业化未来

1、面对Spark这类新兴技术的发展,以及MapReduce市场萎缩的情况,你们如何看待这种市场变化?

迈克:Hadoop由很多部分构成,第一层是HDFS,完全做分布式存储,此外MapReduce用来做分布式处理;有分布式地面向列的开源数据库技术HBase;Impala可以在支持Hadoop的HDFS系统上,直接做SQL的查询;也有Cloudera做的Kudu这样的新型存储技术。

Spark只是其中的新技术之一,并不是好像全世界都只用Spark。当然,我们如果要去比较Spark和MapReduce,从现在的情况来看,Spark的确会胜出,但基于Hadoop还会不断涌现出更多新技术。

道克:没错,Spark的确非常好。在实时批处理上表现优异,但它不是全能的,比如它不具备SQL访问查询、Solr和Lucence搜索倒排索引、HDFS、Kudu的数据存储能力等。Spark仅仅是Spark,它不代表Hadoop所有的技术,Hadoop将会孕育更多新技术出来。

2、王建民:计算机和大数据技术都在日新月异的变化,特别在硬件方面,我们看到很多下一代硬件不断的涌现,这些新产品的涌现对于大数据技术的未来会有什么样的影响?

迈克:像网络、CPU在未来会出现非常多的变化,正确的方法是软件去适配硬件,而不是无视硬件的变化。硬件的升级并不会妨碍未来大数据技术的发展,反而大数据系统会更好的去利用这些新硬件去改变世界,两者不存在替代关系。

过去十年,我们已经看到了很多这类变化。Cloudera有着非常深厚的英特尔背景,我们的很多员工来自于英特尔,英特尔也是我们的投资人之一。我相信我们和英特尔的密切关系,未来会更多的帮助下一代软硬件技术的融合与适配。

道克:很多人在问我,怎么把GPU和Hadoop结合,这其实是一个错误的命题。Hadoop实际上是基于IO Intensive的系统,它整个系统的瓶颈是在系统的IO上,包括磁盘IO、网络IO,所以它需要解决的根本并不是CPU的问题。未来当IO不再困扰我们的时候,也许那时再来谈怎么用CPU加速的技术解决更多问题更有意义。

像谷歌Tenzing的机器学习系统就可以很好的利用GPU,而不是现在吧的大数据系统来加速。但我相信在这个领域将来会有更多的机会,我们将看到很多数据结构、系统结构,会适应新硬件的变化趋势而发生转变。

3、Hadoop3.0的关键特性

迈克:Hadoop3.0的确会有一些侧重,排在首位的就是多租户技术,将来我们会在Hadoop 3.0的平台上看到更多不同的像MapReduce、Spark这样的技术,可以同时在一个平台上被不同的用户运行,就像Yarn正在做的一样。所以Hadoop 3.0的特点就是支持更多的系统可以更好的运行,更好的去实现多租户这个概念。

另外,Hadoop3.0更多的是适配新硬件技术的改变,比如英特尔新推出的优化存储、CPU的新技术,特别是SSD技术。硬件价格的走低,让我们更有可能去利用这些技术。Cloudera新启动的一个Apache开源项目叫Apache Kudu,这是一个新型的存储系统,Kudu就正在利用这样一些这样的新硬件技术。

道克:现在还有另一个我们在做的项目,内容是基于HDFS和新型硬件结合做系统复制。这种复制技术,不只能加快系统的速度,还会提升系统的容量。这个项目的开发者就在英特尔中国公司,中国已经出现了很多很好的创新技术。

4、问题分段:CDH商业产品的未来怎么样?

迈克:Cloudera一直在保持这个系统的开源,虽然上面有很多收费的工具,但是这样做的目的并不是阻止用户。因为现在有很多商业软件巨头会利用我们的开源系统,把它作为商业软件,去获得更多的市场机会,去赢取更多的利润。所以我们一方面会保持底层数据存储、处理引擎系统的开源,让用户可以把这个技术用得更好、让系统变得更易用;同时,坚持收费的举措也让我们能够有能力在大数据系统市场上和大型商业软件公司竞争。

开源将有利于更多人参与系统的开发,让更多的大学可以参与学习,让更多的用户可以接受新知识。所以大家看到了Impala和Spark。我很高兴看到作为一家公司Cloudera在大数据市场上越来越多的成长机会。

道克:开源平台上,Apache仅仅是把所有技术囊括在一起,但Apache上面可能有二十多种不同的打包方式,怎么去安装?怎么去配置?怎么去打包?这些其实对很多用户来讲都非常具有挑战性。所以我们推出CDH Commercial版,已经帮大家把对应的系统打包好了,通过CDH我们会帮助大家更好的管理数据,管理大数据系统。

如果用户愿意去使用免费开源系统这没有任何问题,但是如果用户需要我们的帮助,可以去订购Cloudera的商业版。这就是硅谷现在的开源文化,有越来越多的公司在做开源。开源的东西是免费的,但我们在不断提供增值服务。我们也需要有更多的客户认可这样的服务价值并愿意帮助Cloudera这样的公司在市场上存活下去,跟我们建立更长期的合作关系,支持我们的业务。

二、 关于大数据系统的应用,选择与困扰

5、如果我们现在有一个项目刚开始,面对这么多大数据系统,应该怎么选择一个合适的平台?

道克:这的确很难,我们可能需要去熟悉所有的系统和工具,需要更多的实验,去测试这些系统。在满足工作负载的前提下,比较在哪个系统工具上工作得更好。但幸运的是,这类测试的确越来越容易了,现在有越来越多的工具可以进行辅助。

但是真正在设计的过程中需要去考虑很多技术细节,比如系统处理速度和系统吞吐的平衡。这个过程更像是一门艺术,而不像一个技术。

迈克:你选Cloudera就行了,不用去想更多的(哈哈)。

6、王建民:我们现在碰到的很大问题是面对系统的版本升级,用户需要不断去升级他们建好的系统,Cloudera怎么看待这样的挑战?

迈克:当然,商业版的更新很简单,一键安装新的系统就好了。如果是开源的系统就会很难,因为开源你需要去选择一个适合的文件包,需要自己去重新搭建,需要自己去测试,而这些在Cloudera商业版里都已经帮你做好了。

道克:如果不兼容,就只能来找Cloudera,这样我们的商业服务就能有发展空间了(哈哈)。

王建民:看来这样的机会、这样的服务对于Cloudera而言是一个很有价值的业务。

迈克:我们是一家创新公司,所以首先我们是一群创新者,我们的首要工作是设立未来大数据系统发展的方向。第二件事,我们的确做商业软件,我们会把这些开源系统打包、测试,会在上面做很多工具,我们也会利用它来提供服务。

7、大数据服务的云平台未来应该如何选择?

迈克:在商业层面上各种主流的云平台Cloudera都支持,我们在北美和AWS、谷歌等都有合作,在中国将和腾讯、百度等有更多的合作,可以看到云服务市场增长非常快。

道克:如何选择云服务有很多因素要考虑。第一个是经济角度上,到底哪种方式更具性价比,并不是所有的公有云都比私有云更便宜。第二个是安全,虽然我们可以用多种加密的方式解决这个问题,让别人更安心,但是安全永远是影响抉择的重要因素。还有另一个问题,我们需要考虑得非常清楚,通常我们迁移大数据系统是非常昂贵的,所以我们在选择一个云的运营商之前,首先要意识到,这个运营商给我们提供的技术是不是我们需要的。一旦需要在这个平台上进行转换,是不是很容易操作。我能见到的最大错误就是选择了某个云平台之后被吃定,无法迁移转换。

迈克:我们选择开源有一个非常大的好处,因为底层的技术其实都是一样的,是完全兼容的。如果我们选择了不合适的云运营商,或者不合适的大数据商业软件合作伙伴,我们可以比较容易完成系统迁移。

道克:还有一个融合的问题。比如企业内部有架构存储一部分数据,同时在公有云上也存储一部分数据,如果我们选择混合云的方式,可能会让我们在处理数据时非常困难,因为这两个架构之间任一方向的数据迁移,都非常昂贵。是否需要把数据放在不同的地方,这也是我们在选择云计算架构时必须要非常认真考虑的一个问题。

8、如何去发掘Hadoop系统的应用性领域,尤其在中国?怎样去发现中国真正的大数据市场?

迈克:大数据分析、机器学习等技术发展,都在真实发生着,这些事情触发了我们会有更多的数据,需要更多的处理能力,需要有更多的分析应用,这样正是我们希望看到的市场需求。

2006年我代表Oracle来中国,当时正好是中国“十一五”开端的第一年,中国政府第一次在“十一五”的五年规划中开始强调创新,今年是2016年,是“十三五”的开局之年,中国政府不但强调创新,还强调了创业,我认为中国现在有一个非常好的开端。

对于Cloudera而言,在中国市场需要寻找更多的合作伙伴。我们看到像GM跟上汽合作为全球市场设计新车,中国已经出现越来越多的垂直细分领域,比如像电信、保险,有越来越多的中国公司在使用大数据,成为很好的行业范例。中国大数据的应用前景非常好,已经取得了令人刮目相看的成就。中国市场的体量非常大,增量也会很大,不只是大数据市场,中国在其它细分领域一定会出现更多更好的创新,会孵化出更多大数据的技术与应用。

三、 关于开源及未来

9、事实上,人们对开源还有困惑,很多中国团队的想要致力于开源,你们有什么建议给那些想要参与进来的人?

道克:第一件事是找到一个恰当的领域,现在的开源项目不是那么容易做好,首先要确保你的产品是有用的。

提问:这个领域是什么?

道克:这个很难去做预测,每个细分行业都有不同的现实情况,但相信大家是可以找发掘的。第二点,明确领域后,我们要建立对应的大数据系统;第三点,系统做出来之后我们需要有更多的参与者,需要让大家意识到这个系统的价值,并愿意投入去改进你现在做的系统,愿意加入这个的社区团队。这就是我们讲到的开源文化。

这三步做到之后,你的项目规模自然而然就会增长,就会吸引更多的人参与,而且在这个过程中,所有参与项目的人需要非常开放,乐于帮助,更多这样的人加入才会促使这件事成功。反之,如果我们做的是非常狭隘的一个领域,并希望它控制在一个什么样的范围内,通常这样的项目就难以成功。

迈克:在成为Cloudera的Leader之前,我曾是一个开发人员,做伯克利的数据库。在我的经验中,社区是最重要的。并不是说一个开源社区做出来就是为了免费,关键是有更多人参与。现在中国的团队不只是参与到既有的项目中,有的已经开始去创造自己的新项目。比如说来ebay中国的一群人创造了麒麟这个项目,这个项目现在已经变成了Apache的一个典型项目。所以我非常乐于见到更多来自中国的技术可以贡献在全球。

王建民:现在中国有非常好的开源文化,很多年轻一代都非常热情,愿意去做这件事情,但苦于我们没有找到正确的门路和方法。清华正在做这方面的努力,清华数科院和Cloudera的战略合作,其中非常重要的部分就是如何帮助中国开源社区的成长,我们也希望通过这样的方式,培养更多的中国本土的Leader,将来他们可以去创建多样化的开源社区,去领导更多的项目。

道克:需要强调一下,开源并不是一件容易的事情,它意味着我们需要投入更多的努力。我们需要有大量来自全球的有关需求的沟通,可能你的团队在中国,你的需求来自于英国或者是美国,语言障碍会带来挑战。此外,选择做开源,选择一个更多人可以用的东西,一定意味着需要有更多付出。

举一个例子,我和我孩子做饭,可以选择我自己做,让我的孩子做,或者教我的孩子做。让我做饭很简单,但是让我的孩子做饭一定是个灾难。如果让我选择,教我的孩子如何做饭,虽然培养的过程需要花很多的精力,但最终当孩子学会做饭之后,就能一劳永逸。

开源社区也是这样,开始阶段需要投入比我们现有项目更多的努力,但是一旦我们很好的建立一个社区和社区文化,这个项目就会有一种自我生长、自我繁殖的能力。

10、中国另一个现状就是天赋的缺失,你们有什么建议?

道克:这个的确很难,因为现在大数据技术的变化演进非常快,如果你希望成为一个大数据人才,就必须有非常强的学习新技术的能力。技术变化太快了,只有最好的人才能做到。真正能够解决的方式只有自我不断的学习,以及可以有第三方提供的培训来帮助大家。Cloudera提供了一些课程出来,这个课程对大学是免费的。

王建民:为了解决大数据人才的问题,中国已经有很多大学开设了大数据教育的课程,清华数科院就有相关的硕士计划,第一届已经有150名以上的学生,来自清华不同院系的师资支持这个课程,但是这个课程到底应该怎么去上呢?

参与授课的学生基本上可以分成三类,第一类是有很强的IT背景,可以做很多数据工程的事情;第二类来自社会信息学的领域,在他的工作中有很大部分就是在处理数据。第三类人是来自传统行业,比如像机械工程这样的领域,他们以前没有足够的IT知识和处理数据的技能。

我们在去年的授课过程中也在不断的调整课程,我们认为更好的解决方法,是理论和实践结合,让大家在学习理论课程的同时有更多的实践机会,能够更好的去解决技能问题。Cloudera提供的这些免费课程将会被引进到清华大数据硕士教育的计划中。

11、大数据技术在中国未来会怎样发展?

王建民:第一点,大数据在中国的进步会非常好,数据来源会非常多,中国有越来越多的人、越来越多的机器、越来越多的在线交易,都在产生大量的数据。但是在这个过程中我们要改变现在的文化,让决策听从数据驱动。第二点,不要把大数据神化,认为大数据可以做更多的事情,要有耐心把大数据和我们的业务更好的结合起来。第三点,我们需要更多的注意安全和隐私,我们会有越来越多的数据,数据安全实际上是这个发展的前提。第四点,要更多发展中国自己的技术。

迈克:中国大数据有非常好的未来,清华这边也在做很多和大数据相关的事情,大数据在全球的发展已经非常成功,在中国经济方面、社会方面都会涌现非常多的机会。

道克:是的,中国一定会有很多的机会,而且中国的技术也已经很先进了,更重要的是现在开源社区给了我们更多的机会去参与学习。

12、大数据技术的未来又是什么样的?

道克:这个非常难预测,现在不太可能会知道,如果要知道我就去做了。我认为更可能知道的是在座的各位,如果大家有什么样非常好的想法,可以去积极尝试。

迈克:在中国,小米正在使用Kudu,而Spark社区现在也变得越来越热,这个情况在五年前我们都是见不到的。所以现在开源社区给我们一个非常好的环境和生态系统,像Hadoop这样,可以帮助大家更好的去发展更多新的技术。

王建民:我们能够看到的是,大数据系统对于中国的很多用户来讲,非常难使用,已有的开源技术并不能被很好的利用起来。在我们实验室现在就有这样一个项目,可以帮助大家更简化的使用今天Hadoop的系统,是一种用机器学习的方法更多去完成自动化的参数、自动化的控制,我们正在做更多的努力。

迈克:这个方向很好,机器学习一定是未来的趋势,我们应该思考怎么在更多方面结合这项技术。

注:本稿件摘自数据观入驻自媒体―数据派


Hadoop开源启示录

Apache HBase的适用场景

$
0
0

原文: http://blog.cloudera.com/blog/2011/04/hbase-dos-and-donts/

最近我在 洛杉矶Hadoop用户组 做了一次关于 HBase适用场景 的分享。在场的听众水平都很高,给到了我很多值得深思的反馈。主办方是来自Shopzilla的Jody,我非常感谢他能给我一个在60多位Hadoop使用者面前演讲的机会。可能一些朋友没有机会来洛杉矶参加这次会议,我将分享中的主要内容做了一个整理。如果你没有时间阅读全文,以下是一些摘要:

HBase很棒,但不是关系型数据库或HDFS的替代者; 配置得当才能运行良好; 监控,监控,监控,重要的事情要说三遍。

Cloudera是HBase的铁杆粉丝。我们热爱这项技术,热爱这个社区,发现它能适用于非常多的应用场景。HBase如今已经有很多,所以很多公司也在考虑如何将其应用到自己的架构中。我做这次分享以及写这篇文章的动因就是希望能列举出HBase的适用场景,并提醒各位哪些场景是不适用的,以及如何做好HBase的部署。

何时使用HBase

虽然HBase是一种绝佳的工具,但我们一定要记住,它并非银弹。HBase并不擅长传统的事务处理程序或关联分析,它也不能完全替代MapReduce过程中使用到的HDFS。从文末的中你可以大致了解HBase适用于怎样的应用场景。如果你还有疑问,可以到 社区 中提问,我说过这是一个非常棒的社区。

除去上述限制之外,你为何要选择HBase呢?如果你的应用程序中,数据表每一行的结构是有差别的,那就可以考虑使用HBase,比如在标准化建模的过程中使用它;如果你需要经常追加字段,且大部分字段是NULL值的,那可以考虑HBase;如果你的数据(包括元数据、消息、二进制数据等)都有着同一个主键,那就可以使用HBase;如果你需要通过键来访问和修改数据,使用HBase吧。

后台服务

如果你已决定尝试一下HBase,那以下是一些部署过程中的提示。HBase会用到一些后台服务,这些服务非常关键。如果你之前没有了解过ZooKeeper,那现在是个好时候。HBase使用ZooKeeper作为它的分布式协调服务,用于选举Master等。随着HBase的发展,ZooKeeper发挥的作用越来越重要。另外,你需要搭建合适的网络基础设施,如NTP和DNS。HBase要求集群内的所有服务器时间一致,并且能正确地访问其它服务器。正确配置NTP和DNS可以杜绝一些奇怪的问题,如服务器A认为当前是明天,B认为当前是昨天;再如Master要求服务器C开启新的Region,而C不知道自己的机器名,从而无法响应。NTP和DNS服务器可以让你减少很多麻烦。

我前面提到过,在考虑是否使用HBase时,需要针对你自己的应用场景来进行判别。而在真正使用HBase时,监控则成了第一要务。和大多数分布式服务一样,HBase服务器宕机会有多米诺骨牌效应。如果一台服务器因内存不足开始swap数据,它会失去和Master的联系,这时Master会命令其他服务器接过这部分请求,可能会导致第二台服务器也发生宕机。所以,你需要密切监控服务器的CPU、I/O以及网络延迟,确保每台HBase服务器都在良好地工作。监控对于维护HBase集群的健康至关重要。

HBase架构最佳实践

当你找到了适用场景,并搭建起一个健康的HBase集群后,我们来看一些使用过程中的最佳实践。键的前缀要有良好的分布性。如果你使用时间戳或其他类似的递增量作为前缀,那就会让单个Region承载所有请求,而不是分布到各个Region上。此外,你需要根据Memstore和内存的大小来控制Region的数量。RegionServer的JVM堆内存应该控制在12G以内,从而避免过长的GC停顿。举个例子,在一台内存为36G的服务器上部署RegionServer,同时还运行着DataNode,那大约可以提供100个48M大小的Region。这样的配置对HDFS、HBase、以及linux本身的文件缓存都是有利的。

其他一些设置包括禁用自动合并机制(默认的合并操作会在HBase启动后每隔24小时进行),改为手动的方式在低峰期间执行。你还应该配置数据文件压缩(如LZO),并将正确的配置文件加入HBase的CLASSPATH中。

非适用场景

上文讲述了HBase的适用场景和最佳实践,以下则是一些需要规避的问题。比如,不要期许HBase可以完全替代关系型数据库――虽然它在许多方面都表现优秀。它不支持SQL,也没有优化器,更不能支持跨越多条记录的事务或关联查询。如果你用不到这些特性,那HBase将是你的不二选择。

在复用HBase的服务器时有一些注意事项。如果你需要保证HBase的服务器质量,同时又想在HBase上运行批处理脚本(如使用Pig从HBase中获取数据进行处理),建议还是另搭一套集群。HBase在处理大量顺序I/O操作时(如MapReduce),其CPU和内存资源将会十分紧张。将这两类应用放置在同一集群上会造成不可预估的服务延迟。此外,共享集群时还需要调低任务槽(task slot)的数量,至少要留一半的CPU核数给HBase。密切关注内存,因为一旦发生swap,HBase很可能会停止心跳,从而被集群判为无效,最终产生一系列宕机。

总结

最后要提的一点是,在加载数据到HBase时,应该使用MapReduce+HFileOutputFormat来实现。如果仅使用客户端API,不仅速度慢,也没有充分利用HBase的分布式特性。

用一句话概述,HBase可以让你用键来存储和搜索数据,且无需定义表结构。

Atlas Data Structure

$
0
0

Kerf introduces a new data structure called an “Atlas” that we think is a helpful thing to have inside of a programming language. We’ve found it very useful to have database Tables inside of a programming language, and the Atlas concept is a natural extension of that. Be careful about jumping to conclusions, though, since an Atlas does a few special things that make it unlike what you might expect. I’ll give a preview of the major points here:

Automatic indexing Responds to SQL First-class language type Columnar implementation

We didn’t spend much time talking about Atlases originally, because interest in NoSQL-style computation seemed to be on the wane. Recently, however, we’ve had a lot of requests for those sorts of applications, and so a detailed description seems in order. (If you’ve come across any interesting problems like that in your work, tell us about them .)

If a Table is a way of including a SQL table inside of the language, then an Atlas is a way of including a NoSQL store: none of the rows have to have the same columns. In other words, an Atlas is a schemaless table. The Atlas is a generalization of the Table where the rows don’t have to be uniform. In one sense, an Atlas is a sparse Table. You could also think of a Table as a vectorized Atlas.


Atlas Data Structure
A regular table
Atlas Data Structure
A JSON array of objects
Atlas Data Structure
Awkward tabular representation of the JSON array In Kerf we use the term “Map” to refer to what JSON calls an Object {"a":1} . So the term Atlas to refer to a List of Maps (with an Index) was an obvious choice. We use the special convenience syntax {{ and }} to create a table, and the related {[ and ]} convenience syntax to create an atlas. Both of these came about because they fit in well with JSON, and Kerf is a JSON (& SQL) superset.

1. The first thing that makes an Atlas special is that every key is indexed invisibly and by default. This means that no matter what key you query on, your query will be optimized. Atlases let you forget about indexing entirely. In a typical NoSQL store, if you want optimized queries on a key you have to issue the equivalent of a CREATE INDEX command, wait for the index to be created, incur future performance penalties, and so on. With Atlases you don’t have to fool around with any of that. The keys are already indexed, there’s no additional performance penalty, and adding a never-before-seen key doesn’t impact performance. Effectively, you can just forget about indices entirely, even for nested keys.


Atlas Data Structure
A large, (mostly) random atlas
Atlas Data Structure
Already optimized selects on two keys

2. The second thing that makes Atlases interesting is that you can use SQL on them and it will just work. TypicalNoSQL stores force you to learn a proprietary query language. It’s a lot easier to be able to use the SQL that you already know, and then to have the output be what you would expect. Even though there’s no specification in SQL for how a NoSQL table should behave, most programmers have an intuitive sense of what should come back. A lot of crazy corner cases have to be handled to accommodate this method of thinking, but because that’s all taken care of on our end (the internals), you don’t have to worry about it at all.


Atlas Data Structure
Sample query
Atlas Data Structure
Multiple renamed columns
Atlas Data Structure
Nested keys
Atlas Data Structure
WHERE clause
Atlas Data Structure
Aggregation, GROUP BY
Atlas Data Structure
Integrated language calculations

3. The third thing that make Atlases special is that the data type is integrated with the language. An Atlas is a first-class data type, just like an int or an array . This means that from inside the language, you can create Atlases, query them, manipulate the results, etc. If you’re querying an old-fashioned database, you need to slurp your results in through the tiny straw of an API. But in Kerf, the language and database are the same, so the code you write works directly on the data. There’s no traversal between a language layer and a database layer. Because the two layers are integrated, so to speak, this means that you can perform “out-of-core” computations without putting special thought into it. It also means that there’s no impact to performance.


Atlas Data Structure
Operate on atlases within the language
Atlas Data Structure
Store and modify selections

4. The fourth thing that makes Atlases special is that they are completely and entirely columnar in order to optimize performance. The index is columnar, the keys are columnar, the values are columnar, everything is columnar. This helps with performance and also with serializing the object.

Because a fewexisting solutions for schemaless data don’t really perform as advertised, we’ve come across several companies who are suffering in silence with irregular data problems they don’t know how to solve. But there is a tool that exists to solve it, called an Atlas, and we package it in Kerf. If you are faced with a problem with a lot of columns, or ragged or irregular columns, or sparse data, or more than one table mixed together, or have just been disappointed in NoSQL in general, you may want to look into Kerf. Contact us for any reason at founders@kerfsoftware.com .

MongoDB 的介绍和使用

$
0
0
MongoDB 介绍

之前学过 SQL Server , mysql , SQLite , 除了 SQL Server 学习过原理之外,其它的也只是学习简单的使用就草草了事了,现在又开始入手 MongoDB 了,其实个人感觉所有的数据库操作起来都基本差不多,并不难学。那么我为什么要学习 MongoDB 呢? 因为我想要存取我爬取的数据,最近在学习 python 爬虫,既然浪费时间爬取了数据,为什么不把它存取到数据库中以供以后使用呢?

MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。 MongoDB 把数据存取到硬盘上,如果你追求较高的速度,你可以选择 Redis 数据库,为什么它快,因为它直接把数据存取到内存中。

好了,不Up嗦了,下面开始安装 MongoDB , 下载地址 , 选择适合自己系统的版本进行下载,下载完毕之后进行安装,由于安装过程比较简单,就不在多介绍 。

如果你把 MongoDB 安装在系统盘,那么我推荐你将其移出来,为什么呢?因为当我在系统盘中开启 MongoDB 的时候出现闪退现象,始终无法正常使用。如果你是 windows 操作系统,那么当你安装完毕之后,你进入 MongoDB 文件夹可能是这样的


MongoDB 的介绍和使用

你会发现自己没有 data 文件夹,这个是我自己创建的,用于存储数据的路径,你可以在任意地方创建它。创建完毕后,我们可以创建一个 Windows 批命令用于启动 MongoDB ,如下所示


MongoDB 的介绍和使用

右击编辑,写入内容

mongod --dbpath F:\MongoDB\Server\3.2\bin/data

注意, dbpath 后面的文件路径就是你将要存取数据的路径,配置好之后,你可以双击该批命令启动 MongoDB ,大家也注意到,由于该批命令使用了 mongod 命令,所以要和 mongod 在同一路径下,但是该路径的层级比较深,如果我们每次启动都要去找它,这未免也太麻烦了吧?所以我建议将批命令的路径写入环境变量,写入之后就可以直接在命令行启动,就像我这样


MongoDB 的介绍和使用

好了,这个时候我们已经启动 MongoDB 了,有的人该想了,就让我用命令行操作吗?这么麻烦?不能搞个可视化工具吗?当然可以,下面我们就来介绍 MongoDB 的可视化工具。

MongoDB 可视化工具

一开始我使用的使 MongoVUE ,但是在使用的过程中出现了问题,插入了数据竟然看不到,我的天,看不到数据我要你何用?然后又瞄上了一个软件 MongoBooster ,用起来非常好用,你可以去官网 http://mongobooster.com 去下载软件,下载完毕以后首先创建一个 Connection ,默认就可以


MongoDB 的介绍和使用

点击 Save & Connect 就可以连接到本地数据库了,不过这个时候只能看到一个名为 local 的数据库。

Python 连接 MongoDB

首先要去 http://www.lfd.uci.edu/~gohlke/pythonlibs 下载支持库 pymongo ,下载完毕后,将解压后的三个文件夹 bson, gridfs, pymongo 复制到 Python 安装目录的 Lib 路径下,然后我们就可以在 Python 中使用 MongoDB 了,如下是一种简单的用法

# coding=utf-8 import pymongo # 连接到 MongoDB 数据库 connection = pymongo.MongoClient() # 创建一个名为 TestDB 的数据库 tdb = connection.TestDB # 创建一个名为 test 的表 post_info = tdb.test # 声明一个字典 person = {'name': 'Jack', 'age': '25', 'tel': '18895330799'} # 将名为 person 的字典存进数据库 post_info.insert_one(person).inserted_id

执行过之后,我们刷新一下 MongoBooster 看一下结果


MongoDB 的介绍和使用

好了,今天就讲到这里,睡觉咯,明天回学校上学去啦。

使用Redis做MyBatis的二级缓存

$
0
0

使用Redis做MyBatis的二级缓存

通常为了减轻数据库的压力,我们会引入缓存。在Dao查询数据库之前,先去缓存中找是否有要找的数据,如果有则用缓存中的数据即可,就不用查询数据库了。如果没有才去数据库中查找。这样就能分担一下数据库的压力。另外,为了让缓存中的数据与数据库同步,我们应该在该数据发生变化的地方加入更新缓存的逻辑代码。这样无形之中增加了工作量,同时也是一种对原有代码的入侵。这对于有着代码洁癖的程序员来说,无疑是一种伤害。

MyBatis框架早就考虑到了这些问题,因此MyBatis提供了自定义的二级缓存概念,方便引入我们自己的缓存机制,而不用更改原有的业务逻辑。下面就让我们了解一下MyBatis的缓存机制。

一、缓存概述

正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持;

一级缓存基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 clo se 之后,该Session中的所有 Cache 就将清空。

二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache、Hazelcast等。

对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

MyBatis 的缓存采用了delegate机制 及 装饰器模式设计,当put、get、remove时,其中会经过多层 delegate cache 处理,其Cache类别有:BaseCache(基础缓存)、EvictionCache(排除算法缓存) 、DecoratorCache(装饰器缓存):

BaseCache :为缓存数据最终存储的处理类,默认为 PerpetualCache,基于Map存储;可自定义存储处理,如基于EhCache、Memcached等;

EvictionCache :当缓存数量达到一定大小后,将通过算法对缓存数据进行清除。默认采用 Lru 算法(LruCache),提供有 fifo 算法(FifoCache)等;

DecoratorCache:缓存put/get处理前后的装饰器,如使用 LoggingCache 输出缓存命中日志信息、使用 SerializedCache 对 Cache的数据 put或get 进行序列化及反序列化处理、当设置flushInterval(默认1/h)后,则使用 ScheduledCache 对缓存数据进行定时刷新等。

一般缓存框架的数据结构基本上都是 Key-Value 方式存储,MyBatis 对于其 Key 的生成采取规则为:

[hashcode : checksum : mappedStementId : offset : limit : executeSql : queryParams]。

对于并发 Read/Write 时缓存数据的同步问题,MyBatis 默认基于 JDK/concurrent中的ReadWriteLock,使用 ReentrantReadWriteLock 的实现,从而通过 Lock 机制防止在并发 Write Cache 过程中线程安全问题

二、源码剖析 2.1 执行流程分析

接下来将结合 MyBatis 序列图进行源码分析。在分析其Cache前,先看看其整个处理过程。


使用Redis做MyBatis的二级缓存

通常我们在service层最终都会调用Mapper的接口方法,实现对数据库的操作,本例中是通过id查询product对象。

我们知道Mapper是一个接口,接口是没有对象的,更不能调用方法了,而我们调用的其实是mybatis框架的mapper动态代理对象MapperProxy,而MapperProxy中有封装了配置信息的DefaultSqlSession中的Configuration。动态代理的具体实现请戳 这里 。调用mapper方法的具体代码如下。


使用Redis做MyBatis的二级缓存

在执行mapperMethod的execute的时候,不仅传递了方法参数,还传递了sqlSession。在执行execute,其实是通过判断配置文件的操作类型,来调用sqlSession的对应方法的。本例中,由于是select,而返回值不是list,所以下一步执行的是sqlSession的selectOne方法具体代码如下:


使用Redis做MyBatis的二级缓存

selectOne其实调用了selectList,只不过是取了第一个。具体代码如下:


使用Redis做MyBatis的二级缓存

selectList经过层层调用,最终交给执行器执行。具体执行器的结构待会我们会分析。注意这里的ms参数,其实就是从Configration中得到的一些配置信息,包括mapper文件里的sql语句。具体代码如下:


使用Redis做MyBatis的二级缓存

这里的执行器execute,其实是spring注入的。excute是一个接口,而到时候具体是哪个execute执行,是看配置文件的。而我们的一级缓存和二级缓存其实都是execute中的一种。接下来,我们遍分析一下执行器(Executor)。

2.2 执行器(Executor)

Executor:执行器接口。也是最终执行数据获取及更新的实例。其结构如下:


使用Redis做MyBatis的二级缓存

BaseExecutor:基础执行器抽象类。实现一些通用方法,如createCacheKey之类的。并采用 模板模式 将具体的数据库操作逻辑交由子类实现。另外,可以看到变量localCache:PerpetualCache,在该类采用perpetualCache实现基于map存储的一级缓存,其query方法如下:


使用Redis做MyBatis的二级缓存

一级缓存和二级缓存很相似,都是实现Cache缓存接口,然后等待调用。其中的一级缓存具体实现其实使用了Map存储,原理非常简单。PerPetualCache具体结构如下:


使用Redis做MyBatis的二级缓存

BatchExcutor、ReuseExcutor、SimpleExcutor:这三个就是简单的继承了BaseExcutor,实现了doQuery、doUpdate等发放,同样都是采用了JDBC对数据库进行操作;三者的区别在于,批量执行、重用Statement执行、普通方法执行。具体应用及长江在mybatis文档上都有详细的说明。

CachingExecutor:二级缓存执行器。其中使用了静态代理模式,当二级缓存中没有数据的时候,就使用BaseExecutor做代理,进行下一步执行。具体代码如下:


使用Redis做MyBatis的二级缓存
2.3 Cache的设计

像之前所说,Cache是一个缓存接口,运行时用到的其实是在解析mapper文件的时候根据配置文件生成的对应Cahce实现类。另外这个实现类的构造过程使用了建造者(Builder)模式。在build的过程中,将所有设计到的cache放入基础缓存中,并使用装饰器模式将cache进行装饰。具体设计如下:

1. 从配置文件中获取节点,将配置信息提取出来初始化生成Cache
使用Redis做MyBatis的二级缓存
2. useNewCache方法中使用了建造者(Builder)模式,将从配置文件中读取出来的各个元素组装起来。其中最主要的是build方法。
使用Redis做MyBatis的二级缓存
3. 在build方法中,值得注意的是使用了装饰器模式,将几个基本的Cache装饰了一下。因为我们的Cache只是加入了自定义的缓存功能和逻辑,日志功能、同步功能等其实并没有。所以需要装饰一下,具体代码如下:
使用Redis做MyBatis的二级缓存
使用Redis做MyBatis的二级缓存
4. 最终的缓存实例对象结构:
使用Redis做MyBatis的二级缓存
2.4 总结

总体上看,我们可以把MyBatis关于缓存的这一部分分为三个部分:

解析器:结合mybatis-spring框架,读取spring关于mybatis的配置文件。具体看是否开启缓存(这里指二级缓存),如果开启,生成的执行器为CachingExecutor。


使用Redis做MyBatis的二级缓存
使用Redis做MyBatis的二级缓存

动态代理:实现调用mapper接口的时候执行mybatis逻辑

执行器:执行缓存处理逻辑。在这里二级缓存和一级缓存有所区别。

三、具体实现 3.1 配置文件

开启缓存:修改spring中关于mybatis的配置文件,将cacheEnabled设置为true。


使用Redis做MyBatis的二级缓存

添加实现Cache接口的实现类。重写方法会在查询数据库前后调用,查询、更新、删除、创建缓存需要在这几个方法中实现。值得注意的是,getObject方法,当返回的是null时,就会接着查询。如果不为null,则返回,不再查询了。

/**

* 使用redis做mybatis二级缓存

* @Description

* @file_name MyBatisRedisCache.java

* @time 2016-07-26 下午4:49:13

* @author muxiaocao

*/

public class MyBatisRedisCache implements Cache{

@Value("#{config['redis.ip']}")

protected String redisIp;

@Value("#{config['redis.port']}")

protected Integer redisPort;

private static Log logger = LogFactory.getLog(MyBatisRedisCache.class);

private Jedis redisClient = createClient();

private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

private String id;

public MyBatisRedisCache(final String id) {

if (id == null) {

throw new IllegalArgumentException("缓存没有初始化id");

}

logger.debug("==================MyBatisRedisCache:id=" + id);

this.id = id;

}

@Override

public String getId() {

return this.id;

}

@Override

public int getSize() {

return Integer.valueOf(redisClient.dbSize().toString());

}

@Override

public void putObject(Object key, Object value) {

logger.debug("==================pubObject:" + key + "=" + value);

redisClient.set(SerializeUtil.serialize(key),SerializeUtil.serialize(value));

}

@Override

public Object getObject(Object key) {

Object value = SerializeUtil.unserialize(redisClient.get(SerializeUtil.serialize(key.toString())));

logger.debug("==================getObjec:" + key + "=" + value);

return value;

}

@Override

public Object removeObject(Object k

快照技术原理

$
0
0

一、概念解释

像照相机一样,机器快门一闪,很快就把刚刚的人像停留在了相纸上。存储系统中的数据“快照”与我们生活中所说的“照片”非常相似,所不同的是,照片的对象不是人,而是数据。如同照片留住了我们过去的摸样和岁月,快照把数据在某一时刻的映像也保留了下来。因此我们可以根据快照查找数据在过去某一时刻的映像,常常用来作为增强数据备份系统的一种技术,它可以很大的缩短RTO和RPO两个指标。【一般而言,凡论及灾备方案,都以RTO及RPO作为最基本的标准。RTO (Recovery Time Objective,复原时间目标)是企业可容许服务中断的时间长度。比如说灾难发生后半天内便需要恢复,RTO值就是十二小时;RPO (Recovery Point Objective,复原点目标)是指当服务恢复后,恢复得来的数据所对应时的间点。如果现时企业每天凌晨零时进行备份一次,当服务恢复后,系统内储存的只会是最近灾难发生前那个凌晨零时的资料。】

SNIA(存储网络行业协会)对快照(Snapshot)的定义是:关于指定数据集合的一个完全可用拷贝,该拷贝包括相应数据在某个时间点(拷贝开始的时间点)的映像。快照可以是其所表示的数据的一个副本,也可以是数据的一个复制品。而从具体的技术细节来讲,快照是指向保存在存储设备中的数据的引用标记或指针。

磁盘快照(Snapshot)是针对整个磁盘卷册进行快速的档案系统备份,与其它备份方式最主要的不同点在于「速度」。进行磁盘快照时,并不牵涉到任何档案复制动作。就算数据量再大,一般来说,通常可以在一秒之内完成备份动作。

磁盘快照的基本概念与磁带备份等机制有非常大的不同。在建立磁盘快照时,并不需要复制数据本身,它所作的只是通知LX Series NAS服务器(NAS服务器简单的说,就是一种特殊的文件服务器,它基专用硬件设备上,拥有高性能的处理器并安装特殊操作系统。)将目前有数据的磁盘区块全部保留起来,不被覆写。这个通知动作只需花费极短的时间。接下来的档案修改或任何新增、删除动作,均不会覆写原本数据所在的磁盘区块,而是将修改部分写入其它可用的磁盘区块中。所以可以说,数据复制,或者说数据备份,是在平常档案存取时就做好了,而且对效能影响极低。LX Series NAS档案系统内部会建立一份数据结构,纪录磁盘快照备份及目前作用中档案系统所使用到的磁盘区块及指针,让使用者可以同时存取到主要档案系统及过去的磁盘快照版本。

二、快照技术类型

快照技术的作用:主要是能够进行在线数据恢复,当存储设备发生应用故障或者文件损坏时可以进行及时数据恢复,将数据恢复成快照产生时间点的状态。快照的另一个作用是为存储用户提供了另外一个数据访问通道,当原数据进行在线应用处理时,用户可以访问快照数据,还可以利用快照进行测试等工作。  因此,所有存储系统,不论高中低端,只要应用于在线系统,那么快照就成为一个不可或缺的功能。创建一个快照不同的设备需要不同的命令,但对于系统来说,基本都包括如下几个步骤:

1、首先发起创建指令;

2、在发起时间点,指令通知操作系统暂停应用程序和文件系统的操作;

3、刷新文件系统缓存,结束所有的读写事务;

4、创建快照点;

5、创建完成之后,释放文件系统和应用程序,系统恢复正常运行。

现在,快照技术已经超越了简单的数据保护范畴。我们可以用快照进行高效且无风险的应用软件测试。用快照数据做测试,不会对生产数据造成任何的破坏。对于数据挖掘(data mining)和电子发现(eDiscovery)应用,快照也是理想的测试数据源。在灾难恢复方面,快照是一种非常有效的方法——甚至是首选,非常适合遭到恶意软件攻击、人为误操作和数据损坏等逻辑错误发生时的数据恢复。过去我们认为只有磁盘阵列具备快照功能,但事实上磁盘阵列只是其中之一而已。广义的快照技术通常可有7个不同类型的实现主体:

1、主机文件系统(包括服务器、台式机、笔记本电脑);

2、逻辑卷管理器(LVM);

3、网络附加存储系统(NAS);

4、磁盘阵列;

5、存储虚拟化设备;

6、主机虚拟化管理程序;

7、数据库。

下面将逐项介绍一下在各个系统中快照技术的应用,并对其进行详细的说明。

1、基于文件系统的快照

很多文件系统都支持快照功能,微软的windows NTFS有VSS卷影拷贝服务(Volume Shadow Copy Services, Vista称作Shadow Copy);Sun Solaris的最新文件系统ZFS(Zettabyte File System);Apple公司的Mac OS X 10.6(雪豹);Novell NetWare 4.11(或更高版本)的Novell Storage Services (NSS) ; Novell SUSE linux操作系统下的OES-Linux等等。

“免费”是文件系统快照的优势之一,因为它集成在文件系统内部;另一个优点是非常好用,最新版文件系统的快照功能通常使用起来很简单。不利的一方面是,每个文件系统都必须独立进行管理,当系统数量激增时,管理工作会变得非常繁重。想象一下,如果我们要做快照复制的话,需要给每一个文件系统都配置一套复制关系,而且还只能复制该文件系统自己的快照。此外,不同文件系统所提供的快照种类、快照频率、预留空间等参数也可能不一样,当然也包括设置、操作和管理上的差异。总之,需要管理的服务器和文件系统越多,复杂程度就越高。

2、基于LVM(逻辑卷管理器)的快照

带有快照功能的LVM也很多,比如惠普HP-UX操作系统的 Logical Volume Manager;Linux平台的Logical Volume Manager 和Enterprise Volume Management System系统 ;微软Windows 2000及后续版本自带的Logical Disk Manager系统;SUN Solaris 10操作系统的ZFS;以及赛门铁克公司的Veritas Volume Manager(注:Veritas Volume Manager是赛门铁克Veritas Storage Foundation产品的一部分)。

我们可以创建跨多个文件系统的LVM快照。像赛门铁克的Veritas Volume Manager可以支持大多数常见的操作系统和文件系统。LVM通常还包括存储多路径和存储虚拟化等功能。

使用LVM时,通常要付出额外的成本,包括为每台服务器购买license(许可证)和维护费。而且,像基于文件系统的快照一样,我们可能还要面对系统之间的协调问题和复杂的技术实施问题。

3、基于NAS的快照

NAS本质上就是一个经过优化的、或是专门定制的文件系统,运行在特定的设备上,或集成在存储设备里。大多数中端和企业级NAS系统都提供快照功能,其中既有使用专有操作系统的设备,也包括大量基于Microsoft Windows Storage Server软件的各种NAS。

通过网络连接到NAS的计算机系统都可以使用这种标准的通用快照,包括物理服务器、虚拟机、台式机和笔记本电脑。它也非常容易操作和管理。基于NAS的快照往往同Windows Volume Shadow Copy Services(卷影复制服务VSS)、备份服务器和备份Agent等软件集成在一起使用。一些NAS厂商还为非Windows平台的数据应用系统开发了Agent代理程序。其他一些与NAS快照有关的技术还包括重复数据删除(EMC公司,FalconStor软件公司和NetApp的产品),有些厂商甚至提供了带有自动精简配置功能的快照,目的是让快照占用的空间变得更少。

但是,使用便利的工具和附加功能也需要成本,软件license和维护费相当昂贵,一般是按照机器数量和磁盘卷容量来计算。大多数公司的数据量增长很快,需要使用NAS快照的地方也越来越多,因此,操作和管理也将更复杂。

4、基于磁盘阵列的快照

大多数磁盘阵列的软件系统里都含有快照功能。基于磁盘阵列的快照与基于NAS的快照有非常相似的优点,即所有与磁盘阵列相连的计算机系统都可以使用这种标准的通用快照功能,包括物理服务器、虚拟机、台式机和笔记本电脑等等。快照的实施、操作和管理也都很简单。像NAS一样,很多磁盘阵列的快照功能也可以被Windows VSS、备份服务器和备份Agent等软件直接调用。一些磁盘阵列厂商还有可供非Windows平台应用系统使用的Agent代理程序。

基于磁盘阵列的快照也有一些缺点:license和维护费用昂贵;对非Windows平台的应用程序支持有限;磁盘阵列的数量越多,快照的管理也就越复杂。

5、基于存储虚拟化设备的快照

这里所说的存储虚拟化设备主要用于SAN光纤网络环境,不同于基于文件(NFS)应用的网络设备,像F5 Network公司的Acopia ARX产品就是排除在这个范畴之外的。主要的存储虚拟化软硬件设备(或融合了虚拟化功能的存储系统)包括:Cloverleaf Communication公司的Intelligent Storage Networking System (iSN);DataCore Software公司的 SANsymphony和SANmelody;EMC的Celerra Gateway blades;FalconStor公司的IPStor;HP的XP系列存储;HDS的Universal Storage Platform V/VM;IBM的SAN Volume Controller;LSI的StoreAge Storage Virtualization Manager (SVM)以及NetApp的V-Series storage controllers等等。

磁盘阵列和NAS快照所具备的优点在存储虚拟化设备上同样能够体现,而且某些方面还能做的更好。我们可以将来自不同厂商的很多存储设备聚集在少量的几个控制点或单一控制点上进行管理,提供通用的标准化快照。这样做最大程度的简化了快照的管理操作成本和学习成本。

存储虚拟化快照的缺点与上述类型相比则有些不同。使用存储虚拟化设备会导致I/O延迟的增加,即使是采用旁路架构的设计,最终还是会影响应用程序的响应时间。增加存储虚拟化设备还会使故障分析变得更加困难,潜在的还可能激化厂商之间对故障责任的推诿。从另一个角度看,虽然增加额外的虚拟化存储硬件或软件要产生一定的费用,但是与每个存储系统都独立购买快照功能相比,它的软件license和维护费用都要低一些。

6、基于主机虚拟化软件的快照

随着服务器虚拟化应用的普及,基于主机虚拟化管理软件(hypervisor)的快照技术也逐渐流行起来。像Citrix公司的 XenServer、微软的Hyper – V、SUN的xVM Ops Center、以及VMware的ESX和vSphere4等主机虚拟化产品都支持快照功能。

在主机虚拟化软件层实现快照的优点是简单直接。由于同虚拟机管理软件绑定在一起,因此可以为所有的虚拟机 (VMs) 提供统一的快照,并且还可以同微软的VSS集成,随时调用。相对而言,基于虚拟机的快照很容易部署、使用和管理。

但是,如果非要找出不喜欢这种快照的理由?我想应该是每一套虚拟机软件的快照需要单独管理;而且当我们在非Windows平台下使用这种快照技术时,必须针对整个VM。这意味着我们只能做粗粒度的数据恢复,还要消耗更多的恢复时间。这种快照是在Windows操作系统外部创建,所以它不能架构在应用软件感知的层面,导致快照出来的映像数据有可能是不一致状态。

7、基于数据库的快照

在数据库中,快照动作被称为“snapshot isolation(快照隔离)”。像Oracle和PostgreSQL这样的数据库需要做快照隔离以确保所有的交易命令序列化,就好像被一个个隔开一样,然后再逐个执行。其他的一些数据库也支持快照隔离,但并不要求将交易序列化。在一般情况下,数据库备份工具会利用快照隔离的功能,用快照来恢复崩溃(出现一致性问题)的数据表。

针对数据库内部数据和基于该数据库的相关应用,使用数据库自带的快照比较有效。

相反,数据库快照的重要缺欠就是覆盖的范围非常有限,其作用仅限于特定的数据库内部和数据库相关的应用,无法管理同在一台服务器上的文件系统、文件类应用或其他数据库,更不用说管理到其他的服务器了。有时候我们不得不通过其他层次的快照技术来解决数据库之外的数据保护问题,这样,操作和管理将变得有些复杂。

不同类型的快照及工作原理

通常,我们会提到6种类型的快照技术:

1、Copy-on-write 复制写

2、Redirect-on-write 重定向写

3、Clone or split mirror 克隆或镜像

4、Copy-on-write with background copy后台拷贝的复制写

5、Incremental 增量快照

6、Continuous data protection 持续数据保护

复制写和重定向写快照

Copy-on-write (COW) 复制写快照

COW快照需要消耗一些存储空间–建立快照卷。当我们为一个数据卷创建一个快照之后,这些预留的空间用来存放被变化数据更新的旧数据。COW快照在初始化的过程中仅仅创建用来描述源数据块位置的指针信息(元数据),而不是完整的将源数据块拷贝过来。因此初始化的过程几乎可以在瞬间完成,对系统的影响也很小。

COW快照会跟踪数据卷的写操作和数据块变化。当某个数据块发生改变时,在将旧的数据覆盖之前,首先将该块的旧数据复制到预留的快照卷,该步骤仅在数据卷相应数据块位置发生第一次写操作请求时进行。这个处理过程确保快照出来的数据与发起快照的那个精确时间点保持完全一致。这个过程也描述了“copy on write”这个名字的含义。

如果我们需要访问某个时间点的快照数据,对没有改变过的块直接从数据卷读取;对已经改变并被复制的块则从快照空间读取。从快照被创建那一刻开始,每个快照都会跟踪记录描述块改变的元数据信息。

COW快照的主要优势在于空间的高效利用,因为快照卷只需要保留发生过变化的数据块,与数据卷相比要小得多。但是我们也知道COW快照有个缺点,它会引起数据卷性能的下降,这是因为创建快照之后,对数据卷的写操作会增加一个等待的过程 –即旧数据块复制到快照卷的过程。另外一个关键问题是每个快照卷必须依赖一个完整的数据卷。

Redirect-on-write (ROW) 重定向写快照

“ROW重定向写”与“COW复制写”是相对的概念,它可以避免两次写操作引起的性能损失。ROW同COW一样在空间利用方面效率非常高。那是什么让ROW快照避免了写性能的损耗?其中的原因是ROW把对数据卷的写请求重定向给了快照预留的存储空间,而写操作的重定向设计则把需要两次写才能完成的操作减少为一次写。我们知道COW的两次写包括:1、将旧数据写入快照卷;2、在数据卷写入新数据。而ROW只有写入新数据一步。

使用ROW快照,数据卷存放的是上一个快照时间点的旧数据,新数据最终存放在预留的快照空间。这里也有一个复杂的问题,就是快照的删除。被删除的快照上的数据必须被复制到原始数据卷,并且做一致性回退。创建的快照越多,维护快照的复杂度也会以指数级别上升。这些复杂性包括对原始数据的访问、快照数据和原始数据卷的跟踪、以及快照删除后的数据调整。另一个直接引发的严重问题是,原始数据集中会产生大量的碎片。

克隆或分割镜像快照与后台拷贝的复制写快照

Clone or split-mirror 克隆或分割镜像快照

Clone(或split-mirror)快照所创建的是数据的完整副本。Clone(或split-mirror)快照的对象可以是一个存储卷、一个文件系统或者是一个LUN(logical unit number 逻辑单元号)。Clone快照的优点是它们具有高可用性;缺点是所有的数据都要完整的复制一份,复制的过程也不可能在瞬间完成。我们可以分割一对保持同步状态的镜像卷来启用Clone快照,分割的过程瞬间即可完成。然而,当镜像被分割成Clone快照之后,数据卷也就失去了他的同步镜像。

使用Clone快照需要面对的一个非常严重的问题是每个快照都需要和数据卷一样大的存储空间。尤其是当我们在任何时刻都需要保持一份以上Clone卷的情况,这个成本会非常高。另一个缺点是影响性能,因为在镜像卷之间保持写同步需要一定的系统开销。

Copy-on-write with background copy 后台拷贝的复制写快照

Copy-on-write with background copy快照有两个生成步骤:首先创建一个瞬时即可生成的COW快照;然后利用后台进程将数据卷的数据复制到快照空间,最后生成一份数据卷的克隆或镜像。

创建这种快照的目的是发挥COW快照的优势,同时尽量屏蔽它的不足。因此,这种快照常常被形容为COW和Clone快照的混合体。

增量快照与持续数据保护

(Incremental)增量快照

增量快照的特点是可以跟踪数据卷和快照卷的变化。当一个新的增量快照生成之后,旧的快照数据将被刷新。第一个快照和随后创建的每一个增量快照数据上都有时间戳标记,利用时间戳我们能够将快照数据回滚到任意的一个时间点。增量快照技术能够加快后续快照的生成速度,而且仅仅在名义上多消耗了一点空间而已。由此,我们可以提高创建快照的频率,也能让快照保留得更久一点。

增量快照的不足之处是它需要依靠上面所提到的其他基础技术来创建第一个快照 (COW、ROW、clone/split mirror、copy-on-write with background copy) 。如果用Clone方式,那么第一个快照需要较长的初始化时间;如果用COW方式,数据卷的性能会降低。

持续数据保护(CDP)

CDP的出现是为了实现零数据丢失的RPO指标,以及瞬时数据恢复的RTO指标。它本身与同步数据镜像很类似,不同之处在于CDP还可以对软性灾难进行恢复。包括人为误操作、恶意软件攻击、意外删除、数据损坏等情况。

持续数据保护颇像频率很高的增量快照。它会捕获并复制任何时刻发生的数据变化,并且给这些数据块打上时间戳。CDP本质上相当于每个时刻都创建一份增量快照,提供细粒度的精确数据恢复。有些CDP产品同时提供基于时间和基于事件(例如应用程序升级事件)两种粒度的恢复方式。还有一个理解CDP概念的好方法就是将它看成一个快照的journal日志。

对于邮件系统、数据库和基于数据库的应用来说,CDP是一个极好的保护方案,能将数据回滚到任意的历史时间点,恢复过程也简便、迅速。最有代表性的CDP产品是飞康公司的IPStor,它是一个集成了CDP功能的存储系统兼存储虚拟化设备。

随着越来越多的数据需要保护,备份窗口也变得越来越紧张,因此需要快照技术来帮助我们解决备份问题。在现实的应用环境中,快照利用的是否恰当对数据保护的等级和恢复的速度有着很大的影响。尽管各类型快照之间存在的技术差异不太容易理解,但无论如何,快照技术都将在数据保护领域和日常存储管理中扮演重要的角色。

三、特别注意:快照的一致性问题

如果用快照来处理结构化数据,可能会存在一些问题。结构化数据涉及到数据库,以及数据库类应用(例如邮件系统、ERP或CRM等等)。许多产品中的快照并不能与这些应用程序集成或被直接调用。有一种可能的情况是,在我们创建快照的瞬间,数据库恰好不在静止状态(缓存正在刷新、写操作事务尚未完成、索引和元数据正在更新等等),此刻生成的快照数据是不一致的,很有可能无法正常使用。

在微软的Windows Server平台上,这个问题要简单得多,利用Windows Volume Shadow Copy Services (VSS)和它的API,数据库应用程序可以集成并调用快照工具。VSS是专门为结构化数据应用设计的服务框架,可以驱动数据库等应用进入数据一致性的静止状态,在快照开始初始化之前,完成刷新缓存、结束写操作以及系统状态的更新。

遗憾的是,目前在Linux和Unix操作系统平台上还没有类似VSS的服务或API。VMware公司的vCenter storage API可以说是一个部分解决方案。快照的发起者可以通过vCenter storage API给vCenter发出一个指令,让虚拟机进入静止状态,然后再执行快照。但这个时候,快照由于没有通过应用程序感知,也许会存在不一致的问题。

这里还有一个好办法,可以不通过Windows VSS,获得数据库的一致性快照。这个办法需要备份软件的配合。将快照的API同备份软件集成,就可以从备份服务器端驱动备份软件的数据库代理Agent。Agent备份代理程序可以驱动数据库进入静止状态,然后反向让备份服务器通知快照工具开始执行创建快照的操作。这也是一个比较有效的办法。

四、快照技术使用方法

具体使用快照时,存储管理员可以有三种形式,即冷快照拷贝、暖快照拷贝和热快照拷贝。

冷快照拷贝:进行冷快照拷贝是保证系统可以被完全恢复的最安全的方式。在进行任何大的配置变化或维护过程之前和之后,一般都需要进行冷拷贝,以保证完全的恢复原状(rollback)。冷拷贝还可以与克隆技术相结合复制整个服务器系统,以实现各种目的,如扩展、制作生产系统的复本供测试/开发之用以及向二层存储迁移。

暖快照拷贝:暖快照拷贝利用服务器的挂起功能。当执行挂起行动时,程序计数器被停止,所有的活动内存都被保存在引导硬盘所在的文件系统中的一个临时文件(.vmss文件)中,并且暂停服务器应用。在这个时间点上,复制整个服务器(包括内存内容文件和所有的LUN以及相关的活动文件系统)的快照拷贝。在这个拷贝中,机器和所有的数据将被冻结在完成挂起操作时的处理点上。

当快照操作完成时,服务器可以被重新启动,在挂起行动开始的点上恢复运行。应用程序和服务器过程将从同一时间点上恢复运行。从表面上看,就好像在快照活动期间按下了一个暂停键一样。对于服务器的网络客户机看来,就好像网络服务暂时中断了一下一样。对于适度加载的服务器来说,这段时间通常在30到120秒。

热快照拷贝:在这种状态下,发生的所有的写操作都立即应用在一个虚拟硬盘上,系统的文件以保持高度的一致性。服务器提供让持续的虚拟硬盘处于热备份模式的工具,以通过添加REDO日志文件在硬盘子系统层上复制快照拷贝。

一旦REDO日志被激活,复制包含服务器文件系统的LUN的快照是安全的。在快照操作完成后,可以发出另一个命令,这个命令将REDO日志处理提交给下面的虚拟硬盘文件。当提交活动完成时,所有的日志项都将被应用,REDO文件将被删除。在执行这个操作过程中,会出现处理速度的略微下降,不过所有的操作将继续执行。但是,在多数情况下,快照进程几乎是瞬间完成的,REDO的创建和提交之间的时间非常短。热快照操作过程从表面上看基本上察觉不到服务器速度下降。在最差情况下,它看起来就是网络拥塞或超载的CPU可能造成的一般服务器速度下降。在最好情况下,不会出现可察觉到的影响。

五、快照与镜像、复制的区别

镜像、快照和复制是三种不同的功能

镜像是通过从一个I/O创建两个I/O来复制数据。磁盘镜像通过OS或卷管理软件在主系统上创建。磁盘镜像是依靠平台和本地连接特性的本地选件。镜像可用于DAS和SAN并且大多数NAS支持它。存储转发式镜像磁盘子系统(例如,EMC SRDF, IBM PPRC, Hitachi TrueCopy)主要用于SAN产品。  复制是通过网络传输数据对象(文件、表格等)。传输是从系统到系统进行的,而不是在存储设备之间或子系统之间进行。复制一般也针对具体平台,因此用于Windows 2000复制产品的运行方式与Unix平台存在很大不同。

ASP.NET基础与入门:WebForm,事件驱动编程,Page类

$
0
0

注:因为这个暑假做了一个ASP.NET的项目(WebForms模式),暑假期间太忙没有来得及整理,现在统一梳理下知识(有些我认为可以跟HTML共通的就没记)

推荐几个学习ASP.NET的网站:

W3School
菜鸟教程

书的话。。因为当时项目太紧张。直接动手实战,有不会的直接在上面两个网站查询的。

当时我入门看的书有:

ASP.NET 1.1入门经典-Visual C#.NET 2003编程篇
ASP.NET 3.5 从入门到精通(C#2008版)<—-强推

—–那么,开始ASP.NET学习之旅吧~—–

ASP.NET

ASP.NET 是一个使用 HTML、CSS、javascript 和服务器脚本(在服务器上运行的语言)创建网页和网站的开发框架。

ASP.NET 支持三种不同的开发模式:

Web Pages(Web 页面)

MVC(Model View Controller 模型-视图-控制器)

Web Forms(Web 窗体)


ASP.NET基础与入门:WebForm,事件驱动编程,Page类
ASP.NET简介
ASP.NET 是新一代的 ASP。它无法兼容经典 ASP,但 ASP.NET 可以引用 ASP。
ASP.NET 页面需要编译,因此比经典 ASP 更快。
ASP.NET 拥有更好的语言支持,大量用户控件,基于 XML 的组件,以及对用户认证的整合。
ASP.NET 页面的扩展名是 .aspx,通常由 VB (Visual Basic) 或 C# (C sharp) 编写。
ASP.NET 中的用户控件可以通过不同的语言进行编写,包括 C++ 和 Java。
ASP.NET 文件
ASP.NET 文件类似 HTML 文件
ASP.NET 文件可以包含 HTML、XML 以及脚本
ASP.NET 文件中的脚本在服务器上执行
ASP.NET 文件的文件后缀是 “.aspx”
ASP.NET文件扩展名
ASP 文件的文件扩展名是 .asp ASP.NET 文件的文件扩展名是 .aspx ASP.NET 文件使用 C# 语法的文件扩展名是 .cshtml ASP.NET 文件使用 Razor VB 语法的文件扩展名是 .vbhtml
ASP.NET 如何工作
当浏览器请求 HTML 文件时,服务器会返回该文件当浏览器请求 ASP.NET 文件时,IIS 会把该请求传递给服务器上的 ASP.NET 引擎 ASP.NET 引擎会逐行地读取该文件,并执行文件中的脚本 最后,ASP.NET 文件会以纯 HTML 的形式返回浏览器
从根本上讲,ASP.NET 页面与 HTML 完全相同。
HTML 页面的扩展名是 .htm 或 .html。假如浏览器从服务器请求某张 HTML 页面,服务器不进行任何修改,就会把该页面发往浏览器。

ASP.NET 页面的扩展名是 .aspx。如果浏览器请求某张 ASP.NET 页面,那么在把结果发回浏览器之前,服务器首先会处理页面中的可执行代码。

ASP.NET中的
标记

ASP.NET有一组窗体控件,它们的使用与HTML窗体控件相同,两者的主要区别是服务器控件是在请求时在服务器上动态形成的,然后再发送出去。

ASP.NET版本只需要几个字符的编码,如下所示:


...ASP.NET form...

这个

标记只使用了一个属性,即runant=”server”。该属性告知Web服务器应该处理窗体本身,而不是只将它传送到浏览器。所有ASP.NET窗体都用POST方法传送。
标记允许在服务器上处理窗体控件(例如复选框和下拉列表)。ASP.NET对这些控件进行了自定义。

使用ASP.NET窗体控件有几个优点:

.NET会自动创建和维护状态,允许用户了解请求窗体的人是否就是请求另一个页面的人 ASP.NET提供了一些非常复杂的控件,包括日历控件和栅格控件,来显示数据控件的内容可以从数据库或商务逻辑中生成用户输入到控件中的信息可以进行有效性检查,避免输入错误
WebForm简介
传统的 ASP.NET 事件驱动开发模型。
添加了服务器控件、服务器事件以及服务器代码的网页。
WebForm控件

WebForm中的控件,其实就是服务器控件。带有runat=”server” 属性,必须在服务器进行处理(如果不进行处理,则会报错)

服务器控件是可被服务器理解的标签。

有三种类型的服务器控件:

HTML 服务器控件 - 传统的 HTML 标签 Web 服务器控件 - 新的 ASP.NET 标签 Validation 服务器控件 - 用于输入验证
aspnet-html-服务器控件">ASP.NET - HTML 服务器控件

HTML 服务器控件是服务器可理解的 HTML 标签。

ASP.NET 中的 HTML 元素是作为文本来进行处理的。要想使这些元素可编程,就需要向这些 HTML 元素添加 runat=”server” 属性。该属性指示,此元素是一个服务器控件。同时要添加 id 属性来标识该服务器控件。该 id 引用可用于操作运行时的服务器控件。

注释:所有 HTML 服务器控件必须位于带有 runat=”server” 属性的 标签内。runat=”server” 属性指示该表单应在服务器进行处理。它同时指示其包括在内的控件可被服务器脚本访问。

以下给出最常用的ASP.NET服务器控件,并与以前使用的HTML窗体标记符进行比较:


ASP.NET 服务器控件
对应的HTML窗体标记符
作用
,
,简单文本
显示文本
为用户提供一个选项列表,让用户从中选择
以紧凑的方式为用户提供一个选项列表,让用户从中选择
用户输入的可选择内容

允许用户从一个选项列表中做出选择

允许用户打开或关闭一个功能
把用户的输入发送到服务器
ASP.NET - Web 服务器控件

Web 服务器控件是服务器可理解的特殊 ASP.NET 标签。

类似 HTML 服务器控件,Web 服务器控件也在服务器上创建,它们同样需要 runat=”server” 属性以使其生效。不过,Web 服务器控件没有必要映射任何已存在的 HTML 元素,它们代表更复杂的元素。

创建 Web 服务器控件的语法是:
在下面的例子中,我们在 .aspx 文件中的声明了一个 Button 服务器控件。然后我们为 Click 事件创建了一个事件处理程序,它可修改按钮上的文本:
<script runat="server">
Sub submit(Source As Object, e As EventArgs)
button1.Text="You clicked me!"
End Sub
</script>
ASP.NET - Validation 服务器控件

Validation 服务器控件用于验证用户输入。如果用户输入没有通过验证,将向用户显示一条错误消息。

每种 validation 控件执行一种特定的验证类型(比如验证某个具体的值或者某个范围的值)。

默认地,当点击Button, ImageButton或LinkButton 时,就会执行页面验证。您可通过把 CausesValidation 属性设置为 false,来阻止某个按钮控件被点击时进行验证。

创建 Validation 服务器控件的语法是:
在下面的例子中,我们在 .aspx 文件中声明了一个 TextBox 控件,一个 Button 控件,以及一个 RangeValidator 控件。如果验证失败,文本 “The value must be from 1 to 100!” 将显示在 RangeValidator 控件中:
Enter a number from 1 to 100:
Page类

每一个Web页面实际上都是一个继承自System.Web.UI.Page类的用户自定义的类。通过从Page基类继承,Web页面获得了大量的属性和方法,以供程序员在代码使用。

这些继承的特性包括了允许缓存功能、验证以及跟踪调试等。

以下简要的列出了Page类一些重要的基本属性


属性
描述
IsPostBack
IsPostBack是一个布尔值。当IsPostBack属性为false时,表示该页面是第一次被当前用户请求;当IsPostBack属性为true时,表示该页面是响应控件事件而提交的回传请求,此时页面通常在视图状态中保存了页面的相关信息。在页面的Page.Load事件处理方法中,通常检查IsPostBack属性,以判断页面是第一次被当前用户请求还是回传请求,以确保用于初始化Web页面的代码只被执行一次
EnableViewState
该值只是当前页请求结束时,该页是否保持其视图状态,以及是否保持它包含的每一个服务器控件的视图状态。当把Web页面的EnableViewState属性设置为false时,将覆盖页面中所包含的所有控件的EnableViewState属性,此时页面上的所有控件都不能维护控件的状态信息
Application
Application属性是一个保存应用程序级别信息的集合,该集合用于保存当前Web网站中所有被用户共享的信息。例如,可以使用Application集合来记录页面被访问的次数
Session
Session属性是一个保存单个用户会话信息的集合,会话信息可以在不同的多个页面之间共享。例如,在一个电子商务的网站中,可以使用Session集合来保存当前用户的购物车
Cathe
Cathe属性是一个集合,用于保存那些在创建时比较耗费时间的对象,以便在其他用户访问页面时或在其他页面中快速地重用这些对象。适当的使用该技术可以有效提高Web页面的执行性能。
Request
Request属性是一个对当前页面的HttpRequest对象的引用,其中包含了当前Web请求的相关信心。通过HttpRequest对象,可以获得发起请求的客户端浏览器的详细信息,ASP.NET可以自己处理这些细节信息,因而获取这些浏览器详细信息的意义不大。但是,可以使用HttpRequest对象,通过使用查询字符(query string),将信息从一个页面传递给另一个页面。
Response
Response属性是一个对当前页面的HttpResponse对象的引用,它表示ASP.NET将要发送给客户端浏览器的响应。
Server
Server属性是一个队当前页面的HttpServerUtility对象的引用,通过该对象可以执行一些杂项的任务,比如,可以对字符串进行编码,以便这些字符串可以安全的存放在URL中
User
如果访问网站的用户已经通过了验证,则User属性被初始化为当前用户的信息
事件驱动编程与回送
事件驱动编程从本质上改变了编程模型。
利用事件,服务器上不再是以顺序执行的方式完成任务。

代码的执行顺序取决于与用户的交互。

ASP.NET支持三组事件

第一组是HTML内部的事件,这些事件可以在页面上发生,并由浏览器在客户端处理。例如:在客户端JavaScripts中运行的弹出工具提示。

第二组是ASP.NET生成页面时自动发生的几个事件(ASP.NET页面级事件)。它们不需要用户干涉,在用户看到页面之前发生,我们使用这些事件建立页面。特别重要的页面级事件是postback,在用户单击提交按钮后,页面重新提交给服务器时触发。

最后一组最大,包含用户与页面交互时发生的所有事件。

HTML事件

例:鼠标点击事件


ASP.NET的页面事件

ASP.NET中的一切元素均可归结为对象,特别是page对象。用户创建的每一个Web窗体都是一个page对象。可以将整个Web窗体看成是一个输出为HTML的可执行程序。每当访问服务器时都会经历这些阶段。

在请求ASP.NET Web窗体时,在Web服务器上就会自动发生一系列事件,如下所示:

Page_Init()事件

当初始化页面时发生此事件。可以利用 Page_Init()将该事件与要在.NET在页面上显示控件之前运行的代码建立关联。该事件与Page_Load事件的工作方式相同,但在Page_Load事件之前发生。

如果希望页面上的代码在其他事件发生之前执行,就需要把它们放在Page_Init()事件处理过程中。

Page_PreRender() 事件和Page_Render()

支持高级论题,如事务处理。

Page_Load()事件

当整个页面第一次可见时发生(即在页面被读入内存,进行处理时发生),但在利用Page_Init实现某些服务器控件的初始化并显示出这些控件之后发生。

页面加载事件会自动调用Page_Load()事件处理过程。

Page.IsPostBack 属性
Page_Load 子例程会在页面每次加载时运行。
如果您仅希望在页面第一次加载时执行 Page_Load 子例程中的代码,您可以使用 Page.IsPostBack 属性。如果 Page.IsPostBack 属性为 false,则页面第一次被载入,如果为 true,则页面传回服务器(例如,通过点击表单上的按钮):
<script runat="server">
Sub Page_Load
if Not Page.IsPostBack then
lbl1.Text="The date and time is " & now()
end if
End Sub
Sub Submit(s As Object, e As EventArgs)
lbl2.Text="Hello World!"
End Sub
</script>

上面的例子仅在页面初次加载时创建 “The date and time is….” 这条消息。当用户点击 Submit 按钮时,submit 子例程将在第二个 label 创建 “Hello World!”,但第一个 label 中的日期和时间不会改变。

Page_Unload()事件

页面从IIS内存中卸载并发送给浏览器时发生。在控件事件处理后发生。改事件非常适用于关闭数据库的连接。其名称容易产生误导,因为这个事件并不是浏览器中的用户退出页面或关闭浏览器时发生。术语Unload是从IIS的角度来看的,而不是浏览器。

该事件最适合于结束资源的适用,例如关闭数据库连接。由于Page_Unload()事件是在ASP.NET页面的其他内容完成后执行,所以不能适用他来改变ASP.NET控件。

常见的等待事件(一)

$
0
0

一、Buffer busy waits

从本质上讲,这个等待事件的产生仅说明了一个会话在等待一个Buffer(数据块),但是导致这个现象的原因却是有很多种,常见的两种是:

(1)当一个会话试图修改一个数据块,但这个数据块正在被另一个会话修改时。

(2)当一个会话需要读取一个数据块,但这个数据块正在被另一个会话读取到内存中时。

Oracle操作的最小单位是块(Block),即使你要修改一条记录,也需要对这条记录所在的这个数据块做操作。当你对这个数据块做修改时,其他的会话将被阻止对这个数据块上的数据做修改(即使其他用户修改的不是当前用户修改的数据),但是可以以一致性的方式读取这个数据块(from undo)。当前的用户修改完这个数据块后,将会立即释放加在这个数据块上的排他锁,这样另一个会话可以继续修改它。修改操作是一个非常短暂的时间,这种加锁的机制我们叫做Latch。

当一个会话修改一个数据块时,是按照以下步骤来完成的:

(1)以排他的方式获得这个数据块(Latch)

(2)修改这个数据块

(3)释放Latch。

Buffer busy waits等待时间常用于数据库中存在的热块的时候,当多个用户频繁的读取或者修改同样的数据块时,这个等待事件就会产生。如果等待的时间很长,我们在AWR或者statspack报告中就可以看到了。

这个等待时间有三个参数。

查看有几个参数我们可以利用下面的sql:

SQL> select name, parameter1, parameter2, parameter3 from v$event_name where name='buffer busy waits';
NAME PARAMETER1 PARAMETER2 PARAMETER3
-------------------- -------------------- -------------------- --------------------
buffer busy waits file# block# class#

其他事件的查询也一样。

file#:等待访问数据块所在的文件id号。

block#:等待访问的数据块号。

class#:

二、Buffer Latch

内存在数据块的存放位置是记录在一个hash列表(cache buffer chains)当中的。当一个会话需要访问某个数据块时,它首先要搜索这个hash列表,从列表中获得数据块的地址,然后通过这个地址去访问需要的数据块,这个列表Orale会使用一个latch来保护他的完整性。当一个会话需要访问这个列表时,需要获取一个Latch,只有这样,才能保证这个列表在这个会话的浏览器当中不会发生变化。

产生buffer latch的等待事件的主要原因是:

(1)Buffer chains太长,导致会话搜索这个列表花费的时间太长,使其他的会话处于等待状态。

(2)同样的数据块被频繁访问,就是我们通常说的热块问题。

产生buffer chains太长,我们可以使用多个buffer pool的方式来创建更多的buffer chains,或者使用参数DB_BLOCK_LRU_LATCHES来增加latch的数量,以便于更多的会话可以获得latch,这两种方法可以同时使用。

备注:DB_BLOCK_LRU_LATCHES在11g中没有查到。

这个等待事件有两个参数:

Latch addr:会话申请的latch在SGA中的虚拟地址,通过以下的SQL语句可以根据这个地址找到它对应的Latch名称:

select * from v$latch a,v$latchname b where
addr=latch addr -- 这里的 latch addr 是你从等待事件中看到的值
and a.latch#=b.latch#;

chain#:buffer chains hash 列表中的索引值,当这个参数值等于s 0xfffffff时,说明当前的会话正在等待一个 LRU latch。

三、Control file parallel write

当数据库中有多个控制文件拷贝时,Oracle需要保证信息同步地写道各个控制文件当中,这是一个并行的物理操作过程,因为称为控制文件并行写,当发生这样的操作时,就会产生control file parallel write等待事件。

控制文件频繁写入的原因有很多,比如:

(1)日志切换太过频繁,导致控制文件信息相应地需要频繁更新。

(2)系统I/O出现瓶颈,导致所有I/O出现等待。

当系统出现日志切换过于频繁的情形时,可以适当的考虑增大日志文件的大小来降低日志切换频率。

当系统出现大量的control file parallel write等待事件时,可以通过比如降低控制文件的拷贝数量,将控制文件的拷贝放在不同的物理磁盘上的方式来缓解I/O争用。

这个等待事件,包含三个参数:

Files:Oracle要写入的控制文件个数。

Blocks:写入控制文件的数据块数目。

Requests:写入控制请求的I/O次数。

四、Control file sequential read

当数据库需要读取控制文件上的信息时,会出现这个等待事件,因为控制文件的信息时顺序编写的,所以读取的时候也是顺序的,因此成为控制文件顺序读,它经常发生在以下情况:

(1)备份控制文件

(2)RAC环境下不同实例之间控制文件的信息共享

(3)读取控制文件的文件头信息

(4)读取控制文件的其他信息

这个等待事件有三个参数:

File#:要读取信息的控制文件的文件号。

Block#:读取控制文件信息的起始数据块号。

Blocks:需要读取的控制文件数据块数目。

五、db file parallel read

这是一个很容易引起误导的等待事件,实际上这个等待事件和并行操作(比如并行查询,并行DML)没有关系。这个事件发生在数据库恢复的时候,当有一些数据块需要恢复的时候,Oracle会以并行的方式把他们从数据文件中读入到内存中进行恢复操作。

这个等待事件包含三个参数:

Files:操作需要读取的文件个数。

Blocks:操作需要读取的数据块个数。

Requests:操作西药执行的I/O次数。

六、Db file parallel write

这是一个后台等待事件,它同样和用户的并行操作没有关系,它是由后台进程DBWR产生的,当后台进程DBWR向磁盘上写脏数据时,会发生这个等待。

DBWR会批量地将脏数据并行地写入到磁盘上相应地数据文件中,在这个批次作业完成之前,DBWR将出现这个等待事件。如果仅仅是这一个等待事件,说明此时内存中的可用空间不足,这时候会影响到用户的操作,比如影响到用户将脏数据块读入到内存中。

当出现db file parallel write等待事件时,可以通过启用操作系统的异步I/O的方式来缓解这个等待。当使用异步I/O时,DBWR不在需要一直等到所有数据块全部写入到磁盘上,

它只需要等到这个数据写入到一个百分比之后,就可以继续进行后续的操作。

这个等待事件有两个参数:

Requests:操作需要执行的I/O次数。

Timeouts:等待的超时事件。

Db file scattered read

这个等待事件在实际生产库中经常可以看到,这是一个用户操作引起的等待事件,当用户发出每次I/O需要读取多个数据块这样的sql操作时,会产生这个等待事件,最常见的两种情况就是全表扫描(FTS:Full Table Scan)和索引快速扫描(IFFS:index fast full scan)。

这个名称中的scattered(发散),可能会导致很多人认为它是以scattered的方式来读取数据块的,其实恰恰相反,当发生这种等待事件时,SQL的操作都是顺序地读取数据块的,比如FTS或者IFFS方式(如果忽略需要读取的数据块已经存在内存中的情况)。

这里的scattered指的是读取的数据块在内存中的存放方式,他们被读取到内存中后,是以分散的方式存在内存中,而不是连续的。

这个等待事件有三个参数:

File#:要读取的数据块所在的数据文件的文件号。

Block#:要读取的起始数据快号。

Blocks:需要读取的数据块数目。

八、Db file sequential read

这个等待事件在实际生产库中也是很常见,当Oracle需要每次I/O只读取单个数据块这样的操作时,会产生这个等待事件,最常见的情况有索引的访问(除IFFS外的方式),回滚操作,以ROWID的方式方位表中的数据,重建控制文件,对文件头做DUMP等。

这里的sequential也并非指的是Oracle按顺序的方式来访问数据,和db file scattered read一样,它指的是读取的数据块在内存中是以连续的方式存放的。

这个等待事件有三个参数:

File#:要读取的数据块锁在数据文件的文件号。

Block#:要读取的起始数据块号。

Blocks:要读取的数据块数目(这里应该等于1)。

九 Db file single write

这个等待事件通常只发生在一种情况下,就是Oracle更新数据头文件信息时(比如发生Checkpoint)。

当这个等待事件很明显时,需要考虑是不是数据库中的数据文件数量太大,导致Oracle需要花费很长的时间来做文件头的更新操作(checkpoint)。

这个等待事件有单个参数:

File#:需要更新的数据块所在的数据文件的文件号。

Block#:需要更新的数据块号。

Blocks:需要更新的数据块数目(通常来说应该等于1)。

十、Direct Path read

这个等待事件发生在会话将数据块直接读取到PGA当中而不是SGA中的情况,这些被服务的数据通常是这个会话私有的数据,所以不需要放到SGA作为共享数据,因为这样做没有意义。这些数据通常是来自与临时段上的数据,比如一个会话中SQL的排序数据,并行执行过程中产生的数据,以及Hash Join,merge join产生的排序数据,因为这些数据只对当前会话的SQL操作有意义,所以不需要放到SGA当中。

当发生Direct path read等待事件时,以为这磁盘上有大量的临时数据产生,比如排序,并行执行等操作,或者意味着PGA中空闲空间不足。

这个等待事件有三个参数:

Descriptor address:一个指针,指向当前会话正在等待的一个direct read I/O。

first dba:descriptor address中最旧的一个I/O数据块地址。

Block cnt:descriptor address上下文中涉及的有效的buffer数量。


MongoDB索引详解

$
0
0

索引能够提高数据库的查询效率,没有索引的话,查询会进行全表扫描(scan every document in a collection),严重降低了查询效率。默认情况下,Mongo在一个集合(collection)创建时,自动地对集合的_id创建了唯一索引。

(NOTE:In sharded clusters, if you do not use the _id field as the shard key, then your application must ensure the uniqueness of the values in the _id field to prevent errors. This is most-often done by using a standard auto-generated ObjectId.)

1.索引的分类

1.1单属性索引(Single Field)

针对单属性索引,排序顺序无关紧要,因为MongoDB能够在任意方向来回移动。

(For a single-field index and sort operations, the sort order (i.e. ascending or descending) of the index key does not matter because MongoDB can traverse the index in either direction.)

单属性索引示例图:


MongoDB索引详解

详细信息:https://docs.mongodb.com/manual/core/index-single/

1.2 复合索引(Compound Index)


MongoDB索引详解

针对单复合索引,索引中key的排序顺序决定了索引是否支持排序操作:

举例子:

假如:一个对象包含username和date两个属性,如果创建索引如下:

db.events.createIndex( { "username" : 1, "date" : -1 } )

则查询支持

db.events.find().sort( { username: -1, date: 1 } )

db.events.find().sort( { username: 1, date: -1 } ).

但是不支持如下查询:

db.events.find().sort( { username: 1, date: 1 } ).

详细信息:https://docs.mongodb.com/manual/core/index-compound/ 。

1.3 多值索引(Multikey indexes)
MongoDB索引详解

针对属性包含数组数据的情况,MongoDB支持针对数组中每一个element创建索引,Multikey indexes支持strings,numbers和nested documents。

详细信息:https://docs.mongodb.com/manual/core/index-multikey/ 。

1.4地理空间索引(Geospatial Index):

针对地理空间坐标数据创建索引,类似于oracle geometry类型。

1.5 文本索引(Text Index)

MongoDB提供了针对string内容的文本查询,Text Index支持任意属性值为string或string数组元素的索引查询。注释:一个集合仅支持最多一个Text Index。

详细信息:https://docs.mongodb.com/manual/core/index-text/

1.6 Hashed Index

针对属性的哈希值进行索引查询,当要使用Hashed index时,MongoDB能够自动的计算hash值,无需程序计算hash值。注:hash index仅支持等于查询,不支持范围查询

2.索引属性

2.1 唯一索引(Unique Indexes)

即不允许属性有重复的值。

2.2部分索引(Partial Indexes)(3.2版本新增)

对集合中指定的筛选器表达式筛选后的部分集合进行创建索引,优点:减少了存储空间,提高的查询效率

2.3 稀疏索引

索引只保存一定条目的索引属性值,跳过没有被指定属性;当使用3.2之后的Mongo版本时,应优先考虑Partial Indexes。

(Changed in version 3.2: Starting in MongoDB 3.2, MongoDB provides the option to create partial indexes. Partial indexes offer a superset of the functionality of sparse indexes. If you are using MongoDB 3.2 or later, partial indexes should be preferred over sparse indexes.)

2.4 TTL索引

TTL索引是特殊的索引,MongoDB能够在指定时间之后自动的删除集合中的数据,主要应用场景为机器产生的事件数据、日志、会话信息等。

(TTL indexes are special indexes that MongoDB can use to automatically remove documents from a collection after a certain amount of time. This is ideal for certain types of information like machine generated event data, logs, and session information that only need to persist in a database for a finite amount of time.)

详细信息:https://docs.mongodb.com/manual/core/index-ttl/ 。

3.索引限制

3.1 如果MongoDB的索引项超过索引限制,即1024 bytes,MongoDB将不会创建该索引,注:2.6版本之前能够创建索引,但是不能够对该documents进行索引;

3.2 当试图插入一个包含索引项的属性超过1024 bytes的documents时,MongoDB将插入documents失败,并返回错误;注:2.6版本之前能够插入成功,但是不能够对该documents进行索引;

3.3 当试图更新documents的属性时时,如果索引项的属性超过1024 bytes的,MongoDB将插入documents失败,并返回错误;注:2.6版本之前能够插入成功,但是不能够对该documents进行索引;

3.4 如果documents存在某索引,其索引属性超过了索引限制,则任何更新该documents将会失败;

3.5 针对分片的collections,当数据迁移时,如果数据块中包含索引属性超过了索引限制,数据块的迁移将会失败;

3.6 一个collections最多能够有64个索引;

3.7 针对索引的全名,包含命名空间和“.”分隔符,如:..$,最多不超过128 characters;

3.8 针对复合索引,包含的索引属性不能够超过31个属性;

3.9 查询不能够同时使用文本索引和地理空间索引(Queries cannot use both text and Geospatial Indexes);

3.11 包含2d sphere属性的索引,只能够针对地理空间属性;

3.12 如果通过覆盖索引查询得到的属性值是NaN(Not a Number),则NaN的类型总是double类型;

(If the value of a field returned from a query that is covered by an index is NaN, the type of that NaN value isalways double);

3.13 multikey index不支持covered query。

4.交叉索引

MongoDB可以使用多个索引的交叉来满足查询,通常每个交叉索引包含两个索引,但是MongoDB能够使用多个或嵌套索引交叉来实现查询。

4.1 索引前缀交叉

针对交叉索引,MongoDB能够使用交叉索引中任意一个索引的整个索引或者索引的前缀,索引前缀是指一个复合索引中索引的子集,由第一个或者前N个索引属性中的组成;

举例:

索引项如下:

{ qty: 1 }

{ status: 1, ord_date: -1 }

MongoDB能够使用如下索引:

db.orders.find( { qty: { $gt: 10 } , status: "A" } )

4.2 索引交叉与复合索引

索引交叉并不意味着复合索引没必要存在,因为属性在索引中的排列顺序和排序方式能够影响到复合索引,复合索引不支持不包含索引前缀或者不同的排序方式的查询情况

(a compound index may not support a query condition that does not include theindex prefix keys or that specifies a different sort order)

举例:

如果复合索引如下:

{ status: 1, ord_date: -1 }

复合索引支持如下查询:

db.orders.find( { status: { $in: ["A", "P" ] } } )

db.orders.find(

{

ord_date: { $gt: new Date("2014-02-01") },

status: {$in:[ "P", "A" ] }

})

但不支持如下查询:

db.orders.find( { ord_date: { $gt: new Date("2014-02-01") } } )db.orders.find( { } ).sort( { ord_date: 1 } )

但是如果collections包含如下索引:

{ status: 1 }

{ ord_date: -1 }

这两个索引,可以通过单独或者交叉支持以上4中查询。

4.3 索引交叉和排序

索引交叉不支持排序操作,即要求一个索引安全的从查询谓语分离出来的排序;

举例:collections包含如下索引:

{ qty: 1 }

{ status: 1, ord_date: -1 }

{ status: 1 }

{ ord_date: -1 }

MongoDB不支持如下带有排序的交叉索引:

db.orders.find( { qty: { $gt: 10 } } ).sort( { status: 1 } )

That is, MongoDB does not use the { qty: 1 } index for the query, and the separate { status: 1 }or the { status: 1, ord_date: -1 } index for the sort.

5 查询计划

MongoDB查询优化器执行查询,并针对现有的索引选择最高效的查询计划,查询系统在每次查询执行时使用查询计划,查询优化器仅缓存包含不止一种的可执行计划的查询计划情况。针对每一次查询,查询计划器从查询计划缓存中查询一条满足query shape的计划,如果不存在满足的计划,查询计划器将通过试用一段时间来进行评价,来产生候选查询计划。查询计划器选择胜出的计划,在查询计划缓存中创建一个查询计划,然后使用该计划产生查询结果。

(For each query, the query planner searches the query plan cache for an entry that fits the query shape. If there are no matching entries, the query planner generates candidate plans for evaluation over a trial period. The query planner chooses a winning plan, creates a cache entry containing the winning plan, and uses it to generate the result documents.If a matching entry exists, the query planner generates a plan based on that entry and evaluates its performance through a replanning mechanism. This mechanism makes a pass/fail decision based on the plan performance and either keeps or evicts the cache entry. On eviction, the query planner selects a new plan using the normal planning process and caches it. The query planner executes the plan and returns the result documents for the query)

可以使用db.collection.explain()或者 the cursor.explain() 来查看一个查询的查询计划统计数据。

Query shape:即查询谓语,排序和预测详细计划(A combination of query predicate, sort, and projection specifications)。

查询计划器的执行逻辑如下:


MongoDB索引详解

注释:

a. Catalog operations(比如index的删除或collection的删除)将刷新查询计划缓存;

b. 当Mongod重启或者关闭后,查询计划器缓存将不复存在。

6. 索引过滤(Index Filters)

Index Filters决定了优化器将为query shape评价那个索引,如果Index Filters中包含了该Index Filters,优化器将仅考虑执行Index Filters指定的索引(When an index filter exists for the query shape, MongoDB ignores the hint(). To see whether MongoDB applied an index filter for a query shape, check the indexFilterSet field of either thedb.collection.explain() or the cursor.explain() method.)

Index Filters仅影响了优化器评价哪一个索引优化器也可能仍然选择collection 扫描以得到最优查询计划。

索引过滤有些类似于Oracle的RBO: Rule-Based Optimization基于规则的优化器;

注释:

a. 由于Index Filters覆盖了优化器的预期的行为和hint()方法,所以要有节制的使用index filters;

b. Index filters在MongoDB关闭之后将不复存在,也可以使用命令删除Index Filters。

7.覆盖查询(Covered Queries)

当一个查询的查询条件和查询计划中只包含索引属性时,MongoDB不需要扫描documents或者将documents调入内存中时,这样的查询效率将非常高。

当同时满足如下两个条件时,则该查询是Covered Queries:

a. 查询中的所有属性都是索引的一部分(all the fields in the query are part of an index);

b. 所有查询到的结果中的属性值,都在同一个索引中(all the fields returned in the results are in the same index)。

举例:


MongoDB索引详解

OCM考试总结

$
0
0

经过难熬的两个月,终于迎来了第二次考试,经过两个月魔鬼般的这次考试基本全部满分(小小骄傲下)

此次考试总结如下:

section 1 考试时间130分钟
总结服务器配置总计考试时间130分钟
1、手工建库,预计时间20分钟,这里注意用dbs下的默认init文件,一共12个参数,注意undotbs,注意执行脚本,
2、监听的配置,预计用时5分钟,注意这里有个坑,PROD3在创建时没有域名,如果加了结果是会连不通,注意用sqlplue sys/oracle@PROD3测试
3、创建各种表空间,预计用时10分钟,注意default storage 即可 注意临时表空间组的创建,设置undo表空间的时间和使其自动扩展
4、配置共享服务器连接模式,预计用时10分钟,注意新增lsnr2修改dispatch和session的配置,同时记得开启PROD1的归档
5、修改PROD1的参数,预计用时10分钟,修改share和session以及dispatch参数
6、PROD2修改参数备份,预计用时5分钟,配置db_recovery参数
7、PROD1修改诊断路径,预计用时5分钟,diag参数和手机HR的统计信息。
8、DNFS配置,预计用时10分钟,主要是查看exports下是否有insecure这个配置项,如果没有写上,注意停数据库,重启才可以建立DNFS。
9、补丁的安装,预计用时5分钟,主要是opatch的使用和配置,注意解压,查看是否是在线补丁,注意停库,如果还是不行注意杀掉进程。
10、ASM手工配置相关,预计用时15分钟,这里has开始是关闭的,主要是手工配置数据库监听和ASM,注意新增init+ASM.ora的文件,创建磁盘组修改asm的参数。
总计预计用时90分钟,时间较为充足,主要是注意手工创库的时间,千万要多检查,监听的配置和相关设置一定要清晰。
这次考试用了近1个小时完成的,多出来的时间用来写第五门的脚本了。
section 2(RMAN使用)考试时间40分钟
总结如下总计考试用时40分钟
1、catalog的建立预计用时5分钟 ,要点是recovery_catalog_owner的权限rc_admin同时注意upgrad catalog
2、注册数据库到catalog预计用时5分钟,要点是register database
3、备份数据库,预计用时5分钟,主要是创建相应的目录和备份到指定目录下,prod2全备
4、闪回数据库操作,预计用时15分钟,主要是开启数据库闪回和enable block change tracking using file '//' reuse;
总计用时25分钟,一般剩余时间较为充足,细心不要看错。
section 3(数据管理)考试时间85分钟
1、prod2数据库损坏删除操作,预计用时10分钟,创建public database link 恢复的时候list failure-advise failure- repair failure
2、materialized view 的优化用时15分钟,要点dbms_advisor的使用,dbms_advoisor.tune_mview,dbms_mview.explain_mview('PROD_MV',:taskname_)
3、星形查询预计用时5分钟,主要是star_transformation_enable设置为true和bitmap索引的建立分区表所以记得local compute statistics
4、表空间迁移预计用时12分钟,要点是数据文件的convert和imp的时候注意transport_datafiles='',注意将tablespace trpdata read write
5、外部表的创建使用sqlldr预计用时12分钟,userid=sh/sh control=eee.ctl external_table=generate_only,查看交表语句,然后删除重建外部表即可。
6、并行设置预计用时15分钟,主要是参数设置alter session enable parallel dml然后 在查询里加上/*+parallel(sales,8)*/
总计预计用时70分钟,预留10分钟左右供检查,应该是无太大问题。注意每一题最好做完,别东搞西搞。 结果一个都没做完整。
本次考试用了不到20分钟,继续后面脚本
section 4(空间管理)考试时间110分钟
总结本章总计时常110分钟,除去检查和意外10分钟 总计可用时间为100分钟
1、LOB大对象处理预计用时15分钟,要点是创目录和表空间sf_data创建完毕后执行脚本。最终查询数据是否准确(deduplicate compress)
2、表空间加密预计用时15分钟,要点是PROD3中导入example和创建sh用户,imp数据,然后是encryption的字符串处理和加密表空间enct_data表空间创建
3、16k表空间的使用用时10分钟,要点是创建16k表空间lob_data和使用,创建表导入的时候注意表已创建,ignore=y
4、引用分区的创建用时15分钟,分区表的创建和引用分区的创建,主要是约束使用应用分区,分区迁移和索引重建
5、时间间隔分区创建用时10分钟,主要是应用分区inteval(numtoyminteval(1,'month'))然后是insert表
6、审计功能fga预计用时5分钟,主要是add_policy并使用hr执行语句查询
7、闪回查询和回收站闪回表用时8分钟,主要是闪回查询时记得创建表,闪回表的时候重命名
8、最后一个闪回归档,用时8分钟,主要是闪回表空间fratbs和fra_admin的赋权flashback archive administer 使用该用户创建fra1 retention 1 year
总计用时86分钟,在无意外的情况下最少用时90分钟左右,此时还有剩余10分钟进行检查。主要问题是在导入过程中可能有问题.本次去重未考,如果考了建议放弃.
用了大约85分钟做完,检查了相关参数,准备脚本
section 5(数据优化)考试时间90分钟
==总结如下,性能调优总计考试时间90分钟
1、第一个PROD2数据恢复,预计用时10分钟,建立dblink和synonym
2、resource_manager管理,预计用时15分钟,这个千万不要钻牛角尖,如果无法进行果断放弃,建议背诵下来,三个参数一定要有
3、索引管理,预计用时10分钟,包含函数索引,b树索引和索引监控,比较简单,建议参考sh的customer表
4、拆分表,预计用时5分钟,拆分为两张表,主要是主键约束和联合主键约束
5、统计信息收集,预计用时5分钟,主要是sh的employees的统计信息,表级的统计信息收集,联合索引,索引压缩
6、share_pool的保持预计用时5分钟 收集数据库的统计信息主要是for all columns skewonly
7、表空间迁移,预计用时10分钟,主要是设置表的initrans 5和 dbms_space_admin的tablespace_migrate_from_local的使用如果使用失败按照传统方法迁移
8、全局反序哈希索引并收集sh用户下sales的统计信息预计用时5分钟 主要是no_invalidate为true和reverse global partition by hash(product_id);
9、结果集缓存预计用时10分钟,主要是设置result_cache_mode为manual和result_cache_max_size设置,在脚本中select语句后面加上/*+result_cache*/
10、创建扩展统计信息组合,预计用时5分钟,要点在dbms_stats.create_extended_stats()使用,注意字段用括号括起来,建立玩以后对sh表的customer的字段进行收集for all columns size skewonly for columns() size skewonly
11、SQL性能调优,预计用时20分钟,要点在dbms_sqlpa和dbms_sqltune两个包的使用,生成报告并且进行调优
12、sql基线,预计用时10分钟,要点在dbms_spm的load和evolve的使用,注意流程
13、sql实例球笼,预计用时5分钟,要点在prod1和prod2上将resource_manager_plan和cpu_count置为default和1
==总结,不包括看题这里需要时间总计110分钟,所以理论上讲这一门不用gc无论如何也是做不完的,在考试前由于gc都是安装好的,如果告诉用户密码可以试着用
gc完成sql调优;此时需要进行的第二个思路是gc不可以用的情况下,一定要适当放弃部分题目,资源管理背诵,千万不要在一个题目上耗费太多时间。sql调优是重点
这个一定不能丢,简单而且无脑的调优,最终accept即可
如果可以用点手段,在之前有时间的情况下将一些脚本写好,不至于没时间敲脚本。
这一章一定要熟悉,过了后面基本无障碍。题量大时间紧,一定要冷静冷静再冷静重要的事情说三遍.
之前写的脚本此时起了作用,resource manager 和advisor基本都是无脑的copy和粘贴,但是即使如此也才多出10分钟的样子供检查,所以平常一定要多加练习
section 6(GC使用) 考试时间50分钟
总结如下:
1、拿到题目以后首先做Agent安装,安装过程中有几点需要注意:
2、易错点一操作系统或者管理系统密码问题,管理密码非必填项如果没填安装时报错;
3、易错点二root脚本的问题,不要在安装时勾选,安装完agent后第一步就是去偶数机器执行root,如果不执行DG安装时会报错
4、安装时间较长需要耐心等待,此时可以先解锁各数据库dbsnmp用户
5、一定要在计数机上打开GC,偶数机器非常卡,两次均得以验证
主要时间是在等,题目较为简单,时间上不允许安装两次Agent所以一定要一次成功
section 7(DG配置) 考试时间60分钟
总结如下:
1、和上面的相反,这里不要一上来就配置DG,首先要做的是干掉共享服务器模式,停掉多余listener,开启flashback和block change tracing
2、安装时一定记得选安装的主机,不要看错主机路径,选择偶数机,别安装到gc目录了;
3、如果报错,看看root是否执行,如果未执行记得执行下重新检测就可以了
4、AGD和fast_start failover 的配置直接点就可以了,配置下rman的备份策略,还有记得在备库启动observer
5、安装过程较长,此时可以先写trgger配置备库到主库的监听
6、和第六门一样,基本不存在第二次配置的机会,需要细心,不要点错。
section 8(GI配置) 考试时间60分钟
总结如下:
1、进入VNC之前可以关掉fast_star failover 停掉observer
2、安装时间很久,可以看题,千万不要手贱乱点,如果那个执行脚本那一步不小心点了,CRS就需要手工配置了,最好避免这个错误
3、脚本的执行时间很长,耐心等待,看清楚执行方式
4、配置过程比较简单,基本看清楚题就可以了
section 9(RAC安装) 考试时间50分钟
总结如下:
1、如果8执行脚本出现问题,会出现无法安装RAC数据库情况,此时需要手工加入CRS这一步才可以识别GI
2、安装的是策略管理的(policy-managed)数据库。
3、创建服务和配置tnsname另外就是创建sequence。

难点都在3、4、5了,还有一点就是我们总是忽略的tnsname配置,很大一部分问题就是出在这的,看清楚有无带域名。自己建立的库一般没带域名此时如果配置是连不通的。

第一门很影响士气,如果第一门有问题,后面基本都是恍惚的,所以多练第一门,保证考试有勇气往后面做,越到后面会越觉得容易。

redis(带联接池)结合关系数据库

$
0
0

首先Maven导入

org.springframework.data
spring-data-redis
1.4.2.RELEASE
redis.clients
jedis
2.4.2

再配置spring.xml文件,我这是已经整合好Spring,Mybatis和struts2的xml

mysql.driverName}">LOG4J
没整合的也可只需加入创建redis工厂部分即可。如果用的联接池则也不需要配置redis工厂

DAO层接口加入一些redis常用方法

//redis start
/**
* 存
* @param key
* @param value
*/
public void setKey( String key, String value);
/**
* 根据键取值
* @param key
* @return
*/
public Object getKey( String key);
/**
* 自增
* @param key
*/
public void incr( String key);
/**
* 自减
* @param key
*/
public void decr( String key);
/**
* 在上一个元素的左边存
* @param key
* @param value
*/
//public void lPush( String key, String value);
/**
* 查看是否有这个键
* @param key
* @return
*/
//public boolean checkKey( String key);
/**
* 按键取
* @param key
* @return
*/
//public Object lIndex( String key);
/**
* 求长度
* @param key
* @return
*/
//public Long lLength( String key);
/**
* 从上一个元素的左边取值
* @param key
* @return
*/
//public String lPop( String key);
/**
* 按正则表达式匹配的键取值
* @param pattern
* @return
*/
//public Set getKeys( String pattern);
//redis end
DaoImpl实现类进行实现:
private RedisCache client = new RedisCache();
//redis数据库方法 start
@Override
public void setKey(String key, String value) {
this.client.set(key, value);
}
@Override
public Object getKey(String key) {
if(this.client.get(key)==null){
return null;
}
return this.client.get(key);
}
@Override
public void incr(String key) {
this.client.increment(key);
}
@Override
public void decr(String key) {
this.client.decr(key);
}
//redis数据库方法 end

因为加入了联接池,所以一些自增自减的方法需要在RedisCache类中进行重写

package com.microblog.dao.mybatis.cache;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
import com.microblog.dao.redis.RedisPool;
public class RedisCache implements Cache {
/*
* 日志对象
*/
private static Logger logger = org.apache.log4j.Logger
.getLogger(RedisCache.class);
private String id;
private Jedis redisClient = createRedis();
// 用于同步的锁
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public RedisCache(String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instance requires an Id");
}
logger.debug("create an cache instance with id:" + id);
this.id = id;
}
public RedisCache() {
}
public String getId() {
return this.id;
}
// 将缓存中的数据删除
public void clear() {
logger.debug("clear redis cache");
this.redisClient.flushDB();
}
// 通过key到缓存redis中取值
public Object getObject(Object key) {
// 缓存穿透.
byte[] values = this.redisClient.get(SerializableUtil.serialize(key));
// System.out.println( values );
if (values == null) {
// this.putObject( SerializableUtil.serialize(key) , null);
return null;
}
Object obj = SerializableUtil.unSerialize(values);
logger.debug("get data:" + key + " from cache,result is:" + obj);
return obj;
}
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
public int getSize() {
Long size = this.redisClient.dbSize();
int s = Integer.valueOf(size + "");
return s;
}
public void putObject(Object key, Object value) {
byte[] keybyte = SerializableUtil.serialize(key);
byte[] valuebyte = SerializableUtil.serialize(value);
this.redisClient.set(keybyte, valuebyte);
}
public Object removeObject(Object key) {
byte[] keybyte = SerializableUtil.serialize(key);
return this.redisClient.expire(keybyte, 0);
}
/**
* TODO:jedis从联接池中取
*
* @return
*/
protected static Jedis createRedis() {
// TODO: 获取jedis实例 -> 这个地址要变
// Jedis jedis = new Jedis("192.168.137.128");
Jedis jedis = RedisPool.getPool().getResource();
return jedis;
}
public void set(String key, String value) {
this.redisClient.set(key, value);
}
public Object get(String key) {
return this.redisClient.get(key);
}
public void increment(String key) {
this.redisClient.incr(key);
}
public void decr(String key) {
this.redisClient.decr(key);
}
}
将对象序列化的类
package com.microblog.dao.mybatis.cache;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializableUtil {
/**
* 将对象序列化
*/
public static byte[] serialize(Object obj) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
byte[] bs = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
bs = baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bs;
}
public static Object unSerialize(byte[] bs) {
ByteArrayInputStream bais = null;
Object obj = null;
try {
bais = new ByteArrayInputStream(bs);
ObjectInputStream ois = new ObjectInputStream(bais);
obj = ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bais != null) {
try {
bais.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return obj;
}
}

然后是读取联接池的配置

package com.microblog.dao.redis;
import java.util.ResourceBundle;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* 以单例模式创建一个jedis的联接池
*/
public class RedisPool {
private static JedisPool pool;
public synchronized static JedisPool getPool() {
if( pool==null ){
new RedisPool();
}
return pool;
}
private RedisPool() {
ResourceBundle bundle = ResourceBundle.getBundle("redis");
if (bundle == null) {
throw new IllegalArgumentException(
"[redis.properties] is not found!");
}
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(Integer.valueOf(bundle
.getString("redis.pool.maxActive")));
config.setMaxIdle(Integer.valueOf(bundle
.getString("redis.pool.maxIdle")));
config.setMaxWaitMillis(Long.valueOf(bundle
.getString("redis.pool.maxWait")));
config.setTestOnBorrow(Boolean.valueOf(bundle
.getString("redis.pool.testOnBorrow")));
config.setTestOnReturn(Boolean.valueOf(bundle
.getString("redis.pool.testOnReturn")));
pool = new JedisPool(config, bundle.getString("redis.ip"),
Integer.valueOf(bundle.getString("redis.port")));
}
}
你需要一个redis.properties
redis.pool.maxActive=1024
redis.pool.maxIdle=200
redis.pool.maxWait=1000
redis.pool.testOnBorrow=true
redis.pool.testOnReturn=true
redis.ip=127.0.0.1
redis.password=123
redis.port=6379

再是业务层的实现

package com.microblog.biz.impl;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import com.microblog.bean.Blog;
import com.microblog.biz.BlogBiz;
import com.microblog.dao.BaseDao;
import com.microblog.web.model.BlogModel;
@Service
@Transactional(readOnly = true)
public class BlogBizImpl implements BlogBiz {
private BaseDao baseDao;
@Resource(name = "baseDaoImpl")
public void setBaseDao(BaseDao baseDao) {
this.baseDao = baseDao;
}
/**
* 发布微博存入数据库
*/
@SuppressWarnings("unchecked")
@Transactional(readOnly = false, isolation = Isolation.DEFAULT, rollbackForClassName = "java.lang.RuntimeException", propagation = Propagation.REQUIRED)
public void saveBlog(Blog blog) {
this.baseDao.save(blog, "saveBlog");
}
// 得到总的微博
public BlogModel findAllBlog(BlogModel hs) {
// 查询总记录数
int count = baseDao.getCount(Blog.class, "getBlogCount");
// 计算总页数
int total = count % hs.getSizePage() == 0 ? count / hs.getSizePage()
: count / hs.getSizePage() + 1;
hs.setTotal(total);
// 计算偏移量
int off = (hs.getCurrPage() - 1) * hs.getSizePage();
List hh = this.baseDao.findList(Blog.class, null, "getBlog", off,
hs.getSizePage());
// 操作redis数据库 整合关系数据库
for (Blog blog : hh) {
Long id = blog.getId();
// 获取点赞数
String parse = (String) this.baseDao.getKey("user:parse" + id);
blog.setParse(parse);
// 获取转发数
String relay = (String) this.baseDao.getKey("user:relay" + id);
blog.setRelay(relay);
}
hs.setBlogs(hh);
return hs;
}
// 点赞(redis)
@Override
public String parse(Long id, int uid) {
// 当用户没有点赞,则点赞数+1,redis中用户字段+1;点了赞,则点赞数-1,redis中用户字段-1
if (id > 0 && uid > 0) {
if (this.baseDao.getKey(id + "user:id" + uid) == null
|| Integer.parseInt((String) this.baseDao.getKey(id
+ "user:id" + uid)) == 0) {
this.baseDao.incr("user:parse" + id);
this.baseDao.incr(id + "user:id" + uid);
} else {
this.baseDao.decr("user:parse" + id);
this.baseDao.decr(id + "user:id" + uid);
}
String num = (String) this.baseDao.getKey("user:parse" + id);
return num;
} else {
return null;
}
}
// 转发(redis)
@Override
public String relay(Long id, int uid) {
// 当用户没有转发,则转发数+1,redis中用户字段+1;已转发,则不允许转发
if (id > 0 && uid > 0) {
if (this.baseDao.getKey(id + "user:relayid" + uid) == null
|| Integer.parseInt((String) this.baseDao.getKey(id
+ "user:relayid" + uid)) == 0) {
this.baseDao.incr("user:relay" + id);
this.baseDao.incr(id + "user:relayid" + uid);
String num = (String) this.baseDao.getKey("user:relay" + id);
return num;
} else {
return null;
}
} else {
return null;
}
}
}
测试类
//测试redis点赞数的自增
public void testApp09() {
ApplicationContext ac = new ClassPathXmlApplicationContext(
"beans_mybatis.xml");
BlogBiz ub=(BlogBiz) ac.getBean("blogBizImpl");
System.out.println("当前点赞数"+ub.parse(2L,1));
}
//测试redis转发数
public void testApp10() {
ApplicationContext ac = new ClassPathXmlApplicationContext(
"beans_mybatis.xml");
BlogBiz ub=(BlogBiz) ac.getBean("blogBizImpl");
System.out.println("当前转发数"+ub.relay(2L, 1));
}

在windows环境下搭建mysql集群

$
0
0

1. 前(fei)言(hua)

最近实训老师给我们布置了一个建立mysql集群的任务,并扔了两个博客链接给我们参考,然后就没有然后了。根据老师给的博客上面的步骤试了一下,发现并不能成功建立,于是自己百度,找到了一个挺靠谱的博客,于是参考了一下,感觉总体还是不错的~

2. 理论基础知识

首先需要了解什么是管理节点、数据节点和SQL节点~

(1)管理结点:从名字可以看出来,这种结点的作用就是管理其他结点的,这个节点可以查看其他数据节点和SQL节点的连接状态,并可以控制这些的节点重启。

(2)数据节点:这些节点的作用就是存放数据,每个数据节点都有这个mysql集群的全部数据(数据冗余),也就是只要存在一个能运行就可以了~

(3)SQL节点:这些节点向外提供SQL接口,所有数据库操作都发往这里,也是只要存在一个能运行就可以~

(ps:本文侧重实际操作,理论基础知识请自行百度学习~)

3. 实际操作过程(博主的操作系统是WIN10~)

以下使用5台电脑来实现mysql集群(1个管理节点,2个数据节点,2个SQL节点)

管理节点的IP:192.168.1.66

数据节点1的IP:192.168.1.50

数据节点2的IP:192.168.1.53

SQL节点1的IP:192.168.1.63

SQL节点2的IP:192.168.1.56

(1)到mysql官网下载一个解压版的mysql cluster,下载地址在下面~

下载地址

根据自己的操作系统选择


在windows环境下搭建mysql集群

下载完成后解压

(2)配置管理节点

在管理节点的C盘新建一个mysql文件夹,然后在mysql文件夹下新建一个bin文件夹和mysql-cluster文件夹。在刚刚解压出来的文件夹中的bin文件夹下找到ndb_mgm.exe和ndb_mgmd.exe,然后复制到刚刚新建的bin文件夹下,并在此文件夹下新cluster-logs文件夹、config.ini文件和my.ini文件。


在windows环境下搭建mysql集群
在windows环境下搭建mysql集群

编辑config.ini文件:

[ndbd default]
# Options affecting ndbd processes on all data nodes:
# Number of replicas 数据节点数
NoOfReplicas=2
DataDir=c:/mysqlcluster/datanode/mysql/bin/cluster-data
# Directory for each data node's data files
# Memory allocated to data storage 数据节点存放数据的路径
DataMemory=80M
# Memory allocated to index storage
IndexMemory=18M
# For DataMemory and IndexMemory, we have used the
# default values.
[ndb_mgmd]
# Management process options:
# Hostname or IP address of management node 管理节点 IP
HostName=192.168.1.66
# Directory for management node log files 管理节点日志存放路径
DataDir=C:/mysql/bin/cluster-logs
[ndbd]
# Options for data node "1":
# (one [ndbd] section per data node)
# Hostname or IP address 数据节点1 IP
HostName=192.168.1.50
[ndbd]
# Options for data node "2":
# Hostname or IP address 数据节点2 IP
HostName=192.168.1.53
[mysqld]
# SQL node options:
# Hostname or IP address sql节点1 IP
HostName=192.168.1.63
[mysqld]
# SQL node options:
# Hostname or IP address sql节点2 IP
HostName=192.168.1.56

编辑my.ini文件:

[mysql_cluster]
# Options for management node process config.ini存放路径
config-file=C:/mysql/bin/config.ini

(2)配置数据节点:

在数据节点1新建C:\mysqlcluster\datanode\mysql文件夹,在这个mysql文件夹中新建一个bin文件夹和cluster-data文件夹,在这个新建bin文件夹中新建一个也叫cluster-data的文件夹。接下来将解压的文件夹中data目录下所有文件复制到C:\mysqlcluster\datanode\mysql\cluster-data,再到解压文件夹中的bin目录下复制一个ndbd.exe到C:\mysqlcluster\datanode\mysql\bin,最后再新建一个my.ini文件。

编辑my.ini:

[mysql_cluster]
# Options for data node process:
# location of management server 管理节点IP
ndb-connectstring=192.168.1.66
在windows环境下搭建mysql集群
在windows环境下搭建mysql集群
在windows环境下搭建mysql集群

由于数据节点2的配置与这个一毛一样,你可以选择再弄一次加深印象,也可以在数据节点2先新建C:\mysqlcluster\datanode,然后偷懒把这个数据节点1的C:\mysqlcluster\datanode下的mysql文件夹整个复制到数据节点2的C:\mysqlcluster\datanode目录下。

(3)配置SQL节点

在SQL节点1新建C:\mysqlcluster\sqlnode\mysql文件夹,将安装包文件解压到mysql目录下,然后在C:\mysqlcluster\sqlnode\mysql下新建my.ini文件

编辑my.ini:

[mysqld]
# Options for mysqld process:
# run NDB storage engine
ndbcluster
# location of management server 管理节点IP
ndb-connectstring=192.168.1.66

记得要把my-default.ini 文件删除或更名为其他名字

SQL节点2的配置和SQL节点1一毛一样,自己看着办~

(4)打开mysql cluster

A、先打开SQL节点的服务:(dos命令行)

如果没有安装MySQL服务,则到SQL节点进入C:\mysqlcluster\sqlnode\mysql\bin目录下,使用mysqld –install安装MySQL服务,使用net start mysql命令启动MySQL服务

如果已经安装了MySQL服务,则直接使用net start mysql命令启动MySQL服务


在windows环境下搭建mysql集群

SQL节点2也做相同操作

B、为root用户分配远程连接的相关权限

到管理节点进入C:\mysqlcluster\sqlnode\mysql\bin目录下,使用mysql -uroot -p,然后输入密码(默认为空)


在windows环境下搭建mysql集群

然后输入

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
在windows环境下搭建mysql集群

C、启动管理节点

到管理节点打开命令行窗口,切到C:\mysql\bin目录,输入

ndb_mgmd -f config.ini --configdir=C:\mysql\mysql-cluster
在windows环境下搭建mysql集群

这个窗口不能关掉,否则服务不可用。

打开

D、启动数据节点

到数据节点1打开命令行窗口,切到C:\mysqlcluster\datanode\mysql\bin,输入 ndbd

数据节点1:


在windows环境下搭建mysql集群

数据节点2操作相同:


在windows环境下搭建mysql集群

E、启动SQL节点

到SQL节点1打开命令行窗口,切到C:\mysqlcluster\sqlnode\mysql\bin,输入:
mysqld –console

SQL节点1


在windows环境下搭建mysql集群

SQL节点1启动完成:


在windows环境下搭建mysql集群

SQL节点2操作相同

4. 测试

到任意一个SQL节点创建数据库,在新建的数据库里面新建一张表

create database db;
use db;
create table t (id int) engine=ndbcluster;

到另一个SQL节点查询看看能否看到新建的数据库db和表t,如果有那就没问题了~

show databases;
use db;
show tables;

【深入浅出Mysql】MySql存储引擎之MyISAM(二)

$
0
0

一、MyISAM

1.1 数据存储

MyISAM是默认的mysql插件式存储引擎。它不支持事务和外键。

优势:访问速度快,基本上以SELECT、INSERT为主的应用基本上都可以使用这个引擎来创建表。

每个MyISAM在磁盘上存储称3个文件,其文件名和表名相同,扩展名不同,分别是:

.frm(存储表自定义)

.MYD(MYDATA,存储数据)

.MYI(MYIndex,存储索引) MyISAM的数据文件和索引文件可以放置在不同的目录,平均分布IO,获得更快的速度。其中索引文件需要在创建表的时候通过DATA DIRECTORY和INDEX DIRECTORY语句指定。

注意:文件路径需要是绝对路径,并且具有访问权限。

MyISAM表又支持3种不同的存储格式,分别是:

静态表

动态表

压缩表

1.1.1 静态表

静态表是默认的存储格式。静态表中的字段都是非变长字段,每个记录都是固定长度的。静态表的优缺点如下:

优点:

1存储快、易缓存。

2由于每个记录位置固定,崩溃后容易重建

缺点:

1占用的空间比动态表多。

注意:静态表的数据在存储时会按照列的宽度补足空格,但是我们从数据库读取的时候是不会拿到这个空格的。如果需要保存的内容后面本身是带空格的,也会在返回结果前被去掉。另外一点是如果空格是在内容前面或中间是不会被去掉的。例如:

首先创建一个测试表test,分别插入4条不同数据。如下:

CREATE TABLE `test` (

`name` varchar(20) NOT NULL

) ENGINE=MyISAM DEFAULT CHARSET=gbk

insert into test values('小毛驴');

insert into test values('小毛驴 ');

insert into test values(' 小毛驴');

insert into test values('小 毛驴');

执行查询sql语句:select name,length(name) from test; 运行结果如下:


【深入浅出Mysql】MySql存储引擎之MyISAM(二)

从上面的结果可以看出,第二条插入在小毛驴后面的空格被去掉了而前面的空格保留了下来!

1.1.2 动态表

什么是动态表呢?如果表中存在varchar、blob、text字段,表类型就是动态了。动态表是字段长度不固定,占用空间比静态表小,但频繁的更新删除记录容易产生碎片,需要定期执行OPTIMIZE TABLE语句或MYISAMACHK -r 命令来改善性能,并且出现故障的时候恢复相对比较困难。可使用myisamchk -ei来获取表的统计数据。

优点:

1占用空间小。每条记录都有一个header,作用就是表明该记录有多长,所有的字符串列都是动态的(除非小于4个字节,这种情况下,节省的空间可以忽略不计,增加的复杂度反而会导致性能丢失)

缺点:

1容易产生碎片。例如:更新了用户名'小毛驴'为'小毛驴帅',帅不能立刻就出现在驴的后面,因为空间被其他记录占用,对于出现碎片的列,每个新连接会损失6个字节。如果碎片严重,有可能出现库爆炸。

2出现故障恢复难。

不包括连接的动态记录的空间消耗可以用下面的公式计算:

3+(列数+7)/8+(字符列数)+数字列的打包尺寸+字符串长度+(空列的数量+7)/8

每条记录的header可以表明那个字符串列是空的,那个数字列包含0(非空),在那种情况下不向磁盘存储,非空字符串包含一个长度字节加上字符串内容。

1.1.3 压缩表

MySQL分发版本里默认包含myisampack工具,占据非常小的磁盘空间。因为每个记录时被单独压缩的,已压缩存储格式是由它创建的只读格式。如果使用表压缩技术,要先确认innodb_file_per_table=1,以及innodb_file_format=Barracuda。

SET GLOBAL innodb_file_per_table=1; SET GLOBAL innodb_file_format=Barracuda; CREATE TABLE t1 (c1 INT PRIMARY KEY) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;

如果你指定ROW_FORMAT=COMPRESSED,那么可以忽略KEY_BLOCK_SIZE的值,这时使用默认innodb页的一半,即8kb;

如果你指定了KEY_BLOCK_SIZE的值,那么你可以忽略ROW_FORMAT=COMPRESSED,因为这时会自动启用压缩;

为了指定最合适KEY_BLOCK_SIZE的值,你可以创建表的多个副本,使用不同的值进行测试,比较他们的.ibd文件的大小;

KEY_BLOCK_SIZE的值作为一种提示,如必要,Innodb也可以使用一个不同的值。0代表默认压缩页的值,Innodb页的一半。KEY_BLOCK_SIZE的值只能小于等于innodb page size。如果你指定了一个大于innodb page size的值,mysql会忽略这个值然后产生一个警告,这时KEY_BLOCK_SIZE的值是Innodb页的一半。如果设置了innodb_strict_mode=ON,那么指定一个不合法的KEY_BLOCK_SIZE的值是返回报错。 InnoDB未压缩的数据页是16K,根据选项组合值,mysql为每个表的.ibd文件使用1kb,2kb,4kb,8kb,16kb页大小,实际的压缩算法并不会受KEY_BLOCK_SIZE值影响,这个值只是决定每个压缩块有多大,从而影响多少行被压缩到每个页。设置KEY_BLOCK_SIZE值等于16k并不能有效的进行压缩,因为默认的innodb页就是16k,但是对于拥有很多BLOB,TEXT,VARCHAR类型字段的表可能会有效果的。

优点:

1压缩表占据很小的磁盘空间,从而减少磁盘的I/O,还能提高系统吞吐量。对于读比重多的应用,压缩是特别有用。压缩能够让系统拥有足够的内存来存储热数据。

2每个记录被单独压缩,访问开支小。

3可以处理固定长度或动态长度记录。

缺点:

1耗费较多的CPU资源

什么时候使用压缩表,这取决于你的负载和数据集合,或者特定的配置,可以考虑如下因素:

1、表中有较多重复的字符串

2、已经在应用中压缩过的数据,不适合存储到压缩表中。

3、对于如何压缩表才算最好的,MySQL没有明确的定义,所以压缩后一定要通过like或order by来测试压缩后的索引性能

4、在应用中进行压缩的,不适合再进行表压缩

5、在表上的workload是一个关键性因素,如果更新主要作用在外部存储的长字符串的非索引列上,压缩的开销可能是可以接受的。如果你的负载是I/O bound而非CPU bound的,压缩可能会改善整体性能

6、压缩可以通过消耗CPU来减少IO,如果IO是相对紧缺的资源时,会获得更好的效果

7、选择压缩Page的大小应该比记录更大,否则可能会引起大量的压缩失败,通常情况下key_block_size=8是比较安全的设置

MongoDB3.2.9分布式集群搭建

$
0
0
手把手搭建MongoDB集群
目标
搭建带有安全认证的mongodb集群准生产环境。
一共3个shard,每一个shard有3个replica set,replicat set采用primary、secondary、secondary方式。9个mongod实例,另外,3个config server,3个mongod实例,3个mongos实例。
mongodb版本 3.2.9 社区版本
Cores 4
OS Name CentOS release 6.6 (Final)
OS Version linux version 2.6.32-504.3.3.el6.x86_64
RAM (MB) 3729
注意:关闭SELINUX
注意:服务器时间同步,比如用ntpdate,可以暂时略过不管。

最后会有核武。MongoDB Ops Manager

服务器准备:
服务器-ip
192.168.3.73
192.168.3.74
192.168.3.75

另外准备一台192.168.3.81用作MongoDB Ops Manager。

访问互通

比如在192.168.3.73机器上修改

vi /etc/hosts
192.168.3.73 73.dooioo.org
192.168.3.74 74.dooioo.org
192.168.3.75 75.dooioo.org
192.168.3.76 76.dooioo.org
192.168.3.81 81.dooioo.org
vi /etc/sysconfig/network
HOSTNAME=73.dooioo.org

生效

hostname 73.dooioo.org
下载安装">下载安装

登录到192.168.3.73

$ cd /root
$ wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.2.9.tgz
$ scp mongodb-linux-x86_64-rhel62-3.2.9.tgz root@192.168.3.74:/root
$ scp mongodb-linux-x86_64-rhel62-3.2.9.tgz root@192.168.3.75:/root
$ scp mongodb-linux-x86_64-rhel62-3.2.9.tgz root@192.168.3.76:/root
$ tar zxvf mongodb-linux-x86_64-rhel62-3.2.9.tgz
规划集群和分片

规划3个shard * 3个replicat set + 配置服务


shard rs name
Primary
Secondary
Secondary
port
fang-s-a
a1
a2
a3
28111
fang-s-b
b2
b1
b3
28112
fang-s-c
c3
c1
c2
28113
fang-cs
configserver1
configserver2
configserver3
28200

规划3个config server的mongod实例configserver1、configserver2、configserver3


hostname
实例
73.dooioo.org
a1 b1 c1 configserver1
74.dooioo.org
a2 b2 c2 configserver2
75.dooioo.org
a3 b3 c3 configserver3
规划目录和配置文件

创建必要的目录和文件

#!/usr/bin/env bash
# 登录到192.168.3.73
# 创建db目录 日志目录 mongod配置文件
mkdir -p /mongodb/a1
mkdir -p /home/log/mongodb/a1
mkdir -p /mongodb/b1
mkdir -p /home/log/mongodb/b1
mkdir -p /mongodb/c1
mkdir -p /home/log/mongodb/c1
mkdir -p /mongodb/configserver1
mkdir -p /home/log/mongodb/configserver1
touch /mongodb/mongod-a1-config.yml
touch /mongodb/mongod-b1-config.yml
touch /mongodb/mongod-c1-config.yml
touch /mongodb/mongod-configserver1.yml
# 登录到192.168.3.74
mkdir -p /mongodb/a2
mkdir -p /home/log/mongodb/a2
mkdir -p /mongodb/b2
mkdir -p /home/log/mongodb/b2
mkdir -p /mongodb/c2
mkdir -p /home/log/mongodb/c2
mkdir -p /mongodb/configserver2
mkdir -p /home/log/mongodb/configserver2
touch /mongodb/mongod-a2-config.yml
touch /mongodb/mongod-b2-config.yml
touch /mongodb/mongod-c2-config.yml
touch /mongodb/mongod-configserver2.yml
# 登录到192.168.3.75
mkdir -p /mongodb/a3
mkdir -p /home/log/mongodb/a3
mkdir -p /mongodb/b3
mkdir -p /home/log/mongodb/b3
mkdir -p /mongodb/c3
mkdir -p /home/log/mongodb/c3
mkdir -p /mongodb/configserver3
mkdir -p /home/log/mongodb/configserver3
touch /mongodb/mongod-a3-config.yml
touch /mongodb/mongod-b3-config.yml
touch /mongodb/mongod-c3-config.yml
touch /mongodb/mongod-configserver3.yml
# 登录到192.168.3.73
# 生产和copy秘钥用户实例内部认证
openssl rand -base64 755 > /mongodb/keyfile
chmod 400 /mongodb/keyfile
scp /mongodb/keyfile root@192.168.3.74:/mongodb/
scp /mongodb/keyfile root@192.168.3.75:/mongodb/

列举mongod-a1-config.yml文件。

# yml
# mongod config
# 日志位置
systemLog:
destination: file
logAppend: true
path: /home/log/mongodb/a1/mongodb.log
# Where and how to store data.
# db存储位置
storage:
dbPath: /mongodb/a1
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:
# how the process runs
# fork : fork and run in background 后台运行
# pidFilePath:location of pidfile
processManagement:
fork: true
pidFilePath: /var/run/mongod-a1.pid
# network interfaces
# Listen to local interface only, comment to listen on all interfaces.
net:
port: 28111
bindIp: 0.0.0.0
#security: enabled disabled
#security:
# keyFile: /mongodb/keyfile
# clusterAuthMode: keyFile
#operationProfiling:
operationProfiling:
slowOpThresholdMs: 1000
mode: slowOp
#replication:
replication:
replSetName: fang-s-a
#sharding:
sharding:
clusterRole: shardsvr
## Enterprise-Only Options
#auditLog:
#snmp:

刚才touch的文件按照名称修改配置,比如mongod-b1-config.yml需要修改的内容:a1全部替换问b1, fang-s-a替换为fang-s-b,端口按照规划的28111改为28112

configserver稍微有点不一样的是clusterRole,注意修改,一个为shardsvr,一个为configsvr,其他同理,不同服务器修改数据和配置。按照前面创建的文件名称,目录名称修改。也给出一个配置服务的例子

# yml
# mongod config
systemLog:
destination: file
logAppend: true
path: /home/log/mongodb/configserver1/mongodb.log
# Where and how to store data.
storage:
dbPath: /mongodb/configserver1
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:
# how the process runs
# fork : fork and run in background
# pidFilePath:location of pidfile
processManagement:
fork: true
pidFilePath: /var/run/mongod-configserver1.pid
# network interfaces
# Listen to local interface only, comment to listen on all interfaces.
net:
port: 28200
bindIp: 0.0.0.0
#security: enabled disabled
#security:
# keyFile: /mongodb/keyfile
# clusterAuthMode: keyFile
#operationProfiling:
operationProfiling:
slowOpThresholdMs: 1000
mode: slowOp
#replication:
replication:
replSetName: fang-cs
#sharding:
sharding:
clusterRole: configsvr
## Enterprise-Only Options
#auditLog:
#snmp:
启动实例

启动所有实例:

# 登录到192.168.3.73
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongod -f /mongodb/mongod-a1-config.yml
./mongod -f /mongodb/mongod-b1-config.yml
./mongod -f /mongodb/mongod-c1-config.yml
./mongod -f /mongodb/mongod-configserver1.yml
# 其他两台类似,启动其他8个实例
# 登录到192.168.3.74
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongod -f /mongodb/mongod-a2-config.yml
./mongod -f /mongodb/mongod-b2-config.yml
./mongod -f /mongodb/mongod-c2-config.yml
./mongod -f /mongodb/mongod-configserver2.yml
# 登录到192.168.3.75
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongod -f /mongodb/mongod-a3-config.yml
./mongod -f /mongodb/mongod-b3-config.yml
./mongod -f /mongodb/mongod-c3-config.yml
./mongod -f /mongodb/mongod-configserver3.yml
创建replicat set
# 登录到192.168.3.73
./mongo 127.0.0.1:28111/admin
> use admin
switched to db admin
# 初始化fang-s-a的副本集
> rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "73.dooioo.org:28111",
"ok" : 1
}
# 添加到副本集
fang-s-a:OTHER> rs.add("74.dooioo.org:28111")
{ "ok" : 1 }
fang-s-a:PRIMARY> rs.add("75.dooioo.org:28111")
{ "ok" : 1 }
# 看下副本集配置情况
fang-s-a:PRIMARY> rs.conf()
{
"_id" : "fang-s-a",
"version" : 3,
"protocolVersion" : NumberLong(1),
"members" : [
{
"_id" : 0,
"host" : "73.dooioo.org:28111",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "74.dooioo.org:28111",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "75.dooioo.org:28111",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("57c00e2b9f6b9f6453c488c3")
}
}

可以自行插入记录看看同步效果

# 登录到192.168.3.74 初始化fang-s-b 添加副本集
./mongo 127.0.0.1:28112/admin
rs.initiate()
rs.add("73.dooioo.org:28112")
rs.add("75.dooioo.org:28112")
# 登录到192.168.3.75 初始化fang-s-c 添加副本集
./mongo 127.0.0.1:28113/admin
rs.initiate()
rs.add("73.dooioo.org:28113")
rs.add("74.dooioo.org:28113")
# 登录到192.168.3.74 初始化fang-cs添加副本集
./mongo 127.0.0.1:28200/admin
rs.initiate()
rs.add("74.dooioo.org:28200")
rs.add("75.dooioo.org:28200")
添加分片集群
# 登录到192.168.3.73
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongos --port 28300 --configdb fang-cs/73.dooioo.org:28200,74.dooioo.org:28200,75.dooioo.org:28200 --fork --logpath /home/log/mongodb/mongos.log --bind_ip 0.0.0.0

通过mongos来登录

# 登录到192.168.3.73
cd /root/mongodb-linux-x86_64-rhel62-3.2.9/bin
./mongo 127.0.0.1:28300/admin
mongos> use admin
switched to db admin
mongos> sh.addShard("fang-s-a/73.dooioo.org:28111,74.dooioo.org:28111,75.dooioo.org:28111")
{ "shardAdded" : "fang-s-a", "ok" : 1 }
mongos> sh.addShard("fang-s-b/73.dooioo.org:28112,74.dooioo.org:28112,75.dooioo.org:28112")
{ "shardAdded" : "fang-s-b", "ok" : 1 }
mongos> sh.addShard("fang-s-c/73.dooioo.org:28113,74.dooioo.org:28113,75.dooioo.org:28113")
{ "shardAdded" : "fang-s-c", "ok" : 1 }
mongos>

没有安全认证的集群就搭建好了,下面是关于安全认证的。

建立安全
秘钥文件keyfile

生成秘钥文件

openssl rand -base64 755 > /mongodb/keyfile
chmod 400 /mongodb/keyfile
scp keyfile root@192.168.3.74:/mongodb/
scp keyfile root@192.168.3.75:/mongodb/

创建用户,登录到一个mongos实例,为集群创建root用户

db.createUser({user: "root******",pwd: "**************",roles: [ "root", "userAdminAnyDatabase", "userAdmin", "dbOwner" ]})

所有实例全部停止,使用

./mongod -f /mongodb/mongod-a1-config.yml --shutdown

mongod实例启动添加参数 --keyFile /mongodb/keyfile --auth

启动时可以不使用 --auth参数,因为使用了 --keyFile就必须验证,也就是隐含了 --auth。但是--auth并不隐含 --keyFile。

测试,iostat,观察使用情况

例如,以下命令会每隔一秒展示额外的统计数据和每次展示报表的时间(以MB/s为流量单位):

iostat -xmt 1

Key fields from iostat:

%util: 这对快速查看来说是最有用的字段,它指明了设备/驱动器使用时间的百分比。
avgrq-sz:平均请求大小。该值较小的数字反映了更多的随机IO操作。
核武MongoDB Ops Manager

下面介绍下核武MongoDB Ops Manager。

安装
机器同上(CentOS release 6.6)。官方推荐要求15 GB memory and 50 GB disk space。df -h校验。测试用,少一些没关系。这里测试机器30G硬盘空间,4G内存。需要有root账号。首先安装一个mongod实例,作为ops的db。到官网上下载Ops Manager包,我这里下载的是mongodb-mms-2.0.5.358-1.x86_64.rpm。

执行

sudo rpm -ivh mongodb-mms-2.0.5.358-1.x86_64.rpm
sudo service mongodb-mms start
配置文件位置/opt/mongodb/mms/conf/conf-mms.properties
默认访问8080端口,http://192.168.3.81:8080/.
账号配置

略,比如修改时区为北京时间。

新的部署

登录,可以选择部署新的集群和,管理手动创建的集群


MongoDB3.2.9分布式集群搭建
选择Build New Deployment Where would you like to deploy MongoDB?
选择 Deployment in other remote. What type of MongoDB deployment would you like to build?
选择 Sharded Cluster Provide details for your sharded cluster 规划你的集群配置
Cluster Name : mdb-test-cluster Shard Count : 4 Nodes Per Shard : 3 Shard Name Prefix : mdb-test Data Directory Prefix : /data Install an Automation Agent on each server. 在每个服务器安装自动代理服务。 默认需要12个服务器,因为 4* 3,这里服务器少,选择4台服务器。
选择下载安装配置代理服务器: 基本是一步一步手把手了,

下载代理包

curl -OL http://192.168.3.81:8080/download/agent/automation/mongodb-mms-automation-agent-manager-2.5.19.1732-1.x86_64.rpm

安装代理包

sudo rpm -U mongodb-mms-automation-agent-manager-2.5.19.1732-1.x86_64.rpm

打开配置文件,编辑配置,数据库指定了目录的,必须创建目录。

sudo vi /etc/mongodb-mms/automation-agent.config
mmsGroupId=57be67ffe4b09e1dfa498ee7
mmsApiKey=e5b83213955c886d0ef8ce3324cf8f30
mmsBaseUrl=http://192.168.3.81:8080
sudo mkdir -p /data
sudo chown mongod:mongod /data
sudo service mongodb-mms-automation-agent start

验证通过后,下一步。初始了默认的一些实例:


MongoDB3.2.9分布式集群搭建

你也可以移动。先按默认的下一步。

然后提示: We are deploying your changes. This might take a few minutes…

mysql-proxy解决只能内网访问线上数据库问题

$
0
0

CleverCode的线上数据库,只能通过内网连接到线上。每次都需要登录ssh终端上操作。为了操作方便在在内网开发机上装了一个mysql-proxy去访问线上数据库。

1 架构如下
mysql-proxy解决只能内网访问线上数据库问题

架构说明

线上数据库,只授权了192.168.1.*网段的用户能够访问线上数据库。其它网段都不能访问。

2 线上数据库创建用户

登录到192.168.2.101机器,创建一个授权用户。

# mysql -uclevercode -pc123456 -h 192.168.2.101 -P 3306

mysql>GRANT ALL PRIVILEGES ON *.* TO 'clevercode'@'192.168.1.*' IDENTIFIED BY 'c123456' WITH GRANT OPTION;
mysql>FLUSH RIVILEGES;
3 mysql-proxy安装与配置

3.1 安装

# yum list mysql-proxy
# yum -y install mysql-proxy
# service iptables stop
3.2 配置

vi /etc/mysql-proxy.cnf

[mysql-proxy]
daemon = true
pid-file = /var/run/mysql-proxy.pid
log-file = /var/log/mysql-proxy.log
log-level = debug
max-open-files = 1024
plugins = admin,proxy
user = mysql-proxy
#
#Proxy Configuration(代理开发机)
proxy-address = 192.168.1.101:3316
#线上数据库地址
proxy-backend-addresses = 192.168.2.101:3306
#proxy-read-only-backend-addresses =
#proxy-lua-script =
#proxy-skip-profiling = true
#
# Admin Configuration
#admin-address = 0.0.0.0:4041
admin-lua-script = /usr/lib64/mysql-proxy/lua/admin.lua
admin-username = admin
admin-password = admin
3.3 启动

# mysql-proxy --defaults-file=/etc/mysql-proxy.cnf

可以配置多个配置文件,来代理不同的线上数据库。

4 navicat连接
mysql-proxy解决只能内网访问线上数据库问题

只要自己的windows机器能够访问192.168.1.101的3316端口。msyql-proxy就能够代理到192.168.2.101的3306端口。这个密码要用线上数据库的密码。


基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)

$
0
0

四、数据可视化与Hue简介

1. 数据可视化简介

数据可视化在维基百科上是这样定义的:指一种表示数据或信息的技术,它将数据或信息编码为包含在图形里的可见对象(如点、线、条等),目的是将信息更加清晰有效地传达给用户,是数据分析或数据科学的关键技术之一。简单地说,数据可视化就是以图形化方式表示数据。决策者可以通过图形直观地看到数据分析结果,从而更容易理解业务变化趋势或发现新的业务模式。使用可视化工具,可以在图形或图表上进行下钻,以进一步获得更细节的信息,交互式地观察数据改变和处理过程。
(1)数据可视化的重要性
从人类大脑处理信息的方式看,使用图形图表观察大量复杂数据要比查看电子表格或报表更容易理解。数据可视化就是这样一种以最为普通的方式,向人快速、简单传达信息的技术。通过数据可视化能够有效地利用数据,帮助人们给诸如以下问题快速提供答案:
需要注意的问题或改进的方向。影响客户行为的因素。确定商品放置的位置。销量预测。 通过增加数据可视化的使用,能够使企业更快地发现所要追求的价值。创建更多的信息图表,让人们更快地使用更多的资源,获得更多的信息。同时使人们意识到已经知道很多信息,而这些信息先前就应该是很明显的,从而增加了人们能够提出更好问题的可能。它创建了似乎没有任何联系的数据点之间的连接,让人们能够分辨出有用的和没用的数据,这样,就能最大限度的提高生产力,让信息的价值最大化。
(2)数据可视化的用途
快速理解信息
通过使用业务信息的图形化表示,企业可以以一种清晰的、与业务联系更加紧密的方式查看大量的数据,根据这些信息制定决策。并且由于相对于电子表格的数据分析,图形化格式的数据分析要更快,因此企业可以更加及时地发现问题、解决问题。
标识关系和模式
即使面对大量错综复杂的数据,图形化表示也使数据变得可以理解。企业能够识别高度关联、互相影响的多个因素。这些关系有些是显而易见的,有些则不易发现。识别这些关系可以帮助组织聚焦于最有可能影响其重要目标的领域。
确定新兴趋势
使用数据可视化,可以辅助企业发现业务或市场趋势,准确定位超越竞争对手的自身优势,最终影响其经营效益。企业更容易发现影响产品销量和客户购买行为的异常数据,并把小问题消灭于萌芽之中。
方便沟通交流
一旦从可视化分析中对业务有了更新的深入了解,下一步就需要在组织间沟通这些情况。使用图表、图形或其它有效的数据可视化表示在沟通中是非常重要的,因为这种表示更能吸引人的注意,并能快速获得彼此的信息。
(3)实施数据可视化需要考虑的问题
实施一个新技术,需要采取一些步骤。除了扎实地掌握数据外,还需要理解目标、需求和受众。在组织准备实施数据可视化技术时,先要做好以下功课:
明确试图可视化的数据,包括数据量和基数(一列数据中不同值的个数)。确定需要可视化和传达的信息种类。了解数据的受众,并领会他们如何处理可视化信息。使用一种对受众来说最优、最简的可视化方案传达信息。 在关于数据的属性和作为信息消费者的受众的相关问题有了答案后,就需要准备与大量的数据打交道了。大数据给可视化带来新的挑战,4V(Volume、Velocity、Variety、Veracity)是必须要考虑的问题,而且数据产生的速度经常会比其被管理和分析的速度快。需要可视化的列的基数也是应该重点考虑的因素,高基数意味着该列有大量不同值(如银行账号等),而低基数则说明该列有大量重复值(如性别列)。
(4)几种主要的数据可视化工具
Tableau Desktop(主流桌面BI)Business Object(SAP收购的BI公司)Hyperion(Oracle收购的BI公司)Cognos(IBM收购的BI公司)Pentaho Report(最流行的开源BI)2. Hue简介
前面讨论了数据可视化,那么在Hadoop生态圈中,有哪些图形化的用户界面可以做数据可视化呢?这里就简单介绍一个常用的Hadoop组件——Hue。
(1)Hue是什么
Hue是Hadoop User Experience的缩写,是一个开源的Apache Hadoop UI系统,最早是由Cloudera Desktop演化而来,由Cloudera贡献给开源社区,它是基于python Web框架Django实现的。
我使用的CDH 5.7.0自带的Hue是3.9.0版本。通过使用CDH的Hue Web应用,可以与Hadoop集群进行交互。在Hue中可以浏览HDFS和作业,管理Hive元数据,运行Hive、Impala查询或Pig脚本,浏览HBase,用Sqoop导出数据,提交MapReduce程序,用Solr建立定制的搜索引擎,调度重复执行的Oozie工作流等。
Hue应用运行在Web浏览器中,不需要安装客户端。其体系结构如下图所示。
基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)
Hue Server是Web应用的容器,位于CDH和浏览器之间,是所有Hue Web应用的宿主,负责与CDH组件通信。
(2)Hue功能快速预览
可以从CDH Manager中的连接登录Hue。点击集群中的Hue服务,如下图所示。
基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)
在Hue页面点击Hue Web UI链接,如下图所示。
基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)
这时会打开登录页面,要求输入用户名/密码,首次登录输入任意字符串,会自动作为管理员的用户名和密码,如下图所示。
基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)
登录后Hue会进行配置检查、安装示例、创建或导入用户等向导步骤,然后进入Hue主页。我的Hue主页如下图所示。
基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)
图中最上面是导航条,11个图标都有超链接。Hue图标是“关于 Hue”链接,点击进入刚登录后的向导步骤页面。第二个是主页图标,点击进入“我的文档”页面。后面依次为“查询数据”、“管理数据”、“使用 Oozie 的计划”、“管理HDFS”、“管理作业”、“管理”、“文档”、“演示教程”和“注销”子菜单或超链接。“查询数据”子菜单包括Hive、Impala、DB查询、Pig和作业设计器。“管理数据”子菜单包括Metastore表和Sqoop 传输。“使用 Oozie 的计划”包括WorkFlow、Coordinator、Bundles三种Oozie工作流的仪表板和编辑器。“管理”包括编辑配置文件和管理用户子菜单。
这些是Hue主要的功能,每个主功能下面的详细页面这里就不展示了,都是页面操作,感兴趣的点击试一下便知。在这些功能特性集合中,“查询数据”与数据可视化关系最为密切,也是最常使用的功能。在后面实例部分,将会看到与查询相关的图形化表示,还会演示其它一些Hue的常用功能。
(3)配置元数据存储
像Hadoop的其它组件一样,Hue也有很多配置选项,每个选项的具体含义和配置说明可以从CDH Manager的Hue配置页或相关文档中找到。在这需要说明一下的是Hue自身的元数据存储配置。
Hue服务器需要一个SQL数据库存储诸如用户账号信息、提交的作业、Hive查询等少量数据。CDH 5.7.0缺省安装时,Hue的元数据存储在一个嵌入式数据库SQLite中,但这种配置并不适用于生产环境。Hue也支持MariaDB、mysql、PostgreSQL、Oracle等几种外部数据库。Cloudera强烈推荐在Hue多用户环境,特别是生产环境中使用外部数据库。CDH 5所支持的数据库完整列表链接在http://www.cloudera.com/documentation/enterprise/latest/topics/cdh_ig_req_supported_versions.html#topic_2。
下面说明使用CDH Manager配置Hue服务器在MySQL中存储元数据的详细步骤(注意:Cloudera推荐使用InnoDB作为Hue的MySQL存储引擎。CDH 5的Hue需要InnoDB)。
配置前需求:
安装所用操作系统需要的所有类库。如CentOS/RHEL需要的类库如下: Oracle's JDK (read more here)
ant
asciidoc
cyrus-sasl-devel
cyrus-sasl-gssapi
cyrus-sasl-plain
gcc
gcc-c++
krb5-devel
libffi-devel
libtidy (for unit tests only)
libxml2-devel
libxslt-devel
make
mvn (from apache-maven package or maven3 tarball)
mysql
mysql-devel
openldap-devel
python-devel
sqlite-devel
openssl-devel (for version 7+)
gmp-devel
各操作系统需要的类库完整列表链接在https://github.com/cloudera/hue#development-prerequisites。
确认Hue Server运行在Python 2.6或以上版本上。安装了MySQL数据库(MySQL数据库的安装配置详见http://www.cloudera.com/documentation/enterprise/latest/topics/cm_ig_mysql.html#cmig_topic_5_5)。 在Cloudera Manager管理控制台中,从服务列表中点击“Hue”进入Hue服务状态页面。选择“操作” > “停止”,停止Hue服务,如下图所示。
基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)
选择“操作” > “转储数据库”,将元数据库转储为一个json文件中。注意在“转储数据库”命令执行窗口中,确认转储文件所在的主机,如下图所示。
基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)
在该主机上打开一个终端窗口,编辑/tmp/hue_database_dump.json文件,去掉文件中useradmin.userprofile段中的所有JSON对象,例如:
{
"pk": 14,
"model": "useradmin.userprofile",
"fields":
{ "creation_method": "EXTERNAL", "user": 14, "home_directory": "/user/tuser2" }
},
在/etc/my.cnf文件中设置MySQL严格模式。
[mysqld]
sql_mode=STRICT_ALL_TABLES
在MySQL中建立一个新的数据库并授予一个Hue用户该库的管理员权限,例如:
mysql> create database hue;
Query OK, 1 row affected (0.01 sec)
mysql> grant all on hue.* to 'hue'@'localhost' identified by 'secretpassword';
Query OK, 0 rows affected (0.00 sec)
在Cloudera Manager管理控制台,点击“Hue”服务。点击“配置”标签。“类别”选择“数据库”。指定Hue数据库的类型、主机名、端口、用户名、密码和数据库名。例如下图所示。
基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)
在新数据库还原Hue的元数据。 a. 选择“操作” > “同步数据库”。
b. 确认外键,如下图所示。
$ mysql -uhue -psecretpassword
mysql > SHOW CREATE TABLE auth_permission\G
mysql > SHOW CREATE TABLE desktop_document\G
mysql > SHOW CREATE TABLE django_admin_log\G
基于hadoop生态圈的数据仓库实践――OLAP与数据可视化(四)

c. 删除上一步查出的外键。

mysql > ALTER TABLE auth_permission DROP FOREIGN KEY content_type_id_refs_id_d043b34a;
mysql > ALTER TABLE desktop_document DROP FOREIGN KEY content_type_id_refs_id_800664c4;
mysql > ALTER TABLE django_admin_log DROP FOREIGN KEY content_type_id_refs_id_93d2d1f8;
d. 删除django_content_type表里的数据。
DELETE FROM hue.django_content_type;
e. 在Hue服务页,点击“操作” > “加载数据库”。
f. 添加c步删除的外键。
mysql > ALTER TABLE auth_permission ADD FOREIGN KEY (content_type_id) REFERENCES django_content_type (id);
mysql > ALTER TABLE desktop_document ADD FOREIGN KEY (content_type_id) REFERENCES django_content_type (id);
mysql > ALTER TABLE django_admin_log ADD FOREIGN KEY (content_type_id) REFERENCES django_content_type (id);
13. 启动Hue服务。
如果在上述步骤中报类似“libmysqlclient.so.16: cannot open shared object file: No such file or directory”这种错误,说明MySQL的类库和Hue所需的不兼容,这时只需下载兼容版本的库文件,并放置到/usr/lib64目录,再操作就不会报错了。

数据库高可用架构(MySQL、Oracle、MongoDB、Redis)

$
0
0
一、mysql
MySQL小型高可用架构
方案:MySQL双主、主从 + Keepalived主从自动切换
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:两台PC Server
优点:架构简单,节省资源
缺点:无法线性扩展,主从失败之后需要手动恢复主从架构
MySQL中型高可用架构
方案:MMM + MySQL双主 + 多从高可用方案
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:
1、至少五台PC Server,2台MySQL主库,2台MySQL从库,1台MMM Monitor;
2、1台MMM Monitor选择低配;
3、如果不采用F5作为从库的负载均衡器,可用2台PC SERVER部署LVS或HAProxy+Keepalived组合来代替;
优点:双主热备模式,读写分离,SLAVE集群可线性扩展
缺点:读写分离需要在程序端解决,Master大批量写操作时会产生主从延时
MySQL大型高可用架构
主要思路:中间件+MySQL Sharding
如方案:Cobar等中间件+MySQL技术
图片略。
另外,还分享些MySQL一些主流的高可用架构
1、MySQL双主 + Keepalived主备自动切换方案(上面已有)
2、MySQL主从 + Keepalived主从自动切换方案(上面已有)
3、MMM+MySQL双主 + 多从高可用方案(上面已有)
4、MySQL + Pecemaker(Heartbeat) + DRBD高可用
5、MySQL + RHCS 高可用方案
6、MySQL + Cluser 集群架构
7、Percona Xtradb Cluster 集群高可用性解决方案
8、中间件 + MySQL 大型集群解决方案(上面已提到)
MySQL + Pecemaker(Heartbeat) + DRBD高可用 && MySQL + RHCS 高可用方案
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
Percona Xtradb Cluster 集群高可用性解决方案
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
MySQL多机房部署架构参考
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
二、Oracle
1、Oracle ActiveDataGuard
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:2台PC Server
1、Oracle自己的容灾系统,数据库完全冗余保护,可跨IDC部署;
2、Oracle 11g 以上版本Standby可Redo模式打开,可作为数据仓库使用,也可以作为备份数据库;
3、可切换,一般会采用手动切换方式。
2、Oracle RAC
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:至少两台PC Server作为RAC节点,SAN存储一台,
其他资源:光纤网络环境
RAC的特性:
1、高可用性:保证只要有一个存活的节点,就不会断业务,保持业务连续性
2、双机双工:RAC是并行模式工作的,节点间关系是Active对Active,每个节点都能为客户端提供服务
3、易伸缩:RAC的增加、删除节点非常方便
4、高吞吐量:节点数量和吞吐量是正比关系
3、Oracle MAA
方案:RAC+ASM+Standby(RAC)部署
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:RAC所需要资源*2
其他资源:异地机房
备注:MAA实质上就是RAC+DataGuard的结合体。
Oracle还有很多其他高可用架构,比如结合Oracle Golden Gate做复制等等……
三、MongoDB
MongoDB高可用架构
方案:MongoDB复制集+Sharding分片
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:
1、9台:6台PC Server作为shared节点,3台作为仲裁节点,三个Mongos和Config各部署在三个Shared节点上,如上图;
2、横向扩展分片,一组分片由3台PC Server构成;
3、仲裁节点服务器不存储实际数据,因此低配即可。
备注:
1、考虑到高可扩展问题,放弃MongoDB主从复制方案;
2、对数据安全要求非常高的业务,每组分片可由5台PC Server构成;
3、建议开发人员结合业务选出最合适的片键。
四、Redis
Redis小型高可用架构
方案:Redis主从复制+Keepalived实现Failover
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:两台PC Server
优点:架构简单,节省资源
缺点:主从切换有间隔,这期间客户端将收到错误
方案:Redis Sentinel实现Failover
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:
1、两台PC Server部署Redis,一台Redis Sentinel;
2、Redis可选择一主多从架构;
3、一台Redis Sentinel选择低配。
优点:Redis官方自带HA方案,Redis作者所编写,具备
缺点:发生Failover之后,客户端需要手动更正地址
Redis中型高可用架构
方案:Redis主从+Haproxy负载均衡
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:至少3台PC Server部署Redis主从,两台PC Server部署Haproxy
优点:读写分离,横向扩展Slave
缺点:Master为单点
Redis大型高可用架构
方案:Twemproxy实现Redis存储分片
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
服务器资源:至少6台PC Server部署Redis主从,至少3台PC Server部署Twemproxy,2台PC Server部署HAProxy
优点:分片,负载均衡,Redis和Twemproxy都可以横向扩展
缺点:Twemproxy所存在的缺点:
1、Twemproxy节点扩展,原来的数据需要重新处理分布,避免出现找不到key值;
2、扩展Redis节点,数据不会自动均匀分布,而需人工处理。

点击复制链接 与好友分享!回本站首页

上一篇:相关子查询与非相关子查询
下一篇:SQL复习
相关文章

数据库架构手记

HIVE体系架构

hive架构原理简析-mapreduce部分

hsql使用架构包启动数据库

MicrosoftAzure存储架构设计

IntegrationServices架构概述

数据仓库体系架构

Memcached及Redis架构分析和比较

一个根据配置文件对数据库进行增删改查

成长型公司如何构建存储架构


图文推荐

数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
SQL复习
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
mysql-proxy解决只能
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
MongoDB3.2.9分布式集
数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
windows环境下搭建



文章
读书

Win2000下关闭无用端口
禁止非法用户登录综合设置 [win9x篇]
关上可恶的后门――消除NetBIOS隐患
网络入侵检测系统
潜伏在Windows默认设置中的陷井
调制解调器的不安全
构建Windows 2000服务器的安全防护林
SQL Server 2000的安全配置
黑客攻防技术宝典:Web实战篇(第2版)
超级网管员――网络安全
代码大全(第二版)
软件之道:软件开发争议问题剖析
CSS插件工具箱
CSS入门经典(第3版)
C#并行编程高级教程:精通.NET 4 Pa
CMMI+敏捷整合开发




点击排行

机器学习面试问题7
Mybatis传多个参数(三种解决方案)
mysql分表和表分区详解
Oracle使用——PLSQL的中文乱码显示全
Oracle行转列、列转行的Sql语句总结
oracle11g客户端如何完全卸载
一点实例明白mysql数据库存储过程
实战体验几种MySQLCluster方案







关于我们 |
联系我们 |
广告服务 |
投资合作 |
版权申明 |
在线帮助 |
网站地图 |
作品发布 |
Vip技术培训
版权所有: 红黑联盟--致力于做实用的IT技术学习网站

SQL复习

$
0
0
TOP/LIMIT操作符

当数据过多的时候用于分页操作。

mysql:
SELECT column_name(s)
FROM table_name
LIMIT number;
Oracle:
SELECT column_name(s)
FROM table_name
WHERE ROWNUM <=number;
SQL Server
SELECT TOP number|percent column_name(s) FROM table_name
LIKE操作符

用于where子句中模糊搜索

SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern;

查找不包含的内容

SELECT column_name(s) FROM table_name WHERE column_name NOT LIKE pattern;
SQL中通配符/正则表达式
通配符用于sql语句中代替其他字符 在sql语句中常和sql 的LIKE操作符一起使用
% 代替0个或者多个
_代替一个任意字符
正则表达式 用regexp 或 not regexp来表示 eg: select * from websites where name regexp ‘^[GFS]’; 表示查找 name开始的所有name
IN操作符
IN操作符允许将where的范围限定在几个特定的值中
Select * from websites where name in (‘google’,’菜鸟教程’) 那么搜索的name就在这两个之中
BETWEEN操作符
BETWEEN操作符,选取在两个值中间的数据 这些值可以是数值 文本 或者日期
Select * from websites where alexa between 1 and 20;
Between和in操作符一起使用
select * from websites where alexa between 1 and 20 and country not in ('usa');
SQL别名
别名方便查找,更加直观。
常用的SQL:
SELECT name AS ‘姓名’ FROM websites;
SELECT name ‘姓名’ from websites;
SELECT name 姓名 from websites;

但是在定义别名没有单引号的时候别名不能有空格符号

SQL连接
SQL join用于把来自两个或者多个表的行结合起来,然后展示相关的信息。
INNER JOIN 内联当匹配条件成立时,将返回匹配后的行
SQL复习
LEFT JOIN 左联 左表中没有匹配的的行业会被全部显示出来
SQL复习
RIGHT JOIN 右联 右表中没有匹配的行也会被全部显示出来
SQL复习

MYSQL不支持 FULL JOIN 所以没有关于FULL JOIN 的相关测试记录 可以将FULL JOIN理解为左联加上右联

Java实现基于Redis的分布式锁

$
0
0

单JVM内同步好办, 直接用JDK提供的锁就可以了,但是跨进程同步靠这个肯定是不可能的,这种情况下肯定要借助第三方,我这里实现用Redis,当然还有很多其他的实现方式。其实基于Redis实现的原理还算比较简单的,在看代码之前建议大家先去这里看看原理,我就不翻译了,免得变味了,看懂了之后看代码应该就容易理解了。

我这里不实现JDK的java.util.concurrent.locks.Lock接口,而是自定义一个,因为JDK的有个newCondition方法我这里暂时没实现。这个Lock提供了5个lock方法的变体,可以自行选择使用哪一个来获取锁,我的想法是

最好用带超时返回的那几个方法,因为不这样的话,假如redis挂了,线程永远都在那死循环了(关于这里,应该还可以进一步优化,如果redis挂了,Jedis的操作肯定会抛异常之类的,可以定义个机制让redis挂了的时候通知使用这个lock的用户,或者说是线程)

package cc.lixiaohui.lock;
import java.util.concurrent.TimeUnit;
public interface Lock {
/**
* 阻塞性的获取锁, 不响应中断
*/
void lock;
/**
* 阻塞性的获取锁, 响应中断
*
* @throws InterruptedException
*/
void lockInterruptibly throws InterruptedException;
/**
* 尝试获取锁, 获取不到立即返回, 不阻塞
*/
boolean tryLock;
/**
* 超时自动返回的阻塞性的获取锁, 不响应中断
*
* @param time
* @param unit
* @return {@code true} 若成功获取到锁, {@code false} 若在指定时间内未取到锁
* */
boolean tryLock(long time, TimeUnit unit);
/**
* 超时自动返回的阻塞性的获取锁, 响应中断
*
* @param time
* @param unit
* @return {@code true} 若成功获取到锁, {@code false} 若在指定时间内未获取到锁
* @throws InterruptedException 在尝试获取锁的当前线程被中断
*/
boolean tryLockInterruptibly(long time, TimeUnit unit) throws InterruptedException;
/**
* 释放锁
*/
void unlock;
}

看其抽象实现:

package cc.lixiaohui.lock;
import java.util.concurrent.TimeUnit;
/**
* 锁的骨架实现, 真正的获取锁的步骤由子类去实现.
*
* @author lixiaohui
*
*/
public abstract class AbstractLock implements Lock {
/**
* <pre>
* 这里需不需要保证可见性值得讨论, 因为是分布式的锁,
* 1.同一个jvm的多个线程使用不同的锁对象其实也是可以的, 这种情况下不需要保证可见性
* 2.同一个jvm的多个线程使用同一个锁对象, 那可见性就必须要保证了.
* </pre>
*/
protected volatile boolean locked;
/**
* 当前jvm内持有该锁的线程(if have one)
*/
private Thread exclusiveOwnerThread;
public void lock {
try {
lock(false, 0, null, false);
} catch (InterruptedException e) {
// TODO ignore
}
}
public void lockInterruptibly throws InterruptedException {
lock(false, 0, null, true);
}
public boolean tryLock(long time, TimeUnit unit) {
try {
return lock(true, time, unit, false);
} catch (InterruptedException e) {
// TODO ignore
}
return false;
}
public boolean tryLockInterruptibly(long time, TimeUnit unit) throws InterruptedException {
return lock(true, time, unit, true);
}
public void unlock {
// TODO 检查当前线程是否持有锁
if (Thread.currentThread != getExclusiveOwnerThread) {
throw new IllegalMonitorStateException("current thread does not hold the lock");
}
unlock0;
setExclusiveOwnerThread(null);
}
protected void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
protected final Thread getExclusiveOwnerThread {
return exclusiveOwnerThread;
}
protected abstract void unlock0;
/**
* 阻塞式获取锁的实现
*
* @param useTimeout
* @param time
* @param unit
* @param interrupt 是否响应中断
* @return
* @throws InterruptedException
*/
protected abstract boolean lock(boolean useTimeout, long time, TimeUnit unit, boolean interrupt) throws InterruptedException;
}

基于Redis的最终实现,关键的获取锁,释放锁的代码在这个类的lock方法和unlock0方法里,大家可以只看这两个方法然后完全自己写一个:

package cc.lixiaohui.lock;
import java.util.concurrent.TimeUnit;
import redis.clients.jedis.Jedis;
/**
* <pre>
* 基于Redis的SETNX操作实现的分布式锁
*
* 获取锁时最好用lock(long time, TimeUnit unit), 以免网路问题而导致线程一直阻塞
*
* <a href="http://redis.io/commands/setnx">SETNC操作参考资料</a>
* </pre>
*
* @author lixiaohui
*
*/
public class RedisBasedDistributedLock extends AbstractLock {
private Jedis jedis;
// 锁的名字
protected String lockKey;
// 锁的有效时长(毫秒)
protected long lockExpires;
public RedisBasedDistributedLock(Jedis jedis, String lockKey, long lockExpires) {
this.jedis = jedis;
this.lockKey = lockKey;
this.lockExpires = lockExpires;
}
// 阻塞式获取锁的实现
protected boolean lock(boolean useTimeout, long time, TimeUnit unit, boolean interrupt) throws InterruptedException{
if (interrupt) {
checkInterruption;
}
long start = System.currentTimeMillis;
long timeout = unit.toMillis(time); // if !useTimeout, then it's useless
while (useTimeout ? isTimeout(start, timeout) : true) {
if (interrupt) {
checkInterruption;
}
long lockExpireTime = System.currentTimeMillis + lockExpires + 1;//锁超时时间
String stringOfLockExpireTime = String.valueOf(lockExpireTime);
if (jedis.setnx(lockKey, stringOfLockExpireTime) == 1) { // 获取到锁
// TODO 成功获取到锁, 设置相关标识
locked = true;
setExclusiveOwnerThread(Thread.currentThread);
return true;
}
String value = jedis.get(lockKey);
if (value != null && isTimeExpired(value)) { // lock is expired
// 假设多个线程(非单jvm)同时走到这里
String oldValue = jedis.getSet(lockKey, stringOfLockExpireTime); // getset is atomic
// 但是走到这里时每个线程拿到的oldValue肯定不可能一样(因为getset是原子性的)
// 加入拿到的oldValue依然是expired的,那么就说明拿到锁了
if (oldValue != null && isTimeExpired(oldValue)) {
// TODO 成功获取到锁, 设置相关标识
locked = true;
setExclusiveOwnerThread(Thread.currentThread);
return true;
}
} else {
// TODO lock is not expired, enter next loop retrying
}
}
return false;
}
public boolean tryLock {
long lockExpireTime = System.currentTimeMillis + lockExpires + 1;//锁超时时间
String stringOfLockExpireTime = String.valueOf(lockExpireTime);
if (jedis.setnx(lockKey, stringOfLockExpireTime) == 1) { // 获取到锁
// TODO 成功获取到锁, 设置相关标识
locked = true;
setExclusiveOwnerThread(Thread.currentThread);
return true;
}
String value = jedis.get(lockKey);
if (value != null && isTimeExpired(value)) { // lock is expired
// 假设多个线程(非单jvm)同时走到这里
String oldValue = jedis.getSet(lockKey, stringOfLockExpireTime); // getset is atomic
// 但是走到这里时每个线程拿到的oldValue肯定不可能一样(因为getset是原子性的)
// 假如拿到的oldValue依然是expired的,那么就说明拿到锁了
if (oldValue != null && isTimeExpired(oldValue)) {
// TODO 成功获取到锁, 设置相关标识
locked = true;
setExclusiveOwnerThread(Thread.currentThread);
return true;
}
} else {
// TODO lock is not expired, enter next loop retrying
}
return false;
}
/**
* Queries if this lock is held by any thread.
*
* @return {@code true} if any thread holds this lock and
* {@code false} otherwise
*/
public boolean isLocked {
if (locked) {
return true;
} else {
String value = jedis.get(lockKey);
// TODO 这里其实是有问题的, 想:当get方法返回value后, 假设这个value已经是过期的了,
// 而就在这瞬间, 另一个节点set了value, 这时锁是被别的线程(节点持有), 而接下来的判断
// 是检测不出这种情况的.不过这个问题应该不会导致其它的问题出现, 因为这个方法的目的本来就
// 不是同步控制, 它只是一种锁状态的报告.
return !isTimeExpired(value);
}
}
@Override
protected void unlock0 {
// TODO 判断锁是否过期
String value = jedis.get(lockKey);
if (!isTimeExpired(value)) {
doUnlock;
}
}
private void checkInterruption throws InterruptedException {
if(Thread.currentThread.isInterrupted) {
throw new InterruptedException;
}
}
private boolean isTimeExpired(String value) {
return Long.parseLong(value) < System.currentTimeMillis;
}
private boolean isTimeout(long start, long timeout) {
return start + timeout > System.currentTimeMillis;
}
private void doUnlock {
jedis.del(lockKey);
}
}

如果将来还换一种实现方式(比如zookeeper之类的),到时直接继承AbstractLock并实现lock(boolean useTimeout, long time, TimeUnit unit, boolean interrupt), unlock0方法即可(所谓抽象嘛)

测试

模拟全局ID增长器,设计一个IDGenerator类,该类负责生成全局递增ID,其代码如下:

package cc.lixiaohui.lock;
import java.math.BigInteger;
import java.util.concurrent.TimeUnit;
/**
* 模拟ID生成
* @author lixiaohui
*
*/
public class IDGenerator {
private static BigInteger id = BigInteger.valueOf(0);
private final Lock lock;
private static final BigInteger INCREMENT = BigInteger.valueOf(1);
public IDGenerator(Lock lock) {

A Recipe for Cooking with the Hadoop Ecosystem

$
0
0

It’s part of my job to cover the ecosystem of Hadoop, the open source big data technology, but sometimes it makes my head spin. If this is not your primary job, how can you possibly keep up? I hope that a discussion of what I’ve found to be most important will help those who don’t have the time and energy to devote to this wide-ranging topic.

I was a little late to the party. I first wrote about Hadoop for Ventana Research in2010. Apache Hadoop then was about four years old and consisted of three modules with three top-level projects and a few subprojects. It didn’t reach the version 1.0 designation until a year later, in December 2011. Since then it has continued to evolve at a pace that is always steady and sometimes dizzying. Today the Apache Foundation lists four modules and 11 projects on its Hadoop page and a total of 35 projects that fall into the big data category .

The open source model has had a major impact on the big data market, yet in some ways, the open source approach has succeeded despite its shortcomings. For one thing, it is not an ideal business model. Few “pure” open source companies have been able to make a profit. Red Hat is the most notable financial success in the open source world. Hortonworks , one of the Hadoop distribution vendors, strives to be entirely open source but has struggled to make a profit .

Instead, when it comes to commercializing open source technologies, most vendors use a hybrid licensing model that combines open source components with licensed products to create revenue opportunities. So far, this model hasn’t proven to be financially viable either. Cloudera and MapR have chosen a hybrid Hadoop model, but they are private companies that don’t disclose their financials publicly. By some analysts’ estimates Cloudera won’t be profitable until 2018, and MapR has indicated it won’t have a positive cash flow until mid-2017.

The real, if nonmonetary, value of an open source model is that it helps create a large community, one that few organizations could create on their own. Here the Hadoop community is an outstanding example. The Strata+Hadoop World events will take place in five different locations this year, and organizers expect to attract a combined audience of more than 10,000 attendees. The Hadoop Summits will take place in four different cities and also attract thousands of attendees. On the adoption front, nearly half (48%) of the participants in our big data integration benchmark research said they now use Hadoop or plan to use it within 12 months.

A large community such as this one typically spawns more innovation than a small community. This is both the blessing and the curse of the Hadoop ecosystem.

Hadoop constantly changes. New projects are created as the community seeks to improve or extend the existing capabilities. For example, in many cases, the MapReduce programming model is being supplemented or replaced by Spark, as I have noted . In its original incarnation, Hadoop was primarily a batch-oriented system, but as it grew in popularity users started to apply it in real-time scenarios including Internet of Things (IoT) applications, whichI’ve written about. Multiple Apache projects sprung up to deal with streaming data including Flink, Kafka, NiFi, Spark Streaming and Storm.

Regarding the last capability, all the major Hadoop distribution vendors have adopted some form of streaming data. Cloudera uses Spark and is adding Envelope and Kudu for low-latency workloads. Earlier this year, Hortonworks launched its second product, Hortonworks Data Flow , which is based on Kakfa, NiFi and Storm for streaming data. MapR introduced MapR Streams to deal with streaming data and IoT applications using the Kafka API. It’s clear that Hadoop vendors see a need to provide streaming of data, but the variety of approaches creates confusion for organizations about which approach to use.

Early Hadoop distributions did not emphasize security and governance. In our research more than half (56%) of organizations said they do not plan to deploy big data integration capabilities because it poses security risks or issues. Now those gaps are being addressed. The Apache Knox, Ranger and Sentry projects add security capabilities to Hadoop distributions. Unfortunately, there is not much consistency among vendors on which of these projects they support, again creating more confusion about which projects to use. Two other Apache projects, Atlas and Flacon, are designed to support data governance capabilities. Atlas and Ranger are still in the incubation process , the Apache process for accepting new products, but nothing prevents vendors from adopting these projects at this stage.

So how should your organization deal with
A Recipe for Cooking with the Hadoop Ecosystem
all these moving parts? Here’s my recipe. First it is important to have the skilled resources needed to manage big data projects. In our research 44 percent reported that they don’t have the Hadoop-specific skills needed. Those without them should consider hiring or contracting appropriately skilled Hadoop resources. However, some vendors provide packaged Hadoop offerings that reduce the need to have all the skills in house. For instance, there are cloud-based versions of Cloudera, Hortonworks and MapR. Amazon EMR also provides a managed Hadoop framework. Some vendors recognized the shortage of skills and have built businesses around offering big data as a service including Altiscale and BlueData .

Analytic database and data warehouse vendors have also attempted to make it easier to access and take advantage of Hadoop. These products typically take the form of SQL capabilities on Hadoop, an appliance configuration that comes installed with Hadoop or a cloud-based service that includes Hadoop. This table summarizes several vendors’ offerings.


A Recipe for Cooking with the Hadoop Ecosystem

The Open Data Platform initiative (ODPi), an industry consortium, attempts to reduce the skills needed to master different projects and versions within the Hadoop ecosystem by defining specifications for a common set of core Hadoop components. Currently Hortonworks and IBM offer ODPi-compliant versions of their Hadoop distributions, but Cloudera and MapR do not. The specification provides value to those who are looking for stable versions of the core Hadoop components.

The SQL on Hadoop products mentioned above still require that an organization have Hadoop, but it is worth considering whether you need Hadoop at all. Snowflake Computing was founded on the premise that organizations want to take advantage of the SQL skills they already have. This vendor built a cloud-based elastic data warehouse service that can scale and accommodate diverse data types while retaining a SQL interface. This approach may not be far-fetched; our research shows that relational databases are still the most commonly used big data technology.

To say the least, the Hadoop ecosystem is varied and complex. The large community surrounding big data continues to produce innovations that add to the complexity. While organizations can derive significant value from Hadoop, it does require investment. As your organization considers its investments in big data, determine which approach best suits its requirements and the skills available.

Regards,

David Menninger

SVP & Research Director

Follow Me on Twitter @dmenningerVR and Connect with me on LinkedIn .

Viewing all 6262 articles
Browse latest View live