首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

docker学习笔记002-docker-engine安装过程

虚拟机内核版本: Linux SHDL009020142 2.6.32-642.el6.x86_64 #1 SMP Wed Apr 13 00:51:26 EDT 2016 x86_64 x86_64 x86_64 GNU/Linux 采用手动安装方式,安装docker-engine 直接下载文件安装 [baseuser@SHDL009020139 ~]$ wget https://yum.dockerproject.org/repo/main/centos/6/Packages/docker-engine-1.7.1-1.el6.x86_64.rpm 安装依赖 [baseuser@SHDL009020139 ~]$ sudo yum install -y libcgroup-* [baseuser@SHDL009020139 ~]$ rpm -ivh docker-engine-1.7.1-1.el6.x86_64.rpm warning: docker-engine-1.7.1-1.el6.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID 2c52609d: NOKEY error: Failed dependencies: xz is needed by docker-engine-1.7.1-1.el6.x86_64 报错提示安装依赖XZ, [baseuser@SHDL009020139 ~]$ yum search xz Loaded plugins: product-id, search-disabled-repos, subscription-manager =========================================================== N/S Matched: xz =========================================================== xz.x86_64 : LZMA compression utilities xz-devel.i686 : Devel libraries & headers for liblzma xz-devel.x86_64 : Devel libraries & headers for liblzma xz-libs.i686 : Libraries for decoding LZMA compression xz-libs.x86_64 : Libraries for decoding LZMA compression xz-lzma-compat.x86_64 : Older LZMA format compatibility binaries Name and summary matches only, use "search all" for everything. [baseuser@SHDL009020139 ~]$ sudo yum install -y xz-* [baseuser@SHDL009020139 ~]$ rpm -ivh docker-engine-1.7.1-1.el6.x86_64.rpm warning: docker-engine-1.7.1-1.el6.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID 2c52609d: NOKEY error: can't create transaction lock on /var/lib/rpm/.rpm.lock (Permission denied) [baseuser@SHDL009020139 ~]$ sudo rpm -ivh docker-engine-1.7.1-1.el6.x86_64.rpm warning: docker-engine-1.7.1-1.el6.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID 2c52609d: NOKEY Preparing... ########################################### [100%] 1:docker-engine ########################################### [100%] 查询已安装的docker [baseuser@SHDL009020139 ~]$ yum list installed | grep docker docker-engine.x86_64 1.7.1-1.el6 installed [baseuser@SHDL009020139 ~]$ [baseuser@SHDL009020139 ~]$ ps -ef|grep docker baseuser 4460 3491 0 11:43 pts/0 00:00:00 grep docker [baseuser@SHDL009020139 ~]$ sudo service docker start [sudo] password for baseuser: Starting cgconfig service: [ OK ] Starting docker: [ OK ] [baseuser@SHDL009020139 ~]$ ps -ef|grep docker root 4506 1 2 11:44 pts/0 00:00:00 /usr/bin/docker -d baseuser 4622 3491 0 11:44 pts/0 00:00:00 grep docker [baseuser@SHDL009020139 ~]$ sudo docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://cloud.docker.com/ For more examples and ideas, visit: https://docs.docker.com/engine/userguide/ [baseuser@SHDL009020139 ~]$ sudo docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e5f07cbd2647 hello-world "/hello" 33 seconds ago Exited (0) 32 seconds ago grave_turing [baseuser@SHDL009020139 ~]$ docker version Client version: 1.7.1 Client API version: 1.19 Go version (client): go1.4.2 Git commit (client): 786b29d OS/Arch (client): linux/amd64 Server version: 1.7.1 Server API version: 1.19 Go version (server): go1.4.2 Git commit (server): 786b29d OS/Arch (server): linux/amd64 [baseuser@SHDL009020139 ~]$ 卸载 [baseuser@SHDL009020139 ~]$ yum list installed | grep docker docker-engine.x86_64 1.7.1-1.el6 installed 删除安装包 [baseuser@SHDL009020139 ~]$ sudo yum -y remove docker-engine.x86_64 [baseuser@SHDL009020139 ~]$ yum list installed | grep docker [baseuser@SHDL009020139 ~]$ 以上安装过程。

优秀的个人博客,低调大师

Storm概念学习系列之Blot消息处理者

Bolt消息处理者 认识了消息源Spout和消息的数据存储元组Tuple,接下来了解消息的处理者Bolt。Bolt是接收Spout发出元组Tuple后处理数据的组件,所有的消息处理逻辑被封装在Bolt中,Bolt负责处理输入的数据流并产生输出的新数据流。 1. Bolt介绍 消息处理者Bolt在Storm中是一个被动的角色。Bolt把元组作为输入,然后产生新的元组作为输出。 1.1 Bolt的功能Bolt可以执行过滤、函数操作、合并、写数据库等操作。Bolt还可以简单地传递消息流,复杂的消息流处理往往需要很多步骤,因此也就需要很多Bolt来处理。 Bolt可以发出超过一个的流。为此,使用OutputFieldsDeclarer类的declareStream()方法声明多个流,并使用OutputCollector类的emit()方法指定发射的流。 1.2 Bolt的生命周期 首先,客户端机器创建Bolt,然后将其序列化为拓扑,并提交给集群中的主机。之后集群启动Worker进程,反序列化Bolt,调用prepare方法开始处理元组。 接下来,Bolt处理Tuple,Bolt处理一个输入Tuple,发射0个或者多个Tuple。 然后,调用ack通知Storm自己已经处理过这个Tuple了。Storm提供了一个IBasicBolt自动调用ack。 Bolt类接收由Spout或者其他上游Bolt类发来的Tuple,对其进行处理。Bolt的生命周期如图1所示。 图1 Bolt的生命周期 在创建Bolt对象时,通过构造方法初始化成员变量,当Bolt被提交到集群时,这些成员变量也会被序列化,所以通过反序列化,可以获取到这些成员变量。 1.3 Bolt的组件 IComponent顾名思义,是所有组件的接口:IBasicBolt、IRichBolt、IBatchBolt都继承自IComponent; IBolt接口是IRichBolt要继承的接口; 还有一些以Base开头的Bolt类,如BaseBasicBolt、BaseBatchBolt、BaseRichBolt、BaseTransactionalBolt等,在这些类中需要注意的是所实现的方法都为空,或者返回值为null,其中,还有一个接口BaseComponent,是Storm提供的一个比较方便的抽象类,这个抽象类及其子类都或多或少实现了其接口定义的部分方法。从图1中,可以从整体上看到这些类的关系图,从而理清这些类之间的关系及结构。 图2 Bolt相关组件的继承关系图 1.4 Bolt常用类 Bolt比较常用的类是BaseRichBolt、BaseBasicBolt等。这两个类继承的父类如图3和图4所示,它们的共同之处是父类中都有BaseComponent和ICompont。不同之处是BaseRichBolt的父接口中有IBolt和IRichBolt,而BaseBasicBolt只有IBasicBolt。 图3 BaseRichBolt类图 图4 BaseBasicBolt类图 比较完了父类,还没有真正从使用的本质上区别这两者。下面就比较这两个类的方法。图5为IBolt接口的方法,这是BaseRichBolt继承的父接口或者类之一,IBolt具备的方法与IBasicBolt的方法结构类似,但是有本质区别,那就是方法的作用不同。IBasicBolt接口的方法如图6所示。 图5 IBolt接口的主要方法 图6 IBasicBolt接口的主要方法 IBolt继承了java.io.Serializable,在Nimbus上提交Topology以后,创建出来的Bolt在序列化后被发送到具体执行的Worker上,Worker在执行该Bolt时,先调用prepare方法传入当前执行的上下文,然后调用execute方法,对Tuple进行处理,并用prepare方法传入的OutputCollector的ack方法(表示成功)或fail方法(表示失败)来反馈处理结果。而IBasicBolt接口在执行execute方法时,自动调用ack方法,其目的就是实现该接口的Bolt时,不用在代码中提供反馈结果,Storm内部会自动反馈成功。 Bolt实例 下面的ClassifyBolt实现了BaseRichBolt接口,该类需要实现的主要方法如图7所示。 图7 ClassifyBolt的主要方法 1、prepare方法 prepare方法和Spout中的open方法类似,为Bolt提供了OutputCollector,用来从Bolt中发送Tuple。在Bolt中载入新的线程进行异步处理。OutputCollector是线程安全的,并且随时都可以调用它。 在Bolt中,Tuple的发送可以在prepare、execute、cleanup等方法中进行,但一般都是在execute中进行。 示例代码如下: public void prepare(Map conf, TopologyContext context, OutputCollector collector) { _collector = collector; } 2、declareOutputFields方法 用于声明当前Bolt发送的Tuple中包含的字段,和Spout中的类似。当前Bolt类发送的Tuple包含了两个字段:gt和lt。 示例代码如下: public void declareOutputFields(OutputFieldsDeclarer declarer) { // 在geThan流中声明为gt declarer.declareStream("geThan", new Fields("gt")); // 在lessThan流中声明为lt declarer.declareStream("lessThan", new Fields("lt")); } Bolt可以发射多条消息流,使用OutputFieldsDeclarer.declareStream方法来定义流,之后使用OutputCollector.emit来选择要发射的流。 3、getComponentConf?iguration方法 和Spout类一样,在Bolt中也可以有getComponentConf?iguration方法。示例代码如下: public Map<String, Object> getComponentConf?iguration() { Map<String, Object> conf = new HashMap<String, Object>(); conf.put(Conf?ig.TOPOLOGY_TICK_TUPLE_FREQ_SECS, emitFrequencyInSeconds); return conf; } 此例定义了从系统组件“_system”的“_tick”流中发送Tuple到当前Bolt的频率,当系统需要每隔一段时间执行特定的处理时,就可以利用该系统组件的特性来完成。 4、execute方法 Bolt的主要方法是execute,它以一个Tuple作为输入,Bolt使用OutputCollector来发射Tuple,Bolt必须为它处理的每一个Tuple调用OutputCollector的ack方法,以通知Storm该Tuple被处理完成了,从而通知该Tuple的发射者Spout。 public void execute(Tuple input) { int randomInt = input.getIntegerByField("randomInt"); // 大于等于50的放在一起 if(randomInt >= CLASSIFY_FLAG){ collector.emit("geThan", new Values(randomInt)); }else{ // 小于50的放在一起 collector.emit("lessThan",new Values(randomInt)); } collector.ack(input); } execute是Bolt中最关键的一个方法,对Tuple的处理都可以放到此方法中进行。具体的发送也是通过emit方法来完成的。此时,emit方法有两种情况,一种是方法中只有一个参数,另一种是方法中有两个参数。 1)emit有一个参数:该参数是发送到下游Bolt的Tuple,此时,由上游发来的旧的Tuple在此隔断,新的Tuple和旧的Tuple不再属于同一棵Tuple树。新的Tuple另起一棵新的Tuple树。 2)emit有两个参数:第一个参数是旧的Tuple的输入流,第二个参数是发往下游Bolt的新的Tuple流。此时,新的Tuple和旧的Tuple仍然属于同一棵Tuple树,即如果下游的Bolt处理Tuple失败,则向上传递到当前Bolt,当前Bolt根据旧的Tuple继续往上游传递,申请重发失败的Tuple,保证Tuple处理的可靠性。 这两种情况都要根据用户的场景来确定。示例代码如下: public void execute(Tuple tuple) { _collector.emit(tuple, new Values(tuple.getString(0) + "!!!")); _collector.ack(tuple); } public void execute(Tuple tuple) { _collector.emit(new Values(tuple.getString(0) + "!!!")); } 此外还有ack、fail、cleanup等方法,其中cleanup方法和Spout中的close方法类似,都是在当前组件关闭时调用,但是针对实时计算来说,除非一些特殊的场景要求以外,这两个方法一般都很少用到。 如下面, 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5989707.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Storm概念学习系列之Spout数据源

Spout 数据源 消息源Spout是Storm的Topology中的消息生产者(即Tuple的创造者)。 Spout 介绍 1. Spout 的结构 Spout 是 Storm 的核心组件之一,最源头的接口是 IComponent,如图 1所示,几个Spout接口都继承自IComponent。 图 1 Spout 类图 2.Spout 发出的消息 Spout从外部获取数据后,向Topology中发出的Tuple可以是可靠的,也可以是不可靠的。 注意:一个可靠的消息源可以重新发射一个Tuple(如果该 Tuple 没有被 Storm 成功处理),但是一个不可靠的消息源Spout 一旦发出,一个Tuple 就把它彻底“遗忘”,也就不可能再发了。 3.Spout 发射的流 Spout 可以发射多个流。要达到这样的效果,使用 OutputFieldsDeclarer.declareStream 来定义多个流(即定义多个 Stream),然后使用 SpoutOutputCollector 的emit来发射指定的流。 4.Spout 的重要方法 Spout 的重要方法是nextTuple()。 nextTuple 方法发射一个新的元组到 Topology,如果没有新元组发射,则直接返回。注意任务 Spout 的 nextTuple 方法都不要实现成阻塞的,因为Storm 是在相同的线程中调用 Spout 的方法。 Spout 的另外两个重要方法是ack ()和 fail() 方法。当 Spout 发射的元组被拓扑成功处理时,调用 ack 方法;当处理失败时,调用 fail 方法。 ack和 fail 方法仅被可靠的 Spout 调用。 5.Spout 的组件 Spout的最顶层抽象是ISpout接口。在通常情况下(Shell和事务型的除外),实现一个Spout,可以直接实现接口IRichSpout,如果不想写多余的代码,可以直接继承BaseRichSpout。 Spout 实例 下面通过创建一个实例RandomSpout来介绍Spout, 图1为RandomSpout继承自BasicRichSpout及其实现的原理图。 图2 列出了实例 RandomSpout 继承自 BaseRichSpout 中的几个重要方法。 下面对图2 中的方法进行详细介绍。 (1) open 方法 当一个 Task 被初始化时会调用此 open 方法。一般都会在此方法中初始化发送 Tuple 的对象 SpoutOutputCollector 和配置对象 TopologyContext。 代码示例如下: public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) { this.collector = collector; random = new Random(); } 图2 RandomSpout 类图 图 3-4 RandomSpout 类的主要方法 (2) declareOutputFields 方法 此方法用于声明当前 Spout 的 Tuple 发送流。流的定义是通过 OutputFieldsDeclare.declareStream方法完成的,其中的参数包括了发送的域 Fields。 示例代码如下: public void declareOutputFields(OutputFieldsDeclarer declarer) { declarer.declare(new Fields("randomInt")); } (3) nextTuple 方法 这是 Spout 类中最重要的一个方法。发射一个 Tuple 到 Topology 都是通过该方法来实现的。 示例代码如下: public void nextTuple() { while(true){ Values val = new Values(random.nextInt(100)); collector.emit(val); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } 以上代码从 100 以内的整数中随机生成一个数作为 Tuple 的值,然后通过_collector 发送到 Topology。 另外,除了上述几个方法之外,还有 getComponentConf iguration、ack、fail 和 close 方法等。 getComponentConfiguration 方法用于配置当前组件的参数, Storm 监测到一个 Tuple 被成功处理时调用 ack 方法,处理失败时调用 fail 方法,这两个方法在 BaseRichSpout 类中已经被隐式实现了。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5989285.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

【IBM Tivoli Identity Manager 学习文档】3 系统部署

ITIM 5.0 单服务器配置和部署。 部署ITIM之前要对其组件进行部署: IBM DB2 Enterprise 9.1 with FP2 IBM WebSphere Application Server 6.1 with FP9 IBM Tivoli Directory Server 6.2 IBM Tivoli Directory Integrator 6.1 我们安装系统的软硬件环境是: 地点:某公司 G3/G4机房。两台IBM的台式PC。 1.IP:9.123.108.101 Red Hat Enterprise Linux AS release 4 (Nahant Update 7) MemTotal: 513732 kB SwapTotal: 1048568 kB processor : 1 vendor_id : GenuineIntel model name : Intel(R) Pentium(R) 4 CPU 3.20GHz cpu MHz : 3201.973 cache size : 1024 KB 这台安装 IBM DB2 Enterprise 9.1 with FP2 IBM Tivoli Directory Server 6.2 2.IP:9.123.108.19 Red Hat Enterprise Linux AS release 4 (Nahant Update 4) MemTotal: 2063944 kB SwapTotal: 2031608 kB processor : 1 vendor_id : GenuineIntel model name : Intel(R) Pentium(R) D CPU 2.80GHz cpu MHz : 2793.843 cache size : 1024 KB 这台我们安装 IBM WebSphere Application Server 6.1 with FP9 ITIM 5.0 Fix Pack 3 首先进行DB2的安装配置: 1.运行安装程序: 选择Install a Product,然后按Install New。 在接受完协议后,选择典型安装,随后选择第一个选项,如下图: 进一步,选择安装路径,我们使用默认的路径/opt/ibm/db2/V9.1 然后我们新建一个对DB2 Adminstrator Server进行管理的用户,设定其密码: 选择创建一个DB2实例,并且使用单分区实例,并且设置DB2实例拥有者的信息: 设置保护用户的信息 第11步使用默认的,第十二步不安装DB2提醒。然后点击Finished。 然后就开始安装了: 安装完毕后在Terminal下验证安装是否成功: $su - db2inst1 $db2level 显示如下信息就是正确的了: DB21085I Instance "db2inst1" uses "32" bits and DB2 code release "SQL09010" with level identifier "02010107". Informational tokens are "DB2 v9.1.0.0", "s060629", "LINUXIA32", and Fix Pack "0". Product is installed at "/opt/ibm/db2/V9.1". 2.安装IBM DB2 Enterprise 9.1 Fixpack 2 首先关闭DB2实例和服务器: $su - db2inst1 $. /home/db2inst1/sqllib/db2profile $db2 terminate $db2stop 停止DAS的活动: $su - dasusr1 $. /home/dasusr1/das/dasprofile $db2admin stop 停止保护用户的活动: $su $. /home/db2inst1/sqllib/db2profile $cd /opt/ibm/db2/V9.1/bin $db2fmcu -d $db2fm -d 用grep查看关于db2的进程,没有一个就是对了。 看到所有停止的命令都是successfully就可以安装Fix Pack2了。 安装完毕后查看db2,发现Fix Pack2已经安装上了: 然后安装Tivoli Directory Server 6.2 1.运行安装脚本: 选择安装语言为English. 接受协议后选择自定义安装(Custom)。去掉TDI,稍后我们会另外安装。指定WAS目录时,选择稍后指定。 2.关闭配置工具 在安装完毕后可能会出现配置工具,我们在初次部署时暂时不用,请关闭。 接着部署WAS6.1 1.设置root的umask为0022: 用命令umask查看当前umask的值。 2.确保以下四个包的安装: compat-libstdc++-33-3.2.3-47.3 compat-db-4.1.25-9 xorg-x11-deprecated-libs-6.8.1 or xorg-x11-deprecated-libs-6.8.2 rpm-build-4.3.3-18.nonptl 用命令rpm -pa|grep XXXX检查 3.下载安装包: 在IBM内网中下载以下安装包: WebSphere Application Server V6.1 for Linux on x86Series, 32-bit Support German English International Spanish French Italian Japanese Korean Portuguese Brazilian Chinese Simplified Chinese Traditional (C87QXML) 4.开始安装: 运行launchpad.sh,然后选择“Launch the installation wizard for WebSphere Application Server” 进行安装。一直next就可以了(注意在选择安装类型时选择Application Server)。 然后在以下选项中选择第一个 5.安装IBM HTTP Server 我们暂时不配置Administration Server及其Authentication,在Plug-in里面进行如下配置: 6.安装IBM WebSphere Application Server 6.1 Update Installer 7.安装IBM WebSphere Application Server 6.1 Fixpack 9 和13 注意:在安装WAS 6.1FP9前,必须停掉IBM WebSphere Application Server, IBM HTTP Server, IBM HTTP Administration Server。 停掉服务:/opt/IBM/WebSphere/AppServer/bin/stopServer.sh server1 -username server1 -password XXXXXXX 运行:/opt/IBM/WebSphere/UpdateInstaller/update.sh 在这个地方指定升级的产品: 在这个步骤中指定升级包路径: 若出现CWUPI0026E错误,则说明你的UpdateInstaller版本太久,先删除UpdateInstaller的整个目录,然后再安装新的版本,我装的是7.0 8.启动Server /opt/IBM/WebSphere/AppServer/bin/startServer.sh server1 打开浏览器验证一下: http://localhost:9080/snoop http://localhost:9060/ibm/console 安装IBM Tivoli Directory Integrator 6.1.1 1.运行安装程序 最后我们部署TIM: 1.配置DB2 和 ITDS 6.1的中间件 解压配置中间件的应用程序,运行cfg_itim_mw_xLinux,选择英语 然后选择配置DB2和ITDS的中间件: 它会在DB2和ITDS中创建实例,一般设定密码就好了。 注意在我配置中发觉总是在创建TDS实例的时候失败,后来看了日志发现是默认的程序调用的竟然是V6.0目录中的TDS配置程序,而我安装的TDS是6.2.。。。太不智能了。。。解决方法就是ln -sf V6.2 V6.0就可以了,纯属蒙一下计算机,谁让他耍我。。。 2.安装ITIM 指定WAS,然后一路NEXT后INSTALL。 3.连接数据库 在以上这些需要填写的地方输入你配置中间件的一些信息。 若信息无错,则出现连接正确的提示 随后的配置如下: 大功告成! 4.测试安装结果 http://9.123.101.19:9080/itim/console/main 修改密码即可。 至此ITIM完全部署完毕 然后一步步进行就好了~ 本文转自gnuhpc博客园博客,原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/01/16/2324006.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Webwork 学习之路【01】Webwork与 Struct 的前世今生

Struts 1是全世界第一个发布的MVC框架,它由Craig McClanahan在2001年发布,该框架一经推出,就得到了世界上Java Web开发者的拥护,经过长达6年时间的锤炼,Struts 1框架更加成熟、稳定,性能也有了很好的保证。 到目前为止,Struts 1依然是世界上使用最广泛的MVC框架。目前,基于Web的MVC框架非常多,发展也很快,每隔一段时间就有一个新的MVC框架发布。 虽然Struts 2号称是一个全新的框架,但这仅仅是相对Struts 1而言。Struts 2与 Struts 1相比,确实有很多革命性的改进,但它并不是新发布的新框架,而是在另一个赫赫有名的框架:WebWork基础上发展起来的。从某种程度上来讲,Strut2没有继承Struts 1的血统,而是继承了WebWork的血统。或者说,WebWork衍生出了Struts 2,而不是Struts 1衍生了Struts 2。因为Struts 2是WebWork的升级,而不是一个全新的框架,因此稳定性、性能等各方面都有很好的保证;而且吸收了Struts 1和WebWork两者的优势。 Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与Servlet API完全脱离开。在很多方面Struts仅仅是改变了WebWork下的名称。Struts2对应的有自己的标签,并且功能强大。Webwork也有自己的标签。Struts 2和WebWork成员名称(命名上存在的改变)的对应表: 除此之外,Struts 2也删除了WebWork中少量特性: AroundInterceptor:Struts 2不再支持WebWork中的AroundInterceptor。如果应用程序中需要使用AroundInterceptor,则应该自己手动导入WebWork中的AroundInterceptor类。 富文本编辑器标签:Struts 2不再支持WebWork的富文本编辑器,如果应用中需要使用富文本编辑器,则应该使用Dojo的富文本编辑器。 IoC容器支持:Struts 2不再支持内建的IoC容器,而改为全面支持Spring的IoC容器,以Spring的IoC容器作为默认的Object工厂。 WebWork 框架流转图: WebWork的网站上提供了一个完整的WebWork架构图。它描述了从客户端的一次请求到最后服务器端响应的的整个执行过程。架构图如下: 此架构图一个分为五个部分,其中五个部分分别有五中不同颜色表示。 1、浅灰色方框。分别代表了客户端的一次Http请求,和服务器端运算结束之后的一次响应。 2、浅红色方框。表示一次Action请求所要经过的Servlet filters(Servlet过滤器)。我们可以看到最后一个filter就是我们前面介绍的WebWork的前端控制器。 3、蓝色方框。这是WebWork框架的核心部分。 1)一次请求到了WebWork的前端控制器,它首先会根据请求的URL解析出对应的action名称,然后去咨询ActionMapper这个action是否需要被执行。 2)如果ActionMapper决定这个action需要被执行,前端控制器就把工作委派给ActionProxy。接着她们会咨询WebWork的配置管理器,并读取在web.xml文件中定义的配置信息。接下来ActionProxy会创建ActionInvocation对象。 3)ActionInvocation是Xwork原理的(Command模式)实现部分。它会调用这个Action已定义的拦截器(before方法),Action方法,Result方法。 4)最后,看上面流程的图的方向,它会再执行拦截器(after方法),再回到Servlet Filter部分,最后结束并传给用户一个结果响应。 4、靛色方框。这是拦截器部分,在上面的拦截器章节我们已经有了详细的介绍。 5、黄色方框。这是我们在开发Web应用时,需要自己开发的程序。其中包括:Action类,页面模板,配置文件xwork.xml。 本文转自Orson博客园博客,原文链接:http://www.cnblogs.com/java-class/p/5016415.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Hadoop概念学习系列之Hadoop 产生背景(四)

Hadoop 最早起源于 Apache Nutch 。Nutch 是一个开源的网络搜索引擎,由 Doug Cutting 于 2002 年创建。Nutch 的设计目标是构建一个大型的全网搜索引擎,包括网页抓取、索引、 查询等功能,但随着抓取网页数量的增加,遇到了严重的可扩展性问题,即不能解决数十 亿网页的存储和索引问题。之后,谷歌发表的两篇论文为该问题提供了可行的解决方案。一篇是2003 年发表的关于谷歌分布式文件系统(GFS)的论文 。该论文描述了谷歌搜索引擎网页相关数据的存储架构,该架构可解决 Nutch 遇到的网页抓取和索引过程中产生的超大文件存储需求的问题。但由于谷歌仅开源了思想而未开源代码,Nutch 项目组便根据论文完成了一个开源实现,即 Nutch的分布式文件系统(NDFS)。另一篇是2004 年发表的关于谷歌分布式计算框架MapReduce 的论文 。该论文描述了谷歌内部最重要的分布式计算框架 MapReduce 的设计艺术,该框架可用于处理海量网页的索引问题。同样,由于谷歌未开源代码,Nutch 的开发人员完成了一个开源实现。由于 NDFS 和 MapReduce 不仅适用于搜索领域,2006 年年初,开发人员便将其移出 Nutch,成为 Lucene 的一个子项目,称为Hadoop。大约同一时间,Doug Cutting 加入雅虎公司,且公司同意组织一个专门的团队继 续发展 Hadoop。同年 2 月,Apache Hadoop 项目正式启动以支持 MapReduce 和 HDFS 的独立发展。2008 年 1 月,Hadoop 成为 Apache 顶级项目,迎来了它的快速发展期。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5058129.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android开发学习笔记:Android很有用的代码片段

1:查看是否有存储卡插入 Stringstatus=Environment.getExternalStorageState(); if(status.equals(Enviroment.MEDIA_MOUNTED)){ 说明有SD卡插入 } 2:让某个Activity透明 OnCreate中不设Layout this.setTheme(R.style.Theme_Transparent); 以下是Theme_Transparent的定义(注意transparent_bg是一副透明的图片) 3:在屏幕元素中设置句柄 使用Activity.findViewById来取得屏幕上的元素的句柄.使用该句柄您可以设置或获取任何该对象外露的值. TextViewmsgTextView=(TextView)findViewById(R.id.msg); msgTextView.setText(R.string.push_me); 4:发送短信 Stringbody=”thisismmsdemo”; Intentmmsintent=newIntent(Intent.ACTION_SENDTO,Uri.fromParts(”smsto”,number,null)); mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY,body); mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE,true); mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT,true); startActivity(mmsintent); 5:发送彩信 StringBuildersb=newStringBuilder(); sb.append(”file://”); sb.append(fd.getAbsoluteFile()); Intentintent=newIntent(Intent.ACTION_SENDTO,Uri.fromParts(”mmsto”,number,null)); //Belowextradatasarealloptional. intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_SUBJECT,subject); intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY,body); intent.putExtra(Messaging.KEY_ACTION_SENDTO_CONTENT_URI,sb.toString()); intent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE,composeMode); intent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT,exitOnSent); startActivity(intent); 7:发送Mail mime=“img/jpg”; shareIntent.setDataAndType(Uri.fromFile(fd),mime); shareIntent.putExtra(Intent.EXTRA_STREAM,Uri.fromFile(fd)); shareIntent.putExtra(Intent.EXTRA_SUBJECT,subject); shareIntent.putExtra(Intent.EXTRA_TEXT,body); 8:注册一个BroadcastReceiver registerReceiver(mMasterResetReciever,newIntentFilter(”oms.action.MASTERRESET”)); privateBroadcastReceivermMasterResetReciever=newBroadcastReceiver(){ publicvoidonReceive(Contextcontext,Intentintent){ Stringaction=intent.getAction(); if(”oms.action.MASTERRESET”.equals(action)){ RecoverDefaultConfig(); } } }; 9:定义ContentObserver,监听某个数据表 privateContentObservermDownloadsObserver=newDownloadsChangeObserver(Downloads.CONTENT_URI); privateclassDownloadsChangeObserverextendsContentObserver{ publicDownloadsChangeObserver(Uriuri){ super(newHandler()); } @Override publicvoidonChange(booleanselfChange){} } 10:获得手机UA publicStringgetUserAgent(){ Stringuser_agent=ProductProperties.get(ProductProperties.USER_AGENT_KEY,null); returnuser_agent; } 11:清空手机上Cookie CookieSyncManager.createInstance(getApplicationContext()); CookieManager.getInstance().removeAllCookie(); 12:建立GPRS连接 //DialtheGPRSlink. privatebooleanopenDataConnection(){ //Setupdataconnection. DataConnectionconn=DataConnection.getInstance(); if(connectMode==0){ ret=conn.openConnection(mContext,“cmwap”,“cmwap”,“cmwap”); }else{ ret=conn.openConnection(mContext,“cmnet”,“”,“”); } } 13:PreferenceActivity用法 publicclassSettingextendsPreferenceActivity{ publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); } } Setting.xml: android:key=”seting2″ android:title=”@string/seting2″ android:summary=”@string/seting2″/> android:key=”seting1″ android:title=”@string/seting1″ android:summaryOff=”@string/seting1summaryOff” android:summaryOn=”@stringseting1summaryOff”/> 14:通过HttpClient从指定server获取数据 DefaultHttpClienthttpClient=newDefaultHttpClient(); HttpGetmethod=newHttpGet(“http://www.baidu.com/1.html”); HttpResponseresp; Readerreader=null; try{ //AllClientPNames.TIMEOUT HttpParamsparams=newBasicHttpParams(); params.setIntParameter(AllClientPNames.CONNECTION_TIMEOUT,10000); httpClient.setParams(params); resp=httpClient.execute(method); intstatus=resp.getStatusLine().getStatusCode(); if(status!=HttpStatus.SC_OK)returnfalse; //HttpStatus.SC_OK; returntrue; }catch(ClientProtocolExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); }finally{ if(reader!=null)try{ reader.close(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } 15:显示toast Toast.makeText(this._getApplicationContext(),R.string._item,Toast.LENGTH_SHORT).show(); 16:在当前Activity中启动另外一个Activity startActivity(newIntent(this,目标Activity.class)); 17:从当前ContentView从查找控件 (Button)findViewById(R.id.btnAbout) R.id.btnAbout指控件id。 18:获取屏幕宽高 DisplayMetricsdm=newDisplayMetrics(); //获取窗口属性 getWindowManager().getDefaultDisplay().getMetrics(dm); intscreenWidth=dm.widthPixels;//320 intscreenHeight=dm.heightPixels;//480 19:无标题栏、全屏 //无标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE); //全屏模式 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 注意在setContentView()之前调用,否则无效。 20注册activity 所有用到的Activity都必须在AndroidManifest.xml中注册,否则会报空指针错误。 如:,注意是包名+类名。 会持续更新...................... 本文转自 lingdududu 51CTO博客,原文链接http://blog.51cto.com/liangruijun/722171

优秀的个人博客,低调大师

Android开发学习:使用已有的sql数据库

之前我们使用的数据库都是在代码里面创建的。下面介绍一下如果使用外部已有的sql数据库。 先用SQLite管理工具,sqliteadmin 具体操作很简单,在这里我就不详细介绍的了,但有一个地方时候很值得注意的,就是用sqliteadmin创建数据库的时候,数据库保存的路径不能是中文路径,中文路径会出现下面的错误提示: 我在sqliteadmin 创建好数据库StuDB,里面的表如下: 将创建好的数据库在DDMS中点击导入到data/data/程序的包名/ SQLiteTestActivity.java packagecom.lingdududu.test; importandroid.app.Activity; importandroid.database.Cursor; importandroid.database.sqlite.SQLiteDatabase; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; importandroid.widget.EditText; importandroid.widget.Toast; publicclassSQLiteTestActivityextendsActivity{ /**Calledwhentheactivityisfirstcreated.*/ privateEditTextstudentText; privateEditTextteacherText; privateButtonqueryBtn; SQLiteDatabasestuDb; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); studentText=(EditText)findViewById(R.id.stu_name); teacherText=(EditText)findViewById(R.id.teacher_name); queryBtn=(Button)findViewById(R.id.query); queryBtn.setOnClickListener(newqueryListener()); } classqueryListenerimplementsOnClickListener{ @Override publicvoidonClick(Viewv){ //调用查询方法 query(); stuDb.close(); } } //查询方法 privatevoidquery(){ //打开或者创建数据库 stuDb=SQLiteDatabase.openOrCreateDatabase("data/data/com.lingdududu.test/StuDB.s3db",null); try{ Stringstring=studentText.getText().toString(); Stringsql="SelectsnamefromStudentwheresnumber="+string; Cursorcursor=stuDb.rawQuery(sql,null); cursor.moveToFirst(); teacherText.setText(cursor.getString(cursor.getColumnIndex("sname"))); }catch(Exceptione){ Toast.makeText(this,"请检查输入的学生学号是否正确",Toast.LENGTH_LONG).show(); } } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/input_name" /> <EditText android:id="@+id/stu_name" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/query" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="开始查询" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/teacher_name" /> <EditText android:id="@+id/teacher_name" android:layout_width="fill_parent" android:layout_height="wrap_content" android:editable="false" /> </LinearLayout> strings.xml <?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="hello">HelloWorld,SQLiteTestActivity!</string> <stringname="app_name">SQLiteTest</string> <stringname="input_name">请输入学生学号</string> <stringname="teacher_name">该学生的姓名</string> </resources> 效果图: 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/728272

优秀的个人博客,低调大师

Android开发学习笔记:浅谈3大类菜单

在Android系统中,菜单可以分为三类:选项菜单(Option Menu),上下文菜单(Context Menu)以及子菜单(Sub Menu)。 一.选项菜单(Option Menu) 创建选项菜单的步骤: 1.覆盖Activity的onCreateOptionMenu(Menu menu)方法,当菜单第一次被打开时调用 2.调用Menu的add( )方法添加菜单项(MenuItem),同时可以调用MenuItem的setIcon( )方法来为菜单项设置图标 3.当菜单项(MenuItem)被选择时,覆盖Activity的onOptionsItemSelected(MenuItem item)来响应事件 选项菜单的实例: packagecom.android.menu.activity; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.Menu; importandroid.view.MenuItem; publicclassOptionMenuActivityextendsActivity{ //声明菜单项常量 privatestaticfinalintITEM_1=Menu.FIRST; privatestaticfinalintITEM_2=Menu.FIRST+1; privatestaticfinalintITEM_3=Menu.FIRST+2; publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); } //覆盖onCreateOptionsMenu(Menumenu)来添加菜单项 publicbooleanonCreateOptionsMenu(Menumenu){ //android.R使用的是系统自带的图标 menu.add(0,ITEM_1,0,"开始").setIcon(android.R.drawable.ic_media_play); menu.add(0,ITEM_2,0,"帮助").setIcon(android.R.drawable.ic_menu_help); menu.add(0,ITEM_3,0,"退出").setIcon(android.R.drawable.ic_menu_close_clear_cancel); returntrue; } //覆盖onOptionsItemSelected(MenuItemitem)来响应菜单选项被单击事件 publicbooleanonOptionsItemSelected(MenuItemitem){ switch(item.getItemId()){ caseITEM_1: setTitle("开始游戏!"); break; caseITEM_2: setTitle("查看帮助!"); break; caseITEM_3: setTitle("退出游戏!"); break; } returntrue; } } 效果图: 二.上下文菜单(Context Menu) 创建上下文菜单的步骤: 1.覆盖Activity的onCreateOptionMenu(Menu menu)方法,调用Menu的add( )方法添加菜单项(MenuItem). 2.覆盖Activity的onOptionsItemSelected(MenuItem item)来响应事件 3.调用registerForContextMenu( )方法来为视图注册上下文菜单 上下文菜单的实例(按住“测试Context Menu”2秒,就会出现上下文菜单): packagecom.android.context.activity; importandroid.app.Activity; importandroid.graphics.Color; importandroid.os.Bundle; importandroid.view.ContextMenu; importandroid.view.Menu; importandroid.view.MenuItem; importandroid.view.View; importandroid.view.ContextMenu.ContextMenuInfo; importandroid.widget.TextView; publicclassContextMenuActivityextendsActivity{ privatestaticfinalintITME_1=Menu.FIRST; privatestaticfinalintITME_2=Menu.FIRST+1; privatestaticfinalintITME_3=Menu.FIRST+2; privateTextViewtext; publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); text=(TextView)findViewById(R.id.TextView_1); //调用registerForContextMenu()来注册上下文菜单 registerForContextMenu(text); } @Override publicvoidonCreateContextMenu(ContextMenumenu,Viewv, ContextMenuInfomenuInfo){ menu.add(0,ITME_1,0,"红色背景"); menu.add(0,ITME_2,0,"蓝色背景"); menu.add(0,ITME_3,0,"白色背景"); } @Override publicbooleanonContextItemSelected(MenuItemitem){ switch(item.getItemId()){ caseITME_1: //设置TextView的背景颜色 text.setBackgroundColor(Color.RED); break; caseITME_2: text.setBackgroundColor(Color.BLUE); break; caseITME_3: text.setBackgroundColor(Color.WHITE); break; } returntrue; } } 效果图: 三.子菜单(Sub Menu) 创建子菜单的步骤: 1.覆盖Activity的onCreateOptionMenu(Menu menu)方法,调用Menu的addSubMenu( )方法来添加子菜单(Sub Menu) 2.调用SubMenu的add( )方法来添加子菜单(Sub Menu) 3.覆盖onContextItemSelect( )方法来响应菜单单击事件 子菜单的实例: packagecom.android.sub.activity; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.Menu; importandroid.view.MenuItem; importandroid.view.SubMenu; publicclassSubMenuActivityextendsActivity{ privatestaticfinalintITEM_1=Menu.FIRST; privatestaticfinalintITEM_2=Menu.FIRST+1; publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); } //覆盖onCreateOptionsMenu(Menumenu)方法,添加子菜单项 publicbooleanonCreateOptionsMenu(Menumenu){ SubMenuad=menu.addSubMenu("添加").setIcon(android.R.drawable.ic_menu_add); SubMenure=menu.addSubMenu("关闭").setIcon(android.R.drawable.ic_menu_close_clear_cancel); ad.add(0,ITEM_1,0,"文件"); ad.add(0,ITEM_2,0,"图片"); returntrue; } //覆盖onOptionsItemSelected(MenuItemitem),响应菜单选项被单击事件 publicbooleanonOptionsItemSelected(MenuItemitem){ switch(item.getItemId()){ caseITEM_1: setTitle("添加文件!"); break; caseITEM_2: setTitle("添加图片!"); break; } returntrue; } } 效果图: 注:menu.add的方法中的参数: 1.int类型的group ID参数,代表的是组概念,你可以将几个菜单项归为一组,以便更好的以组的方式管理你的菜单按钮。可以用到的方法有: removeGroup(id) setGroupCheckable(id, checkable, exclusive) setGroupEnabled(id,boolean enabled) setGroupVisible(id,visible)2.int类型的item ID参数,代表的是项目编号。这个参数非常重要,一个item ID对应一个Menu中的选项。在后面使用菜单的时候,就是靠这个item ID来判断,你选中的是哪个选项。3.int类型的order ID参数,代表的是菜单项的显示顺序。默认是0,表示菜单的显示顺序就是按照add的顺序来显示。4.String类型的title参数,表示选项中显示的文字。 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/641275

优秀的个人博客,低调大师

Android开发学习笔记:Button事件实现方法的总结

下面介绍Button事件实现的两种方法 main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/myButton1" android:text="按钮1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/myButton2" android:text="按钮2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> strings.xml <?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="hello">HelloWorld,ButtonDemoActivity!</string> <stringname="app_name">ButtonDemo</string> </resources> 第一种: ButtonDemoActivity.java packagecom.android.ButtonDemo.activity; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; importandroid.widget.Toast; publicclassButtonDemoActivityextendsActivity{ ButtonmyButton1,myButton2; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); myButton1=(Button)findViewById(R.id.myButton1); myButton2=(Button)findViewById(R.id.myButton2); //使用匿名类注册Button事件 myButton1.setOnClickListener(newOnClickListener() { publicvoidonClick(Viewv) { Toast.makeText(ButtonDemoActivity.this,"你点击了按钮1",Toast.LENGTH_LONG).show(); } }); myButton2.setOnClickListener(newOnClickListener() { publicvoidonClick(Viewv) { Toast.makeText(ButtonDemoActivity.this,"你点击了按钮2",Toast.LENGTH_LONG).show(); } }); } } 第二种: ButtonDemoActivity.java packagecom.android.ButtonDemo.activity; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; importandroid.widget.Toast; publicclassButtonDemoActivityextendsActivity{ ButtonmyButton1,myButton2; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); myButton1=(Button)findViewById(R.id.myButton1); myButton2=(Button)findViewById(R.id.myButton2); myButton1.setOnClickListener(newButtonClick()); myButton2.setOnClickListener(newButtonClick()); } //创建一个类,来响应OnClickListener classButtonClickimplementsOnClickListener { publicvoidonClick(Viewv) { switch(v.getId()){ caseR.id.myButton1: Toast.makeText(ButtonDemoActivity.this,"你点击了按钮1",Toast.LENGTH_LONG).show(); break; caseR.id.myButton2: Toast.makeText(ButtonDemoActivity.this,"你点击了按钮2",Toast.LENGTH_LONG).show(); break; default: break; } } } } 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/629329

优秀的个人博客,低调大师

Hadoop HDFS概念学习系列之HDFS Block(八)

块是文件系统中的一个很重要的概念。在UNIX/Linux系统中有一个数据块(DataBlock)的概念,Data Block是文件系统读写的最小数据单元。一般在文件系统中数据块的大小是512字节,一个文件所占的大小就是数据块大小的整数倍.对于用户来讲对文件的访问/存取都是透明的,同样系统管理员可以利用系统本身的命令对数据块进行相关操作。因此单从文件系统来讲,HDFS也有一个块(Block)的概念,不同之处在于HDFS为了满足大数据的效率和整个集群的吞吐量选择了更大的数值,默认为64MB。和一般的文件系统不同的是:虽然块设置得比较大,但是当一个文件的大小小于HDFS的块大小时,实际存储所占的大小并不占用一个块的大小。 客户端在读取HDFS上的一个文件时就以块为基本的数据单元。例如一次简单读取,首先,客户端把文件名和程序指定的字节偏移,根据固定的Block大小,转换成文件的Block索引。然后,客户端把文件名和Block索引发送给Master节点,Master节点将相应的Block标识和副本的位置信息返回给客户端,客户端用文件名和Block索引作为key缓存这些信息,之后客户端发送请求到其中的一个副本,一般会选择最近的。请求信息包含了Block的标识和字节范围。在对这个Block的后续读取操作中,客户端不必再和Master节点通信了,除非缓存的元数据信息过期或文件被重新打开。实际上,客户端通常会在一次请求中查询多个Block信息,Master节点的回应也可能包含了紧跟着这些被请求的Block后面的Block的信息。在实际应用中,这些额外的信息在不花费任何代价的情况下,避免了客户端和Master节点未来可能会发生的几次通信。 我们知道,在操作系统中都有一个文件块的概念,文件以块的形式存储在磁盘中,此处块的大小代表系统读/写可操作的最小文件大小。也就是说,文件系统每次只能操作磁盘块大小的整数倍数据。通常来说,一个文件系统块大小为几千字节,而磁盘块大小为512字节。文件的操作都由系统完成,这些对用户来说都是透明的。 这里,我们所要介绍的HDFS中的块是一个抽象的概念,它比上面操作系统中所说的块要大得多。在配置Hadoop系统时会看到,它的默认块大小为64MB。和单机上的文件系统相同,HDFS分布式文件系统中的文件也被分成块进行存储,它是文件存储处理的逻辑单元。 HDFS作为一个分布式文件系统,设计是用来处理大文件的,使用抽象的块会带来很多好处。一个好处是可以存储任意大的文件而又不会受到网络中任一单个节点磁盘大小的限制。可以想象一下,单个节点存储100TB的数据是不可能的,但是由于逻辑块的设计,HDFS可以将这个超大的文件分成众多块,分别存储在集群的各台机器上。另外一个好处是使用抽象块作为操作的单元可简化存储子系统。这里之所以提到简化,是因为这是所有系统的追求,而对故障出现频繁和种类繁多的分布式系统来说,简化就显得尤为重要。在HDFS中块的大小固定,这样它就简化了存储系统的管理,特别是元数据信息可以和文件块内容分开存储。不仅如此,块更有利于分布式文件系统中复制容错的实现。在HDFS中,为了处理节点故障,默认将文件块副本数设定为3份,分别存储在集群的不同节点上。当一个块损坏时,系统会通过NameNode获取元数据信息,在另外的机器上读取一个副本并进行存储,这个过程对用户来说都是透明的。当然,这里的文件块副本冗余量可以通过文件进行配置,比如在有些应用中,可能会为操作频率较高的文件块设置较高的副本数最以提高集群的吞吐量。 在HDFS中,可以通过终端命令直接获得文件和块信息,比如以下命令可以列出文件系统中组成各个文件的块。 hadoop fsck/ -files -blocks 我们知道数据块(Block) 在讨论文件系统的时候,特别是在分析文件系统的实现时,我们知道,为了便于管理,设备往往将存储空间组织成为具有一定结构的存储单位。如磁盘,文件是以块的形式存储在磁盘中,块的大小代表系统读/写操作的最小单位;在Linux的Ext3文件系统中,块大小默认为4095字节。文件系统通过一个块大小的整数倍的数据块,来使用磁盘。磁盘上的数据块管理属于文件系统实现的内部细节,对于通过系统调用读写文件的用户来说,是透明的。 HDFS也有块的概念,不过是更大的单元,默认FiDFS数据块大小是64MB。和普通文件系统类似,HDFS上的文件也进行分块,块作为单独的存储单元,以Linux上普通文件的形式保存在数据节点的文件系统中。数据块是HDFS的文件存储处理的单元。 HDFS是针对大文件设计的分布式系统,使用数据块带来了很多的好处,具体如下: 1) HDFS可以保存比存储节点单一磁盘大的文件。 文件块可以保存在不同的磁盘上。其实,在HDFS中,文件数据可以存放在集群上的任何一个磁盘上,不需要保存在同一个磁盘上。或同一个机器的不同磁盘上。 2)简化了存储子系统。 简单化是所有系统的追求,特别是在故障种类繁多的分布式系统,将管理“块”和管理“文件”的功能区分开,简化了存储管理,也消除了分布式管理文件元数据的复杂性。 3)方便容错,有利干数据复制。 在HDFS中,为了应对损坏的块以及磁盘、机器故障,数据块会在不同的机器上进行复制(一般副本数为3,即一份数据保存在3个不同的地方),如果一个数据块副本丢失或者损坏了,系统会在其他地方读取副本,这个过程对用户来说是透明的,它实现了分布式系统中的位置透明性和故障透明性。同时,一个因损坏或机器故障而丢失的块会从其他地方复制到某一个正常运行的机器,以保证副本数目恢复到正常水平。该正常水平的副本数,也称副本系数。 HDFS的数据块比前面讨论过的磁盘块大得多,一个典型HDFS系统中,磁盘块的大小为64MB,也有使用128MB和256MB数据块大小的集群。为什么在HDFS中要使用这么大的数据块呢?原因和在磁盘上使用大磁盘块的原理是一样的。在普通文件系统中使用较大的磁盘块,可以减少管理数据块需要的开销,如在Linux中可以减少保存在i-node中磁盘地址表中的信息链的长度:同时,在对文件进行读写时,可以减少寻址开销,即磁盘定位数据块的次数。HDFS中使用大数据块,可以减少名字节点上管理文件和数据块关系的开销,同时,对数据块进行读写时,可以有效地减少建立网络连接需要的成本。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5081487.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Hadoop MapReduce概念学习系列之MapReduce模型(十二)

在并行计算领域最著名的就是MPI模型,MPI是一种消息传递编程模型,在大规模科学计算领域已经成功应用了数年,而MapReduce则是一种近几年出现的相对较新的并行编程技术,但是MapReduce计算模型也是建立在数学和计算机科学基础上的,实践已经证明这种并行编程模型具有简单、高效的特点,最为重要的两个概念就是Map和Reduce.最基本的处理思想就是“分而治之,然后归约”。Hadoop会将一个大任务分解为可以同时执行的多个小任务,从而达到并行计算的目的。举个简单的例子,对于一个大型任务,单机处理需要1024分钟,而分解为1024个子任务并行执行就可在1分钟完成处理。在对处理的数据集的要求上,相比于传统关系数据库的结构化数据,MapReduce模型的Hadoop框架适合半结构化或非结构化的数据。 Hadoop通过自动分割将要执行的问题(程序)、拆解成Map(映射)和Reduce(化简)的方式,其分解过程的实质是将问题分为几个部分,划分为可以应用于程序的数据,再将数据分解,然后对分解的数据进行并行操作,在自动分割后通过Map程序将数据映射成不相关的区块,分配(调度)给大星的i十算机进行处理以达到分散运算的效果,再通过Reduce程序将结果汇总整合,输出开发者需要的结果。 Hadoop向用户提供了一个规范化的MapReduce编程接口,用户只需要编写Map和Reduce函数,这两个函数都是运行在键-值对基础上的,数据的切分,节点之间的通信协调等全部由Hadoop框架木身来负责。一般一个用户作业提交到Hadoop集群后会根据输入数据的大小并行启动多个Map进程及多个Reduce进程(也可以是0个或者1个)来执行.MapReduce也具有弹性适应性,小数据和大数据仅仅通过调整节点就可以处理,而不需要用户修改程序MapReduce模型处理流程如下图所示。 上图就是MapReduce的数据处理流程图,在Map之前会对输入的数据有split的过程,默认split就是写人数据时的逻辑块,每一个块对应一个split,一个split就对应一个Map进程,正是split保证了任务的并行效率。在Map之后还会有shuffe和sort的过程.shuffle简单描述就是一个Map的输出应该映射到哪个Reduce作为输入,sort就是指在Map运行完输出后会根据输出的键进行排序。这两个处理步骤对于提高Reduce的效率及减小数据传输的压力有很大的帮助。 从本质上讲MapReduce借鉴了函数式程序设计语言的设计思想,其软件实现是指定一个Map函数,把键值对(key/value)映射成新的键值对(key/value),形成一系列中间结果形式的键值对(key/value ),然后把它们传给Reduce(归约)函数,把具有相同中间形式key的value合并在一起。Map和Reduce。函数具有一定的关联性。其算法描述为: Map(k, v) ->list(k1,v1) Reduce(k1,list(v1)) ->list (v1) 在Map过程中将数据并行,即把数据用映射函数规则分开,而Reduce则把分开的数据用归约函数规则合在一起,即Map是个分的过程,Reduce则对应着合。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5080590.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Hadoop概念学习系列之Hadoop实现接口(十五)

Hadoop对于不同的开发者提供了三种接口: 第一种就是原生的Hadoop Java api接口; 第二种就是Hadoop Streaming接口,是通过标准输入/输出交互的,可以使用任何能操纵标准输人/输出的语言来编写MapReduce程序; 第三种就是Hadoop Pipes接口,专门针对C/C++的接。使用socket通信作为用户程序和Hadoop来进行交互。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5081055.html,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册