Winse Blog

走走停停都是风景, 熙熙攘攘都向最好, 忙忙碌碌都为明朝, 何畏之.

Hadoop安装与升级-(3)HA配置

官网的文档[HDFSHighAvailabilityWithQJM.html]很详细,但是没有一个整体的案例。这里整理下操作记录下来。

配置

hadoop-master1和hadoop-master2之间无密钥登录(failover要用到):

1
2
3
[hadoop@hadoop-master2 hadoop-2.2.0]$ ssh-keygen
[hadoop@hadoop-master2 hadoop-2.2.0]$ ssh-copy-id hadoop-master2
[hadoop@hadoop-master2 hadoop-2.2.0]$ ssh-copy-id hadoop-master1

配置文件修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
[hadoop@hadoop-master1 hadoop-2.2.0]$ vi etc/hadoop/core-site.xml 

<property>
<name>fs.defaultFS</name>
<value>hdfs://zfcluster</value>
</property>

<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop-master1</value>
</property>

<property>
<name>hadoop.tmp.dir</name>
<value>/data/tmp</value>
</property>

[hadoop@hadoop-master1 hadoop-2.2.0]$ vi etc/hadoop/hdfs-site.xml 

<property>
<name>dfs.replication</name>
<value>1</value>
</property>

<property>
<name>dfs.namenode.secondary.http-address</name>
<value> </value>
</property>

<property>
<name>dfs.nameservices</name>
<value>zfcluster</value>
</property>

<property>
<name>dfs.ha.namenodes.zfcluster</name>
<value>nn1,nn2</value>
</property>

<property>
<name>dfs.namenode.rpc-address.zfcluster.nn1</name>
<value>hadoop-master1:8020</value>
</property>

<property>
<name>dfs.namenode.rpc-address.zfcluster.nn2</name>
<value>hadoop-master2:8020</value>
</property>

<property>
<name>dfs.namenode.http-address.zfcluster.nn1</name>
<value>hadoop-master1:50070</value>
</property>

<property>
<name>dfs.namenode.http-address.zfcluster.nn2</name>
<value>hadoop-master2:50070</value>
</property>

<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop-master1:8485/zfcluster</value>
</property>

<property>
<name>dfs.client.failover.proxy.provider.zfcluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

<property>
<name>dfs.journalnode.edits.dir</name>
<value>/data/journal</value>
</property>

<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>

<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hadoop/.ssh/id_rsa</value>
</property>

<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>

启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
[hadoop@hadoop-master1 hadoop-2.2.0]$ cd ..
[hadoop@hadoop-master1 ~]$ for h in hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do rsync -vaz --delete --exclude=logs hadoop-2.2.0 $h:~/ ; done

[hadoop@hadoop-master1 ~]$ cd hadoop-2.2.0/

[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/hadoop-daemon.sh start journalnode

[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/hadoop-daemon.sh start namenode
[hadoop@hadoop-master2 hadoop-2.2.0]$ bin/hdfs namenode -bootstrapStandby

[hadoop@hadoop-master1 hadoop-2.2.0]$ bin/hdfs namenode -initializeSharedEdits

#// 此时可以启动datanode,通过50070端口看namenode的状态

#// Automatic failover,zkfc和namenode没有启动顺序的问题!
[hadoop@hadoop-master1 hadoop-2.2.0]$ bin/hdfs zkfc -formatZK
[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/hadoop-daemon.sh start zkfc
[hadoop@hadoop-master2 hadoop-2.2.0]$ sbin/hadoop-daemon.sh start zkfc

[hadoop@hadoop-master1 hadoop-2.2.0]$ bin/hdfs haadmin -failover nn1 nn2

#// 测试failover,把一个active的namenode直接kill掉,看看另一个是否变成active!

# 重启
[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/stop-dfs.sh
16/01/07 10:57:50 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Stopping namenodes on [hadoop-master1 hadoop-master2]
hadoop-master1: stopping namenode
hadoop-master2: stopping namenode
hadoop-slaver1: stopping datanode
hadoop-slaver2: stopping datanode
hadoop-slaver3: stopping datanode
Stopping journal nodes [hadoop-master1]
hadoop-master1: stopping journalnode
16/01/07 10:58:08 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Stopping ZK Failover Controllers on NN hosts [hadoop-master1 hadoop-master2]
hadoop-master2: no zkfc to stop
hadoop-master1: no zkfc to stop

[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/start-dfs.sh
16/01/07 10:59:14 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Starting namenodes on [hadoop-master1 hadoop-master2]
hadoop-master2: starting namenode, logging to /home/hadoop/hadoop-2.2.0/logs/hadoop-hadoop-namenode-hadoop-master2.out
hadoop-master1: starting namenode, logging to /home/hadoop/hadoop-2.2.0/logs/hadoop-hadoop-namenode-hadoop-master1.out
hadoop-slaver1: starting datanode, logging to /home/hadoop/hadoop-2.2.0/logs/hadoop-hadoop-datanode-hadoop-slaver1.out
hadoop-slaver3: starting datanode, logging to /home/hadoop/hadoop-2.2.0/logs/hadoop-hadoop-datanode-hadoop-slaver3.out
hadoop-slaver2: starting datanode, logging to /home/hadoop/hadoop-2.2.0/logs/hadoop-hadoop-datanode-hadoop-slaver2.out
Starting journal nodes [hadoop-master1]
hadoop-master1: starting journalnode, logging to /home/hadoop/hadoop-2.2.0/logs/hadoop-hadoop-journalnode-hadoop-master1.out
16/01/07 10:59:30 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Starting ZK Failover Controllers on NN hosts [hadoop-master1 hadoop-master2]
hadoop-master2: starting zkfc, logging to /home/hadoop/hadoop-2.2.0/logs/hadoop-hadoop-zkfc-hadoop-master2.out
hadoop-master1: starting zkfc, logging to /home/hadoop/hadoop-2.2.0/logs/hadoop-hadoop-zkfc-hadoop-master1.out

[hadoop@hadoop-master1 ~]$ jps
15241 DFSZKFailoverController
14882 NameNode
244 QuorumPeerMain
18715 Jps
15076 JournalNode

参考

–END

Hadoop安装与升级-(2)2.2升级到2.6

升级的命令很简单,但是不要瞎整!升级就一个命令就搞定了!

部署2.6.3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[hadoop@hadoop-master1 ~]$ tar zxvf hadoop-2.6.3.tar.gz 

[hadoop@hadoop-master1 ~]$ cd hadoop-2.6.3/share/
[hadoop@hadoop-master1 share]$ rm -rf doc/

[hadoop@hadoop-master1 hadoop-2.6.3]$ rm -rf lib/native/*

#// 拷贝四个配置文件到hadoop-2.6.3
[hadoop@hadoop-master1 hadoop-2.6.3]$ cd etc/hadoop/
[hadoop@hadoop-master1 hadoop]$ cp -f ~/hadoop-2.2.0/etc/hadoop/*-site.xml ./
[hadoop@hadoop-master1 hadoop]$ cp -f ~/hadoop-2.2.0/etc/hadoop/slaves ./

[hadoop@hadoop-master1 hadoop]$ cd 
[hadoop@hadoop-master1 ~]$ for h in hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do rsync -vaz --delete --exclude=logs hadoop-2.6.3 $h:~/ ; done

升级(最佳方式)

直接使用upgrade选项启动dfs即可。(secondarynamenode不要单独操作来升级,反正就是执行upgrade启动dfs就好了)。

1
2
3
4
5
[hadoop@hadoop-master1 hadoop-2.6.3]$ sbin/start-dfs.sh -upgrade

// 2.2和2.6都没有这个命令
// hadoop dfsadmin -upgradeProgress status
hadoop dfsadmin -finalizeUpgrade

参考[Hadoop: The Definitive Guide/Chapter 10. Administering Hadoop/Maintenance/Upgrades]

瞎整1

1
2
3
4
# 先停集群
[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/stop-dfs.sh

[hadoop@hadoop-master1 hadoop-2.6.3]$ sbin/start-dfs.sh

直接在原来的2.2基础上启动,datanode启动没问题,但是namenode报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[hadoop@hadoop-master1 hadoop-2.6.3]$ less logs/hadoop-hadoop-namenode-hadoop-master1.log 
...
2016-01-07 08:05:23,582 FATAL org.apache.hadoop.hdfs.server.namenode.NameNode: Failed to start namenode.
java.io.IOException: 
File system image contains an old layout version -47.
An upgrade to version -60 is required.
Please restart NameNode with the "-rollingUpgrade started" option if a rolling upgrade is already started; or restart NameNode with the "-upgrade" option to start a new upgrade.
        at org.apache.hadoop.hdfs.server.namenode.FSImage.recoverTransitionRead(FSImage.java:232)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.loadFSImage(FSNamesystem.java:1022)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.loadFromDisk(FSNamesystem.java:741)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.loadNamesystem(NameNode.java:538)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.initialize(NameNode.java:597)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:764)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:748)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.createNameNode(NameNode.java:1441)
        at org.apache.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:1507)
2016-01-07 08:05:23,583 INFO org.apache.hadoop.util.ExitUtil: Exiting with status 1
2016-01-07 08:05:23,585 INFO org.apache.hadoop.hdfs.server.namenode.NameNode: SHUTDOWN_MSG: 
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at hadoop-master1/172.17.0.1
************************************************************/

重新启动,使用upgrade选项启动:

1
2
[hadoop@hadoop-master1 hadoop-2.6.3]$ sbin/stop-dfs.sh
[hadoop@hadoop-master1 hadoop-2.6.3]$ sbin/start-dfs.sh -upgrade

或者还原到2.2:

1
2
3
4
5
6
7
# **所有**slaver节点的VERSION改回47
[hadoop@hadoop-slaver3 ~]$ vi /data/tmp/dfs/data/current/VERSION 
...
layoutVersion=-47

[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/stop-dfs.sh
[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/start-dfs.sh -rollback

原理

升级的时刻,首先备份原来的数据到previous目录下,升级后的放置到current目录下。namenode这样没啥大问题,但是datanode也是这样结构current和previous,那相当有问题,那数据量不是翻倍了?

查看数据后,发现一个名字的文件current和previous里面使用的是一个inode。也就是说用的是硬链接,数据只有一份!

1
2
3
4
5
6
7
8
9
10
11
[hadoop@hadoop-master1 hadoop-2.2.0]$ bin/hadoop fs -put *.txt /

[hadoop@hadoop-slaver3 ~]$ cd /data/tmp/dfs/data/

[hadoop@hadoop-slaver3 BP-1695500896-172.17.0.1-1452152050513]$ test current/finalized/subdir0/subdir0/blk_1073741825 -ef previous/finalized/blk_1073741825
[hadoop@hadoop-slaver3 BP-1695500896-172.17.0.1-1452152050513]$ echo $?
0
[hadoop@hadoop-slaver3 BP-1695500896-172.17.0.1-1452152050513]$ ls -i current/finalized/subdir0/subdir0/blk_1073741825 
142510 current/finalized/subdir0/subdir0/blk_1073741825
[hadoop@hadoop-slaver3 BP-1695500896-172.17.0.1-1452152050513]$ ls -i previous/finalized/blk_1073741825
142510 previous/finalized/blk_1073741825

–END

Hadoop安装与升级-Docker中安装(1)

其实部署一个hadoop集群不难,按照步骤一步步的操作: 无密钥登录,防火墙(以及selinux),JDK,配置,启动(包括format)。

集群机器准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@cu2 ~]# docker -v
Docker version 1.6.2, build 7c8fca2/1.6.2

[root@cu2 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
centos              centos6             62068de82c82        4 months ago        250.7 MB

[root@cu2 ~]# docker run -d --name hadoop-master1 -h hadoop-master1 centos:centos6 /usr/sbin/sshd -D
c975b0e41429a3c214e86552f2a9f599ba8ee7487e8fbdc25fd59d29adacca4f
[root@cu2 ~]# docker run -d --name hadoop-master2 -h hadoop-master2 centos:centos6 /usr/sbin/sshd -D
fac1d2ee4a05ab8457f4bd6756622ac8236f64423544150d355f9e3091764d8f
[root@cu2 ~]# docker run -d --name hadoop-slaver1 -h hadoop-slaver1 centos:centos6 /usr/sbin/sshd -D
cc8734f2a0963a030b994f69be697308a13e511557eaefc7d4aca7e300950ded
[root@cu2 ~]# docker run -d --name hadoop-slaver2 -h hadoop-slaver2 centos:centos6 /usr/sbin/sshd -D
7e4b5410a7cb8585436775f15609708b309a5b83930da74d6571533251c26355
[root@cu2 ~]# docker run -d --name hadoop-slaver3 -h hadoop-slaver3 centos:centos6 /usr/sbin/sshd -D
26018b256403d956b4272b6bda09a58d1fc6938591d18f9892ba72782c41880b

[root@cu2 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND               CREATED              STATUS              PORTS               NAMES
26018b256403        centos:centos6      "/usr/sbin/sshd -D"   About a minute ago   Up About a minute                       hadoop-slaver3      
7e4b5410a7cb        centos:centos6      "/usr/sbin/sshd -D"   About a minute ago   Up About a minute                       hadoop-slaver2      
cc8734f2a096        centos:centos6      "/usr/sbin/sshd -D"   About a minute ago   Up About a minute                       hadoop-slaver1      
fac1d2ee4a05        centos:centos6      "/usr/sbin/sshd -D"   About a minute ago   Up About a minute                       hadoop-master2      
c975b0e41429        centos:centos6      "/usr/sbin/sshd -D"   8 minutes ago        Up 8 minutes                            hadoop-master1      

[root@cu2 ~]# docker ps | grep hadoop | awk '{print $1}' | xargs -I{} docker inspect -f ' ' {}
172.17.0.6 hadoop-slaver3
172.17.0.5 hadoop-slaver2
172.17.0.4 hadoop-slaver1
172.17.0.3 hadoop-master2
172.17.0.2 hadoop-master1

重启docker后,可以直接通过名称启动即可:

1
2
3
4
5
6
7
8
[root@cu2 ~]# service docker start
Starting docker:                                           [  OK  ]
[root@cu2 ~]# docker start hadoop-master1 hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3
hadoop-master1
hadoop-master2
hadoop-slaver1
hadoop-slaver2
hadoop-slaver3

重启后,hosts文件会被重置!最好就是测试好之前不要重启docker!(长期用docker集群实例,还是指定DNS!!)

机器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
[root@cu2 ~]# ssh root@172.17.0.2
root@172.17.0.2's password: 
Last login: Thu Jan  7 06:17:11 2016 from 172.17.42.1
[root@hadoop-master1 ~]# 
[root@hadoop-master1 ~]# vi /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

172.17.0.6 hadoop-slaver3
172.17.0.5 hadoop-slaver2
172.17.0.4 hadoop-slaver1
172.17.0.3 hadoop-master2
172.17.0.2 hadoop-master1

[root@hadoop-master1 ~]# ssh-keygen
[root@hadoop-master1 ~]# 
[root@hadoop-master1 ~]# ssh-copy-id hadoop-master1
[root@hadoop-master1 ~]# ssh-copy-id hadoop-master2
[root@hadoop-master1 ~]# ssh-copy-id hadoop-slaver1
[root@hadoop-master1 ~]# ssh-copy-id hadoop-slaver2
[root@hadoop-master1 ~]# ssh-copy-id hadoop-slaver3

# 拷贝hosts
[root@hadoop-master1 ~]# for h in hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do scp /etc/hosts $h:/etc/ ; done

# 安装需要的软件
[root@hadoop-master1 ~]# for h in hadoop-master1 hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do ssh $h "yum install man rsync curl wget tar" ; done

# 创建用户
[root@hadoop-master1 ~]# for h in hadoop-master1 hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do ssh $h useradd hadoop ; done

#// 把要设置的密码拷贝一下,接下来直接右键(CRT)粘贴弄5次就可以了。如果是几十几百台机器可以使用expect来实现
[root@hadoop-master1 ~]# for h in hadoop-master1 hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do ssh $h passwd hadoop ; done
New password: hadoop
BAD PASSWORD: it is based on a dictionary word
BAD PASSWORD: is too simple
Retype new password: hadoop
Changing password for user hadoop.
passwd: all authentication tokens updated successfully.
...

# 建立数据目录,赋权给hadoop用户
[root@hadoop-master1 ~]# for h in hadoop-master1 hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do ssh $h "mkdir /data; chown hadoop:hadoop /data" ; done

[root@hadoop-master1 ~]# su - hadoop
[hadoop@hadoop-master1 ~]$ ssh-keygen 
[hadoop@hadoop-master1 ~]$ ssh-copy-id hadoop-master1
[hadoop@hadoop-master1 ~]$ ssh-copy-id hadoop-master2
[hadoop@hadoop-master1 ~]$ ssh-copy-id hadoop-slaver1
[hadoop@hadoop-master1 ~]$ ssh-copy-id hadoop-slaver2
[hadoop@hadoop-master1 ~]$ ssh-copy-id hadoop-slaver3

[hadoop@hadoop-master1 ~]$ ll
total 139036
drwxr-xr-x 9 hadoop hadoop      4096 Oct  7  2013 hadoop-2.2.0
-rw-r--r-- 1 hadoop hadoop 142362384 Jan  7 07:14 jdk-7u60-linux-x64.gz
drwxr-xr-x 8 hadoop hadoop      4096 Jan  7 07:11 zookeeper-3.4.6
[hadoop@hadoop-master1 ~]$ tar zxvf jdk-7u60-linux-x64.gz 
[hadoop@hadoop-master1 ~]$ tar zxvf hadoop-2.2.0.tar.gz 
[hadoop@hadoop-master1 ~]$ tar zxvf zookeeper-3.4.6.tar.gz 

# 清理生产上无用的数据
[hadoop@hadoop-master1 ~]$ rm hadoop-2.2.0.tar.gz zookeeper-3.4.6.tar.gz jdk-7u60-linux-x64.gz 

[hadoop@hadoop-master1 ~]$ cd zookeeper-3.4.6/
[hadoop@hadoop-master1 zookeeper-3.4.6]$ rm -rf docs/ src/

[hadoop@hadoop-master1 zookeeper-3.4.6]$ cd ../hadoop-2.2.0/
[hadoop@hadoop-master1 hadoop-2.2.0]$ cd share/
[hadoop@hadoop-master1 share]$ rm -rf doc/

程序配置与启动

  • java
1
2
3
4
5
6
7
[hadoop@hadoop-master1 ~]$ cd
[hadoop@hadoop-master1 ~]$ vi .bashrc 
...
JAVA_HOME=~/jdk1.7.0_60
PATH=$JAVA_HOME/bin:$PATH

export JAVA_HOME PATH

退出shell再登录,或者source .bashrc!

  • zookeeper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[hadoop@hadoop-master1 ~]$ cd zookeeper-3.4.6/conf
[hadoop@hadoop-master1 conf]$ cp zoo_sample.cfg zoo.cfg
[hadoop@hadoop-master1 conf]$ vi zoo.cfg 
...
dataDir=/data/zookeeper

[hadoop@hadoop-master1 ~]$ mkdir /data/zookeeper

[hadoop@hadoop-master1 ~]$ cd ~/zookeeper-3.4.6/
[hadoop@hadoop-master1 zookeeper-3.4.6]$ bin/zkServer.sh start
JMX enabled by default
Using config: /home/hadoop/zookeeper-3.4.6/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[hadoop@hadoop-master1 zookeeper-3.4.6]$ 
[hadoop@hadoop-master1 zookeeper-3.4.6]$ jps
244 QuorumPeerMain
265 Jps

[hadoop@hadoop-master1 zookeeper-3.4.6]$ less zookeeper.out 
  • hadoop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
[hadoop@hadoop-master1 ~]$ cd ~/hadoop-2.2.0/etc/hadoop/
[hadoop@hadoop-master1 hadoop]$ rm *.cmd
[hadoop@hadoop-master1 hadoop]$ vi hadoop-env.sh 
# 修改java_home和hadoop_pid,以及yarn_pid

[hadoop@hadoop-master1 hadoop]$ vi core-site.xml 

<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop-master1:9000</value>
</property>

<property>
<name>hadoop.tmp.dir</name>
<value>/data/tmp</value>
</property>


[hadoop@hadoop-master1 hadoop]$ vi hdfs-site.xml 

<property>
<name>dfs.replication</name>
<value>1</value>
</property>

<property>
<name>dfs.namenode.secondary.http-address</name>
<value> </value>
</property>


[hadoop@hadoop-master1 hadoop]$ vi mapred-site.xml

<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>

<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop-master1:10020</value>
</property>

<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hadoop-master1:19888</value>
</property>


[hadoop@hadoop-master1 hadoop]$ vi yarn-site.xml 

<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>

<property>
<name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
<value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>

<property>
<name>yarn.resourcemanager.address</name>
<value>hadoop-master1:8032</value>
</property>

<property>
<name>yarn.resourcemanager.scheduler.address</name>
<value>hadoop-master1:8030</value>
</property>

<property>
<name>yarn.resourcemanager.resource-tracker.address</name>
<value>hadoop-master1:8031</value>
</property>

<property>
<name>yarn.resourcemanager.admin.address</name>
<value>hadoop-master1:8033</value>
</property>

<property>
<name>yarn.resourcemanager.webapp.address</name>
<value>hadoop-master1:8080</value>
</property>

启动Hadoop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[hadoop@hadoop-master1 hadoop-2.2.0]$ bin/hadoop version
Hadoop 2.2.0
Subversion https://svn.apache.org/repos/asf/hadoop/common -r 1529768
Compiled by hortonmu on 2013-10-07T06:28Z
Compiled with protoc 2.5.0
From source with checksum 79e53ce7994d1628b240f09af91e1af4
This command was run using /home/hadoop/hadoop-2.2.0/share/hadoop/common/hadoop-common-2.2.0.jar

[hadoop@hadoop-master1 hadoop-2.2.0]$ bin/hadoop namenode -format

# 默认自带的libhadoop有点问题,start-dfs.sh通过hdfs getconf -namenodes输出信息导致执行错误
[hadoop@hadoop-master1 hadoop-2.2.0]$ rm lib/native/libh*

[hadoop@hadoop-master1 ~]$ cd 
[hadoop@hadoop-master1 ~]$ for h in hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do scp -r jdk1.7.0_60 $h:~/ ; done
[hadoop@hadoop-master1 ~]$ for h in hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do scp -r hadoop-2.2.0 $h:~/ ; done
[hadoop@hadoop-master1 ~]$ for h in hadoop-master2 hadoop-slaver1 hadoop-slaver2 hadoop-slaver3 ; do scp -r .bashrc $h:~/ ; done

[hadoop@hadoop-master1 ~]$ cd hadoop-2.2.0/
[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/start-dfs.sh

[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/stop-dfs.sh
[hadoop@hadoop-master1 hadoop-2.2.0]$ sbin/start-dfs.sh
[hadoop@hadoop-master1 hadoop-2.2.0]$ jps
244 QuorumPeerMain
3995 NameNode
4187 Jps

通过CRT的Port Forwarding的dynamic socket5,浏览器配置socket5代理就可以通过50070端口查看hadoop hdfs集群的状态了。

–END

Postgresql入门

简单介绍下软件的安装,配置。同时实践下从mysql迁移到postgres。

安装配置

这里直接使用rpm包来安装。如果是centos6.6以下版本的系统需要更新openssl。

使用YUM安装看https://wiki.postgresql.org/wiki/YUM_Installation

1
2
3
4
5
6
7
8
9
10
11
[root@hadoop-master1 postgres]# ll
total 20708
-rw-r--r-- 1 root root  1593932 Dec 11 10:02 openssl-1.0.1e-42.el6.x86_64.rpm
-rw-r--r-- 1 root root  1085208 Dec 11 09:12 postgresql94-9.4.5-1PGDG.rhel6.x86_64.rpm
-rw-r--r-- 1 root root   541376 Dec 11 09:12 postgresql94-contrib-9.4.5-1PGDG.rhel6.x86_64.rpm
-rw-r--r-- 1 root root  1600736 Dec 11 09:12 postgresql94-devel-9.4.5-1PGDG.rhel6.x86_64.rpm
-rw-r--r-- 1 root root 11485008 Dec 11 09:13 postgresql94-docs-9.4.5-1PGDG.rhel6.x86_64.rpm
-rw-r--r-- 1 root root   198968 Dec 11 09:12 postgresql94-libs-9.4.5-1PGDG.rhel6.x86_64.rpm
-rw-r--r-- 1 root root    60688 Dec 11 09:12 postgresql94-plperl-9.4.5-1PGDG.rhel6.x86_64.rpm
-rw-r--r-- 1 root root    68884 Dec 11 09:12 postgresql94-plpython-9.4.5-1PGDG.rhel6.x86_64.rpm
-rw-r--r-- 1 root root  4556880 Dec 11 09:11 postgresql94-server-9.4.5-1PGDG.rhel6.x86_64.rpm
  • 安装命令:
1
2
3
4
# yum install -y openssl-1.0.1e-42.el6.x86_64.rpm 

# useradd postgres
# rpm -i postgresql94-*
  • 配置环境变量、初始化数据库、启动数据库:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# su - postgres
$ vi .bash_profile

export PGDATA=/var/lib/pgsql/9.4/data
PG_HOME=/usr/pgsql-9.4
PATH=$PG_HOME/bin:$PATH
export PATH

$ initdb

$ vi $PGDATA/pg_hba.conf
  host    all             all              192.168.0.0/16          md5

$ vi /var/lib/pgsql/9.4/data/postgresql.conf
  listen_addresses = '*'

# 切回root

# service postgresql-9.4 start
# chkconfig postgresql-9.4 on --level 2345

pg_hba.conf用来控制什么用于可以被远程访问。而postgresql.conf修改的监听的地址,默认是localhost改成*后就可以所有地址都可以访问了。

  • 建立库,创建数据库用户
1
2
3
4
5
-bash-4.1$ psql 

 create user dpi;
 create database dpi owner dpi;
 alter user dpi with password 'XXXX';

建表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE TABLE t_dta_illegalweb (
...
  day varchar(10) DEFAULT NULL,
...
);

create or replace function t_dta_illegalweb_insert_trigger()
returns trigger as $$
begin
  return null;
end; 
$$ language plpgsql;

CREATE TRIGGER trigger_t_dta_illegalweb_insert
    BEFORE INSERT ON t_dta_illegalweb
    FOR EACH ROW EXECUTE PROCEDURE t_dta_illegalweb_insert_trigger();

后面会使用分区表,先把触发器都建好。把框框搭好,后面修改就行了。

数据迁移

  1. postgres创建表:
1
2
3
4
5
CREATE TABLE IF NOT EXISTS t_dta_illegalweb20151211 (check(day = '2015-12-11')) INHERITS (t_dta_illegalweb);
CREATE TABLE IF NOT EXISTS t_dta_illegalweb20151210 (check(day = '2015-12-10')) INHERITS (t_dta_illegalweb);
CREATE TABLE IF NOT EXISTS t_dta_illegalweb20151209 (check(day = '2015-12-09')) INHERITS (t_dta_illegalweb);
CREATE TABLE IF NOT EXISTS t_dta_illegalweb20151208 (check(day = '2015-12-08')) INHERITS (t_dta_illegalweb);
CREATE TABLE IF NOT EXISTS t_dta_illegalweb20151207 (check(day = '2015-12-07')) INHERITS (t_dta_illegalweb);
  1. mysql导出数据:
1
2
3
select * from t_dta_illegalweb where day='2015-12-09' into outfile '/tmp/etl/t_dta_illegalweb20151209.sql'  fields terminated by '|';
select * from t_dta_illegalweb where day='2015-12-08' into outfile '/tmp/etl/t_dta_illegalweb20151208.sql'  fields terminated by '|';
select * from t_dta_illegalweb where day='2015-12-07' into outfile '/tmp/etl/t_dta_illegalweb20151207.sql'  fields terminated by '|';

数据在mysql服务器的/tmp/etl目录下面。如果mysql和postgres不在同一台机,需要把这些文件拷贝到postgres的服务器。

  1. 导入数据到postgres:

用psql登录dpi,然后执行copy命令把数据导入到对应的表。

1
2
3
\copy  t_dta_illegalweb20151209 from  '/tmp/etl/t_dta_illegalweb20151209.sql' using delimiters '|' ;
\copy  t_dta_illegalweb20151208 from  '/tmp/etl/t_dta_illegalweb20151208.sql' using delimiters '|' ;
\copy  t_dta_illegalweb20151207 from  '/tmp/etl/t_dta_illegalweb20151207.sql' using delimiters '|' ;

程序修改

程序修改是一件头痛的事情,虽然大部分都是SQL,但是MYSQL的比较宽泛,很多语句都兼容不报错也能出来想要的结果。但是这些语句在postgres下面执行是会报错的。比如说,select count(*)对所有数据count的时刻不能加order by(提示要groupby);再比如,mysql遇到字符串字段和数字比较会统一转换成数字比较,等等这些在postgres中都需要在SQL中显示的转换的。

那么postgres的类型转换怎么实现呢?两种形式cast(X as TYPE) 或者 X::TYPE。

由于程序是用hibernate来做数据库访问的,会遇到如下的问题

  • 如果用hql的话CAST函数hibernate首先会进行转换。(转换类型与hibernate对象的类型不匹配)
  • 而用X::TYPE会把:TYPE作为一个name parameter。
  • 不用hql用sql的话,要自己做对象转换,这是我们不愿意去做的事情(不然用hibernate干嘛)

各种尝试过后,修改PostgreSQLDialect来实现,添加一个自定义的hibernate函数,把字符串转成bigint即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.sql.Types;

import org.hibernate.Hibernate;
import org.hibernate.dialect.function.SQLFunctionTemplate;


public class PostgreSQLDialect extends org.hibernate.dialect.PostgreSQLDialect {
  
  public PostgreSQLDialect() {
      super();
      registerFunction( "bigint", new SQLFunctionTemplate(Hibernate.BIG_INTEGER, "cast(?1 as bigint)") );
  }

}

使用如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
StringBuilder hql = new StringBuilder("from IllegalWebInfo where 1=1 ");
List<Object> params = new ArrayList<>();

String domain = queryBean.getDomain();
if (StringUtils.isNotBlank(domain)) {
  hql.append(" and ").append("domain=?");
  params.add(domain.toLowerCase());
}
String houseId = queryBean.getHouseId();
if (StringUtils.isNotBlank(houseId)) {
  hql.append(" and ").append("houseId=?");
  params.add(houseId);
}
String day = queryBean.getDay();
if (StringUtils.isNotBlank(day)) {
  hql.append(" and ").append("day=?");
  params.add(day);
}
int threshold = queryBean.getThreshold();
if(threshold > 0){
  hql.append(" and ").append("bigint(visitsCount) >= ?");
  params.add(BigInteger.valueOf(threshold)); // 注意这里的类型转换,把int装成bigint
}

Object[] paramArray = params.toArray();
String detailHQL = hql.toString(); // + " order by bigint(visitsCount) desc ";
List<ActiveResourcesDomainInfo> hist = activeResourcesDomainDao.findPageable(detailHQL, currentPage, pageSize, paramArray);

String countHQL = "select count(*) " + hql;
long count = (long) illegalWebDao.findByHql(countHQL, paramArray).iterator().next();

定时任务,创建和更新触发器函数

函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
create or replace function create_partition_table_everyday (t TEXT) returns timestamp as $$
declare 
  i int;
  cnt int;
  stmt text;
  select_stmt text;
  day date;
  isInherit BOOLEAN;
begin

  day := now() + interval '-1 day';
  stmt := 'CREATE TABLE IF NOT EXISTS ' || t || to_char(day, 'YYYYMMDD') || '(check(day = ''' || to_char(day, 'YYYY-MM-DD') || ''')) INHERITS (' || t || ')';
  RAISE INFO '[DEBUG] %', stmt;
  EXECUTE stmt;

  day := now() + interval '-183 day';
  stmt := 'DROP TABLE IF EXISTS ' || t || to_char(day, 'YYYYMMDD');
  RAISE INFO '[DEBUG] %', stmt;
  EXECUTE stmt;

    -- try-catch
BEGIN
  day := now() + interval '-32 day';
  stmt := 'ALTER TABLE IF EXISTS ' || t || to_char(day, 'YYYYMMDD') || ' NO INHERIT ' || t;
  RAISE INFO '[DEBUG] %', stmt;
  EXECUTE stmt;
EXCEPTION WHEN OTHERS THEN
  RAISE INFO '[WARN] % %', SQLERRM, SQLSTATE;
END;

  i := 0;
  cnt := 6; -- 用于生成触发器分发最近几天的insert功能

  day := now() + interval '-1 day';
  stmt :=         ' create or replace function ' || t || '_insert_trigger() returns trigger as $' || '$ ';
  stmt := stmt || ' begin ';
  stmt := stmt || ' if (new.day = ''' || to_char(day, 'YYYY-MM-DD') || ''') then INSERT INTO ' || t || to_char(day, 'YYYYMMDD') || ' VALUES (new.*); ';
  while i < cnt 
  loop
      day := day + interval '-1 day';
      stmt := stmt || ' elsif (new.day = ''' || to_char(day, 'YYYY-MM-DD') || ''') then INSERT INTO ' || t || to_char(day, 'YYYYMMDD') || ' VALUES (new.*); ';

      i := i + 1;
  end loop;
  stmt := stmt || ' else raise exception ''DATE out of range. Fix the ' || t || '_insert_trigger() func!!''; ';
  stmt := stmt || ' end if; ';
  stmt := stmt || ' return null; ';
  stmt := stmt || ' end;  ';
  stmt := stmt || ' $' || '$ language plpgsql; ';
  RAISE INFO '[DEBUG] %', stmt;
  EXECUTE stmt;

  return now();
end;
$$ language plpgsql;

脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

vi update_dta_postgres.sh

#!/bin/sh

source ~/.bash_profile

psql -d dpi -c "select create_partition_table_everyday('t_dta_illegalweb')"
psql -d dpi -c "select create_partition_table_everyday('t_dta_activeresources_domain')"
psql -d dpi -c "select create_partition_table_everyday('t_dta_activeresources_ip')"

$ 
chmod +x update_dta_postgres.sh 
crontab -e


10 0 * * * sh ~/scripts/update_dta_postgres.sh >~/scripts/update_dta_postgres.log 2>&1

参考

–END

搭梯笔记

准备一个SSH账号

2017年1月25日11:20:55 - 现在都换成Shadowsocks了,下载 Shadowsocks使用教程合集及相关客户端下载 然后配置地址就行了。多配几个地址开启 高可用 完美。

2017年6月19日09:50:22 - 域名经常改啊,也苦了人家了,搭梯人不易。http://www.moonss.club 咨询QQ:58277266

2018年6月9日14:10:44 - 在aliyun买了一台国外的服务器,安装Shadowsocks-server。

SSH -N -D 或者MyEnTunnel

使用MyEnTunel的话,设置程序为【启动软件时自动连接】,同时把程序的快捷方式加到【C:\Users\winse\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\】目录下。

浏览器智能访问

Chrome的版本速度快一点。配置好后,等待一段时间就智能的适配了,firefox的等的时间略长。

Chrome + SwitchyOmega + gfwlist

可以做到智能代理功能,gfwlist的才会走代理。加速访问国内网站,同时减少不必要的流量。

Firefox + FoxyProxy + gfwlist

–END