公司要將監控數據存入opentsdb,而opentsdb使用了hbase做爲存儲。因此想搭建一套高可用的分佈式存儲來供opentsdb使用。java
由於機器有限,因此測試過程當中將三臺集羣的環境安裝在docker上。node
一:宿主機版本和docker版本nginx
宿主機:Centos7.2 3.10.0-862.14.4.el7.x86_64web
docker:Docker version 1.13.1, build 94f4240/1.13.1docker
二:鏡像版本shell
docker.io/centos 數據庫
三:建立docker鏡像apache
mkdir -p /home/dockerfile/hbasehabootstrap
上傳軟件包至此目錄centos
zookeeper-3.4.12.tar.gz
hbase-1.3.2.1-bin.tar.gz
hadoop-2.6.5.tar.gz
jdk8.tar.gz
建立Dockerfile。
vi Dockerfile
# 選擇一個已有的os鏡像做爲基礎 FROM centos # 安裝openssh-server和sudo軟件包,而且將sshd的UsePAM參數設置成no RUN yum install -y openssh-server sudo RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config #安裝openssh-clients RUN yum install -y openssh-clients # 添加測試用戶root,密碼root,而且將此用戶添加到sudoers裏 RUN echo "root:root" | chpasswd RUN echo "root ALL=(ALL) ALL" >> /etc/sudoers # 下面這兩句比較特殊,在centos6上必需要有,不然建立出來的容器sshd不能登陸 RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key # 啓動sshd服務而且暴露22端口 RUN mkdir /var/run/sshd EXPOSE 22 CMD ["/usr/sbin/sshd", "-D"]
ADD jdk8.tar.gz /usr/local/
RUN mv /usr/local/jdk1.8.0_171 /usr/local/jdk1.8
ENV JAVA_HOME /usr/local/jdk1.8
ENV PATH $JAVA_HOME/bin:$PATH
ADD hadoop-2.6.5.tar.gz /usr/local
#安裝which軟件包
RUN yum install -y which
#安裝net-tools軟件包
RUN yum install -y net-tools
ENV HADOOP_HOME /usr/local/hadoop-2.6.5
ENV PATH $HADOOP_HOME/bin:$PATH
ADD zookeeper-3.4.12.tar.gz /usr/local
ENV ZOOKEEPER_HOME /usr/local/zookeeper-3.4.12
ENV PATH $ZOOKEEPER_HOME/bin:$PATH
ADD hbase-1.3.2.1-bin.tar.gz /usr/local
建立鏡像命令:
docker build -t pro/hbase .
建立完成後查看鏡像生成狀況:
docker images
四:啓動容器,並規劃IP
1-虛擬機規劃
name | role | IP |
hab0 | Hadoop namenode/Hbase Master/ResourceManager | 172.17.0.21 |
hab1 | Hadoop namenode/Hbase Master/ResourceManager | 172.17.0.22 |
hab2 | 172.17.0.23 |
2-啓動容器
docker run --name hab0 --hostname hab0 -d -P -p 50070:50070 -p 8088:8088 pro/hbase docker run --name hab1 --hostname hab1 -d -P pro/hbase docker run --name hab2 --hostname hab2 -d -P pro/hbase
3-安裝bridge-utils 和pipework
bridge-utils用來管理網橋,pipework能夠用來給docker容器設置固定IP
yum -y install bridge-utils unzip pipework-master.zip mv pipework-master pipework cp -rp pipework/pipework /usr/local/bin/
4-設置容器IP
pipework docker0 hab0 172.17.0.20/24 pipework docker0 hab1 172.17.0.21/24 pipework dcoker0 hab2 172.17.0.22/24
五:安裝Zookeeper
1-進入hab0/hab1/hab2 並配置免密登錄
docker exec -it hab0 /bin/bash
hab0/1/2都須要添加以下hosts
vi /etc/hosts 172.17.0.20 hab0 172.17.0.21 hab1 172.17.0.22 hab2
在hab0上執行以下操做 cd ~ mkdir .ssh cd .ssh ssh-keygen -t rsa(一直按回車便可) ssh-copy-id -i localhost ssh-copy-id -i hab0 ssh-copy-id -i hab1 ssh-copy-id -i hab2 在hab1上執行下面操做 cd ~ cd .ssh ssh-keygen -t rsa(一直按回車便可) ssh-copy-id -i localhost ssh-copy-id -i hab1 在hab2上執行下面操做 cd ~ cd .ssh ssh-keygen -t rsa(一直按回車便可) ssh-copy-id -i localhost ssh-copy-id -i hab2
2-修改zookeeper文件
/usr/local/zookeeper-3.4.12/conf
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg 在文件末尾追加
dataDir=/home/hadoop/zookeeper-3.4.12/data/zkData //在最後添加,指定zookeeper集羣主機及端口,機器數必須爲奇數 server.1=hab0:2888:3888 server.2=hab1:2888:3888 server.3=hab2:2888:3888
3-建立data/zkData目錄,並創經myid. 待會兒同步配置後須要修改三個節點的myid的值。
//在zookeeper根目錄下建立zoo.cfg中配置的目錄 mkdir data/zkData/ -p //建立並編輯文件 vi myid //輸入1,即表示當前機器爲在zoo.cfg中指定的server.1 1 //保存退出 :wq
4-拷貝zookeeper到其餘節點
上述操做是在hab0機器上進行的,要將zookeeper拷貝到其餘zookeeper集羣機器上:
集羣中各組件的安裝目錄最好保持一致。
cd /usr/local scp -r zookeeper-3.4.12/ hab1:/usr/local scp -r zookeeper-3.4.12/ hab2:/usr/local
5-修改hab1 和hab2的myid
myid
文件是做爲當前機器在zookeeper集羣的標識,這些標識在zoo.cfg
文件中已經配置好了,可是以前在hab0這臺機器上配置的myid
爲1,因此還須要修改其餘機器的myid
文件:
//在hab1機器上 echo 2 > /usr/local/zookeeper-3.4.12/data/zkData/myid //在hab2機器上 echo 3 > /usr/local/zookeeper-3.4.12/data/zkData/myid
6-啓動zookeeper集羣
cd zookeeper-3.4.12/bin/ //分別在hab0、hab一、hab2上啓動 ./zkServer.sh start //查看狀態 ./zkServer.sh status 三臺機器的zookeeper狀態必須只有一個leader,其餘都是follower。 //查看進程,如有QuorumpeerMain,則啓動成功 jps
六:安裝並啓動hadoop的ha集羣
1-修改hadoop 5大配置文件
進入hadoop配置目錄
cd /usr/local/hadoop-2.6.5/etc/hadoop
vi hadoop-env.sh
JAVA_HOME=/usr/local/jdk1.8
vi core-site.xml
<configuration> <!-- hdfs地址,ha模式中是鏈接到nameservice --> <property> <name>fs.defaultFS</name> <value>hdfs://junode</value> </property> <!-- 這裏的路徑默認是NameNode、DataNode、JournalNode等存放數據的公共目錄,也能夠單獨指定 --> <property> <name>hadoop.tmp.dir</name> <value>/usr/local/hadoop-2.6.5/tmp</value> </property> <!-- 指定ZooKeeper集羣的地址和端口。注意,數量必定是奇數,且很多於三個節點--> <property> <name>ha.zookeeper.quorum</name> <value>hab0:2181,hab1:2181,hab2:2181</value> </property> </configuration>
vi hdfs-site.xml
<configuration> <!-- 指定副本數,不能超過機器節點數 --> <property> <name>dfs.replication</name> <value>3</value> </property> <!-- 爲namenode集羣定義一個services name --> <property> <name>dfs.nameservices</name> <value>junode</value> </property> <!-- nameservice 包含哪些namenode,爲各個namenode起名 --> <property> <name>dfs.ha.namenodes.junode</name> <value>hab0,hab1</value> </property> <!-- hab0的namenode的rpc地址和端口號,rpc用來和datanode通信 --> <property> <name>dfs.namenode.rpc-address.junode.hab0</name> <value>hab0:9000</value> </property> <!---hab1的namenode的rpc地址和端口號,rpc用來和datanode通信 --> <property> <name>dfs.namenode.rpc-address.junode.hab1</name> <value>hab1:9000</value> </property> <!--hab0的namenode的http地址和端口號,用來和web客戶端通信 --> <property> <name>dfs.namenode.http-address.junode.hab0</name> <value>hab0:50070</value> </property> <!-- hab1的namenode的http地址和端口號,用來和web客戶端通信 --> <property> <name>dfs.namenode.http-address.junode.hab1</name> <value>hab1:50070</value> </property> <!-- namenode間用於共享編輯日誌的journal節點列表 --> <property> <name>dfs.namenode.shared.edits.dir</name> <value>qjournal://hab0:8485;hab1:8485;hab2:8485/junode</value> </property> <!-- 指定該集羣出現故障時,是否自動切換到另外一臺namenode --> <property> <name>dfs.ha.automatic-failover.enabled.junode</name> <value>true</value> </property> <!-- journalnode 上用於存放edits日誌的目錄 --> <property> <name>dfs.journalnode.edits.dir</name> <value>/usr/local/hadoop-2.6.5/tmp/data/dfs/journalnode</value> </property> <!-- 客戶端鏈接可用狀態的NameNode所用的代理類 --> <property> <name>dfs.client.failover.proxy.provider.junode</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value> </property> <!-- 一旦須要NameNode切換,使用ssh方式進行操做 --> <property> <name>dfs.ha.fencing.methods</name> <value>sshfence</value> </property> <!-- 若是使用ssh進行故障切換,使用ssh通訊時用的密鑰存儲的位置 --> <property> <name>dfs.ha.fencing.ssh.private-key-files</name> <value>/root/.ssh/id_rsa</value> </property> <!-- connect-timeout超時時間 --> <property> <name>dfs.ha.fencing.ssh.connect-timeout</name> <value>30000</value> </property> </configuration>
vi mapred-site.xml
<!-- 採用yarn做爲mapreduce的資源調度框架 --> <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>
vi yarn-site.xml
<configuration> <!-- 啓用HA高可用性 --> <property> <name>yarn.resourcemanager.ha.enabled</name> <value>true</value> </property> <!-- 指定resourcemanager的名字 --> <property> <name>yarn.resourcemanager.cluster-id</name> <value>yrc</value> </property> <!-- 使用了2個resourcemanager,分別指定Resourcemanager的地址 --> <property> <name>yarn.resourcemanager.ha.rm-ids</name> <value>rm1,rm2</value> </property> <!-- 指定rm1的地址 --> <property> <name>yarn.resourcemanager.hostname.rm1</name> <value>hab0</value> </property> <!-- 指定rm2的地址 --> <property> <name>yarn.resourcemanager.hostname.rm2</name> <value>hab1</value> </property> <!-- 指定當前機器hab0做爲rm1 --> <property> <name>yarn.resourcemanager.ha.id</name> <value>rm1</value> </property> <!-- 指定zookeeper集羣機器 --> <property> <name>yarn.resourcemanager.zk-address</name> <value>hab0:2181,hab1:2181,hab2:2181</value> </property> <!-- NodeManager上運行的附屬服務,默認是mapreduce_shuffle --> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> </configuration>
vi slaves
hab0 hab1 hab2
2-拷貝hadoop目錄到其餘節點
scp -r hadoop-2.6.5 hab1:/usr/local scp -r hadoop-2.6.5 hab2:/usr/local
3-修改hab1的yarn-site.xml
在hab1機器,即ResourceManager備用主節點上修改以下屬性,表示當前機器做爲rm2::
<property> <name>yarn.resourcemanager.ha.id</name> <value>rm2</value> </property>
同時刪除hab2節點上的該屬性對,由於hab2機器並不做爲ResourceManager。
3-啓動hadoop
啓動Journalnode
cd hadoop-2.6.5/sbin/ ./hadoop-daemon.sh start //查看進程JouralNode是否啓動 jps
4-格式化 NameNode和ZKFC
在hab0機器上,執行格式化操做:
cd hadoop-2.6.5/bin ./hdfs namenode -format ./hdfs zkfc -formatZK
../sbin/hadoop-daemon.sh start namenode
5-備用主節點同步主節點元數據
在hab1(備用主節點)機器上,執行同步操做:
cd hadoop-2.6.5/bin ./hdfs namenode -bootstrapStandby
6-安裝fuster
若服務器是最小化安裝centeros時,有可能系統沒有fuster程序,那麼跳過這個安裝步驟直接進行後面的操做時,將有可能出現如下問題:
hab0做爲主節點時,kill掉hab0上的NameNode和ResourceManager進程時,能夠實現故障轉移,hab1將從stanby狀態自動變成active狀態;可是當hab1做爲主節點時,
若kill掉hab1上的進程,hab0上的進程狀態卻仍是stanby,並不能實現故障自動轉移。緣由是咱們在 hdfs-site.xml中配置了當集羣須要故障自動轉移時採用SSH方式進行,
而由於缺乏fuster程序,將在zkfc的日誌文件中發現以下錯誤:
PATH=$PATH:/sbin:/usr/sbin fuser -v -k -n tcp 9000 via ssh: bash: fuser: 未找到命令 Unable to fence service by any configured method java.lang.RuntimeException: Unable to fence NameNode at master hab1/172.17.0.21:9000
在hab0/hab1/hab2上執行
sudo yum install psmisc
7-啓動HDFS、YARN、ZookeeperFailoverController
在hab0上
cd hadoop-2.6.5/sbin ./start-dfs.sh //驗證,顯示NameNode和DataNode jps ./start-yarn.sh //驗證,顯示ResourceManager和NodeManager jps ./hadoop-daemon.sh start zkfc //驗證,顯示ZookeeperFailoverController jps
在hab1機器上,啓動ResourceManager,備用主節點的ResourceManager須要手動啓動:
cd hadoop-2.6.5/sbin yarn-daemon.sh start resourcemanager
查看hab0 Namenode、ResourceManager狀態
hdfs haadmin -getServiceState hab0 yarn rmadmin -getServiceState rm1 hdfs haadmin -getServiceState hab1 yarn rmadmin -getServiceState rm2
也能夠經過Web界面來查看,瀏覽器中輸入 ip:50070 查看HDFS,輸入 ip:8088/cluster/cluster 查看YARN。
8-測試高可用
kill掉主節點的namenode,查看備用主節點的namenode狀態是否切換爲active;
kill掉主節點的ResourceManager,查看備用主節點的ResourceManager是否切換爲active;
若上述操做執行成功,那麼再測試反向故障自動轉移
先啓動被殺死的原主節點的namenode和ResourceManager
hadoop-daemon.sh start namenode yarn-daemon.sh start resourcemanager
再kill備用主節點的namenode和ResourceManager,查看主節點的狀態,若能切換爲active,那麼Hadoop HA高可用集羣搭建完成。
補充當前三臺機器網元啓動狀態
hab0 [root@hab0 sbin]# jps
5794 DataNode
5186 JournalNode
2835 ResourceManager
3219 DFSZKFailoverController
38 QuorumPeerMain
7274 Jps
5483 NameNode
3694 HRegionServer
2943 NodeManager
[root@hab1 logs]# jps
2258 NameNode
2403 JournalNode
1333 NodeManager
1765 HRegionServer
2684 DataNode
3262 Jps
30 QuorumPeerMain
1487 ResourceManager
[root@hab2 ~]#jps
1891 Jps
1496 JournalNode
249 QuorumPeerMain
1129 HRegionServer
1596 DataNode
959 NodeManager
七:在ha的hadoop集羣上搭建Hbase
1-修改hbase配置
進入hbase-1.3.2.1//conf/目錄,修改配置文件: cd /usr/local/hbase-1.3.2.1/conf/
建立pid目錄
mkdir -p /usr/local/hbase-1.3.2.1/data/hbase/pids
vi hbase-env.sh
//配置JDK export JAVA_HOME=/usr/local/jdk1.8 //保存pid文件 export HBASE_PID_DIR=/usr/local/hbase-1.3.2.1/data/hbase/pids //修改HBASE_MANAGES_ZK,禁用HBase自帶的Zookeeper,由於咱們是使用獨立的Zookeeper export HBASE_MANAGES_ZK=false
vi hbase-site.xml
<configuration> <!-- 設置HRegionServers共享目錄,請加上端口號 --> <property> <name>hbase.rootdir</name> <value>hdfs://junode/hbase</value> </property> <!-- 指定HMaster主機 --> <property> <name>hbase.master</name> <value>hdfs://hab0:60000</value> </property> <!-- 啓用分佈式模式 --> <property> <name>hbase.cluster.distributed</name> <value>true</value> </property> <!-- 指定Zookeeper集羣位置 --> <property> <name>hbase.zookeeper.quorum</name> <value>hab0:2181,hab1:2181,hab2:2181</value> </property> <!-- 指定獨立Zookeeper安裝路徑 --> <property> <name>hbase.zookeeper.property.dataDir</name> <value>/usr/local/zookeeper-3.4.12</value> </property> <!-- 指定ZooKeeper集羣端口 --> <property> <name>hbase.zookeeper.property.clientPort</name> <value>2181</value> </property> </configuration>
vi regionservers
修改regionservers文件,由於當前是使用獨立的Zookeeper集羣,因此要指定RegionServers所在機器:
hab0 hab1 hab2
2-拷貝hbase到其餘節點
scp -r hbase-1.3.2.1 hab1:/usr/local scp -r hbase-1.3.2.1 hab2:/usr/local
3-在主節點上啓動HBase(這裏的主節點是指NameNode狀態爲active的節點)
cd hbase-1.3.2.1/bin ./start-hbase.sh //查看HMaster、Regionserver進程是否啓動 jps
注意:此時Hadoop集羣應處於啓動狀態,而且是在主節點執行start-hbase.sh啓動HBase集羣,不然HMaster進程將在啓動幾秒後消失,而備用的HMaster進程須要在備用主節點單獨啓動,命令是:./hbase-daemon.sh start master。
備用節點啓動hmaster cd hbase-1.3.2.1/bin ./hbase-daemon.sh start master
4-Hbase高可用測試
在瀏覽器中輸入 ip:16010 ,查看主節點和備用主節點上的HMaster的狀態,在備用主節點的web界面中,能夠看到「Current Active Master: master188」,表示當前HBase主節點是master188機器; 主節點--->備用主節點 這裏的主節點指使用start-hbase.sh命令啓動HBase集羣的機器 kill掉主節點的HMaster進程,在瀏覽器中查看備用主節點的HBase是否切換爲active; 若上述操做成功,則在主節點啓動被殺死的HMaster進程: cd hbase-1.3.2.1/bin/ ./hbase-daemon.sh start master 而後,kill掉備用主節點的HMaster進程,在瀏覽器中查看主節點的HBase是否切換爲active,若操做成功,則HBase高可用集羣搭建完成;
5-Hbase基本操做
//啓動HBase [root@vnet ~] start-hbase.sh //進入HBase Shell [root@vnet ~] hbase shell //查看當前HBase有哪些表 hbase(main):> list //建立表t_user,cf1和cf2是列族,列族通常不超過3個 hbase(main):> create 't_user','cf1','cf2' //得到表t_user的描述信息 hbase(main):> describe 't_user' //禁用表 hbase(main):> disable 't_user' //刪除表,刪除表以前要先把表禁用掉 hbase(main):> drop 't_user' //查詢表是否存在 hbase(main):> exists 't_user' //查看全表數據 hbase(main):> scan 't_user' //插入數據,分別是表名、key、列(列族:具體列)、值。HBase是面向列的數據庫,列可無限擴充 hbase(main):> put 't_user' ,'001','cf1:name','chenxj' hbase(main):> put 't_user' ,'001','cf1:age','18' hbase(main):> put 't_user' ,'001','cf2:sex','man' hbase(main):> put 't_user' ,'002','cf1:name','chenxj' hbase(main):> put 't_user' ,'002','cf1:address','fuzhou' hbase(main):> put 't_user' ,'002','cf2:sex','man' //獲取數據,可根據key、key和列族等進行查詢 hbase(main):> get 't_user','001' hbase(main):> get 't_user','002','cf1' hbase(main):> get 't_user','001','cf1:age'