zoukankan      html  css  js  c++  java
  • hbase

    hbase
    HBase是建立在Hadoop文件系统之上的分布式可扩展的 列式数据库。属于Nosql
    HBase是一个数据模型,类似于谷歌的bigTable设计,可以提供快速随机访问海量结构化数据。它利用了Hadoop文件系统(HDFS)提供的容错能力
    LSM树原理把一棵大树拆分成N棵小树,它首先写入内存中,随着小树越来越大,内存中的小树会flush到磁盘中,磁盘中的树定期可以做merge操作,合并成一棵大树,以优化读性能。
    HBase架构及组件
    hbase架构图
    以上这些大概就是HBase存储的设计主要思想,这里分别对应说明下:
    因为小树先写到内存中,为了防止内存数据丢失,写内存的同时需要暂时持久化到磁盘,对应了HBase的MemStore和HLog
    MemStore上的树达到一定大小之后,需要flush到HRegion磁盘中(一般是Hadoop DataNode),这样MemStore就变成了DataNode上的磁盘文件StoreFile,定期HRegionServer对DataNode的数据做merge操作,彻底删除无效空间,多棵小树在这个时机合并成大树,来增强读性能。
    Client:包含HBase的接口,并维护cache来加快对HBase的访问,比如region的位置信息
    Master:
    1、为Region Server分配Region
    2、负责Region Server的负载均衡
    3、发现失效的Region Server并重新分配其上的region
    4、管理用户对table的增删改查操作
    Region Server:
    1、Region Serever 维护region,处理对这些region的IO请求
    2、Region Server负责切分在运行过程中变得过大的region
    Region:是HBase中对表进行切割的单元
    Zookeeper:
    1、通过选举,保证任何时候、集群中只有一个master,Master与RegionServers启动时会向Zookeeper注册
    2、存储所有Region的寻址入口
    3、实时监控Region Server的上线和下线信息。并实时通知给Master
    4、存储HBase的schema和table元数据
    5、默认情况下,HBase管理Zookeeper实例,比如,启动或者停止Zookeeper
    6、Zookeeper的引入使得Master不再是单点故障
    HBase物理存储
    1、Table中的所有行都按照row key的字典序排列
    2、Table在行的方向上分割为多个Hregion
    3、region按大小分割(默认10g),每个表一开始只有一个region,随着数据不断插入表,region不断增大,当增大到一个阀值的时候,Hregion就会分成两个新的Hregion。当Table中的行不断增多,就会有越来越多的Hregion。
    4、Hregion是HBase中分布式存储和负载均衡的最小单元。最小单元就表示不同的Hregion可以分布到不同的Hregion Server上。但一个Hregion是不会拆分到多个server上的。
    5、Hregion虽然是负载均衡的最小单元,但并不是物理存储的最小单元。Hregion由一个或多个Store组成,每个store保存一个column family。每个Store又由一个位于内存的memStore和0至多个位于硬盘的StoreFile组成
    写操作先写入memstore,当memstore中的数据量达到某个阈值,HregioniServer启动flashcache进行写入storeFile,每次写入形成单独一个storefile。
    当storefile大小超过一定阈值后,会把当前的region分割成两个,并有Hmaster分配给相应的region服务器,实现负载均衡。
    客户端检索数据时,先在memstore找,找不到再找storefile
    HBase基本概念
    HBase表由多行组成,一行在HBase由行键和一个或多个列的值组成
    存储结构
    行序时按照行键的字典序进行排序的
    列是表中的最基本的元素,HBase的列包含一个列族和一个列限定符,列属于一个列族,列族属于一个行。
    Hbase含有版本的概念,一个列的数据可以有多个历史版本,体现的形式就是时间戳。
    每一列的值或单元格的值都具有时间戳,默认由系统指定,也可以由用户显示设置。一个单元格的不同版本的值按照降序排列在一起,访问的时候优先读取最新的值。这种优化的目的在于让新值比老值更容易被读取。
    HBase中,列族是一行中一个或多个列的集合,就是一行数据的一部分。列族需要在表创建时就定义好。
    列族中可以包含多个列,一个表中的某个列的定位方式就成了meta:size 这种方式。称之为列限定符
    一个单元格是行、列族、和列限定符的结合,也就是说,通过这三个值(也称之为坐标)来唯一确定一个单元格。单元格中的值与关系型数据库不同的是,其如果没有值的话,就为空,也不占用底层物理存储。
    时间戳就是写入某个单元格中的数据的具体时间,用来表示一个单元格中的数据的新旧
    HBase 写流程
    默认情况下,执行写入时回写到两个地方:预写日志(write-ahead log 也称HLog)和MemStore。HBase的默认方式时把写入动作记录在这两个地方,以保证数据持久化。只有当这两个地方的变化信息都写入并确认后,才认为写动作完成。
    MemStore时内存的写入缓冲区,当MemStore填满后,数据会刷写到硬盘,生成一个HFile。HFile是HBase使用的底层存储格式。HFile对应于列族,一个列族可以有多个HFile,但一个Hfile不能存储多个列族的数据。在集群的每个节点上,每个列族有一个MemStore
    HBase在写动作完成之前先写入WAL。HBase集群中每台服务器维护一个WAL来记录发生的变化。WAL是底层文件系统上的一个文件。直到WAL新纪录成功写入后,写动作才被认为成功完成。这样可以保证HBase和支撑它的文件系统满足持久性。
    如果HBase服务器宕机,没有从MemStore里刷写到HFile的数据可以通过回放WAL来恢复,自动执行
    a) Client发起了一个HTable.put(Put)请求给HRegionServer
    b) HRegionServer会将请求匹配到某个具体的HRegion上面
    c) 决定是否写WAL log。WAL log文件是一个标准的Hadoop SequenceFile,文件中存储了HLogKey,这些Keys包含了和实际数据对应的序列号,主要用于崩溃恢复。
    d) Put数据保存到MemStore中,同时检查MemStore状态,如果满了,则触发Flush to Disk请求。
    e) HRegionServer处理Flush to Disk的请求,将数据写成HFile文件并存到HDFS上,并且存储最后写入的数据序列号,这样就可以知道哪些数据已经存入了永久存储的HDFS中。
    由于不同的列族会共享region,所以有可能出现,一个列族已经有1000万行,而另外一个才100行。当一个要求region分割的时候,会导致100行的列会同样分布到多个region中。所以,一般建议不要设置多个列族。
    HBase读流程
    如果想快速访问数据,通用的原则是数据保持有序并尽可能的保存在内存里。
    HBas在读操作上使用了LRU(最近最少使用算法)缓存技术。这种缓存也叫做BlockCache,和MemStore在一个JVM堆里。BlockCache设计用来保存从HFile里读入内存的频繁访问的数据,避免硬盘读。每个列族都有自己的BlockCache
    Block是HBase从硬盘完成一次读取的数据单位。HFile物理存放形式是一个Block的序列外加这些Block索引。从HBase里读取一个Block需要先在索引上查找一次该Block然后从硬盘读出。Block大小按照列族设定,默认值是64KB。根据使用场景可能会调大或者调小该值。
    如果主要用于随机查询,可能需要细粒度的Block索引,小一点的Block更好一些。Block变小会导致索引变大,进而消耗更多内存。如果经常执行顺序扫描,一次读取多个Block,大一点的Block更好一些。Block变大意味着索引项变少,索引变小,因此节省内存。
    从HBase中读出一行,首先会检查MemStore等修改的队列,然后检查BlockCache看包含该行的Block是否被访问过,最后访问硬盘上的对应HFile
    注意:HFile存放某个时刻MemStore刷写时的快照。一个完整行的数据可能存放在多个HFile里。为了读出完整行,HBase可能需要读取包含该行信息的所有HFile
    HBase删流程
    Delete命令并不立即删除内容。实际上,它只是给记录打上删除的标记。针对那个内容的一条“墓碑”(tombstone)记录写入进来,作为删除的标记。”墓碑“记录用来标志删除的内容不能在Get和Scan命令中返回结果。因为HFile文件是不能改变的,直到执行一次大合并(major compaction),这些墓碑记录才会被处理,被删除,占用的空间才会被释放。
    合并分为两种:大合并(major compaction)和小合并(minorco mpaction)。两者将会重整存储在HFile里的数据。小合并把多个小HFile合并生成一个大HFile。因为读出一条完整的行可能引用很多文件,限制HFile的数量对于读性能很重要。执行合并时,HBase读出已有的多个HFile的内容,把记录写入一个新文件。然后,把新文件设置为激活状态,删除构成这个新文件的所有老文件。HBase根据文件的号码和大小决定合并哪些文件。小合并的设计出发点时轻微影响HBase的性能,所以涉及的HFile的数量有上限。
    大合并将处理给定region的一个列族的所有HFile。大合并完成后,这个列族的所有HFile合并成一个文件。可以从Shell中手工触发整张表的大合并。这个动作相当耗费资源,不要经常使用。小合并时轻量级的,可以频繁发生。大合并是HBase清理被删除记录的唯一机会。因为我们不能保证被删除的记录和墓碑标记记录在一个HFile里面。HBase可以确保同时访问到两种记录。
    HBase和Hive的区别
    hive和hbase是两种基于Hadoop的不同技术。
    Hive的定位是数据仓库,虽然也有增删改查,但其删改对应的是整张表,而不是单行数据,查询的延迟较高。其本质是更加方便的使用MR来进行离线分析的一个数据分析工具。
    HBase的定位是Hadoop的数据库,是一个典型的Nosql,所以Hbase是用来在大量数据中进行低延迟的随机查询。
    HBase 数据查找路由
    参考:http://blog.csdn.net/wangzhen199009/article/details/41593289
    HBase的rowKey的设计原则
    RowKey长度原则
    RowKey是一个二进制码流,RowKey的长度被很多开发者建议说设计在10~100个字节,不过建议是越短越好,不要超过16个字节。
    原因:
    1、数据的持久化文件HFile中是按照KeyValue存储的,如果rowKey过长,1000万列数据光RowKey就要占用100*1000万=10亿个字节,将近1g数据,这会极大影响HFile的存储效率
    2、MemStore讲缓存部分数据到内存,如果RowKey字段过长内存的有效利用率降低,系统将无法缓存更多的数据,这会降低检索效率。因此RowKey的字节长度越短越好。
    3、目前操作系统都是64位系统,内存8字节对齐。控制在16个字节,8字节的整数倍利用操作系统的最佳特性。
    RowKey散列原则
    提高数据均衡分布在每个RegionServer实现负载均衡的几率。如果没有散列值,首字段直接是时间信息,将产生所有新数据都在一个RegionServer上堆积的热点现象,这样在做数据检索的时候负载将会集中在个别RegionServer,降低查询效率
    RowKey唯一原则
    必须在设计上保证其唯一性,rowkey是按照字典顺序排序存储的,因此,设计rowkey的时候,要充分利用这个排序的特点,将经常读取的数据存储到一起,将最近可能会被访问的数据放到一起
    什么是热点
    HBase中的行是按照rowkey的字段顺序排序的,这种设计优化了scan操作,可以将相关的行以及会被一起读取的行存取在临近位置,便于scan,然而糟糕的rowkey设计是热点的源头。热点发生在大量client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量的访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region的请求。
    避免热点方法
    加盐
    这里所说的加盐不是密码学中的加盐,而是rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。分配的前缀种类数量应该和你想使用数据分散到不同的region的数量一致。加盐之后的rowkey就会根据随机生成的前缀分散到各个region上,以避免热点。
    哈希
    哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一行数据
    反转
    反转固定长度或者数字格式的rowkey。这样使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。
    反转rowkey的例子 以手机号为rowkey,将手机反转后的字符串作为rowkey,这样就避免了以手机号比较固定开头导致的热点问题。
    时间戳反转一个常见的数据处理问题使快速获取数据的最近版本,使用反转的时间作为rowkey的一部分堆这个问题十分有用,可以用 Long.Max_Value - timestamp追加到key的末尾,例
    [key][reverse_timestamp]
    其他建议
    尽量减少行和列的大小,value永远和它的key一起传输的。当具体的值在系统间传输时,它的rowkey、列名、时间戳也会一起传输。如果你的rowkey和列明很大,甚至可以和具体的值相比较,那么你将会遇到一些有趣的问题。
    HBase storefiles中的索引(有助于随机访问)最终占据了HBase分配的大量内存,因为具体的值和它的key很大。可以增加block大小使得storefiles索引再更大的时间间隔增加,或者修改表的模式以减小rowkey和列名的大小。压缩有助于更大的索引。
    列族尽可能越短越好,最好是一个字符
    冗长的属性名虽然可读性好,但是更短的属性名存储再HBase中会更好





    不忘初心,方得始终! 坚持!坚持!坚持!!
  • 相关阅读:
    Serialize and Deserialize Binary Tree
    sliding window substring problem汇总贴
    10. Regular Expression Matching
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第七章 链接
    程序员如何写一份合格的简历?(附简历模版)
    9个提高代码运行效率的小技巧你知道几个?
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第六章 存储器层次结构
    24张图7000字详解计算机中的高速缓存
    《深入理解计算机系统》(CSAPP)实验四 —— Attack Lab
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第五章 优化程序性能
  • 原文地址:https://www.cnblogs.com/sumboy/p/10641975.html
Copyright © 2011-2022 走看看