1,row是有序的,可以看做RDBMS的一级索引
2,一个列簇CF的所有列存储在一个HFile里
3,CF要在建表时定义,少变化,更不要建太多
4,version和timestamp是对应的,每个cell有不同的版本,就说明是在不同的timestamp存储的,如果重复的timestamp,那么就说明是一个版本
5,定位一个数据,需要rowkey,column和timestamp,即SortedMap<RowKey,List<SortedMap<Column,List<Value,Timestamp>>>>
6,初始一个region,之后自动sharding,一台server大概10-1000个region,每个region大小为1-2GB
7,每一个HFile有一个block index,可以只用一次disk seek完成查询
8,数据更新时要写commit log即常说的WAL——write-ahead-log,每次操作都会记录在内存memstore,当memstore满了以后自动flush到HFile的disk,在做flush时,reader和writer不被阻塞,可以继续服务(这是因为,flush做的是一个滚动操作,老的满的数据flush到磁盘,而完成后的新的空的memstore继续服务,因为memstore已经是按key的顺序排好的,所以不需要额外操作,只要写和flush就行)
9,删除操作是逻辑的,因为存储文件不可变,所以会放置一个删除标记到每个键值对
10,通过compaction将小的hfile合并为大的,compaction有两种类型:minor和major,前者通过多路归并完成多个小文件到少量大文件的合并;后者重写整个CF到一个新的文件,在做compaction的时候可以把之前标记过delete的kv pair放弃,即不写到新的文件
11,HBase由客户端库,一台master server和多台region server组成,master负责regions的负载均衡,master不存储数据,只做调度
12,扫表scan是线性时间的,查询是对数时间的,而极端情况的查询是常数时间的(使用bloom filter)
13,在put时,要注意flush的时间,没有flush的数据是不会被get到的,从源码可以了解到,flush有两种情况,一是显示调用flushCommits();另外就是到了client端的writebuffer上限触发,hbase默认client的writebuffer size是2M,可以通过配置去修改
14,HBase的client里,caching针对行模式(返回多少行),而batching针对列模式(返回多少列),都是在scan时提高效率(减少RPC)的方法
15,用HBase的接口时,通过Filter的使用可以减少网络传输的数据量,从而减轻在客户端使用的时间成本,get或scan你想要的东西,不要的东西直接在server通过filter过滤到
16,在重用Configuration时,要记得每次都会增加一个引用数,因此在使用完后最好调用close方法将connection释放掉
17,HBase的block size和hdfs的block size是不一样的,前者是指处理block操作时的数据大小,默认是64KB,而后者是用来分布式存储文件,默认大小是64MB
18,RDBMS和Hbase的区别:存储结构b树或b+树,Hbase采用类似LSM树的做法(Log-Structured Merge Trees),LSMT的简单过程描述是,数据首先被顺序存储到一个log file里,在写满后将这些数据更新到in memory store,然后flush有序key value pair到磁盘,生成一个文件。磁盘文件的组织形式类似B树,但是对于磁盘顺序访问做了优化,其中每个文件都被完全填充为单页或多页的block,而这些文件的update本身是rolling merge策略,即系统在直到block写满的时候才将in memory的数据打包。因为flush是经常进行的,导致系统中会有很多的文件,一个后台进程在不断的合并小文件到大文件从而将磁盘seek缩减到少量的文件范围。于此同时,磁盘的树也可以进行分裂操作,将大文件分割为若干文件以便扩展更新。而所有的存储都是key有序的。
19,Hbase查询时,先到in memory里查,再到on disk里查,这样的行为可以保证了一致性;删除时是逻辑删除,先将delete标志打上,后期在异步重写的时候,标记了delete的key会被最终物理删除。
20,HBase有两类文件,一类用于WAL的log,另一类用于数据存储。
21,一般HBase的访问流程是:先到zookeeper quorum取row key,通过从zk中查询-ROOT-里的服务器名字实现;接着拿着取到的服务器名字去region server查询持有.META. 表region并且包含了rowkey的server名字;最后查询.META.服务器,获取到包含对应rowkey region的server name。一旦获取这些信息,客户端将其缓存起来,以后就知道如何到哪里去查找并且直接和region server联系了。
22,在源码级别,HMaster负责分配HRegionServer,HRegionServer维护一个HRegion,当HRegion建立时,为每张表的每个HColumnFamily建立一个Store,每个Store包含一个或者多个StoreFile(轻量级的HFile包装),一个Store同时也有一个MemStore,还有一个HRegionServer共享的HLog。
23,在做put操作时,region server先检查本次put是否需要写WAL,一旦数据写入WAL,那么它就进入MemStore,同时检查MemStore是否满,如果是,做一次flush,写到一个HFile里存到HDFS,同时维护一个最后一次写入的序列号,以便系统知道到目前为止的持久数据信息。
24,在HFile被持久化后,log文件就不再有用了,这时自动从.log目录移动到.oldlog目录(当然也有配置可以配置滚动周期),默认10分钟后由HBase自动删除。
25,每个table有一个目录,在这个目录里,每个列族有一个自己的目录。
26,region split发生在当一个region的存储文件大小达到配置的hbase.hregion.max.filesize时进行。具体过程就是:系统为新的region创建两个原region的索引文件,每个各持有原来一半的数据,region server在父region创建一个splits目录,接着关闭region拒绝新请求,然后再splits目录里构建必要的新的region目录文件结构存放刚才的两个half 大小的文件。成功后,系统将两个新的region目录添加到表目录,更新.META.表以表明父region做了split,同时表明新的两个region是什么。
27,HFile基于Hadoop的TFile类型,模仿了BigTable的SSTable格式;文件是变长的,其中定长的部分是file info 和trailer,而数据以keyvalue存入data块,默认大小64KB,而HDFS默认块大小是64MB,两者没有关系。结构类似:
28,KeyValue在HFile中就是一个简单的字节序列,结构类似
29,WAL是容灾的重要武器,类似mysql的binlog,记录了所有的变化,这就可以保证在数据进入memstore后而没有持久这段时间因为突发原因导致数据丢失时候的容灾。流程如下:
30,在上面这图中,有LogSyncer和LogRoller,前者是默认关闭的,如果开启后,那么每次写入都会触发一次sync,将update同步到其他的server,而且还是pipeline形式的顺序写,不是多路复写;后者负责滚动记录log,可以设置时间间隔每隔一定时间来滚动日志,也可以根据大小来滚动,这个都可以配置。
31,容灾恢复数据的一项重要措施是replay日志,也就是重放WAL;日志回放有两种触发条件:一是集群启动时,二是服务器fail时;当master启动时,检查.log目录里是否有log文件,有的话则做log splitting——读入log然后根据记录的region将其分配到新文件。
32,get和scan在近几个版本中实现等价,因为对于特定行和列没有索引的概念,而最小的访问单元是block,因此如果要请求数据,那么一定会加载一个RegionServer的实例的block然后扫描它,Get其实就是一个确定了row的scan。
33,在查询时,一个周期是这样的:因为客户端缓存region的,所以,会先到自己的cache中查找对应region,找到的话则直接访问(1次网络请求即可),如果找不到,则到region server的.META.中去取(3次),如果再找不到,则到-ROOT-找.META.信息(5次),再找不到,只好去zk中取(7次)(这是第21条tip的逆过程) 。
34,region有9种状态(offline,pending open,opening,open,pending close,closing,closed,splitting,split),状态转移可以再master做,也可以在持有region的region server上做。集群通过zk来跟踪状态变化。
35,Hbase的复制策略为容灾提供了高可用,基本模式是:master-push,因为WAL的存在,跟踪复制变得很容易;一个master cluster可以复制到任意数量的slave clusters,region server负责自己的复制。