hbase的副本是对历史数据的备份,是新旧数据,而非相同数据的copy;hdfs的副本是同一数据的copy。
hbase的数据文件存放在hdfs上,但是在hdfs上具体如何存储对hbase是透明的。hbase的hfile
文件是存储在hdfs的普通文件,这个文件同hdfs上的其他文件一样,会自动备份成多份,并由namenode管理,而hbase只是通过namenode去访问hfile,具体访问的文件位置对hbase是透明的。
所以你的问题的答案是:只跟hdfs的副本数有关,跟hbase的副本数无关。即3
因为DataNode和RegionServer通常会部署在相同的机器上,所以会产生Locality这样的概念。
HBase的Locality是通过HDFS的Block复制实现的。在复制Block时,HBase是这样选择副本的位置的:
就是这样,在flush或compact后,HBase的Region实现了Locality。
当一个RegionServer处在failover的情况下(rebalance或重启)时,可能会分配到一些没有本地StoreFiles的Region(因为此时没有可用的本地副本)。然而,有新数据再写入这些Region的时候,或者是对表进行compact的时候,StoreFiles将会被重写,这些Region也会再次变成RegionServer的“local”Region。
有一个相关的指标“data locality”,即Region保存在本地的StoreFile的百分比。这个指标影响了major compact的执行。
hbase1.3
HTable 是我们对数据读取, *** 作的入口, implements HTableInterface, RegionLocator
内部构造
有一个检查 的动作待详细查看.
关于BufferedMutator, 是用来缓存客户端的 *** 作的, hbase 将客户端的DML抽象成了 Mutation , 子类有: Append, Delete, Increment, Put *** 作.
put方法将Put对象包装成Mutation,交给BufferedMutator, 到达设置的大小限制,或者主动调用flush *** 作, 会触发 backgroundFlushCommits(boolean synchronous) *** 作, 然后Mutation由 AsyncProcess 提交,详细查看 BufferedMutatorImpl 类.
由 AscncProcess 提交后, (注释:Action类是将行与对应 *** 作结合的类), 由connection去寻找每一行对应的region位置, 包装action, server, region等信息添加到 MutiAction 中去, 这个类持有按照region分组的actions,
然后会对每个action都创建 SingleServerRequestRunnable (rpc caller 和rpc callable, caller call callable), 交给线程池去运行.
删除 *** 作很简单: 创建 RegionServerCallable , 然后rpc工厂类创建rpc caller来调用它
get和scan都是继承了Query
get很简单:首先检查,这个get是否只是检查数据存在否, 并且检查是否指定了一致性等级(默认 (Consistency.STRONG) ), 之后创建rpc请求Request, 如果 不是强一致性Consistency.TIMELINE , 则调用 RpcRetryingCallerWithReadReplicas , 它可以从replica上读取, 返回的数据被标记为stale(读 *** 作是通过 Consistency.TIMELINE ,然后读RPC将会首先发送到主region服务器上,在短时间内(hbase.client.primaryCallTimeout.get默认为10ms),如果主region没有响应RPC会被发送到从region。 之后结果会从第一个完成RPC的返回。如果响应是来自主region副本,我们就会知道数据是最新的,Result.isStale() API是检查过期数据,如果结果是 从region返回,那么Result.isStale()为true,然后用户就可以检查关于过期数据可能的原因。).
当replica_id=0的regin不可以时候, 给所有的replica region发送请求,获取第一个从这些replica返回的数据, 客户端可以 Result.isStale()检查是否是来自副本的数据
Scan 类可以设置一系列的属性, startkey,endkey, 过滤器, 版本,缓存,最大取回大小等等, 但是获取数据是由 getScanner(Scan)返回的 ResultScanner *** 作的.
返回的 ResultScanner 有small, Reversed,big和纯client 的不同,
什么是small scan?
见 https://issues.apache.org/jira/browse/HBASE-7266
hbase里面有两种读 *** 作:pread and seek+read.
pread是一个函数,用于带偏移量地原子的从文件中读取数据。
读路径: https://yq.aliyun.com/articles/602377/
seek + read is fast but can cause two problem:
(1) resource contention
(2) cause too much network io
另外,一些其他的解释:前者适合小于一个数据块(默认64k)的smallScan(openScanner, next, closeScanner将在同一次rpc中实现);而后者则会使用hdfs预读取,在DN中缓存一些数据(HBASE-7266、HBASE-9488)
查看最普通的 ClientScanner , 初始化的时候调用 initializeScannerInConstruction , 这个方法去调用 nextScanner() , 获取为下一个region准备的scanner , 这个scanner会发起rpc调用, 参数是 ScannerCallable 对象, 这是scanner 的动作的抽象, reversed 和 small 都有对应的 ScannerCallable 子类
ScannerCallable 在初始化后, 的prepare阶段, 会从对应的region,获取对应的server, 获取这个server的ClientService.BlockingInterface接口, 并设置, 以便被调用的时候知道该向谁发起rpc请求
call阶段, 在创建 RequestScan的时候, 参数nextCallSeq在client和server端都维持,,每次调用都会增加, 是为了client能正确获取下一批的数据 .
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)