HBASE数据库
HBase中的表一般有这样的特点:
下载地址
操作步骤说明:
wget http://mirrors.hust.edu.cn/apache/hbase/1.3.1/hbase-1.3.1-bin.tar.gz
tar -zxvf hbase-1.3.1-bin.tar.gz -C /export/servers/
cd ../servers/
mv hbase-1.3.1 hbase
vi /etc/profile
-
export HBASE_HOME=/export/servers/hbase
export PATH=${HBASE_HOME}/bin:$PATH
-
source /etc/profile
进入配置文件所在的目录
cd /export/servers/hbase/conf/
修改第一个配置文件 regionservers
vi regionservers
-
node02
node03
修改第二个配置文件 hbase-site.xml
注意:以下配置集成的是hadoop ha集群。
如果您的集群没有配置ha,hbase.rootdir 配置项目需要修改:hdfs://master:9000/hbase
vi hbase-site.xml
-
<configuration>
<property>
<name>hbase.rootdirname>
<value>hdfs://ns1/hbasevalue>
property>
<property>
<name>hbase.cluster.distributedname>
<value>truevalue>
property>
<property>
<name>hbase.master.portname>
<value>16000value>
property>
<property>
<name>hbase.zookeeper.property.dataDirname>
<value>/export/data/zk/value>
property>
<property>
<name>hbase.zookeeper.quorumname>
<value>node01,node02,node03value>
property>
<property>
<name>hbase.zookeeper.property.clientPortname>
<value>2181value>
property>
configuration>
修改第三个配置文件 hbase-env.sh
HBASE_MANAGES_ZK=false 表示,hbase和大家伙公用一个zookeeper集群,而不是自己管理集群。
vi hbase-env.sh
-
export JAVA_HOME=/export/servers/jdk
export HBASE_MANAGES_ZK=false
修改第四个配置文件 拷贝hadoop配置文件
拷贝hadoop的配置文件到hbase的配置文件目录
分发配置文件
scp -r /export/servers/hbase/ node02:/export/servers/
scp -r /export/servers/hbase/ node03:/export/servers/
启动集群
startzk.sh
start-dfs.sh
start-hbase.sh
启动异常:
2017-12-27 06:27:54,882 INFO [node01:16000.activeMasterManager] master.ServerManager: Waiting for region servers count to settle; currently checked in 0, slept for 67247 ms, expecting minimum of 1, maximum of 2147483647, timeout of 4500 ms, interval of 1500 ms.
解决办法:
保证每台机器时间一致。
ntpdate -u 0.uk.pool.ntp.org
ntpdate -u 1.uk.pool.ntp.org
hbase shell
create 'user','base_info'
put 'user','rowkey_10','base_info:username','张三'
put 'user','rowkey_10','base_info:birthday','2014-07-10'
put 'user','rowkey_10','base_info:sex','1'
put 'user','rowkey_10','base_info:address','北京市'
put 'user','rowkey_16','base_info:username','张小明'
put 'user','rowkey_16','base_info:birthday','2014-07-10'
put 'user','rowkey_16','base_info:sex','1'
put 'user','rowkey_16','base_info:address','北京'
put 'user','rowkey_22','base_info:username','陈小明'
put 'user','rowkey_22','base_info:birthday','2014-07-10'
put 'user','rowkey_22','base_info:sex','1'
put 'user','rowkey_22','base_info:address','上海'
put 'user','rowkey_24','base_info:username','张三丰'
put 'user','rowkey_24','base_info:birthday','2014-07-10'
put 'user','rowkey_24','base_info:sex','1'
put 'user','rowkey_24','base_info:address','河南'
put 'user','rowkey_25','base_info:username','陈大明'
put 'user','rowkey_25','base_info:birthday','2014-07-10'
put 'user','rowkey_25','base_info:sex','1'
put 'user','rowkey_25','base_info:address','西安'
scan 'user'
get 'user','rowkey_16'
get 'user','rowkey_16','base_info'
get 'user','rowkey_16','base_info:username'
get 'user', 'rowkey_16', {
COLUMN => ['base_info:username','base_info:sex']}
delete 'user', 'rowkey_16', 'base_info:username'
truncate 'user'
alter 'user', NAME => 'f2'
alter 'user', 'delete' => 'f2'
disable 'user'
drop 'user'
可以通过HbaseUi界面查看表的信息
端口60010打不开的情况,是因为hbase 1.0 以后的版本,需要自己手动配置,在文件 hbase-site
<property>
<name>hbase.master.info.portname>
<value>60010value>
property>
<dependency>
<groupId>org.apache.hbasegroupId>
<artifactId>hbase-clientartifactId>
<version>1.3.1version>
dependency>
在resource目录下创建hbase-site.xml
<configuration>
<property>
<name>hbase.zookeeper.quorumname>
<value>zk01,zk02,zk03value>
<description>The directory shared by region servers.
description>
property>
configuration>
// hbase的两种连接方式:1)读取配置文件 只需要配置zookeeper
Configuration config = HBaseConfiguration.create();
Connection connection = ConnectionFactory.createConnection(config);
//2)通过代码配置
Configuration configuration = new Configuration();
configuration.set("hbase.zookeeper.quorum", "zk01:2181,zk02:2181,zk03:2181");
connection = ConnectionFactory.createConnection();
public static void main(String[] args) throws IOException {
// 1.连接HBase
// 1.1 HBaseConfiguration.create();
Configuration config = HBaseConfiguration.create();
// 1.2 创建一个连接
Connection connection = ConnectionFactory.createConnection(config);
// 1.3 从连接中获得一个Admin对象
Admin admin = connection.getAdmin();
// 2.创建表
// 2.1 判断表是否存在
TableName tableName = TableName.valueOf("user");
if (!admin.tableExists(tableName)) {
//2.2 如果表不存在就创建一个表
HTableDescriptor hTableDescriptor = new HTableDescriptor(tableName);
hTableDescriptor.addFamily(new HColumnDescriptor("base_info"));
admin.createTable(hTableDescriptor);
System.out.println("创建表");
}
}
。
<dependency>
<groupId>org.apache.hbasegroupId>
<artifactId>hbase-clientartifactId>
<version>1.3.1version>
dependency>
在resource目录下创建hbase-site.xml
<configuration>
<property>
<name>hbase.zookeeper.quorumname>
<value>zk01,zk02,zk03value>
<description>The directory shared by region servers.
description>
property>
configuration>
// hbase的两种连接方式:1)读取配置文件 只需要配置zookeeper
Configuration config = HBaseConfiguration.create();
Connection connection = ConnectionFactory.createConnection(config);
//2)通过代码配置
Configuration configuration = new Configuration();
configuration.set("hbase.zookeeper.quorum", "zk01:2181,zk02:2181,zk03:2181");
connection = ConnectionFactory.createConnection();
public static void main(String[] args) throws IOException {
// 1.连接HBase
// 1.1 HBaseConfiguration.create();
Configuration config = HBaseConfiguration.create();
// 1.2 创建一个连接
Connection connection = ConnectionFactory.createConnection(config);
// 1.3 从连接中获得一个Admin对象
Admin admin = connection.getAdmin();
// 2.创建表
// 2.1 判断表是否存在
TableName tableName = TableName.valueOf("user");
if (!admin.tableExists(tableName)) {
//2.2 如果表不存在就创建一个表
HTableDescriptor hTableDescriptor = new HTableDescriptor(tableName);
hTableDescriptor.addFamily(new HColumnDescriptor("base_info"));
admin.createTable(hTableDescriptor);
System.out.println("创建表");
}
}
@Before
public void initConnection() {
try {
connection = ConnectionFactory.createConnection(config);
} catch (IOException e) {
System.out.println("连接数据库失败");
}
}
@Test
public void tableInfo() throws IOException {
// 1.定义表的名称
TableName tableName = TableName.valueOf("user");
// 2.获取表
Table table = connection.getTable(tableName);
// 3.获取表的描述信息
HTableDescriptor tableDescriptor = table.getTableDescriptor();
// 4.获取表的列簇信息
HColumnDescriptor[] columnFamilies = tableDescriptor.getColumnFamilies();
for (HColumnDescriptor columnFamily : columnFamilies) {
// 5.获取表的columFamily的字节数组
byte[] name = columnFamily.getName();
// 6.使用hbase自带的bytes工具类转成string
String value = Bytes.toString(name);
// 7.打印
System.out.println(value);
}
}
@Before
public void initConnection() {
try {
connection = ConnectionFactory.createConnection(config);
} catch (IOException e) {
System.out.println("连接数据库失败");
}
}
@Test
public void put() throws IOException {
// 1.定义表的名称
TableName tableName = TableName.valueOf("user");
// 2.获取表
Table table = connection.getTable(tableName);
// 3.准备数据
String rowKey = "rowkey_10";
Put zhangsan = new Put(Bytes.toBytes(rowKey));
zhangsan.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"), Bytes.toBytes("张三"));
zhangsan.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("sex"), Bytes.toBytes("1"));
zhangsan.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("address"), Bytes.toBytes("北京市"));
zhangsan.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("birthday"), Bytes.toBytes("2014-07-10"));
// 4. 添加数据
table.put(zhangsan);
table.close();
}
@Test
public void get() throws IOException {
// 1.定义表的名称
TableName tableName = TableName.valueOf("user");
// 2.获取表
Table table = connection.getTable(tableName);
// 3.准备数据
String rowKey = "rowkey_10";
// 4.拼装查询条件
Get get = new Get(Bytes.toBytes(rowKey));
// 5.查询数据
Result result = table.get(get);
// 6.打印数据 获取所有的单元格
List<Cell> cells = result.listCells();
for (Cell cell : cells) {
// 打印rowkey,family,qualifier,value
System.out.println(Bytes.toString(CellUtil.cloneRow(cell))
+ "==> " + Bytes.toString(CellUtil.cloneFamily(cell))
+ "{" + Bytes.toString(CellUtil.cloneQualifier(cell))
+ ":" + Bytes.toString(CellUtil.cloneValue(cell)) + "}");
}
}
@Test
public void scan() throws IOException {
// 1.定义表的名称
TableName tableName = TableName.valueOf("user");
// 2.获取表
Table table = connection.getTable(tableName);
// 3.全表扫描
Scan scan = new Scan();
// 4.获取扫描结果
ResultScanner scanner = table.getScanner(scan);
Result result = null;
// 5. 迭代数据
while ((result = scanner.next()) != null) {
// 6.打印数据 获取所有的单元格
List<Cell> cells = result.listCells();
for (Cell cell : cells) {
// 打印rowkey,family,qualifier,value
System.out.println(Bytes.toString(CellUtil.cloneRow(cell))
+ "==> " + Bytes.toString(CellUtil.cloneFamily(cell))
+ "{" + Bytes.toString(CellUtil.cloneQualifier(cell))
+ ":" + Bytes.toString(CellUtil.cloneValue(cell)) + "}");
}
}
}
在4.8的基础上修改代码如下
Scan scan = new Scan();
scan.setStartRow(Bytes.toBytes("rowkey_1"));
scan.setStopRow(Bytes.toBytes("rowkey_2"));
//创建RowFilter过滤器
RowFilter rowFilter = new RowFilter(CompareFilter.CompareOp.EQUAL
, new BinaryComparator("rowkey_10".getBytes()));
//创建familyFilter过滤器
FamilyFilter familyFilter = new FamilyFilter(CompareFilter.CompareOp.NO_OP,
new BinaryComparator("base_Info".getBytes()));
//创建qualifierFilter过滤器
QualifierFilter qualifierFilter = new QualifierFilter(CompareFilter.CompareOp.EQUAL,
new BinaryComparator("username".getBytes()));
//创建valueFilter过滤器
ValueFilter valueFilter = new ValueFilter(CompareFilter.CompareOp.EQUAL,
new BinaryComparator("张三".getBytes()));
@Test
public void tesValueFilter() throws IOException {
//1、创建过滤器
ValueFilter filter = new ValueFilter(CompareFilter.CompareOp.EQUAL, new BinaryComparator("张三".getBytes()));
//2、创建扫描器
Scan scan = new Scan();
//3、将过滤器设置到扫描器中
scan.setFilter(filter);
//4、获取HBase的表
Table table = connection.getTable(TableName.valueOf("user"));
//5、扫描HBase的表(注意过滤操作是在服务器进行的,也即是在regionServer进行的)
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
// 6.打印数据 获取所有的单元格
List<Cell> cells = result.listCells();
for (Cell cell : cells) {
// 打印rowkey,family,qualifier,value
System.out.println(Bytes.toString(CellUtil.cloneRow(cell))
+ "==> " + Bytes.toString(CellUtil.cloneFamily(cell))
+ "{" + Bytes.toString(CellUtil.cloneQualifier(cell))
+ ":" + Bytes.toString(CellUtil.cloneValue(cell)) + "}");
}
}
}
HBase是三维有序存储的,通过rowkey(行键),column key(column family和qualifier)和TimeStamp(时间戳)这个三个维度可以对HBase中的数据进行快速定位。
HBase中rowkey可以唯一标识一行记录,三种查询方式
rowkey是一个二进制码流,可以是任意字符串,最大长度64kb,实际应用中一般为10-100bytes,以byte[]形式保存,一般设计成定长。
建议越短越好,不要超过16个字节
数据的持久化文件HFile中是按照KeyValue存储的,如果rowkey过长,比如超过100字节,1000w行数据,光rowkey就要占用100*1000w=10亿个字节,将近1G数据,这样会极大影响HFile的存储效率;
MemStore将缓存部分数据到内存,如果rowkey字段过长,内存的有效利用率就会降低,系统不能缓存更多的数据,这样会降低检索效率。
目前操作系统都是64位系统,内存8字节对齐,控制在16个字节,8字节的整数倍利用了操作系统的最佳特性。
如果rowkey按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将rowkey的高位作为散列字段,由程序随机生成,低位放时间字段,这样将提高数据均衡分布在每个RegionServer,以实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息,所有的数据都会集中在一个RegionServer上,这样在数据检索的时候负载会集中在个别的RegionServer上,造成热点问题,会降低查询效率。
必须在设计上保证其唯一性,rowkey是按照字典顺序排序存储的,因此,设计rowkey的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。
HBase中的行是按照rowkey的字典顺序排序的,这种设计优化了scan操作,可以将相关的行以及会被一起读取的行存取在临近位置,便于scan。然而糟糕的rowkey设计是热点的源头。热点发生在大量的client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region不可用,这也会影响同一个RegionServer上的其他region,由于主机无法服务其他region的请求。设计良好的数据访问模式以使集群被充分,均衡的利用。
为了避免写热点,设计rowkey使得不同行在同一个region,但是在更多数据情况下,数据应该被写入集群的多个region,而不是一个。
这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。分配的前缀种类数量应该和你想使用数据分散到不同的region的数量一致。加盐之后的rowkey就会根据随机生成的前缀分散到各个region上,以避免热点。
哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据
第三种防止热点的方法时反转固定长度或者数字格式的rowkey。这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。
以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题