HBase、Cassandra性能简要测评
引言
HBase和Cassandra是目前国内外分布式存储研究当中最为关注的两种列式存储的非关系型数据库,其中HBase倾向于CP,强调强一致性,而Cassandra倾向于AP,强调不存在单点故障的可用性。两种数据库的生态圈各有千秋,HBase基于Hadoop平台,并且使用了Zookeeper的一致性算法进行调度,能够很好的支持MapReduce计算;而Cassandra则具有可调节的一致性级别,运维上比较简单,支持线性拓展,但也存在例如大文件不适合存储的问题。本文通过HBase、Cassandra两种数据库的集群搭建过程和YCSB负载性能测试对其性能进行简要测评。
环境准备
创建三台虚拟机,各虚拟机系统版本为CentOS7,内存4GB,硬盘20GB。配置网络及主机名如下:
主机名 | IP地址 |
---|
hadoop0 | 192.168.84.128/24 | hadoop1 | 192.168.84.129/24 | hadoop2 | 192.168.84.130/24 |
各软件版本:hadoop3.3.0、Zookeeper3.4.14、HBase1.4.13、Cassandra3.11.10、jdk1.8、maven3.8.1、ycsb0.17
在三台主机上安装各软件并修改/etc/profile环境变量
export JAVA_HOME=/app/jdk
export PATH=$PATH:$JAVA_HOME/bin
export HADOOP_HOME=/app/hadoop
export PATH=$PATH:$HADOOP_HOME/bin
export PATH=$PATH:$HADOOP_HOME/sbin
export ZK_HOME=/app/zookeeper
export PATH=$PATH:$ZK_HOME/bin
export HBASE_HOME=/app/hbase
export PATH=$PATH:$HBASE_HOME/bin
export MAVEN_HOME=/app/maven
export PATH=$PATH:$MAVEN_HOME/bin
export CASSANDRA_HOME=/app/cassandra
export PATH=$PATH:$CASSANDRA_HOME/bin
HBase集群搭建
Hadoop集群搭建
由于HBase基于Hadoop的HDFS文件系统,故首先需要搭建起Hadoop分布式集群环境。
集群各节点功能规划如下:
| hadoop0 | haddop1 | hadoop2 |
---|
HDFS | NameNode、DataNode | DataNode | SecondaryNameNode、DataNode | YARN | NodeManager | ResourceManager、NodeManager | NodeManager |
其中NameNode为Hadoop文件系统管理者,有单点故障特性;SecondaryNameNode为NameNode的一个备用,能够在NameNode宕机时减少损失;ResourceManager管理各节点NodeManager。
Hadoop各配置文件如下:
core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:8020</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/app/hdfs/tmp</value>
</property>
<property>
<name>hadoop.http.staticuser.user</name>
<value>wenxin</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<property>
<name>dfs.namenode.http-address</name>
<value>hadoop0:9870</value>
</property>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>hadoop2:9868</value>
</property>
</configuration>
yarn-site.xml
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop1</value>
</property>
<property>
<name>yarn.nodemanager.env-whitelist</name>
<value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
</property>
</configuration>
mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
完成配置后,使用特殊的linux shell程序xsync工具将hadoop包分发到其他两台从机上
xsync文件传输工具封装如下:
#!/bin/bash
if [ $# -lt 1 ]
then
echo Not Enough Arguement!
exit;
fi
for host in hadoop0 hadoop1 hadoop2
do
echo =========== $host ============
for file in $@
do
if [ -e $file ]
then
pdir=$(cd -P $(dirname $file); pwd)
fname=$(basename $file)
ssh $host "mkdir -p $pdir"
rsync -av $pdir/$fname $host:$pdir
else
echo $file does not exists!
fi
done
done
将该脚本放在任意环境变量目录下,修改其权限777,即可方便的在集群环境中分发已经配置好的程序包。
启动集群:
1.集群初始化:hdfs namenode -format 将文件系统格式化
 此时执行jps可以看到守护进程出现Jps
2.在主机hadoop0上运行 start-dfs.sh 
此时dfs相关的NameNode、SecondaryNameNode、DataNode均正常启动
3.在对应从机(hadoop1)上运行 sbin/start-yarn.sh

此时yarn相关的ResourceManager、NodeManager启动完毕
本地访问hadoop0:9870出现HDFS的web端界面

Zookeeper集群搭建
根据Zookeeper的一致性算法,若节点个数为偶数则发生冗余,故配置奇数个Zookeeper节点,在三台机器上同时配置。
安装Zookeeper后,在conf/目录下将模板的配置文件复制为zoo.cfg
cp zoo_sample.cfg zoo.cfg
并在zoo.cfg文件内做如下配置
tickTime=2000 //通信心跳时间
initLimit=10 //初始连接时follower和leader之间容忍的最多心跳数
syncLimit=5 //通常情况下follower和leader之间请求、答应的最多心跳数
dataDir=/app/ztmp/zookeeper //存放myid以及VERSION等信息
clientPort=2181 //客户端端口,默认2181
//集群各服务器编号、地址、内部通信端口、选举端口
server.0=192.168.84.128:2888:3888
server.1=192.168.84.129:2888:3888
server.2=192.168.84.130:2888:3888
配完zoo.cfg后,在每台机器的dataDir对应路径下新建myid文件,并且填上对应的服务器编号(仅写一个数字),用于标识集群中该服务器的id
启动各节点服务:zkServer.sh start

查看当前节点状态(follower | leader):zkServer.sh status  
HBase集群配置
将以下环境变量添加到hbase-env.sh export HBASE_MANAGES_ZK=false export JAVA_HOME=/app/jdk/ export HBASE_LOG_DIR=${HBASE_HOME}/logs export HADOOP_HOME=/app/hadoop
配置hbase-site.xml
<configuration> <property> <name>hbase.rootdir</name> <value>hdfs://localhost:8020/hbase</value> </property> <property> <name>hbase.cluster.distributed</name> <value>true</value> </property> <property> <name>hbase.zookeeper.quorum</name> <value>hadoop0:2181,hadoop1:2181,hadoop2:2181</value> </property> <property> <name>zookeeper.znode.parent</name> <value>/hbase</value> </property> <property> <name>hbase.tmp.dir</name> <value>/app/tmp/hbase</value> </property> <property> <name>hbase.unsafe.stream.capability.enforce</name> <value>false</value> </property></configuration>
在conf/regionservers文件内写入集群各服务器主机名,一行对应一台主机,不要有多余空格
在conf/下新建backup-masters文件,写入备份数据的主机名
再将hadoop的core-site.xml、hdfs-site.xml拷贝到/conf目录下
运行 start-hbase.sh 启动服务,最先启动服务的服务器自动变成Master节点
 从启动的打印日志可以看到先启动该主机的Master,接着跑各RegionServer,最后运行备份Master节点 使用jps查看当前守护进程

本地访问hadoop0:16010进入HBase的web端界面

Cassandra集群搭建
Cassandra集群的搭建较为简易,没有前置集群的配置过程,只需要设置好配置文件和环境变量即可顺利启动。
cassandra.yaml
启动集群命令:cassandra -R 注意先启动两台seed节点 
使用nodetool status查看当前节点运行状态
YCSB性能测试
测试用例
针对HBase和Cassandra之间的读写性能差异,对YCSB测试功能提供的workloads工作负载进行改写,读写占比步长均为0.1,插入和查找所占比例均设置为0;再将load和run的加载记录条数和操作数都设置成100000,表示共测试10万行数据,数据分布采用zipfian离散幂律分布。
形成workload01~workload11共11个测试负载,具体workload配置如下:
recordcount=100000operationcount=100000workload=site.ycsb.workloads.CoreWorkloadreadallfields=true
在测试过程中采用8线程并行操作的方式load数据到hbase和
测试HBase所做配置
安装好YCSB后,cd到目录下,找到对应HBase版本的hbase14-binding,将hbase-site.xml配置文件放到该目录conf目录中
使用hbase shell进入hbase数据库的客户端,创建一个默认测试数据表格usertable,列族为family
create 'usertable','family'
测试Cassandra所做配置
测试Cassandra时最新的YCSB存在slf4j.jar包问题,把ycsb/cassandra-binding/lib目录内的slf4j-api.jar依赖包换成slf4j-simple.jar依赖,解决报错问题
使用cqlsh hadoop0进入Cassandra集群客户端,创建一个测试数据键空间及对应默认测试表,默认表含十个字段
CREATE KEYSPACE ycsb WITH replication = {'class':'SimpleStrategy', 'replication_factor' : 3};use ycsb;CREATE TABLE usertable ( y_id text PRIMARY KEY, field0 text, field1 text, field2 text, field3 text, field4 text, field5 text, field6 text, field7 text, field8 text, field9 text);
测试过程
反复使用ycsb的load、run指令测试数据库性能,并将结果存入ycsb目录下out/ loadx.log | runx.log 记录中
所得数据记录文件如下所示: 
数据汇总
将测试所得结果进行整理和汇总,得出如下数据
HBase | | | | | | |
---|
实验编号 | 读比例 | 写比例 | 运行时间(ms) | 吞吐量(ops/sec) | 平均读延迟(us) | 平均写延迟(us) | 1 | 0 | 1 | 22758 | 4394.059 | - | 1678.506 | 2 | 0.1 | 0.9 | 28676 | 3487.237 | 2664.148 | 2100.768 | 3 | 0.2 | 0.8 | 26767 | 3735.944 | 1896.634 | 2026.893 | 4 | 0.3 | 0.7 | 29098 | 3436.662 | 1897.643 | 2319.394 | 5 | 0.4 | 0.6 | 31621 | 3162.455 | 2063.382 | 2588.263 | 6 | 0.5 | 0.5 | 28889 | 3461.525 | 1848.109 | 2473.038 | 7 | 0.6 | 0.4 | 28772 | 3475.601 | 1901.301 | 2532.787 | 8 | 0.7 | 0.3 | 27045 | 3697.541 | 1780.163 | 2596.65 | 9 | 0.8 | 0.2 | 23906 | 4183.05 | 1572.547 | 2583.392 | 10 | 0.9 | 0.1 | 20538 | 4869.023 | 1283.398 | 3483.514 | 11 | 1 | 0 | 12416 | 8054.124 | 862.706 | - | Cassandra | | | | | | | 实验编号 | 读比例 | 写比例 | 运行时间(ms) | 吞吐量(ops/sec) | 平均读延迟(us) | 平均写延迟(us) | 1 | 0 | 1 | 60763 | 1645.738 | - | 4594.483 | 2 | 0.1 | 0.9 | 68796 | 1453.573 | 6135.836 | 5118.771 | 3 | 0.2 | 0.8 | 68567 | 1458.428 | 5551.948 | 5144.268 | 4 | 0.3 | 0.7 | 71732 | 1394.078 | 5546.74 | 5428.321 | 5 | 0.4 | 0.6 | 66704 | 1499.16 | 5110.334 | 5034.541 | 6 | 0.5 | 0.5 | 65425 | 1528.468 | 4920.686 | 4996.547 | 7 | 0.6 | 0.4 | 63207 | 1582.103 | 4731.804 | 4873.388 | 8 | 0.7 | 0.3 | 52387 | 1908.871 | 3690.642 | 4115.61 | 9 | 0.8 | 0.2 | 50224 | 1991.08 | 3560.607 | 4082.804 | 10 | 0.9 | 0.1 | 45376 | 2203.808 | 3331.516 | 3807.191 | 11 | 1 | 0 | 44305 | 2257.082 | 3278.479 | - |
根据实验[2-10]数据,在excle中绘制HBase、Cassandra不同读写负载下的性能变化曲线图


测试总结
在进行了10万条数据记录、8线程并行操作的数据库读写性能测试实验后,发现在各个场景下HBase的吞吐量和读/写延迟相比Cassandra都具有相当大的性能优势。
导致这种情况的可能原因有:
- ycsb对不同数据库的测试记录大小不一致。观察到HBase的K-V式存储,10万行记录实际是10万个K-V键值对,而Cassandra的数据库键空间内的测试表是10个字段一条记录,对于这个原因可以再探讨。
- 测试完一组load、run后都要TRUNCATE测试表,截断表时有一定延迟数据才恢复稳定,HBase截断很快就表示截断完成,而Cassandra截断后nodetool status查看状态需要一定时间恢复稳定。
- 本测试中Cassandra一致性级别设置的是QUORUM,在不同的一致性级别下Cassandra的读写性能会有不同。
|