前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hbase初识

Hbase初识

作者头像
小爷毛毛_卓寿杰
发布2019-02-13 15:13:21
5100
发布2019-02-13 15:13:21
举报
文章被收录于专栏:Soul Joy Hub

模块

这里写图片描述
这里写图片描述

hmaster、hregionserver、zookeeper、hregion、root表、meta表、hfile、hstore、memstore、blockcache

  • hmaster
    • 启动时HRegion的分配,以及负载均衡和修复时HRegion的重新分配。
    • 监控集群中所有HRegionServer的状态(通过Heartbeat和监听ZooKeeper中的状态)。
    • 创建、删除、修改Table的定义
  • hregionserver 主要负责响应用户的I/O请求,向HDFS文件系统中读写数据。
  • zookeeper root表的父节点,记录root表的Lacation
  • hregion HBase使用RowKey将表水平切割成多个HRegion,从HMaster的角度,每个HRegion都纪录了它的StartKey和EndKey,由于RowKey是排序的,因而Client可以通过HMaster快速的定位每个RowKey在哪个HRegion中。
  • root表 mata表的父节点,记录meta表的Region信息,只有一个Region
  • meta表 UserTable的父节点,记录UserTable的Region信息,可以有多个region。
  • hfile 是StoreFile的底层实现,对应LSM tree中的大树
  • hstore hstore是Hbase存储的核心,其中有两部分组成,一部分是MenStore,一部分是StoreFile
  • memstore Sorted Memory Buffer,用户写入的数据首先会放入menstore,对应LSM tree中的小树,当menstore满了以后会执行flush操作变成一个storefile
  • blockcache blockcache是一个读缓存,即“引用局部性”原理将数据预读取到内存中,以提升读的性能。

基本API

DDL

  • 生成conf -> 生成admin
代码语言:javascript
复制
Configuration conf = HBaseConfiguration.create();
HBaseAdmin admin = new HBaseAdmin(conf);
  • 生成tableName -> 生成tableDescriptor
代码语言:javascript
复制
TableName tableName = TableName.valueOf("test");
HTableDescriptor tableDescriptor = new HTableDescriptor(tableName);
  • 生成columnDescriptor(列族)-> 加入到tableDescriptor
代码语言:javascript
复制
tableDescriptor.addFamily(columnDescriptor);
  • tableDescriptor -> admin生成table
代码语言:javascript
复制
admin.createTable(tableDescriptor);

DML

  • conf & tableName -> 生成 table ,用于 DML 和 DQL
代码语言:javascript
复制
HTable table = new HTable(conf, tableName);
  • 生成 row -> 生成put ,Hbase中传入传出数据库中的值用的都是byte[] , 要注意与String类型转换
代码语言:javascript
复制
byte[] row = Bytes.toBytes("row1");
Put put = new Put(row);
  • 生成 想添加的val 以及它所在 列族 和 列 -> 加入到 put
代码语言:javascript
复制
byte[] colfam = Bytes.toBytes("data");
byte[] col = Bytes.toBytes(String.valueOf(1));
byte[] val = Bytes.toBytes("value1");
put.add(colfam, col, val);
  • put -> table put
代码语言:javascript
复制
table.put(put);

DQL

get

  • 生成 row -> 生成get
代码语言:javascript
复制
byte[] row = Bytes.toBytes("row1");
Get get = new Get(row);
  • get -> table getResult 生成 result
代码语言:javascript
复制
Result result = table.get(get);
  • 生成 查询的 列族 和 列 -> result getValue
代码语言:javascript
复制
byte[] colfam = Bytes.toBytes("data");
byte[] col = Bytes.toBytes(String.valueOf(1));
System.out.println("get value is " + Bytes.toString(result.getValue(colfam, col)));

scan

  • 生成scan -> table getScanner 生成 ResultScanner。
代码语言:javascript
复制
Scan scan = new Scan();
ResultScanner scanner = table.getScanner(scan);
  • ResultScanner可以理解为Result数组,遍历生成要查询的列族和列 -> result getValue
代码语言:javascript
复制
int i = 0;
for (Result scanresult : scanner) {
byte[] scancol = Bytes.toBytes(String.valueOf(++i));
System.out.println("scan value is " + Bytes.toString(scanresult.getValue(colfam, scancol)));
}

注意: HBaseAdmin,HTable,ResultScanner 对象最后都要close()

Example

代码语言:javascript
复制
package ExampleClient;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.Bytes;

public class ExampleClient {

    public static void main(String[] args) throws MasterNotRunningException, ZooKeeperConnectionException, IOException {
        // TODO Auto-generated method stub
        Configuration conf = HBaseConfiguration.create();
        HBaseAdmin admin = new HBaseAdmin(conf);
        try {

            TableName tableName = TableName.valueOf("test");
            HTableDescriptor tableDescriptor = new HTableDescriptor(tableName);
            HColumnDescriptor columnDescriptor = new HColumnDescriptor("data");
            tableDescriptor.addFamily(columnDescriptor);
            admin.createTable(tableDescriptor);

            HTable table = new HTable(conf, tableName);
            try {
                for (int i = 1; i <= 3; ++i) {
                    byte[] row = Bytes.toBytes("row" + i);
                    Put put = new Put(row);
                    byte[] colfam = Bytes.toBytes("data");
                    byte[] col = Bytes.toBytes(String.valueOf(i));
                    byte[] val = Bytes.toBytes("value" + i);
                    put.add(colfam, col, val);
                    table.put(put);
                }
                byte[] row = Bytes.toBytes("row1");
                Get get = new Get(row);
                Result result = table.get(get);
                byte[] colfam = Bytes.toBytes("data");
                byte[] col = Bytes.toBytes(String.valueOf(1));
                System.out.println("get result is " + Bytes.toString(result.getValue(colfam, col)));

                Scan scan = new Scan();
                ResultScanner scanner = table.getScanner(scan);
                try {
                    int i = 0;
                    for (Result scanresult : scanner) {
                        byte[] scancol = Bytes.toBytes(String.valueOf(++i));
                        System.out.println("scan result is " + Bytes.toString(scanresult.getValue(colfam, scancol)));
                    }
                } finally {
                    // TODO: handle finally clause
                    scanner.close();
                }
            } finally {
                // TODO: handle finally clause
                table.close();
            }
        } finally {
            // TODO: handle finally clause
            admin.close();
        }
    }

}

B+ tree与LSM tree

B+树

根节点和枝节点分别记录每个叶子节点的最小值,并用一个指针指向叶子节点。

B+树对读友好。叶子节点里每个键值都指向真正的数据块,每个叶子节点都有前指针和后指针,这是为了做范围查询时,叶子节点间可以直接跳转。

B+树对写不友好。最大的性能问题是会产生大量的随机IO,随着新数据的插入,叶子节点会慢慢分裂,逻辑上连续的叶子节点在物理上往往不连续,甚至分离的很远,但做范围查询时,会产生大量读随机IO。

这里写图片描述
这里写图片描述

关系数据库中常用B+树组织数据。如上图所示,内部节点已经存满,再插入一个新记录时,需要在B+树中插入一个新的内部节点,再链到B+树中。这里的问题是新的内部节点在磁盘上可能存放在很远的地方,在顺序扫描数据时,不得不seek磁盘。

LSM树

LSM树本质上就是在读写之间取得平衡,和B+树相比,它牺牲了部分读性能,用来大幅提高写性能。

它的原理是把一颗大树拆分成N棵小树, 它首先写入到内存中(内存没有寻道速度的问题,随机写的性能得到大幅提升),在内存中构建一颗有序小树,随着小树越来越大,内存的小树会flush到磁盘上。当读时,由于不知道数据在哪棵小树上,因此必须遍历所有的小树,但在每颗小树内部数据是有序的。

Hbase中的LSM树

  1. insert/update写入log后,再写入内存(memory store)
  2. memory store写满后,flush到磁盘上
  3. 后台进程/线程对磁盘上多个文件进行合并,组成排序后的B+树,同时处理删除、更新、TTL等 查询时先查内存中的数据,再查磁盘
这里写图片描述
这里写图片描述
  • WAL 因为数据是先写到内存中,如果断电,内存中的数据会丢失,因此为了保护内存中的数据,需要在磁盘上先记录logfile,当内存中的数据flush到磁盘上时,就可以抛弃相应的Logfile。
  • memstore, LSM树就是一堆小树,在内存中的小树即memstore,每次flush,内存中的memstore变成磁盘上一个新的storefile。
  • compact 随着小树越来越多,读的性能会越来越差,因此需要在适当的时候,对磁盘中的小树进行merge,多棵小树变成一颗大树。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年07月16日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 模块
  • 基本API
    • DDL
      • DML
        • DQL
          • get
          • scan
        • Example
        • B+ tree与LSM tree
          • B+树
            • LSM树
              • Hbase中的LSM树
              相关产品与服务
              TDSQL MySQL 版
              TDSQL MySQL 版(TDSQL for MySQL)是腾讯打造的一款分布式数据库产品,具备强一致高可用、全球部署架构、分布式水平扩展、高性能、企业级安全等特性,同时提供智能 DBA、自动化运营、监控告警等配套设施,为客户提供完整的分布式数据库解决方案。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档