架构图
架构图摘自网络,后续例子使用个人集群进行讲解
HBase写流程详解
假如我们有三台机器,ruozedata001 ruozedata002 ruozedata003
写流程:
首先要写数据,要有客户端、zookeeper
架构图中的:Put:table/RowKey/CF/Column: V,例如插入一条数据:
数据表:bigdata:student ,RowKey:1001,info列族,字段name,值为zhangsan
1.Client 先访问 zookeeper,获取 hbase:meta 表位于哪个 Region Server,请求到meta信息后,zookeeper将信息返回给客户端。
例如meta信息为ruozedata001
2.访问对应的 Region Server,获取 hbase:meta 表,根据读请求的 namespace:table/rowkey, 查询出目标数据位于哪个 Region Server 中的哪个 Region 中。并将该 table 的 region 信息以 及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问。
例如RegionServer信息为ruozedata003
3.与目标 Region Server 进行通讯
例如获取到的RegionServer信息为RegionServer信息为ruozedata003,那么zookeeper会向ruozedata003发送写的请求。
4.此时会进行真正的写操作。
例如此时会将数据写入到ruozedata003中
写操作的详细步骤:
- (a)将数据顺序写入(追加)到 WAL
- (b)将数据写入对应的 MemStore,数据会在 MemStore 进行排序
5.向客户端发送 ack,通知客户端写操作结束
6.等达到 MemStore 的刷写时机后,将数据刷写到 HFile。
关于HBase读的流程实际操作查看
1.在zookeeper中,找 meta表所在的位置
通过客户端工具zkCli.sh,进入zookeeper
get /hbase/meta-region-server
在zookeeper中,可以查看到HBase的RegionServer的信息,可以看到meta表在ruozedata001来维护
[zk: ruozedata001:2181(CONNECTED) 6] get /hbase/meta-region-server
�regionserver:60020�ac�%���PBUF
ruozedata001������-
cZxid = 0xd0000012a
ctime = Sat Oct 12 01:33:50 CST 2019
mZxid = 0xd0000012a
mtime = Sat Oct 12 01:33:50 CST 2019
pZxid = 0xd0000012a
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 66
numChildren = 0
我们也可以通过HBase web界面来查看meta表在哪台机器维护:
即 客户端找到 meta表在ruozedata001来维护
2.请求ruozedata001,读regision server内容
进入hbase shell执行
scan 'hbase:meta'
查看我们创建的 bigdata:student表,一共四个列
主要看的信息, info:server(标红部分)
column=info:server
column=info:serverstartcode,
在info:server中能够找到维护这张表的机器,例如执行 scan 'hbase:meta' 获取到的信息:value=ruozedata003:60020
bigdata:student,,1570815704167.86c3a column=info:regioninfo, timestamp=1570815744872, value={ENCODED => 86c3a55ff244676f7ae33bec6bc88311, NAME =>
55ff244676f7ae33bec6bc88311. 'bigdata:student,,1570815704167.86c3a55ff244676f7ae33bec6bc88311.', STARTKEY => '', ENDKEY => ''}
bigdata:student,,1570815704167.86c3a column=info:seqnumDuringOpen, timestamp=1570815744872, value=\x00\x00\x00\x00\x00\x00\x00\x05
55ff244676f7ae33bec6bc88311.
bigdata:student,,1570815704167.86c3a column=info:server, timestamp=1570815744872, value=ruozedata003:60020
55ff244676f7ae33bec6bc88311.
bigdata:student,,1570815704167.86c3a column=info:serverstartcode, timestamp=1570815744872, value=1570815142190
55ff244676f7ae33bec6bc88311.
该信息也可以通过hbase的web界面,通过table regions 找到
3.客户端请求ruozedata003服务器的RegionServer,并进行数据写入的操作
注意
早期版本hbase,存在 -ROOT- 表用来存储meta信息,但是新版本不存在-ROOT-表,
历史版本流程:
zookeeper获取-ROOT- 表的信息,-ROOT-存储 meta表信息,meta表存储数据表信息。
早起考虑到 meta表过大,可能或对meta表进行切分,如果meta表切分之后,就无法通过zookeeper获取到meta表完整的信息
关于数据写入WAL的详细流程
可在hbase源码:HRegion.java中查看到详细步骤
1.Try to acquire as many locks as we can,and ensure we accquire at least one
尽可能多地获取锁,并确保至少获取一个,用到的锁是 java.util.concurrent.locas.Lock;来保证读写分离
获取行锁、Region更新共享锁: HBase中使用行锁保证对同一行数据的更新都是互斥操作,用以保证更新的原子性,要么更新成功,要么失败。
2.Update any LATEST_TIMESTAMP timestamp
更新最后的时间戳
即我们写入数据的时候,hbase添加的时间戳,即hbase此时用的是hbase的时间戳
3.Buil WAL edit
构建 WAL,仅仅在内存构建,但是没有写入到hdfs。
4.Append the final edit to WAL. Do not sync wal.
把最后的内容追加到最后的 WAL中,此时不需要执行sync操作
5.Write back to memstore
把数据写入内存中。
HBase中每个列族都会对应一个store,用来存储该列族数据。每个store都会有个写缓存memstore,用于缓存写入数据。HBase并不会直接将数据落盘,而是先写入缓存,等缓存满足一定大小之后再一起落盘。
6.Release row locks, etc.
释放锁以及共享锁
7.Sync wal.
同步
8.Advance mvcc. This will make this put visible to scanners and getters.
WAL写入成功,会将数据写入到内存中
如果Sync失败,将memstore中已经写入的数据移除,即执行回滚操作。
9. Run coprocessor post hooks. This should be done after the wal is synced so that the coprocessor contract is adhered to.