简介
数据存储模型及关系型数据库的区别
一般都是牺牲一致性, 最终达到最终一致性
HBase 概念
区别
基础架构
HBASE 原理和操作
写流程
预写入会写入HLog 里面, 通过HLog 来保证数据不丢失
读流程
模块协作
shell 命令
学会用 help , 可以获取使用说明
比如: help 'status'
# HBase shell中的帮助命令非常强大,使用help获得全部命令的列表,使用help ‘command_name’获得某一个命令的详细信息
help 'status'
# 查询服务器状态
status
# 查看所有表
list
# 创建一个表
create 'FileTable','fileInfo','saveInfo'
# 获得表的描述
describe 'FileTable'
# 添加一个列族
alter 'FileTable', 'cf'
# 删除一个列族
alter 'FileTable', {NAME => 'cf', METHOD => 'delete'}
# 插入数据
put 'FileTable', 'rowkey1','fileInfo:name','file1.txt'
put 'FileTable', 'rowkey1','fileInfo:type','txt'
put 'FileTable', 'rowkey1','fileInfo:size','1024'
put 'FileTable', 'rowkey1','saveInfo:path','/home'
put 'FileTable', 'rowkey1','saveInfo:creator','tom'
put 'FileTable', 'rowkey2','fileInfo:name','file2.jpg'
put 'FileTable', 'rowkey2','fileInfo:type','jpg'
put 'FileTable', 'rowkey2','fileInfo:size','2048'
put 'FileTable', 'rowkey2','saveInfo:path','/home/pic'
put 'FileTable', 'rowkey2','saveInfo:creator','jerry'
# 查询表中有多少行
count 'FileTable'
# 获取一个rowkey的所有数据
get 'FileTable', 'rowkey1'
# 获得一个id,一个列簇(一个列)中的所有数据
get 'FileTable', 'rowkey1', 'fileInfo'
# 查询整表数据
scan 'FileTable'
# 扫描整个列簇
scan 'FileTable', {COLUMN=>'fileInfo'}
# 指定扫描其中的某个列
scan 'FileTable', {COLUMNS=> 'fileInfo:name'}
# 除了列(COLUMNS)修饰词外,HBase还支持Limit(限制查询结果行数),STARTROW(ROWKEY起始行。会先根据这个key定位到region,再向后扫描)、STOPROW(结束行)、TIMERANGE(限定时间戳范围)、VERSIONS(版本数)、和FILTER(按条件过滤行)等。比如我们从RowKey1这个rowkey开始,找下一个行的最新版本
scan 'FileTable', { STARTROW => 'rowkey1', LIMIT=>1, VERSIONS=>1}
# Filter是一个非常强大的修饰词,可以设定一系列条件来进行过滤。比如我们要限制名称为file1.txt
scan 'FileTable', FILTER=>"ValueFilter(=,'name:file1.txt’)"
# FILTER中支持多个过滤条件通过括号、AND和OR的条件组合
scan 'FileTable', FILTER=>"ColumnPrefixFilter('typ') AND ValueFilter ValueFilter(=,'substring:10')"
# 通过delete命令,我们可以删除某个字段,接下来的get就无结果
delete 'FileTable','rowkey1','fileInfo:size'
get 'FileTable','rowkey1','fileInfo:size'
# 删除整行的值
deleteall 'FileTable','rowkey1'
get 'FileTable',’rowkey1'
# 通过enable和disable来启用/禁用这个表,相应的可以通过is_enabled和is_disabled来检查表是否被禁用
is_enabled 'FileTable'
is_disabled 'FileTable'
# 使用exists来检查表是否存在
exists 'FileTable'
# 删除表需要先将表disable
disable 'FileTable'
drop 'FileTable'
java api
过滤器
很少会用到自定义过滤器
hbase 优化
以下要注意的,可能很耗性能
cmpact 检查
服务端优化策略
以上的参数都是对调优很有参考价值
常用优化策略
rowkey 不能过长,尽量短
根据需求,设计 宽表还是高表
高表查询性能更好,而 宽表 事务更好
读写优化策略
异步提交可能会丢失数据, 去调WAL也会可能丢失数据。虽然可以提高写效率
协处理器
协处理器还是有风险,搞不好就会影响稳定性
协处理器代码加载到HBASE 中
容灾与监控
备份与恢复
即将 某个表的数据复制到 另一个表里面
将CoprocessorTest 表数据 到出到 HDFS的 coprocessorTest.db 里面
监控
JMX监控
查看hadoop jms 比如 http://192.168.0.205:50070/jmx
然后就可以自己写一个项目, 使用 http 请求 来 定时获取 hadoop 上面的 jmx 信息了,这样就可以获取监控信息了
package com.imooc.bigdata.hbase.monitor;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.imooc.bigdata.hbase.monitor.entity.DataNodeInfo;
import com.imooc.bigdata.hbase.monitor.entity.HdfsSummary;
/**
* Created by jixin on 18-3-24.
*/
public class HadoopUtil {
public static long mbLength = 1048576L;
public static long gbLength = 1073741824L;
public static final String hadoopJmxServerUrl = "http://localhost:50070";
public static final String jmxServerUrlFormat = "%s/jmx?qry=%s";
public static final String nameNodeInfo = "Hadoop:service=NameNode,name=NameNodeInfo";
public static final String fsNameSystemState = "Hadoop:service=NameNode,"
+ "name=FSNamesystemState";
public static HdfsSummary getHdfsSummary(StatefulHttpClient client) throws IOException {
HdfsSummary hdfsSummary = new HdfsSummary();
String namenodeUrl = String.format(jmxServerUrlFormat, hadoopJmxServerUrl, nameNodeInfo);
MonitorMetrics monitorMetrics = client.get(MonitorMetrics.class, namenodeUrl, null, null);
hdfsSummary.setTotal(doubleFormat(monitorMetrics.getMetricsValue("Total"), gbLength));
hdfsSummary.setDfsFree(doubleFormat(monitorMetrics.getMetricsValue("Free"), gbLength));
hdfsSummary
.setDfsUsed(doubleFormat(monitorMetrics.getMetricsValue("Used"), gbLength));
hdfsSummary.setPercentUsed(
doubleFormat(monitorMetrics.getMetricsValue("PercentUsed")));
hdfsSummary.setSafeMode(monitorMetrics.getMetricsValue("Safemode").toString());
hdfsSummary.setNonDfsUsed(
doubleFormat(monitorMetrics.getMetricsValue("NonDfsUsedSpace"), gbLength));
hdfsSummary.setBlockPoolUsedSpace(
doubleFormat(monitorMetrics.getMetricsValue("BlockPoolUsedSpace"),
gbLength));
hdfsSummary
.setPercentBlockPoolUsed(
doubleFormat(monitorMetrics.getMetricsValue("PercentBlockPoolUsed")));
hdfsSummary.setPercentRemaining(
doubleFormat(monitorMetrics.getMetricsValue("PercentRemaining")));
hdfsSummary.setTotalBlocks((int) monitorMetrics.getMetricsValue("TotalBlocks"));
hdfsSummary.setTotalFiles((int) monitorMetrics.getMetricsValue("TotalFiles"));
hdfsSummary.setMissingBlocks((int) monitorMetrics.getMetricsValue("NumberOfMissingBlocks"));
String liveNodesJson = monitorMetrics.getMetricsValue("LiveNodes").toString();
String deadNodesJson = monitorMetrics.getMetricsValue("DeadNodes").toString();
List<DataNodeInfo> liveNodes = dataNodeInfoReader(liveNodesJson);
List<DataNodeInfo> deadNodes = dataNodeInfoReader(deadNodesJson);
hdfsSummary.setLiveDataNodeInfos(liveNodes);
hdfsSummary.setDeadDataNodeInfos(deadNodes);
String fsNameSystemStateUrl = String
.format(jmxServerUrlFormat, hadoopJmxServerUrl,
fsNameSystemState);
MonitorMetrics hadoopMetrics = client
.get(MonitorMetrics.class, fsNameSystemStateUrl, null, null);
hdfsSummary.setNumLiveDataNodes((int) hadoopMetrics.getMetricsValue("NumLiveDataNodes"));
hdfsSummary.setNumDeadDataNodes((int) hadoopMetrics.getMetricsValue("NumDeadDataNodes"));
hdfsSummary
.setVolumeFailuresTotal((int) hadoopMetrics.getMetricsValue("VolumeFailuresTotal"));
return hdfsSummary;
}
public static List<DataNodeInfo> dataNodeInfoReader(String jsonData) throws IOException {
List<DataNodeInfo> dataNodeInfos = new ArrayList<DataNodeInfo>();
Map<String, Object> nodes = JsonUtil.fromJsonMap(String.class, Object.class, jsonData);
for (Entry<String, Object> node : nodes.entrySet()) {
Map<String, Object> info = (HashMap<String, Object>) node.getValue();
String nodeName = node.getKey().split(":")[0];
DataNodeInfo dataNodeInfo = new DataNodeInfo();
dataNodeInfo.setNodeName(nodeName);
dataNodeInfo.setNodeAddr(info.get("infoAddr").toString().split(":")[0]);
dataNodeInfo.setLastContact((int) info.get("lastContact"));
dataNodeInfo.setUsedSpace(doubleFormat(info.get("usedSpace"), gbLength));
dataNodeInfo.setAdminState(info.get("adminState").toString());
dataNodeInfo
.setNonDfsUsedSpace(doubleFormat(info.get("nonDfsUsedSpace"), gbLength));
dataNodeInfo.setCapacity(doubleFormat(info.get("capacity"), gbLength));
dataNodeInfo.setNumBlocks((int) info.get("numBlocks"));
dataNodeInfo.setRemaining(doubleFormat(info.get("remaining"), gbLength));
dataNodeInfo
.setBlockPoolUsed(doubleFormat(info.get("blockPoolUsed"), gbLength));
dataNodeInfo.setBlockPoolUsedPerent(doubleFormat(info.get("blockPoolUsedPercent")));
dataNodeInfos.add(dataNodeInfo);
}
return dataNodeInfos;
}
public static DecimalFormat df = new DecimalFormat("#.##");
public static double doubleFormat(Object num, long unit) {
double result = Double.parseDouble(String.valueOf(num)) / unit;
return Double.parseDouble(df.format(result));
}
public static double doubleFormat(Object num) {
double result = Double.parseDouble(String.valueOf(num));
return Double.parseDouble(df.format(result));
}
}
public class DataNodeInfo {
//datanode的hostname
private String nodeName;
//datanode的ip地址
private String nodeAddr;
//datanode的上次链接数量
private int lastContact;
//datanode上hdfs的已用空间 GB
private double usedSpace;
//datanode的状态
private String adminState;
//datanode上非hdfs的空间大小 GB
private double nonDfsUsedSpace;
//datanode上的总空间大小
private double capacity;
//datanode的block
private int numBlocks;
private double remaining;
private double blockPoolUsed;
private double blockPoolUsedPerent;
public class HdfsSummary {
//"name": "Hadoop:service=NameNode,name=NameNodeInfo"
//总空间大小 GB
private double total;
//hdfs已使用的空间大小 GB
private double dfsUsed;
//hdfs已使用空间百分比
private double percentUsed;
//hdfs空闲空间 GB
private double dfsFree;
//hdfs是否处于safemode
private String safeMode;
//非hdfs空间大小 GB
private double nonDfsUsed;
//集群该namespace的hdfs使用容量大小
private double blockPoolUsedSpace;
//集群该namespace的hdfs使用容量所占百分比
private double percentBlockPoolUsed;
private double percentRemaining;
//集群总的block数
private int totalBlocks;
//集群总的文件数
private int totalFiles;
//集群丢失的block数量
private int missingBlocks;
//处于可用状态的datanode汇总
private List<DataNodeInfo> liveDataNodeInfos;
//处于不可用状态的datanode汇总
private List<DataNodeInfo> deadDataNodeInfos;
//"name": "Hadoop:service=NameNode,name=FSNamesystemState"
//处于可用状态的datanode数量
private int numLiveDataNodes;
//处于不可用状态的datanode数量
private int numDeadDataNodes;
//坏盘的数量
private int volumeFailuresTotal;
Phoenix
安装 使用
启动 在 phoenix 下 bin , ./sqlline.py
这样可以 在 shell 下使用或者 通过API去使用
比如 phonenix + mybatis 一起来使用
hbase 适合的业务需求: Object stroe on Habse
也可以 将hbase 作为 对象存储, l 类似 比如 阿里的 OSS , Amazon S3
开源的对象存储服务 : MINIO
hbse 的不足
来源:oschina
链接:https://my.oschina.net/ouminzy/blog/4355936