架构图
架构图摘自网络,后续例子使用个人集群进行讲解
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中已经写入的数据移除,即执行回滚操作。