慕課網_《HBase 存儲原理剖析》學習總結

慕課網《HBase 存儲原理剖析》學習總結

第一章:課程介紹

1-1 課程介紹

課程目標java

  • HBase的存儲模式
  • HBase數據表解析
  • HBase存儲設計
  • HBase數據存取解析

第二章:存儲模式

2-1 存儲模式

行式存儲與列式存儲介紹node

image

行式存儲與列式存儲特色git

  • 行式存儲github

    • 維護大量的索引
    • 存儲成本高
    • 不可以作到線性擴展
    • 隨機讀取效率很是高
    • 對事務的支持很是好
  • 列式存儲web

    • 根據同一列數據的類似性原理,利於對數據進行壓縮
    • 存儲成本低
    • 因爲每列數據分開存儲,能夠並行查找多列的數據

行式存儲與列式存儲場景算法

  • 行式存儲spring

    • 表與表之間有關聯關係,數據量不大(小於千萬量級)
    • 強事務關聯的特性
  • 列式存儲數據庫

    • 對於單列或者相對比較少的列獲取頻率較高
    • 針對多列查詢,使用並行處理的查詢
    • 利於數據壓縮和線性擴展的存儲
    • 事務使用率不高,讀取的場景頻率不高,同時數據量很是大
    • 隨機更新某一行的頻率不高

列簇式存儲:概念apache

  • 列簇(多個數據列的組合),HBase表中的每一個列都歸屬於某個列簇
  • 列簇是表的schame的一部分,可是列並非
  • 建立表時,須要給出列簇的名稱,不須要給出列的名稱
  • 列名都是以列簇做爲前綴
  • 訪問控制磁盤和內存的使用統計都是在列簇層面進行
  • HBase準確的說是列簇數據庫,而不是列數據庫
  • 列簇數據庫將列組織爲列簇,每列都必須是某個列簇的一部分
  • 訪問數據的單元也是列

HBase表的組成json

  • Table = RowKey + Family + Column + Timestamp + Value
  • RowKey :HBase中用RowKey去標識惟一的一行數據,一行數據中包含多個列簇
  • Family:多個列簇。每一列簇包含多個列
  • Column:列標識符。每一列數據包含了版本和值
  • Timestamp:版本。能夠理解爲時間戳,也能夠理解爲一個數據的版本
  • Value:數據值。數據自己的值

HBase數據存儲的模式

  • (Table, RowKey, Family, Column, Timestamp)-> Value
  • 其實就是HBase表反過來看的樣子
  • 【重點】更抽象一點,其實HBase表數據就是Key-Value結構的

圖解

image

列簇式存儲:列數據屬性

HBase重要特性:列數據版本的概念,默認一列數據能夠保存三個版本

image

列簇式存儲:數據存儲原型

image

2-2 存儲示例

示例表定義

image

示例表數據

image

第三章 表的解析

3-1 建表語句

示例表語句定義

image

壓縮算法

算法 壓縮率 編碼速度 解碼速度
GZip 13.4% 21MB/s 118MB/s
LZO 20.5% 135MB/s 410MB/s
Snappy 22.2% 172MB/s 409MB/s

3-2 存儲目錄

hbase-site.xml文件中配置或查看存儲目錄的節點

<property>
    <name>hbase.rootdir</name>
    <value>/home/hbase_data</value>
</property>

進入到HBase系統目錄

  • .tmp

    • 當對錶作建立或刪除操做時,將表移動到tmp目錄下,而後再進行處理
    • 臨時交換的表,臨時存儲一些當前須要修改的數據結構
  • WALs

    • 預寫日誌,被HLog實例管理的WAL文件
    • 能夠理解爲存儲HBase的日誌,HBase分佈式數據庫系統的操做日誌
  • archive

    • 存儲表的歸檔和快照
    • HBase在作分割或合併操做完成後,會將Hfile文件移動到該目錄中,而後將以前的Hfile刪除掉
    • 是由Master上的定時任務按期去處理,這個目錄的做用能夠簡單理解爲去管理HBase的數據
  • corrupt

    • 用於存放損壞的日誌文件,通常是空的
  • data

    • HBase存儲數據的核心目錄
    • 系統表和用戶表數據都存儲在這裏
  • hbase.id

    • HBase啓動運行後,是集羣中的惟一ID,用來標識HBase進程用的
  • hbase.version

    • 代表了集羣的文件格式版本信息
    • 其實就是代表了Hfile的版本信息
  • oldWALs

    • 備份WALs中的日誌文件

data目錄解析

image

HBase元信息表

Row Key Value
table、key、time region server

第四章:存儲設計

4-1 存儲思想

HBase中的LSM存儲思想

  • 什麼是LSM樹

    LSM日誌結構合併樹,有兩個或兩個以上存儲數據的結構組成的,每個數據結構各自對應本身的存儲介質
  • LSM樹的簡易模型描述

    image
  • LSM思想在HBase中的思想

    image

4-2 存儲模塊

HBase數據存儲模塊簡介

RegionServer = Region + Store + MemStore + StoreFile + HFile + HLog

image

HBase Region解析

  • 什麼是Region

    每個Region都會存儲於肯定的RegionServer上
    image
  • Region的特色

    • 是HBase中分佈式存儲和負載均衡的最小單元
    • Region的數據不能低於集羣中節點的數量
    • RegionServer對Region進行拆分
    • 儘可能讓Row key分散到不一樣的Region

HBase HFile解析

  • Store + MemStore + StoreFile

    • Store與列簇是一對一的關係
    • MemStore是一個內存數據結構,保存修改的數據
    • StoreFile是由內存數據寫入到文件後造成的
> ![image](https://note.youdao.com/yws/api/personal/file/BC358BAF87A44E01AC1E29C9742DF6F2?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)
  • HFile 文件

    • 是HBase存儲數據文件的最基本的組織形式
    • 底層是Hadoop的二進制格式文件
    • 是用戶數據的實際載體,存儲Key-Value的數據
    • Scanned block section:會被讀取,主要是存儲用戶數據
    • Nonscanned block section:不會被讀取,主要包含元數據塊
    • Load-on-open section:RegionServer啓動時加載,主要是HFile的元數據
    • Trailer:HFile的基本信息,HFile元數據的一部分
> ![image](https://note.youdao.com/yws/api/personal/file/27F88E086AC5419F83F5BC9473060F52?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)
  • Data Block

    • HBase中數據的最基本的存儲單元
    • 是實際存儲用戶數據的數據結構
    • 包含不少Key-Value
> ![image](https://note.youdao.com/yws/api/personal/file/6C175A6EF8D546FCB02CED9E10B364DE?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)

HBase WAL解析

  • 簡介介紹WAL(預寫日誌)

    • WAL最重要的功能就是災難恢復
    • WAL解決了什麼問題:HA(高可用)問題
    • 怎麼解決:遠程備份
> ![image](https://note.youdao.com/yws/api/personal/file/993E28018DCA4AD7AABDDF494154F91B?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)
  • HLog

    • WAL是經過HLog模塊實現的
    • HLog是什麼:HLog是實現WAL的類,一個RegionServer對應一個HLog實例
> ![image](https://note.youdao.com/yws/api/personal/file/C7E652C51E564E0A811C1F23FFBB2F0E?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)
  • HLogKey

    • WAL使用Hadoop的序列化文件將記錄存儲爲Key-Value的數據集,Key就是HLog的Key
> ![image](https://note.youdao.com/yws/api/personal/file/3F4EADB35EB74A66B9CBD736C7989B07?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)
  • HLogSyncer

    • 是日誌同步刷寫類
> ![image](https://note.youdao.com/yws/api/personal/file/A9A568573E9042C3BFE4F33042F7DB2B?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)
  • HLogRoller

    • 特色的時間去滾動日誌,造成新的日誌,避免單個日誌文件過大
    • 根據HLog的序列化的number對比已經持久化的HFile的序列號,刪除舊的,不須要的日誌
> ![image](https://note.youdao.com/yws/api/personal/file/F1AB5E58BBAE435FA5F35957EE3276C3?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)

HBase Compaction解析

  • 什麼是Compaction

    • Compaction會從一個Region的Store中選擇一些HFile文件進行合併
  • 爲何要Compaction

    • 隨着系統不停的刷寫,會致使存儲目錄中有過多的數據文件
  • Compaction分類

    • MinorCompaction:小合併
    • MajorCompaction:大合併
> ![image](https://note.youdao.com/yws/api/personal/file/053CA3350B764F60B0A2DB01D841FAEA?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)
  • Compaction觸發時機

    • MemStore 內存數據寫入到硬盤上
> ![image](https://note.youdao.com/yws/api/personal/file/C9D3EA024E1848178E3879F80C1536A0?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)

4-3 存取解析

HBase數據存儲流程解析

  • HBase Client

    • 請求Zookeeper,肯定 MetaTable所在RegionServer的地址
    • 在根據RowKey找到歸屬的RegionServer
    • HBase Client Put(Delete)數據,提交到RegionServer
> ![image](https://note.youdao.com/yws/api/personal/file/FCE4E73CC9774EFEA2C0A060C142CD61?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)
  • HBase Server

    • Region Server 去獲取行鎖,Region更新共享鎖
    • 寫HLog,WAL
    • 寫緩存,MemStore
    • 將日誌同步到HDFS
    • 寫滿緩存後,啓動異步線程將數據寫入到硬盤上
    • 可能觸發Compaction或拆分
> ![image](https://note.youdao.com/yws/api/personal/file/C6724DFE164448E694FF61FE657CE68F?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)

HBase數據獲取流程解析

  • HBase Client

    • 請求Zookeeper,肯定 MetaTable所在RegionServer的地址
    • 去對應的RegionServer地址拿到對應數據
> ![image](https://note.youdao.com/yws/api/personal/file/31D60278867C4C27BDCA35AEBD57436E?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)
  • HBase Server

    • Region Server 構建RegionScanner準備進行檢索
    • 有多少個列簇就構建多少個StoreScanner,用於對肯定的列簇數據檢索
> ![image](https://note.youdao.com/yws/api/personal/file/8840F5554C354B39A14D00E2B39CBF5C?method=download&shareKey=416cc5492bf4a2243d657a2c6999b735)

4-4 數據存取

HBase數據存取api介紹

新增api
void put(Put put)throws IOException

Put構造方法
Put(byte[] row)
Put(byte[] row,long ts)

填充值
Put add(byte[] family,byte[] qualifier,byte[] value)
Put add(byte[] family,byte[] qualifier,long timestamp,byte[] value)
Put add(KeyValue kv)throws IOException

原子檢查寫
boolean checkAndPut(add(byte[] row,byte[] family,byte[] qualifier,byte[] value,put))

刪除api
void delete(Delete delete)throws IOException

構造方法
Delete(byte[] row)

填充值
Delete deleteFamily(byte[] family)
Delete deleteColumns(byte[] family,byte[] qualifier)
Delete deleteColumns(byte[] family,byte[] qualifier,long timestamp)

原子檢查刪除
boolean checkAndDelete(byte[] row,byte[] family,byte[] qualifier,byte[] value,Delete delete)throws IOException

獲取api
Result get(Get get)throws IOException

構造方法
Get(byte[] row)

填充值
Get addFamily(byte[] family)
Get addColumn(byte[] family,byte[] qualifier)
Get setTimeRange(long minStamp,long maxStamp)throws IOException
Get setTimeStamp(long timestamp)
Get setMaxVersions()
Get setMaxVersions(int maxVersions)throws IOException

第五章:案例演示

5-1 案列演示

建立名爲hbase-demo的maven工程pom以下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.myimooc</groupId>
    <artifactId>hbase-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>jdk.tools</groupId>
            <artifactId>jdk.tools</artifactId>
            <version>1.7</version>
            <scope>system</scope>
            <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.spring4all</groupId>
            <artifactId>spring-boot-starter-hbase</artifactId>
            <version>1.0.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.45</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

1.編寫User類

package com.myimooc.hbase.demo.dto;

/**
 * <br>
 * 標題: 用戶表<br>
 * 描述: 用戶表<br>
 *
 * @author zc
 * @date 2018/06/21
 */
public class User {

    /**
     * 行鍵
     */
    private String row;
    /**
     * 基礎信息
     */
    private BaseInfo baseInfo;
    /**
     * 其餘信息
     */
    private OtherInfo otherInfo;

    public User() {
    }

    public User(String row, BaseInfo baseInfo, OtherInfo otherInfo) {
        this.row = row;
        this.baseInfo = baseInfo;
        this.otherInfo = otherInfo;
    }

    @Override
    public String toString() {
        return "User{" +
                "row='" + row + '\'' +
                ", baseInfo=" + baseInfo +
                ", otherInfo=" + otherInfo +
                '}';
    }

    public String getRow() {
        return row;
    }

    public void setRow(String row) {
        this.row = row;
    }

    public BaseInfo getBaseInfo() {
        return baseInfo;
    }

    public void setBaseInfo(BaseInfo baseInfo) {
        this.baseInfo = baseInfo;
    }

    public OtherInfo getOtherInfo() {
        return otherInfo;
    }

    public void setOtherInfo(OtherInfo otherInfo) {
        this.otherInfo = otherInfo;
    }

    /**
     * 使用內部類表示 b 列簇 基礎信息
     */
    public static class BaseInfo {
        /**
         * 名稱
         */
        private String name;
        /**
         * 年齡
         */
        private Integer age;
        /**
         * 性別
         */
        private String sex;

        public BaseInfo() {
        }

        public BaseInfo(String name, Integer age, String sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        public String getSex() {
            return sex;
        }

        public void setSex(String sex) {
            this.sex = sex;
        }
    }

    /**
     * 使用內部類表示 o 列簇 其餘信息
     */
    public static class OtherInfo {
        /**
         * 電話
         */
        private String phone;
        /**
         * 地址
         */
        private String address;

        public OtherInfo() {
        }

        public OtherInfo(String phone, String address) {
            this.phone = phone;
            this.address = address;
        }

        @Override
        public String toString() {
            return "OtherInfo{" +
                    "phone='" + phone + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }
    }

}

2.編寫UserRowMapper類

package com.myimooc.hbase.demo.mapper;

import com.myimooc.hbase.demo.dto.User;
import com.spring4all.spring.boot.starter.hbase.api.RowMapper;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.util.Bytes;

/**
 * <br>
 * 標題: 用戶表ORM<br>
 * 描述: 用戶表ORM<br>
 *
 * @author zc
 * @date 2018/06/21
 */
public class UserRowMapper implements RowMapper<User> {

    private static byte[] FAMILY_B = "b".getBytes();
    private static byte[] FAMILY_B_NAME = "name".getBytes();
    private static byte[] FAMILY_B_AGE = "age".getBytes();
    private static byte[] FAMILY_B_SEX = "sex".getBytes();

    private static byte[] FAMILY_O = "o".getBytes();
    private static byte[] FAMILY_O_PHONE = "phone".getBytes();
    private static byte[] FAMILY_ADDRESS = "address".getBytes();

    @Override
    public User mapRow(Result result, int i) throws Exception {
        User.BaseInfo baseInfo = new User.BaseInfo(
            Bytes.toString(result.getValue(FAMILY_B, FAMILY_B_NAME)),
            Bytes.toInt(result.getValue(FAMILY_B, FAMILY_B_AGE)),
            Bytes.toString(result.getValue(FAMILY_B, FAMILY_B_SEX)));
        User.OtherInfo otherInfo = new User.OtherInfo(
            Bytes.toString(result.getValue(FAMILY_O, FAMILY_O_PHONE)),
            Bytes.toString(result.getValue(FAMILY_O, FAMILY_ADDRESS)));
        return new User(Bytes.toString(result.getRow()),baseInfo,otherInfo);
    }
}

3.編寫HbaseService類

package com.myimooc.hbase.demo.service;

import org.apache.hadoop.hbase.client.Mutation;

import java.util.List;

/**
 * <br>
 * 標題: HBase服務<br>
 * 描述: HBase服務<br>
 *
 * @author zc
 * @date 2018/06/21
 */
public interface HbaseService<T> {

    /**
     * 查詢指定行鍵的表數據
     * @param tableName 表名
     * @param row 行鍵
     * @return 數據
     */
    T findByRow(String tableName,String row);

    /**
     * 查詢指定行鍵之間的表數據
     * @param tableName 表名
     * @param startRow 開始行鍵
     * @param endRow 結束行鍵
     * @return 數據集合
     */
    List<T> findByStartEndRow(String tableName,String startRow,String endRow);

    /**
     * 保存或修改數據
     * @param tableName 表名
     * @param datas 數據集合
     * @return 數據集合
     */
    List<Mutation> saveOrUpdate(String tableName,List<Mutation> datas);

}

4.編寫UserHbaseServiceImpl類

package com.myimooc.hbase.demo.service.impl;

import com.myimooc.hbase.demo.dto.User;
import com.myimooc.hbase.demo.mapper.UserRowMapper;
import com.myimooc.hbase.demo.service.HbaseService;
import com.spring4all.spring.boot.starter.hbase.api.HbaseTemplate;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.Bytes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <br>
 * 標題: 用戶服務<br>
 * 描述: 用戶服務<br>
 *
 * @author zc
 * @date 2018/06/22
 */
@Service
public class UserHbaseServiceImpl implements HbaseService<User> {

    @Autowired
    private HbaseTemplate hbaseTemplate;

    @Override
    public User findByRow(String tableName, String row) {
        return hbaseTemplate.get(tableName, row, new UserRowMapper());
    }

    @Override
    public List<User> findByStartEndRow(String tableName, String startRow, String endRow) {
        Scan scan = new Scan(Bytes.toBytes(startRow), Bytes.toBytes(endRow));
        return hbaseTemplate.find(tableName, scan, new UserRowMapper());
    }

    @Override
    public List<Mutation> saveOrUpdate(String tableName, List<Mutation> datas) {
        hbaseTemplate.saveOrUpdates(tableName, datas);
        return datas;
    }
}

5.編寫application.properties

# Zookeeper 地址
spring.data.hbase.quorum=192.168.0.104:2181
# HBase 存儲路徑
spring.data.hbase.rootDir=hdfs://zccoder.com:9000/hbase/
# HBase 在 Zookeeper上的根節點名稱
spring.data.hbase.nodeParent=/hbase

6.編寫Application類

package com.myimooc.hbase.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }

}

7.編寫UserHbaseServiceImplTest類

package com.myimooc.hbase.demo.service;

import com.alibaba.fastjson.JSON;
import com.myimooc.hbase.demo.Application;
import com.myimooc.hbase.demo.dto.User;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

/**
 * <br>
 * 標題: 單元測試類<br>
 * 描述: 單元測試類<br>
 *
 * @author zc
 * @date 2018/06/22
 */
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE,classes = Application.class)
public class UserHbaseServiceImplTest {

    @Autowired
    private HbaseService<User> service;

    /**
     * 數據表名稱
     */
    private String tableName;

    @Before
    public void init(){
        tableName = "demo:user";
    }

    @Test
    public void testFindByRow(){
        System.out.println(JSON.toJSONString(service.findByRow(tableName,"root")));
    }

    @Test
    public void testFindByStartEndRow(){
        System.out.println(JSON.toJSONString(service.findByStartEndRow(tableName,"r","z")));
    }

    @Test
    public void testSaveOrUpdate(){
        List<Mutation> datas = new ArrayList<>();
        Put put= new Put(Bytes.toBytes("root"));
        put.addColumn(Bytes.toBytes("b"),Bytes.toBytes("name"),Bytes.toBytes("imooc"));
        put.addColumn(Bytes.toBytes("b"),Bytes.toBytes("age"),Bytes.toBytes("18"));
        put.addColumn(Bytes.toBytes("b"),Bytes.toBytes("sex"),Bytes.toBytes("m"));
        put.addColumn(Bytes.toBytes("o"),Bytes.toBytes("phone"),Bytes.toBytes("123456789"));
        put.addColumn(Bytes.toBytes("o"),Bytes.toBytes("address"),Bytes.toBytes("北京市朝陽區"));
        datas.add(put);

//        Delete delete = new Delete(Bytes.toBytes("root"));
//        datas.add(delete);

        List<Mutation> results = service.saveOrUpdate(tableName,datas);
        System.out.println(results);
    }
}
相關文章
相關標籤/搜索