HBase的学习
HBase写入过程从源码角度
1.客户端
首先校验put
validatePut(put);
static void validatePut(Put put, int maxKeyValueSize) throws IllegalArgumentException {
if (put.isEmpty()) {
throw new IllegalArgumentException("No columns to insert");
}
if (maxKeyValueSize > 0) {
for (List<Cell> list : put.getFamilyCellMap().values()) {
for (Cell cell : list) {
if (cell.getSerializedSize() > maxKeyValueSize) {
throw new IllegalArgumentException("KeyValue size too large");
}
}
}
}
Cell:
解析:校验是否为空,cell序列化的长度是否比maxKeyValueSize(配置里面的参数)
rpcControllerFactory
rpcCallerFactory
客户端的RPC请求,是由 ClientServiceCallable.doMutate 提交,RPC通信使用的是谷歌的protobuf协议。服务器端IPC实现类为RSRpcServices类,由mutate方法实现
在mutate方法中,会将protobuf流反序列化为PUT、APPEND、INCREMENT、DELETE对象。在进行PUT对象处理时会检查相关表是否有协处理器,如果没有即调用HRegion的PUT方法进行处理。 RSRpcServices.mutate部分实现代码如下:
调用服务端得Hregion得put方法:
checkReadOnly();检查region是否是只读模式
checkResources();检查资源,如果mss.getHeapSize() + mss.getOffHeapSize() > this.blockingMemStoreSize则进行一次flush操作
//region size = Heap size + offHeap size (不是dataSize)
startRegionOperation(Operation.PUT);开始进行put操作
检查完region 的memStore 之后,即进入写入流程。忽略掉其它一些检查,进入doMiniBatchMutate方法(核心操作)
步骤1: 对BatchOperation对象上锁,返回的是一个表示正在处理中的对象MiniBatchOperationInProgress
步骤2:更新所有操作对象的时间戳,确保是最新的。
步骤3: 初始化或构造 WAL edit对象
步骤4:将WALEdits对象提交并持久化(即写WAL)
步骤5:写memStore
步骤6:完成写入操作
Get
Get操作调用的是RSRpcServices的get方法,调用过程首先找到包含数据的Region,然后从这个Region中获取需要的数据。
public GetResponse get(final RpcController controller,
final GetRequest request) throws ServiceException {
...
try {
...
Region region = getRegion(request.getRegion());
...
if (get.hasClosestRowBefore() && get.getClosestRowBefore()) {
...
r = region.getClosestRowBefore(row, family);
} else {
...
r = region.get(clientGet);
...
}
...
return builder.build();
...
}
region.getClosestRowBefore实际也是调用的region.get方法,所以直接看get方法
public Result get(final Get get) throws IOException {
checkRow(get.getRow(), "Get");
// Verify families are all valid
if (get.hasFamilies()) {
for (byte [] family: get.familySet()) {
checkFamily(family);
}
} else { // Adding all families to scanner
for (byte[] family: this.htableDescriptor.getFamiliesKeys()) {
get.addFamily(family);
}
}
List<Cell> results = get(get, true);
boolean stale = this.getRegionInfo().getReplicaId() != 0;
return Result.create(results, get.isCheckExistenceOnly() ?
!results.isEmpty() : null, stale);
}
这个方法特别有意思,如果这个请求里包含了family,就检查下这些family是否存在;如果这个请求里不包含family,就把这个表里所有的family都加到这个请求里。所以不设置family时,就会遍历所有的family来找到需要的数据。然后看List<Cell> results = get(get, true);
,这个方法创建了一个Scan,调用了Scan,所以要了解Get,还看Scan!