从1.2版本开始,Ehcache可以使用分布式的缓存了。
分布式这个特性是以plugin的方式实现的。Ehcache自带了一些默认的分布式缓存插件实现,这些插件可以满足大部分应用的需要。如果需要使用其他的插件那就需要自己开发了,开发者可以通过查看distribution包里的源代码及JavaDoc来实现它。
尽管不是必须的,在使用分布式缓存时理解一些ehcahce的设计思想也是有帮助的。这可以参看分布式缓存设计的页面。
以下的部分将展示如何让分布式插件同ehcache一起工作。
下面列出的是一些分布式缓存中比较重要的方面:
你如何知道集群环境中的其他缓存?分布式传送的消息是什么形式?什么情况需要进行复制?增加(Puts),更新(Updates)或是失效(Expiries)?采用什么方式进行复制?同步还是异步方式?
为了安装分布式缓存,你需要配置一个PeerProvider、一个CacheManagerPeerListener,它们对于一个CacheManager来说是全局的。每个进行分布式操作的cache都要添加一个cacheEventListener来传送消息。
正确的元素类型
只有可序列化的元素可以进行复制。
一些操作,比如移除,只需要元素的键值而不用整个元素;在这样的操作中即使元素不是可序列化的但键值是可序列化的也可以被复制,
成员发现(Peer Discovery)
Ehcache进行集群的时候有一个cache组的概念。每个cache都是其他cache的一个peer,没有主cache的存在。刚才我们问了一个问题:你如何知道集群环境中的其他缓存?这个问题可以命名为成员发现(Peer Discovery)。
Ehcache提供了两种机制用来进行成员发现,就像一辆汽车:手动档和自动档。
要使用一个内置的成员发现机制要在ehcache的配置文件中指定cacheManagerPeerProviderFactory元素的class属性为net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory。
自动的成员发现
自动的发现方式用TCP广播机制来确定和维持一个广播组。它只需要一个简单的配置可以自动的在组中添加和移除成员。在集群中也不需要什么优化服务器的知识,这是默认推荐的。
成员每秒向群组发送一个“心跳”。如果一个成员 5秒种都没有发出信号它将被群组移除。如果一个新的成员发送了一个“心跳”它将被添加进群组。
任何一个用这个配置安装了复制功能的cache都将被其他的成员发现并标识为可用状态。
要设置自动的成员发现,需要指定ehcache配置文件中cacheManagerPeerProviderFactory元素的properties属性,就像下面这样:
peerDiscovery=automatic multicastGroupAddress=multicast address | multicast host name multicastGroupPort=port
# (timeToLive属性详见常见问题部分的描述)
timeToLive=0-255
示例
假设你在集群中有两台服务器。你希望同步sampleCache1和sampleCache2。每台独立的服务器都要有这样的配置:
配置server1和server2
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=32"/>
手动进行成员发现
进行手动成员配置要知道每个监听器的IP地址和端口。成员不能在运行时动态地添加和移除。在技术上很难使用广播的情况下就可以手动成员发现,例如在集群的服务器之间有一个不能传送广播报文的路由器。你也可以用手动成员发现进行单向的数据复制,只让server2知道server1而server1不知道server2。
配置手动成员发现,需要指定ehcache配置文件中cacheManagerPeerProviderFactory的properties属性,像下面这样:
peerDiscovery=manual rmiUrls=//server:port/cacheName,
rmiUrls配置的是服务器cache peers的列表。注意不要重复配置。
示例
假设你在集群中有两台服务器。你要同步sampleCache1和sampleCache2。下面是每个服务器需要的配置:
配置server1
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12"/>
配置server2
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40001/sampleCache11|//server1:40001/sampleCache12"/>
配置CacheManagerPeerListener
每个CacheManagerPeerListener监听成员们发向当前CacheManager的消息。
配置CacheManagerPeerListener需要指定一个CacheManagerPeerListenerFactory,它以插件的机制实现,用来创建CacheManagerPeerListener。
cacheManagerPeerListenerFactory的属性有:
class – 一个完整的工厂类名。
properties – 只对这个工厂有意义的属性,使用逗吃分隔。
Ehcache有一个内置的基于RMI的分布系统。它的监听器是RMICacheManagerPeerListener,这个监听器可以用RMICacheManagerPeerListenerFactory来配置。
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40001,
socketTimeoutMillis=2000"/>
有效的属性是:
hostname (可选) – 运行监听器的服务器名称。标明了做为集群群组的成员的地址,同时也是你想要控制的从集群中接收消息的接口。
在CacheManager初始化的时候会检查hostname是否可用。
如果hostName不可用,CacheManager将拒绝启动并抛出一个连接被拒绝的异常。
如果指定,hostname将使用InetAddress.getLocalHost().getHostAddress()来得到。
警告:不要将localhost配置为本地地址127.0.0.1,因为它在网络中不可见将会导致不能从远程服务器接收信息从而不能复制。在同一台机器上有多个CacheManager的时候,你应该只用localhost来配置。
port – 监听器监听的端口。
socketTimeoutMillis (可选) – Socket超时的时间。默认是2000ms。
配置CacheReplicators
每个要进行同步的cache都需要设置一个用来向CacheManagerr的成员复制消息的缓存事件监听器。这个工作要通过为每个cache的配置增加一个cacheEventListenerFactory元素来完成。
<!-- Sample cache named sampleCache2. -->
<cache name="sampleCache2"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="false">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true "/>
</cache>
name:缓存名称。通常为缓存对象的类名(非严格标准)。
maxElementsInMemory:设置基于内存的缓存可存放对象的最大数目。
maxElementsOnDisk:设置基于硬盘的缓存可存放对象的最大数目。
eternal:如果为true,表示对象永远不会过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false;
timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期。当对象过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地处于空闲状态。
timeToLiveSeconds:设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期。当对象过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义。
overflowToDisk:如果为true,表示当基于内存的缓存中的对象数目达到了maxElementsInMemory界限后,会把益出的对象写到基于硬盘的缓存中。
class – 使用net.sf.ehcache.distribution.RMICacheReplicatorFactory
这个工厂支持以下属性:
replicatePuts=true | false – 当一个新元素增加到缓存中的时候是否要复制到其他的peers. 默认是true。
replicateUpdates=true | false – 当一个已经在缓存中存在的元素被覆盖时是否要进行复制。默认是true。
replicateRemovals= true | false – 当元素移除的时候是否进行复制。默认是true。
replicateAsynchronously=true | false – 复制方式是异步的(指定为true时)还是同步的(指定为false时)。默认是true。
replicateUpdatesViaCopy=true | false – 当一个元素被拷贝到其他的cache中时是否进行复制(指定为true时为复制),默认是true。
你可以使用ehcache的默认行为从而减少配置的工作量,默认的行为是以异步的方式复制每件事;你可以像下面的例子一样减少RMICacheReplicatorFactory的属性配置:
<!-- Sample cache named sampleCache4. All missing RMICacheReplicatorFactory properties default to true -->
<cache name="sampleCache4"
maxElementsInMemory="10"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
</cache>
常见的问题Windows上的Tomcat
有一个Tomcat或者是JDK的bug,在tomcat启动时如果tomcat的安装路径中有空格的话,在启动时RMI监听器会失败。参见http://archives.java.sun.com/cgi-bin/wa?A2=ind0205&L=rmi-users&P=797和http://www.ontotext.com/kim/doc/sys-doc/faq-howto-bugs/known-bugs.html。
由于在Windows上安装Tomcat默认是装在“Program Files”文件夹里的,所以这个问题经常发生。
广播阻断
自动的peer discovery与广播息息相关。广播可能被路由阻拦,像Xen和VMWare这种虚拟化的技术也可以阻拦广播。如果这些都打开了,你可能还在要将你的网卡的相关配置打开。
一个简单的办法可以告诉广播是否有效,那就是使用ehcache remote debugger来看“心跳”是否可用。
广播传播的不够远或是传得太远
你可以通过设置badly misnamed time to live来控制广播传播的距离。用广播IP协议时,timeToLive的值指的是数据包可以传递的域或是范围。约定如下:
0是限制在同一个服务器
1是限制在同一个子网
32是限制在同一个网站
64是限制在同一个region
128是限制在同一个大洲
255是不限制
译者按:上面这些资料翻译的不够准确,请读者自行寻找原文理解吧。
在Java实现中默认值是1,也就是在同一个子网中传播。改变timeToLive属性可以限制或是扩展传播的范围。
原文地址为 http://ehcache.sourceforge.net/documentation/distributed_caching.html
通常,集群里的一台机器被指定为 NameNode,另一台不同的机器被指定为JobTracker。这些机器是 masters。余下的机器即作为DataNode 也作为TaskTracker。这些机器是 slaves\ 官方地址:(http://hadoop.apache.org/common/docs/r0.19.2/cn/cluster_setup.html)
1 先决条件确保在你集群中的每个节点上都安装了所有必需软件:sun-JDK ,ssh,Hadoop
JavaTM1.5.x,必须安装,建议选择Sun公司发行的Java版本。
ssh 必须安装并且保证 sshd一直运行,以便用Hadoop 脚本管理远端Hadoop守护进程。
2 实验环境搭建2.1 准备工作操作系统:Ubuntu
部署:Vmvare
在vmvare安装好一台Ubuntu虚拟机后,可以导出或者克隆出另外两台虚拟机。
说明:
保证虚拟机的ip和主机的ip在同一个ip段,这样几个虚拟机和主机之间可以相互通信。
为了保证虚拟机的ip和主机的ip在同一个ip段,虚拟机连接设置为桥连。
准备机器:一台master,若干台slave,配置每台机器的/etc/hosts保证各台机器之间通过机器名可以互访,例如:
10.64.56.76 node1(master)
10.64.56.77 node2 (slave1)
10.64.56.78 node3 (slave2)
主机信息:
机器名IP地址作用
Node110.64.56.76NameNode、JobTracker
Node210.64.56.77DataNode、TaskTracker
Node310.64.56.78DataNode、TaskTracker
为保证环境一致先安装好JDK和ssh:
2.2 安装JDK
#安装JDK
$ sudo apt-get install sun-java6-jdk1.2.3
这个安装,java执行文件自动添加到/usr/bin/目录。
验证 shell命令 :java -version 看是否与你的版本号一致。
2.3下载、创建用户$ useradd hadoop
$ cd /home/hadoop
在所有的机器上都建立相同的目录,也可以就建立相同的用户,最好是以该用户的home路径来做hadoop的安装路径。
例如在所有的机器上的安装路径都是:/home/hadoop/hadoop-0.20.203,这个不需要mkdir,在/home/hadoop/下解压hadoop包的时候,会自动生成)
(当然可以安装/usr/local/目录下,例如/usr/local/hadoop-0.20.203/
chown -R hadoop /usr/local/hadoop-0.20.203/
chgrp -R hadoop /usr/local/hadoop-0.20.203/
)
(最好不要使用root安装,因为不推荐各个机器之间使用root访问 )
2.4 安装ssh和配置1) 安装:sudo apt-get install ssh
这个安装完后,可以直接使用ssh命令 了。
执行$ netstat -nat 查看22端口是否开启了。
测试:ssh localhost。
输入当前用户的密码,回车就ok了。说明安装成功,同时ssh登录需要密码。
(这种默认安装方式完后,默认配置文件是在/etc/ssh/目录下。sshd配置文件是:/etc/ssh/sshd_config):
注意:在所有机子都需要安装ssh。
2) 配置:
在Hadoop启动以后,Namenode是通过SSH(Secure Shell)来启动和停止各个datanode上的各种守护进程的,这就须要在节点之间执行指令的时候是不须要输入密码的形式,故我们须要配置SSH运用无密码公钥认证的形式。
以本文中的三台机器为例,现在node1是主节点,他须要连接node2和node3。须要确定每台机器上都安装了ssh,并且datanode机器上sshd服务已经启动。
( 说明:hadoop@hadoop~]$ssh-keygen -t rsa
这个命令将为hadoop上的用户hadoop生成其密钥对,询问其保存路径时直接回车采用默认路径,当提示要为生成的密钥输入passphrase的时候,直接回车,也就是将其设定为空密码。生成的密钥对id_rsa,id_rsa.pub,默认存储在/home/hadoop/.ssh目录下然后将id_rsa.pub的内容复制到每个机器(也包括本机)的/home/dbrg/.ssh/authorized_keys文件中,如果机器上已经有authorized_keys这个文件了,就在文件末尾加上id_rsa.pub中的内容,如果没有authorized_keys这个文件,直接复制过去就行.)
3) 首先设置namenode的ssh为无需密码的、自动登录。
切换到hadoop用户( 保证用户hadoop可以无需密码登录,因为我们后面安装的hadoop属主是hadoop用户。)
$ su hadoop
cd /home/hadoop
$ ssh-keygen -t rsa
然后一直按回车
完成后,在home跟目录下会产生隐藏文件夹.ssh
$ cd .ssh
之后ls 查看文件
cp id_rsa.pub authorized_keys
测试:
$ssh localhost
或者:
$ ssh node1
第一次ssh会有提示信息:
The authenticity of host ‘node1 (10.64.56.76)’ can’t be established.
RSA key fingerprint is 03:e0:30:cb:6e:13:a8:70:c9:7e:cf:ff:33:2a:67:30.
Are you sure you want to continue connecting (yes/no)?
输入 yes 来继续。这会把该服务器添加到你的已知主机的列表中
发现链接成功,并且无需密码。
4 ) 复制authorized_keys到node2 和node3 上
为了保证node1可以无需密码自动登录到node2和node3,先在node2和node3上执行
$ su hadoop
cd /home/hadoop
$ ssh-keygen -t rsa
一路按回车.
然后回到node1,复制authorized_keys到node2 和node3
[hadoop@hadoop .ssh]$ scp authorized_keys node2:/home/hadoop/.ssh/
[hadoop@hadoop .ssh]$ scp authorized_keys node3:/home/hadoop/.ssh/
这里会提示输入密码,输入hadoop账号密码就可以了。
改动你的 authorized_keys 文件的许可权限 [hadoop@hadoop .ssh]$chmod 644 authorized_keys
测试:ssh node2或者ssh node3(第一次需要输入yes)。
如果不须要输入密码则配置成功,如果还须要请检查上面的配置能不能正确。
2.5 安装Hadoop#切换为hadoop用户
su hadoop
wgethttp://apache.mirrors.tds.net//hadoop/common/hadoop-0.20.203.0/hadoop-0.20.203.0rc1.tar.gz
下载安装包后,直接解压安装即可:
$ tar -zxvfhadoop-0.20.203.0rc1.tar.gz
1 ) 安装Hadoop集群通常要将安装软件解压到集群内的所有机器上。并且安装路径要一致,如果我们用HADOOP_HOME指代安装的根路径,通常,集群里的所有机器的
HADOOP_HOME路径相同。
2 ) 如果集群内机器的环境完全一样,可以在一台机器上配置好,然后把配置好的软件即hadoop-0.20.203整个文件夹拷贝到其他机器的相同位置即可。
3 ) 可以将Master上的Hadoop通过scp拷贝到每一个Slave相同的目录下,同时根据每一个Slave的Java_HOME 的不同修改其hadoop-env.sh 。
4) 为了方便,使用hadoop命令或者start-all.sh等命令,修改Master上/etc/profile 新增以下内容:
export HADOOP_HOME=/home/hadoop/hadoop-0.20.203
exportPATH=$PATH:$HADOOP_HOME/bin
修改完毕后,执行source /etc/profile 来使其生效。
6)配置conf/hadoop-env.sh文件
配置conf/hadoop-env.sh文件
#添加 export JAVA_HOME=/usr/lib/jvm/java-6-sun/
这里修改为你的jdk的安装位置。
测试hadoop安装:
Bin/hadoop jar hadoop-0.20.2-examples.jarwordcount conf/ /tmp/out
3. 集群配置(所有节点相同)3.1配置文件:conf/core-site.xml
fs.default.name
hdfs://node1:49000
hadoop.tmp.dir
/home/hadoop/hadoop_home/var
1)fs.default.name是NameNode的URI。hdfs://主机名:端口/
2)hadoop.tmp.dir :Hadoop的默认临时路径,这个最好配置,如果在新增节点或者其他情况下莫名其妙的DataNode启动不了,就删除此文件中的tmp目录即可。不过如果删除了NameNode机器的此目录,那么就需要重新执行NameNode格式化的命令。
3.2配置文件:conf/mapred-site.xml
mapred.job.tracker
node1:49001
mapred.local.dir
/home/hadoop/hadoop_home/var
1)mapred.job.tracker是JobTracker的主机(或者IP)和端口。主机:端口。
3.3配置文件:conf/hdfs-site.xml
dfs.name.dir
/home/hadoop/name1, /home/hadoop/name2 #hadoop的name目录路径
dfs.data.dir
/home/hadoop/data1, /home/hadoop/data2
dfs.replication
2
1) dfs.name.dir是NameNode持久存储名字空间及事务日志的本地文件系统路径。 当这个值是一个逗号分割的目录列表时,nametable数据将会被复制到所有目录中做冗余备份。
2) dfs.data.dir是DataNode存放块数据的本地文件系统路径,逗号分割的列表。 当这个值是逗号分割的目录列表时,数据将被存储在所有目录下,通常分布在不同设备上。
3)dfs.replication是数据需要备份的数量,默认是3,如果此数大于集群的机器数会出错。
注意:此处的name1、name2、data1、data2目录不能预先创建,hadoop格式化时会自动创建,如果预先创建反而会有问题。
3.4配置masters和slaves主从结点配置conf/masters和conf/slaves来设置主从结点,注意最好使用主机名,并且保证机器之间通过主机名可以互相访问,每个主机名一行。
vi masters:
输入:
node1
vi slaves:
输入:
node2
node3
配置结束,把配置好的hadoop文件夹拷贝到其他集群的机器中,并且保证上面的配置对于其他机器而言正确,例如:如果其他机器的Java安装路径不一样,要修改conf/hadoop-env.sh
$ scp -r /home/hadoop/hadoop-0.20.203 root@node2: /home/hadoop/
4 hadoop启动4.1 格式化一个新的分布式文件系统先格式化一个新的分布式文件系统
$ cd hadoop-0.20.203
$ bin/hadoop namenode -format
成功情况下系统输出:
12/02/06 00:46:50 INFO namenode.NameNode:STARTUP_MSG:
/************************************************************
STARTUP_MSG: Starting NameNode
STARTUP_MSG: host = ubuntu/127.0.1.1
STARTUP_MSG: args = [-format]
STARTUP_MSG: version = 0.20.203.0
STARTUP_MSG: build =http://svn.apache.org/repos/asf/hadoop/common/branches/branch-0.20-security-203-r 1099333; compiled by 'oom' on Wed May 4 07:57:50 PDT 2011
************************************************************/
12/02/0600:46:50 INFO namenode.FSNamesystem: fsOwner=root,root
12/02/06 00:46:50 INFO namenode.FSNamesystem:supergroup=supergroup
12/02/06 00:46:50 INFO namenode.FSNamesystem:isPermissionEnabled=true
12/02/06 00:46:50 INFO common.Storage: Imagefile of size 94 saved in 0 seconds.
12/02/06 00:46:50 INFO common.Storage: Storagedirectory /opt/hadoop/hadoopfs/name1 has been successfully formatted.
12/02/06 00:46:50 INFO common.Storage: Imagefile of size 94 saved in 0 seconds.
12/02/06 00:46:50 INFO common.Storage: Storagedirectory /opt/hadoop/hadoopfs/name2 has been successfully formatted.
12/02/06 00:46:50 INFO namenode.NameNode:SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode atv-jiwan-ubuntu-0/127.0.0.1
************************************************************/
查看输出保证分布式文件系统格式化成功
执行完后可以到master机器上看到/home/hadoop//name1和/home/hadoop//name2两个目录。在主节点master上面启动hadoop,主节点会启动所有从节点的hadoop。
4.2 启动所有节点启动方式1:
$ bin/start-all.sh (同时启动HDFS和Map/Reduce)
系统输出:
starting namenode, logging to /usr/local/hadoop/logs/hadoop-hadoop-namenode-ubuntu.out
node2: starting datanode, loggingto /usr/local/hadoop/logs/hadoop-hadoop-datanode-ubuntu.out
node3: starting datanode, loggingto /usr/local/hadoop/logs/hadoop-hadoop-datanode-ubuntu.out
node1: starting secondarynamenode,logging to /usr/local/hadoop/logs/hadoop-hadoop-secondarynamenode-ubuntu.out
starting jobtracker, logging to/usr/local/hadoop/logs/hadoop-hadoop-jobtracker-ubuntu.out
node2: starting tasktracker,logging to /usr/local/hadoop/logs/hadoop-hadoop-tasktracker-ubuntu.out
node3: starting tasktracker,logging to /usr/local/hadoop/logs/hadoop-hadoop-tasktracker-ubuntu.out
As you can see in slave's output above, it will automatically format it's storage directory(specified by dfs.data.dir) if it is not formattedalready. It will also create the directory if it does not exist yet.
执行完后可以到master(node1)和slave(node1,node2)机器上看到/home/hadoop/hadoopfs/data1和/home/hadoop/data2两个目录。
启动方式2:
启动Hadoop集群需要启动HDFS集群和Map/Reduce集群。
在分配的NameNode上,运行下面的命令启动HDFS:
$ bin/start-dfs.sh(单独启动HDFS集群)
bin/start-dfs.sh脚本会参照NameNode上${HADOOP_CONF_DIR}/slaves文件的内容,在所有列出的slave上启动DataNode守护进程。
在分配的JobTracker上,运行下面的命令启动Map/Reduce:
$bin/start-mapred.sh (单独启动Map/Reduce)
bin/start-mapred.sh脚本会参照JobTracker上${HADOOP_CONF_DIR}/slaves文件的内容,在所有列出的slave上启动TaskTracker守护进程。
4.3 关闭所有节点从主节点master关闭hadoop,主节点会关闭所有从节点的hadoop。
$ bin/stop-all.sh
Hadoop守护进程的日志写入到 ${HADOOP_LOG_DIR} 目录 (默认是 ${HADOOP_HOME}/logs).
${HADOOP_HOME}就是安装路径.
5 .测试1)浏览NameNode和JobTracker的网络接口,它们的地址默认为:
NameNode - http://node1:50070/
JobTracker - http://node2:50030/
3) 使用netstat –nat查看端口49000和49001是否正在使用。
4) 使用jps查看进程
要想检查守护进程是否正在运行,可以使用 jps 命令(这是用于 JVM 进程的ps 实用程序)。这个命令列出 5 个守护进程及其进程标识符。
5)将输入文件拷贝到分布式文件系统:
$ bin/hadoop fs -mkdir input
$ bin/hadoop fs -put conf/core-site.xml input
运行发行版提供的示例程序:
$ bin/hadoop jar hadoop-0.20.2-examples.jar grep input output 'dfs[a-z.]+'
6.补充
Q: bin/hadoop jar hadoop-0.20.2-examples.jar grep input output 'dfs[a-z.]+' 什么意思啊?
A: bin/hadoop jar(使用hadoop运行jar包) hadoop-0.20.2_examples.jar(jar包的名字) grep (要使用的类,后边的是参数)input output 'dfs[a-z.]+'
整个就是运行hadoop示例程序中的grep,对应的hdfs上的输入目录为input、输出目录为output。
Q: 什么是grep?
A: A map/reduce program that counts the matches of a regex in the input.
查看输出文件:
将输出文件从分布式文件系统拷贝到本地文件系统查看:
$ bin/hadoop fs -get output output
$ cat output/*
或者
在分布式文件系统上查看输出文件:
$ bin/hadoop fs -cat output/*
统计结果:
root@v-jiwan-ubuntu-0:~/hadoop/hadoop-0.20.2-bak/hadoop-0.20.2#bin/hadoop fs -cat output/part-00000
3 dfs.class
2 dfs.period
1 dfs.file
1 dfs.replication
1 dfs.servers
1 dfsadmin
7. HDFS常用操作
hadoopdfs -ls 列出HDFS下的文件
hadoop dfs -ls in 列出HDFS下某个文档中的文件
hadoop dfs -put test1.txt test 上传文件到指定目录并且重新命名,只有所有的DataNode都接收完数据才算成功
hadoop dfs -get in getin 从HDFS获取文件并且重新命名为getin,同put一样可操作文件也可操作目录
hadoop dfs -rmr out 删除指定文件从HDFS上
hadoop dfs -cat in/* 查看HDFS上in目录的内容
hadoop dfsadmin -report 查看HDFS的基本统计信息,结果如下
hadoop dfsadmin -safemode leave 退出安全模式
hadoop dfsadmin -safemode enter 进入安全模式
8.添加节点可扩展性是HDFS的一个重要特性,首先在新加的节点上安装hadoop,然后修改$HADOOP_HOME/conf/master文件,加入 NameNode主机名,然后在NameNode节点上修改$HADOOP_HOME/conf/slaves文件,加入新加节点主机名,再建立到新加节点无密码的SSH连接
运行启动命令:
start-all.sh
然后可以通过http://(Masternode的主机名):50070查看新添加的DataNode
9负载均衡start-balancer.sh,可以使DataNode节点上选择策略重新平衡DataNode上的数据块的分布
结束语:遇到问题时,先查看logs,很有帮助。
说到业务是个让人又爱又恨的东西,客户、领导把它看的很重,不少“技术控”却瞧不起它,认为它是“低智商”的代名词。当然了,这些看法都很偏激。技术仅仅是一个工具,因“业务”的需求而诞生至使用,小说里常常写到,当一个人学会了屠龙之术,却发现天地之间没有龙给他“屠”,这个是最悲惨的事情了,这里的“龙”就是业务,“屠龙之术”就是技术,离开了业务的技术是没有意义的。
业务本身是个抽象的集合,真正把它搞懂了其实也能锻炼人的抽象能力。
说来说去“业务”是个什么东西,似乎没有明确的定义,我觉得“业务”就是个“标准”,程序员完成的系统必须满足这个“标准”,不同行业,不同硬件环境都会有自己的合适的标准,某项技术都有其对应的“标准”。
比如一直讨论很久的问题,C++和Java到底谁快,为此也有衍生出了很多讨论,技术控也是乐此不疲,但是或多或少都脱离具体环境。
计算机语言发展了这么多年,都会相互学习优点,不过总有些本质的区别,比如C++的优势是和硬件结合紧密,Java的优势是屏蔽了硬件限制,两者在诞生的时候发展的方向就有不同,比如通信系统的交换机等各类硬件的程序非C/C++莫属,Java在这里难有使用的地方,但是在异构硬件集群中,现在很火的“云”系统,Java的优势就很明显,现在常用的服务器系统大多都是Java。当然也有人说Java免费,所以比C++更容易推广,的确没错,但是这也属于“业务”的范畴。
说完了业务的大范围,下面说说具体行业的业务。我最熟悉的是电信的业务。相比金融、电商系统,从网上的信息来看似乎电信的系统是最没技术含量的,其实电信的数据量远大于金融、电商,只是大量的数据是后台处理,可以异步展现,所以给的要求并不高,总体来说电信系统是入门的技术低,做好了很不容易。
我和不少电信的程序员人聊过,他们纷纷吐槽是,工作就是配置各种业务参数,体力活。但是说到具体的业务模型时,却说不清楚。
我总结的电信系统分2两大部分,业务模型(CRM)和工作流(IOM)。CRM和IOM是比较老的名词了,新的我也不太清楚。
模型如下:
主产品+子产品+产品规则+动作
解释如下:
主产品,和硬件挂钩。现在的电信产品有手机(移动,联通,电信分属不同网段)、固话、ADSL、光纤、2B+D、30B+D等。
子产品,依赖于主产品。比如移动电话的各种优惠包,宽带的互联星空等。
产品规则,这里是最让人抓狂的。产品规则分3类、
1、主产品规则,主产品之间是没有任何关系的,比如一家人可以装两条宽带,用多个手机。
2、子产品规则,基于不同主产品的子产品之间没有任何关系,基于同一主产品的子产品之间有各种规则,比如手机的资费包开通了一个就不能开通另一个,这类为互斥。不同的优惠可以共同作用,这类为叠加。由于各种子产品的数量繁多,所以这些规则的校验和实现是个很庞大的数字。
3、运营商制定的规则,比如,从硬件角度来说,装宽带、装电话、开通手机是互不相干的,但是运营商制定了各种套餐,“强迫”统一办理。这个无论是对程序员还是消费者都是是很讨厌的……
动作,装、拆,(改=装+拆)
分析完了以后可以发现真正麻烦的地方是业务规则这块,一个电信客户系统的质量高低很大程度上就由这个“业务规则引擎”决定,如果只是闷头往这个引擎里加参数的确无聊,但是这正了解这个引擎的工作步骤还是很有趣的,个人认为理解一个系统的运行是很容易提高能力的。
下面说说“工作流”,消费者的任何一个请求在电信系统中都会转变一个流程,某些特殊的业务流程会很长,比如装高清宽带,需要人上门施工,并测试宽带质量等,这些都成功了才会触发其它的步骤。消费者的业务请求在后端实现往往是“事务”型的,比如原来是套餐A,改成套餐B的会有3个步骤,不熟悉电信业务的人可以想下“神州行”改“全球通”。当步骤1和2施工成功后,步骤3发现现有条件不满足时(这里的判断不在当前系统中,或者说当前系统无法判断,必须将数据发送到另一个平台之后由那个平台来判断,这种情况在电信系统里很常见,比如当前系统没有客户资料,所以无法判断),也就意味着不能办理套餐B,这样得回复成套餐A,这样需要对步骤1和2得进行反向施工,也就是“事务回滚”。先后这就是“工作流”的任务。
工作流在电信系统中是很重要的角色,相比于是电商和金融系统,电信系统的工作流最强大。
简单解释下工作流,工作流有两个最基本单元(节点),逻辑节点和工作节点(不同的系统中叫法也不同,但是作用都一样)。
逻辑节点,就是if判断。
工作节点,就是一个具体的施工环节,一般关联一个平台。
一般工作流的具体配置都由这两种节点组成。
工作流定义的关系有,串行和并行(电信里的叫法是同进同退,一般直接定义成事务)。
于一个系统来说,业务层的调优效果优于代码层的调优效果(代码错误引起的宕机问题不属于调优范围)。比如,一个业务的判断规则精简了,比你优化几个计算语句强的多。比如之前说的例子,在步骤1、2、3中,因为3出了问题,导致1、2得反向施工,所以实际有5步操作,1、2、3、2反向、1反向。所以如果3最容易出问题,那么应该调整顺序应该是3、1、2,把最容易出问题的放在最开始,这样可以避免不必要的步骤。其实在系统上线后运行一段时间,就可以统计出那些平台的出错率高,调整顺序几乎是0修改,但是带来的效率提升是明显的,但是没有几个地方有这么做的。
说了这么多,我觉得把整个系统的框架搞明白还是很能提高个人能力,抽象逻辑对于程序员来说必不可少。所以现在每次抱怨工作无聊时,我都会想想,真的就不能挖出点东西么?