一键部署 Hbase 集群攻略

2,549 阅读7分钟
原文链接: cloudinsight.daoapp.io

或许你也像我一样,工作后才发现学校里学的技术是多么落后。C++ 和 MySQL 或许已经不再是 IT 公司的宠儿。互联网时代对数据库的要求,也与传统有着很大的差别。

而这差别中比较突出的一点就是数据量的问题,在数据量非常庞大的今天关系型数据库可能无法实现存储并处理海量数据,但是分布式数据库可以实现这些要求。举个例子,关系型数据库对于程序的扩展性很差,数据字段确定后不能再扩展一些相关字段的;但对于分布式数据库来说,数据库中的字段可以随意添加,扩展性极强,不用担心快速迭代过程中的业务拓展。

正因此,一些大公司也纷纷转投 Hbase 的怀抱,比如某猫。

Hbase 表的特点:

  • 大:一个表可以有数十亿行,上百万列;
  • 无模式:每行都有一个可排序的主键和任意多的列,列可以根据需要动态的增加,同一张表中不同的行可以有截然不同的列;
  • 面向列:面向列(族)的存储和权限控制,列(族)独立检索;
  • 稀疏:空(null)列并不占用存储空间,表可以设计的非常稀疏;
  • 数据多版本:每个单元中的数据可以有多个版本,默认情况下版本号自动分配,是单元格插入时的时间戳;
  • 数据类型单一:Hbase中的数据都是字符串,没有类型。

言归正传,接下来讲讲我的 Hbase 体验。

Hbase 实战

手里有一台可以随意折腾的机器,16G 内存 4 核 1T 磁盘,装有 fedora24 系统。之前用过 vagrant & virtualbox 来搭建集群,效果还不错。但可能是自己的配置不是很合适,只起了 5 个虚拟机来做 hbase 集群。后来又用 docker 折腾,开到 7 个容器来跑 hbase 集群,十分好用。

心满意足之后,就想着试试一键部署———于是有了本文。

部署结构

查看图片

具体各个软件的配置文件都会出现在下面。

本地机器主要软件版本

  • docker: Docker version 1.10.3, build 19b5791/1.10.3,启动虚拟机用的。
  • ansible: ansible 2.1.0.0,python 写的部署工具,好处是 remote 机器不需要安装客户端什么的。事实上,用到的一些功能时还是需要安装一些包的,具体可以在后面的 Dockerfile 中看到。
  • expect: 在使用 ansible 前需要本地到 remote 的免密钥 ssh 登入,expect 的作用是免去每次输入密码的麻烦。

remote需要用到的一些包

以下列出一些我在用的软件包,基本上是最新的 stable 版,可自行根据需要调整。

jdk-8u60-linux-x64.tar.gz  
zookeeper-3.4.8.tar.gz  
hadoop-2.7.2.tar.gz  
hbase-1.1.5-bin.tar.gz  

Docker image

有一堆真机器的土豪也可以简单看看,这里面还是会涉及到一些机器环境设置的 : D

1.首先,你要有docker。

sudo dnf install -y docker  
sudo systemctl start docker  
sudo systemctl enable docker  

2.不用 sudo 使用 docker 的方法

# 添加docker用户组
sudo groupadd docker  
# 把自己加到docker用户组中
sudo gpasswd -a myusername docker  
# 重启docker后台服务
sudo service docker restart  
# 注销,然后再登陆
exit  
# 不是用ssh远程登入的话,就直接注销再登入

3.Dockerfile

为了跑 hbase 集群,我们需要的是尽可能小又足够用的容器,也就是需要一个尽可能小又足够用的镜像。

先拉一个镜像下来docker pull fedora。这个是后面的Dockerfile用到的镜像基础,一般而言都是官方最新的。如果 dockerhub 网络不好的话,就去 fedora 官网下载,迅雷的话会很快哦。

然后docker load < [imageFileName]。至于为什么是 fedora 而不是 centos、ubuntu 或者 arch 什么的,仅仅是个人偏好(如果是要用 ambari 部署 HDP 集群的话,请避免 fedora,目前暂不支持)。

然后建一个文件夹,touch Dockerfile,写上下面内容。

# make image for zookeeper, hadoop and hbase

FROM docker.io/fedora:24

MAINTAINER LukeEuler "513973890@qq.com"

RUN dnf install -y openssh-server sudo openssh-clients procps-ng hostname which  
RUN dnf install -y python libselinux-python tar  
RUN dnf install -y pexpect  
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config \  
        && useradd litchi \
        && echo "litchi:123456" | chpasswd \
        && echo "litchi   ALL=(ALL)       ALL" >> /etc/sudoers \
        && ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key \
        && ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key \
        && mkdir /var/run/sshd

EXPOSE 22  
CMD ["/usr/sbin/sshd", "-D"]  

然后可以建镜像了,docker build -t litchi:hbase [path/to/Dockerfile],过程会有点慢。 path/to/Dockerfile 里除了 Dockerfile 以外,请务必不要放其他奇怪的东西。

简单说明 Dockerfile

其中: * 第三行的FROM是说这个新镜像是从什么镜像上生成的,也就是一开始让大家 pull 的。 * 第五行请自行修改或删除,也请大家记住我的称呼和联系方式(笑)。 * 第七行是安装一些集群运作所必要的软件,大概(可以精简的话请务必分享哦) * 第八行和第九行是安装一些为 ansible 部署提供方便的软件,都是大家认识的,所以可以放心使用。 * 后面的就是为打开 sshd 服务做准备的。 * 另外这个镜像添加了user: litchi & passward: 123456,请自行修改,以保密。 * 肯定有人问为什么是 litchi,因为夏天到了,荔枝可好吃啦~

测试一下litchi:hbase是否可用

# 后台启动容器
docker run -d -P --name=test -h test litchi:hbase  
# 查看容器ip和其他参数
docker inspeck test  
ssh litchi@[ip]  

ansible

sudo dnf install -y ansible官网上有很多其他安装方式,请自行摸索。

sudo dnf install -y expect装这个是因为bash不提供交互应答的地方(如果读者知道更好的方法,请 email 我)

修改/etc/hosts文件,添加:

172.17.0.2  n1  
172.17.0.3  n2  
172.17.0.4  n3  
172.17.0.5  n4  
172.17.0.6  n5  
172.17.0.7  n6  
172.17.0.8  n7  

这是 docker 启动容器后自动安顺序分配的 ip,如果不同,请自行修改。之后就不用记写 ip 了,机智如我。

然后修改一下/ect/ansible.hosts

[zookeeper]
n[3:7]

[hbase]
n[1:7] ansible_sudo_pass='123456'

[journalNode]
n[3:5]  

下面就是我折腾的结果了,一键部署的主要执行文件,和预先写好的集群配置文件

主要执行文件

start.sh

放到你需要的位置,记得chmod +x start.sh

#!/bin/bash

docker stop $(docker ps -a -q)

docker rm $(docker ps -a -q)

for i in {1..7}  
do  
    docker run -d -P --name=n$i -h n$i \
    --add-host n1:172.17.0.2 \
    --add-host n2:172.17.0.3 \
    --add-host n3:172.17.0.4 \
    --add-host n4:172.17.0.5 \
    --add-host n5:172.17.0.6 \
    --add-host n6:172.17.0.7 \
    --add-host n7:172.17.0.8 \
    litchi:hbase
done

rm /home/luke/.ssh/known_hosts

/home/luke/git/note/projects/shell/sshCopyId.expect.sh
ansible-playbook /home/luke/git/note/ansible/build.yml  

注意:我会默认清理docker的容器以避免冲突,所以如果有需要运行的其他容器,请妥善处理(都要起 hbase 集群了,应该干不了其他事了吧,大概)。

最后两行分别写了 sshCopyId.expect.shbuild.yml 的绝对路径,请根据需要修改。

sshCopyId.expect.sh

请把他放到 start.sh 标明的位置,记得chmod +x sshCopyId.expect.sh。主要是实现本地到 remote 的免密钥 ssh 登入,是 ansible 部署的前提。

#!/usr/bin/expect

set password 123456

for {set i 1} {$i < 8} {incr i 1} {  
  spawn ssh-copy-id litchi@n$i
  expect {
    "*yes/no*" { send "yes\r"; exp_continue }
    "*assword:*" { send "$password\r" }
  }
  interact
}

build.yml

请把他放到start.sh标明的位置。另外,它不是执行文件,是 ansible 的一个部署配置文件——playbook,请这么称呼它。放到这里,完全是因为写起来方便,不服来打我啊~

---
- hosts: hbase
  remote_user: litchi
  tasks:
    - file: path=/home/litchi/.ssh/id_rsa state=absent
      name: remove id_rsa
    - file: path=/home/litchi/.ssh/id_rsa.pub state=absent
      name: remove id_rsa.pub
    - shell: ssh-keygen -t rsa -f /home/litchi/.ssh/id_rsa -N ''
      name: ssh-keygen
    - file: path=/home/litchi/.ssh/known_hosts state=absent
      name: remove known_hosts
    - expect:
        command: ssh-copy-id litchi@n{{ item }}
        responses:
          "(yes/no)": "yes"
          "password": "123456"
      name: ssh-copy-id between each other among {n1..n7}
      with_sequence: count=7

- hosts: hbase
  remote_user: litchi
  tasks:
    - unarchive: src=/home/luke/packages/jdk-8u60-linux-x64.tar.gz dest=/home/litchi
      name: upload & tar jdk
    # actually, i do not know which way is better, maybe i will test it later
    # - name: translate jdk
    #   copy: src=/home/luke/packages/jdk-8u60-linux-x64.tar.gz dest=/home/litchi/jdk.tar.gz
    # - name: tar jdk
    #   shell: tar xvzf jdk.tar.gz
    #   args:
    #     chdir: /home/litchi/
    - unarchive: src=/home/luke/packages/hadoop-2.7.2.tar.gz dest=/home/litchi
      name: upload & tar hadoop
    - unarchive: src=/home/luke/packages/hbase-1.1.5-bin.tar.gz dest=/home/litchi
      name: upload & tar hbase

- hosts: zookeeper
  remote_user: litchi
  tasks:
    - unarchive: src=/home/luke/packages/zookeeper-3.4.8.tar.gz dest=/home/litchi
      name: upload & tar zookeeper
    - copy: src=/home/luke/git/note/messSource/zoo.cfg dest=/home/litchi/zookeeper-3.4.8/conf/zoo.cfg
      name: add zoo.cfg
    - file: path=/home/litchi/zookeeper state=directory
      name: mkdir zookeeper
    - file: path=/home/litchi/zookeeper/myid state=touch
      name: touch myid
    - shell: hostname | cut -c 2 >> /home/litchi/zookeeper/myid
      name: write X in myid

- hosts: hbase
  remote_user: litchi
  tasks:
    - lineinfile: dest=/home/litchi/hadoop-2.7.2/etc/hadoop/hadoop-env.sh regexp={JAVA_HOME} line="export JAVA_HOME=/home/litchi/jdk1.8.0_60/"
      name: edit JAVA_HOME
    - file: path=/home/litchi/hadoop-2.7.2/etc/hadoop/core-site.xml state=absent
      name: remove old core-site.xml
    - copy: src=/home/luke/git/note/messSource/core-site.xml dest=/home/litchi/hadoop-2.7.2/etc/hadoop/core-site.xml
      name: add new core-site.xml
    - file: path=/home/litchi/hadoop-2.7.2etc/hadoop/hdfs-site.xml state=absent
      name: remove old hdfs-site.xml
    - copy: src=/home/luke/git/note/messSource/hdfs-site.xml dest=/home/litchi/hadoop-2.7.2/etc/hadoop/hdfs-site.xml
      name: add new hdfs-site.xml
    - file: path=/home/litchi/hadoop-2.7.2/etc/hadoop/slaves state=absent
      name: remove old slaves
    - copy: src=/home/luke/git/note/messSource/slaves dest=/home/litchi/hadoop-2.7.2/etc/hadoop/slaves
      name: add new slaves

- hosts: hbase
  remote_user: litchi
  tasks:
    - lineinfile: dest=/home/litchi/hbase-1.1.5/conf/hbase-env.sh regexp="# export JAVA_HOME=/usr/java/jdk1.6.0/" line="export JAVA_HOME=/home/litchi/jdk1.8.0_60/"
      name: edit hbase-env.sh JAVA_HOME
    - lineinfile: dest=/home/litchi/hbase-1.1.5/conf/hbase-env.sh regexp="# export HBASE_MANAGES_ZK=true" line="export HBASE_MANAGES_ZK=false"
      name: edit hbase-env.sh HBASE_MANAGES_ZK true => false
    - file: path=/home/litchi/hbase-1.1.5/conf/hbase-site.xml state=absent
      name: remove old hbase-site.xml
    - copy: src=/home/luke/git/note/messSource/hbase-site.xml dest=/home/litchi/hbase-1.1.5/conf/hbase-site.xml
      name: add new hbase-site.xml
    - file: path=/home/litchi/hbase-1.1.5/conf/regionservers state=absent
      name: remove old regionservers
    - copy: src=/home/luke/git/note/messSource/regionservers dest=/home/litchi/hbase-1.1.5/conf/regionservers
      name: add new regionservers
    - file: path=/home/litchi/hbase-1.1.5/conf/backup-masters state=touch
      name: touch backup-masters
    - shell: echo -e "n2" >> /home/litchi/hbase-1.1.5/conf/backup-masters
      name: write backup-masters

- hosts: zookeeper
  remote_user: litchi
  tasks:
    - shell: PATH=/home/litchi/jdk1.8.0_60/bin:$PATH /home/litchi/zookeeper-3.4.8/bin/zkServer.sh start
      name: start zookeeper

- hosts: n1
  remote_user: litchi
  tasks:
    - shell: /home/litchi/hadoop-2.7.2/bin/hdfs zkfc -formatZK
      name: formatZK @n1

- hosts: journalNode
  remote_user: litchi
  tasks:
    - shell: /home/litchi/hadoop-2.7.2/sbin/hadoop-daemon.sh start journalnode
      name: start journalnode @n3,n4,n5

- hosts: n1
  remote_user: litchi
  tasks:
    - shell: /home/litchi/hadoop-2.7.2/bin/hdfs namenode -format
      name: format namenode @n1
    - shell: scp -r /home/litchi/hadoop/ litchi@n2:~/
      name: copy /home/litchi/hadoop/ => litchi@n2:~/
    - command: /home/litchi/hadoop-2.7.2/sbin/start-dfs.sh
      name: start hdfs
    - command: /home/litchi/hadoop-2.7.2/sbin/stop-dfs.sh
      name: stop hdfs
    - command: /home/litchi/hadoop-2.7.2/sbin/start-dfs.sh
      name: start hdfs
    - command: /home/litchi/hadoop-2.7.2/sbin/hadoop-daemon.sh start zkfc
      name: start zkfc
    - command: /home/litchi/hbase-1.1.5/bin/start-hbase.sh
      name: start hbase

集群的配置文件

请根据build.yml中的写法放到合适的位置,本机的位置/home/luke/git/note/messSource,务必做相应的修改。

core-site.xml

  
  
    hadoop.tmp.dir
    /home/litchi/tmp
  
  
    fs.defaultFS
    hdfs://CHC
  
  
    io.file.buffer.size
    4096
  
  
    ha.zookeeper.quorum
    n3,n4,n5,n6,n7
  
  

hbase-site.xml

  
  
    hbase.rootdir
    hdfs://n1:9000/hbase
  
  
    hbase.cluster.distributed
    true
  
  
    hbase.zookeeper.quorum
    n3,n4,n5,n6,n7
  
  
    dfs.replication
    3
  
  

hdfs-site.xml

  
  
    dfs.nameservices
    CHC
  
  
    dfs.ha.namenodes.CHC
    os1,os2
  
  
    dfs.namenode.rpc-address.CHC.os1
    n1:9000
  
  
    dfs.namenode.http-address.CHC.os1
    n1:50070
  
  
    dfs.namenode.rpc-address.CHC.os2
    n2:9000
  
  
    dfs.namenode.http-address.CHC.os2
    n2:50070
  
  
    dfs.namenode.shared.edits.dir
    qjournal://n3:8485;n4:8485;n5:8485/CHC
  
  
    dfs.journalnode.edits.dir
    /home/litchi/hadoop/tmp/journal
  
  
    dfs.ha.automatic-failover.enabled.CHC
    true
  
  
    dfs.client.failover.proxy.provider.CHC
    org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider
  
  
    dfs.ha.fencing.methods
    sshfence
  
  
    dfs.ha.fencing.ssh.private-key-files
    /home/litchi/.ssh/id_rsa
  
  
    dfs.ha.fencing.ssh.connect-timeout
    30000
  
  
    dfs.namenode.name.dir
    /home/litchi/hadoop/tmp/name
  
  
    dfs.datanode.data.dir
    /home/litchi/hadoop/tmp/data
  
  
    dfs.replication
    3
  
  
    dfs.webhdfs.enabled
    true
  
  

regionservers

n3  
n4  
n5  
n6  
n7  

slaves

n3  
n4  
n5  
n6  
n7  

zoo.cfg

tickTime=2000  
initLimit=10  
syncLimit=5  
dataDir=/home/litchi/zookeeper  
clientPort=2181  
server.3=n3:2888:3888  
server.4=n4:2888:3888  
server.5=n5:2888:3888  
server.6=n6:2888:3888  
server.7=n7:2888:3888  

集群的软件

jdk-8u60-linux-x64.tar.gz  
zookeeper-3.4.8.tar.gz  
hadoop-2.7.2.tar.gz  
hbase-1.1.5-bin.tar.gz  

不要忘了把他们也下载下来,放到 build.yml 所指定的位置。如果版本不同,也请做相应的文字修改。

一键超人

/start.sh  

后记

匆匆写完,必然有所错误与遗漏,望请指正,方便你我。

署名-相同方式共享 3.0 中国大陆