摘录自《HBase不睡觉书》,转载请注明出处。
HBase提供了快照(snapshot)功能。可以使用快照来将某个表恢复到某个时刻的结构和数据,而且不需要担心创建和恢复的过程会很缓慢,实际上这个速度非常快,往往只有数秒。
快照并不实际地复制数据,而是保存一份文件列表,通过修改表链接的文件来修改表的数据,所以这样做有两个好处:
- 速度极快
- 不额外占用磁盘空间
HBase默认开启了快照功能,可以通过设置hbase.snapshot.enabled为false来禁用。
<property>
<name>hbase.snapshot.enabled</name>
<value>true</value>
</property>
下面我们通过实际案例示范快照相关操作:
需求:对某表创建快照,修改表,恢复表到修改之前的状态
测试前准备 :
1. 创建测试表:create 'test_snapshot','mycf'
2. 插入一条数据:put 'test_snapshot','row1','mycf:name','jack'
测试完整代码:
package com.igdata.hbase;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
import java.util.List;
/**
* Author: xianghu.wang
* Date: 2018/9/27
* Description:
*/
public class SnapShotDemo {
public static void main(String[] args) {
// 获取配置
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "idayan00:2181");
Connection conn = null;
try {
conn = ConnectionFactory.createConnection(conf);
TableName tableName = TableName.valueOf("test_snapshot");
Table table = conn.getTable(tableName);
Admin admin = conn.getAdmin();
Scan scan = new Scan();
// 读取表中所有数据
System.out.println("快照前数据: ");
printRs(table, scan);
// 获取当前快照列表
System.out.println("当前快照列表: ");
printSnapshotList(admin);
// 创建快照testSnapshot
admin.snapshot("testSnapshot", tableName);
System.out.println("创建快照后快照列表: ");
printSnapshotList(admin);
// 修改数据表
Put put = new Put(Bytes.toBytes("row2"));
put.addColumn(Bytes.toBytes("mycf"), Bytes.toBytes("name"), Bytes.toBytes("Delete"));
table.put(put);
// 修改后表数据
System.out.println("修改后表数据: ");
printRs(table, scan);
// 恢复快照到 testSnapshot
// 1. 禁用表
admin.disableTable(tableName);
// 2.恢复并启用表
System.out.println("开始恢复表...");
while (true) {
Thread.sleep(1000);
if (admin.isTableDisabled(tableName)) {
admin.restoreSnapshot("testSnapshot");
admin.enableTable(tableName);
break;
}
}
System.out.println("表恢复完成...");
// 查看恢复后的表数据
System.out.println("恢复后表数据: ");
printRs(table, scan);
// 删除快照
admin.deleteSnapshot("testSnapshot");
// 查看快照列表
System.out.println("删除快照后快照列表:");
printSnapshotList(admin);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 获取快照列表
*
* @param admin
*/
public static void printSnapshotList(Admin admin) {
List<HBaseProtos.SnapshotDescription> SnapshotDescription = null;
try {
SnapshotDescription = admin.listSnapshots();
if (SnapshotDescription == null || SnapshotDescription.size() < 1) {
System.out.println("当前表没有快照...");
return;
}
} catch (IOException e) {
e.printStackTrace();
}
int snapShotCount = 0;
for (HBaseProtos.SnapshotDescription snapshotDescription : SnapshotDescription) {
System.out.println(String.format("快照%s :", ++snapShotCount) + snapshotDescription.getName());
}
System.out.println();
}
/**
* 打印表中所有数据
*
* @param table
* @param scan
*/
public static void printRs(Table table, Scan scan) {
ResultScanner rsBefore = null;
try {
rsBefore = table.getScanner(scan);
} catch (IOException e) {
e.printStackTrace();
}
for (Result r : rsBefore) {
System.out.println(r);
}
System.out.println();
}
}
运行结果:
快照前数据:
keyvalues={row1/mycf:name/1538025051772/Put/vlen=4/seqid=0}
当前快照列表:
当前表没有快照...
创建快照后快照列表:
快照1 :testSnapshot
修改后表数据:
keyvalues={row1/mycf:name/1538025051772/Put/vlen=4/seqid=0}
keyvalues={row2/mycf:name/1538029349738/Put/vlen=6/seqid=0}
开始恢复表...
表恢复完成...
恢复后表数据:
keyvalues={row1/mycf:name/1538025051772/Put/vlen=4/seqid=0}
删除快照后快照列表:
当前表没有快照...