Hbase知识点全复习

参考链接HBase 底层原理详解(深度好文,建议收藏)
B站视频尚硅谷HBase教程(hbase框架快速入门)

HBase简介

HBase 是一个分布式的、面向列的开源数据库。建立在 HDFS 之上。Hbase的名字的来源是 Hadoop database,即 Hadoop 数据库。HBase 的计算和存储能力取决于 Hadoop 集群。 它介于 NoSql 和 RDBMS之间,仅能通过主键(row key)和主键的 range 来检索数据,仅支持单行事务(可通过 Hive 支持来实现多表 join 等复杂操作)。
HBase中表的特点:
大:一个表可以有上十亿行,上百万列
面向列:面向列(族)的存储和权限控制,列(族)独立检索。
稀疏:对于为空(null)的列,并不占用存储空间,因此,表可以设计的非常稀疏。

HBase底层原理

在这里插入图片描述

  • Client
    包含访问hbase的接口,Client维护着一些cache来加快对hbase的访问,比如regione的位置信息.
  • Zookeeper
    HBase可以使用内置的Zookeeper,也可以使用外置的,在实际生产环境,为了保持统一性,一般使用外置Zookeeper。
  • Zookeeper在HBase中的作用:
  1. 保证任何时候,集群中只有一个master
  2. 存贮所有Region的寻址入口
  3. 实时监控Region Server的状态,将Region Server的上线和下线信息实时通知给Master
  • HMaster
  1. 为Region Server分配Region
  2. 负责Region Rerver的负载均衡
  3. 发现失效的Region Server并重新分配其上的Region
  4. HDFS上的垃圾文件回收
  5. 处理schema更新请求
  • HRegion Server
  1. HRegion Server维护HMaster分配给它的Region,处理对这些Region的IO请求
  2. HRegion Server负责切分在运行过程中变得过大的region
  3. 从图中可以看到,Client访问HBase上数据的过程并不需要HMaster参与(寻址访问Zookeeper和HRegion server,数据读写访问HRegione server)

HMaster仅仅维护者table和HRegion的元数据信息,负载很低。

HBase 表数据模型

在这里插入图片描述

  • 行键 Row Key
    与nosql数据库一样,rowkey是用来检索记录的主键。访问hbase table中的行,只有三种方式:
  1. 通过单个row key访问
  2. 通过row key的range
  3. 全表扫描
  • Row Key 行键可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在hbase内部,rowkey保存为字节数组。Hbase会对表中的数据按照rowkey排序(字典顺序)
    存储时,数据按照Row key的字典序(byte order)排序存储。设计key时,要充分排序存储这个特性,将经常一起读取的行存储放到一起。(位置相关性)
    注意: 字典序对int排序的结果是 1,10,100,11,12,13,14,15,16,17,18,19,2,20,21 …
    。要保持整形的自然序,行键必须用0作左填充。

  • 行的一次读写是原子操作 (不论一次读写多少列)。这个设计决策能够使用户很容易的理解程序在对同一个行进行并发更新操作时的行为。

  • 列族 Column Family
    HBase表中的每个列,都归属于某个列族列族是表的schema的一部分(而列不是)必须在使用表之前定义

  • 列名都以列族作为前缀。例如 courses:history , courses:math 都属于 courses 这个列族。
    访问控制、磁盘和内存的使用统计都是在列族层面进行的列族越多,在取一行数据时所要参与IO、搜寻的文件就越多,所以,如果没有必要,不要设置太多的列族

  • 列 Column
    列族下面的具体列,属于某一个ColumnFamily,类似于在mysql当中创建的具体的列。

  • 时间戳 Timestamp
    HBase中通过row和columns确定的为一个存贮单元称为cell。每个 cell都保存着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由hbase(在数据写入时自动
    )赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面
    为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,hbase提供了两种数据版本回收方式:

  1. 保存数据的最后n个版本
  2. 保存最近一段时间内的版本(设置数据的生命周期TTL)。
    用户可以针对每个列族进行设置。

单元 Cell 由{row key, column( = +

  • 版本号 VersionNum
    数据的版本号,每条数据可以有多个版本号,默认值为系统时间戳,类型为Long。

物理存储

在这里插入图片描述

  • Table 中的所有行都按照 Row Key 的字典序排列。
  • Table 在行的方向上分割为多个 HRegion。
  • HRegion按大小分割的(默认10G),每个表一开始只有一 个HRegion,随着数据不断插入表,HRegion不断增大,当增大到一个阀值的时候,HRegion就会等分会两个新的HRegion。当Table 中的行不断增多,就会有越来越多的 HRegion。
  • HRegion 是 HBase 中分布式存储和负载均衡的最小单元。最小单元就表示不同的 HRegion 可以分布在不同的 HRegion Server 上。但一个 HRegion 是不会拆分到多个 Server 上的。
  • HRegion 虽然是负载均衡的最小单元,但并不是物理存储的最小单元。
    事实上,HRegion 由一个或者多个 Store 组成,每个 Store 保存一个 Column Family。每个 Strore 又由一个 MemStore 和0至多个 StoreFile 组成。如上图。

HLog(WAL log)

  • WAL 意为Write ahead log,类似 mysql 中的 binlog,用来 做灾难恢复时用,Hlog记录数据的所有变更,一旦数据修改,就可以从log中进行恢复。
  • 每个Region Server维护一个Hlog,而不是每个Region一个。这样不同region(来自不同table)的日志会混在一起,这样做的目的是不断追加单个文件相对于同时写多个文件而言,可以减少磁盘寻址次数因此可以提高对table的写性能。带来的麻烦是,如果一台region server下线,为了恢复其上的region,需要将region server上的log进行拆分,然后分发到其它region server上进行恢复
  • HLog文件就是一个普通的Hadoop Sequence File:
    HLog Sequence File 的Key是HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括 sequence number和timestamp,timestamp是”写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。
    HLog Sequece File的Value是HBase的KeyValue对象,即对应HFile中的KeyValue

写流程:

  1. Client 先访问 zookeeper,获取 hbase:meta 表位于哪个 Region Server。
  2. 访问对应的 Region Server,获取 hbase:meta 表,根据读请求的 namespace:table/rowkey,
    查询出目标数据位于哪个 Region Server 中的哪个 Region 中。并将该 table 的 region 信息以 及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问。
  3. 与目标 Region Server 进行通讯;
  4. 将数据顺序写入(追加)到 WAL;
  5. 将数据写入对应的 MemStore,数据会在 MemStore 进行排序;
  6. 向客户端发送 ack;
  7. 等达到 MemStore 的刷写时机后,将数据刷写到 HFile。
    在这里插入图片描述

细节

  • HBase使用MemStore和StoreFile存储对表的更新。
  • 数据在更新时首先写入Log(WAL log)和内存(MemStore)中,MemStore中的数据是排序的当MemStore累计到一定阈值时,就会创建一个新的MemStore,并且将老的MemStore添加到flush队列,由单独的线程flush到磁盘上,成为一个StoreFile。于此同时,系统会在zookeeper中记录一个redo point,表示这个时刻之前的变更已经持久化了
  • 当系统出现意外时,可能导致内存(MemStore)中的数据丢失,此时使用Log(WAL log)来恢复checkpoint之后的数据。
    StoreFile是只读的,一旦创建后就不可以再修改。因此HBase的更新其实是不断追加的操作。当一个Store中的StoreFile达到一定的阈值后,就会进行一次合并(minor_compact, major_compact),将对同一个key的修改合并到一起,形成一个大的StoreFile,当StoreFile的大小达到一定阈值后,又会对 StoreFile进行split,等分为两个StoreFile
  • 由于对表的更新是不断追加的,compact时,**需要访问Store中全部的 StoreFile和MemStore,**将他们按row key进行合并,由于StoreFile和MemStore都是经过排序的,并且StoreFile带有内存中索引,合并的过程还是比较快
  • Hbase写数据是先将数据写入wal(预写日志),再写入内存。在代码实现中,首先要获得锁,(因为要写数据)。然后写入日志文件。但并不同步(也就是不写入hdfs中)。再写入内存,之后进行释放锁(写完数据了)。之后同步日志文件(写入hdfs中)。如果wal同步失败了,就进行回滚操作单元格,将keys从内存中移除。所以最后要判断是否日志文件写入成功,如果成功,内存中数据就保留;如果不成功,内存中数据就删除。保证了数据一致性。

重要信息

  • Hbase表非常稀疏,但是不占存储空间。
  • DDL:是表的增删改查:describe
  • DML:是数据的增删改查:put(增,改),scan,get,delete
  • HMaster将与客户端交互的部分交给了ZK,客户端对标数据的增改不需要访问Hmaster,只需要请求ZK
  • 一个regionServer存在多个region,一个region是一个切片,包括多个列族,也就是多个store,一个store中保存一个memstore。一个列族对应多个store。但一个region中肯定是不同的列族

刷写:flush

memstore memstore向hdfs中保存数据。两个标注:

  1. 时间
  2. 大小
  3. 预刷写

1. 按时间

(hbase.regionserver.optionalcacheflushinterval)默认:1h
内存中的文件在自动刷新之前能够存活的最长时间

<!-- 内存中的文件在自动刷新之前能够存活的最长时间,默认是1h -->  
    <property>  
        <name>hbase.regionserver.optionalcacheflushinterval</name>  
        <value>3600000</value>  
        <description>  
            Maximum amount of time an edit lives in memory before being automatically  
            flushed.  
            Default 1 hour. Set it to 0 to disable automatic flushing.  
        </description>  
    </property>

2. 按大小

一种是regionserver范围内的size;一种是region范围内的size。在regionserver中求的是所有region的memstore的总和hbase.regionserver.global.memstore.size,如果大于限定值,那么所有region都需要执行刷写操作,并且为了保护内存安全,在刷写操作过程中需要阻塞客户端读写(所有region中的memstore),防止客户端操作比刷写的操作还快,容易造成堆溢出。注意默认为*Defaults to 40% of heap (0.4).刷写过程是按照memstore从大到小的顺序进行刷写的

<!-- regionServer的全局memstore的大小,超过该大小会触发flush到磁盘的操作,默认是堆大小的40%,而且regionserver级别的   
        flush会阻塞客户端读写 -->  
    <property>  
        <name>hbase.regionserver.global.memstore.size</name>  
        <value></value>  
        <description>Maximum size of all memstores in a region server before  
            new  
            updates are blocked and flushes are forced. **Defaults to 40% of heap (0.4).  **
            Updates are blocked and flushes are forced until size of all  
            memstores  
            in a region server hits  
            hbase.regionserver.global.memstore.size.lower.limit.  
            The default value in this configuration has been intentionally left  
            emtpy in order to  
            honor the old hbase.regionserver.global.memstore.upperLimit property if  
            present.  
        </description>  
    </property>

(hbase.regionserver.global.memstore.size.lower.limit)默认:堆大小 * 0.4 * 0.95
有时候集群的“写负载”非常高,写入量一直超过flush的量,这时,我们就希望memstore不要超过一定的安全设置。在这种情况下,写操作就要被阻塞一直到memstore恢复到一个“可管理”的大小, 这个大小就是默认值是堆大小 * 0.4 * 0.95,*也就是当regionserver级别的flush操作发送后,会阻塞客户端写,一直阻塞到整个regionserver级别的memstore的大小为 堆大小 * 0.4 0.95为止

<!--可以理解为一个安全的设置,有时候集群的“写负载”非常高,写入量一直超过flush的量,这时,我们就希望memstore不要超过一定的安全设置。   
        在这种情况下,写操作就要被阻塞一直到memstore恢复到一个“可管理”的大小, 这个大小就是默认值是堆大小 * 0.4 * 0.95,也就是当regionserver级别   
        的flush操作发送后,会阻塞客户端写,一直阻塞到整个regionserver级别的memstore的大小为 堆大小 * 0.4 *0.95为止 -->  
    <property>  
        <name>hbase.regionserver.global.memstore.size.lower.limit</name>  
        <value></value>  
        <description>Maximum size of all memstores in a region server before  
            flushes are forced.  
            Defaults to 95% of hbase.regionserver.global.memstore.size (0.95).  
            A 100% value for this value causes the minimum possible flushing to  
            occur when updates are  
            blocked due to memstore limiting.  
            The default value in this configuration has been intentionally left  
            emtpy in order to  
            honor the old hbase.regionserver.global.memstore.lowerLimit property if  
            present.  
        </description>  
    </property>  

按大小2:(hbase.hregion.memstore.flush.size)默认:128M。单个region里memstore的缓存大小,超过那么整个HRegion就会flush但只会阻止向该memstore的读写操作

预刷写

(hbase.hregion.preclose.flush.size)默认为:5M
当一个 region 中的 memstore 的大小大于这个值的时候,我们又触发了region的 close时,会先运行“pre-flush”操作,清理这个需要关闭的memstore,然后 将这个 region 下线
当一个 region下线了,我们无法再进行任何写操作。如果一个 memstore 很大的时候,flush 操作会消耗很多时间。"pre-flush"操作意味着在 region 下线之前,会先把 memstore 清空。这样在最终执行 close 操作的时候,flush 操作会很快。

Hbase读流程

在这里插入图片描述LRU:最近最少使用
Block Cache是块缓存,因为要存最近最常用的数据。删除数据的话就遵循LRU原则,删除最近最少使用的数据。
因为数据的顺序是按照时间戳控制的,所以需要比较磁盘和内存中的数据。所以不是先访问内存,而是两个要一起读,要比较时间戳。从磁盘的数据放在cache,节省时间。以后block
cache有就不读磁盘里相应的文件了。因为磁盘里的其他文件也可能包含当前读取对象。

  • Hbase是读比写慢的,因为无论如何都需要读磁盘。
  • block cache只存放磁盘里的文件

StoreFile Compaction(小文件合并)

由于memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp) 和不同类型(Put/Delete)有可能会分布在不同的 HFile 中,因此查询时需要遍历所有的 HFile。为了减少 HFile 的个数,以及清理掉过期和删除的数据,会进行 StoreFile Compaction。 Compaction 分为两种,分别是 Minor Compaction(小合并) 和 Major Compaction(大合并)。Minor Compaction 会将临近的若干个较小的 HFile合并成一个较大的 HFile但不会清理过期和删除的数据Major Compaction 会将一个 Store 下的所有的 HFile合并成一个大 HFile,并且会清理掉过期 和删除的数据。
在这里插入图片描述
当文件数超过三个的时候,走的也是大合并
一个region进行 major compaction合并的周期,在这个点的时候, 这个region下的所有hfile会进行合并,默认是7天,major compaction非常耗资源,建议生产关闭(设置为0),在应用空闲时间手动触发

 <!-- 一个region进行 major compaction合并的周期,在这个点的时候, 这个region下的所有hfile会进行合并,默认是7,major   
        compaction非常耗资源,建议生产关闭(设置为0),在应用空闲时间手动触发 -->  
    <property>  
        <name>hbase.hregion.majorcompaction</name>  
        <value>604800000</value>  
        <description>The time (in miliseconds) between 'major' compactions of  
            all  
            HStoreFiles in a region. Default: Set to 7 days. Major compactions tend to  
            happen exactly when you need them least so enable them such that they  
            run at  
            off-peak for your deploy; or, since this setting is on a periodicity that is  
            unlikely to match your loading, run the compactions via an external  
            invocation out of a cron job or some such.  
        </description>  
    </property>  

一个store里面允许存的hfile的个数,超过这个个数会被写到新的一个hfile里面 也即是每个region的每个列族对应的memstore在fulsh为hfile的时候,默认情况下当达到3个hfile的时候就会对这些文件进行合并重写为一个新文件设置个数越大可以减少触发合并的时间,但是每次合并的时间就会越长(hbase.hstore.compactionThreshold)

    <!-- 一个store里面允许存的hfile的个数,超过这个个数会被写到新的一个hfile里面 也即是每个region的每个列族对应的memstore在fulsh为hfile的时候,默认情况下当达到3个hfile的时候就会对这些文件进行合并重写为一个新文件,设置个数越大可以减少触发合并的时间,但是每次合并的时间就会越长 -->  
    <property>  
        <name>hbase.hstore.compactionThreshold</name>  
        <value>3</value>  
        <description>  
            If more than this number of HStoreFiles in any one HStore  
            (one HStoreFile is written per flush of memstore) then a compaction  
            is run to rewrite all HStoreFiles files as one. Larger numbers  
            put off compaction but when it runs, it takes longer to complete.  
        </description>  
    </property>  

数据的删除

正常的数据读写操作不需要访问master。但元数据还需要查看master。但也是从ZK找master,master节点是高可用的,位置会发生变化,也是通过ZK进行管理。

删除无用数据

删除数据除了在大合并storeFile时,还有一种情况是flush,也就是在内存中的数据会进行合并。例如同一rowkey首先put 1,再put 2,然后flush进行刷写。再查所有版本的信息会只存在2,1的插入信息根本就不会刷写进磁盘。但注意这是因为在同一内存中的操作进行合并,只关心内存空间,不关心磁盘空间。

那操作标记怎么删除呢?

在flush的时候不删,在compact(major)的时候才会删除。因为flush时候是只关心内存空间的,但在磁盘中会存在多个文件,可能当前操作对应的数据还存在其他文件中,会造成数据混乱。例如向10001里put数据1,然后flush,此时硬盘上会出现一个文件。再向10001里put数据2,然后再删除10002的该数据。此时扫面版本是只存在delete操作,进行flush后,写入磁盘文件,该文件就包含delete操作。因为flush里不能删除,该操作对应的数据也存在第一次刷写的硬盘中。若删除了这个数据,那么在之后compact(major)时,10001为1的数据又会出现了。(例子进行简化了,方便解释)

Region Split

默认情况下,每个 Table 起初只有一个 Region,随着数据的不断写入,Region 会自动进行拆分。刚拆分时,两个子 Region 都位于当前的 Region Server,但处于负载均衡的考虑,HMaster 有可能会将某个 Region 转移给其他的 RegionServer
Region Split 时机:

  1. 当1个region中的某个Store下所有StoreFile的总大小超过hbase.hregion.max.filesize, 该 Region 就会进行拆分(0.94 版本之前)。
  2. 当 1 个 region 中 的 某 个 Store 下所有 StoreFile 的 总 大 小 超 过 Min(R^2 * “hbase.hregion.memstore.flush.size”,hbase.hregion.max.filesize"),该
    Region 就会进行拆分,其中 R 为当前 Region Server 中属于该 Table 的个数(0.94 版本之后)。但这样就会造成数据倾斜,每个region的负载不一样,会造成负载不均衡。
    在这里插入图片描述
    Region切分是按照行键进行切分的,所以一个region的不同store也要根据行键进行切分。
    所以官方不建议使用多个列族,因为多个列族会造成列族数据增长速度可能不同,进行切分时,再进行flush,就会形成多个小文件(因为有些列族不常用)。但也可以让列族增长速度尽可能一样来解决。

HRegion管理

任何时刻,一个HRegion只能分配给一个HRegion Server。HMaster记录了当前有哪些可用的HRegion Server。以及当前哪些HRegion分配给了哪些HRegion Server,哪些HRegion还没有分配。当需要分配的新的HRegion,并且有一个HRegion Server上有可用空间时,HMaster就给这个HRegion Server发送一个装载请求,把HRegion分配给这个HRegion Server。HRegion Server得到请求后,就开始对此HRegion提供服务。

HRegion Server上线

HMaster使用zookeeper来跟踪HRegion Server状态。当某个HRegion Server启动时,会首先在zookeeper上的server目录下建立代表自己的znode。由于HMaster订阅了server目录上的变更消息,当server目录下的文件出现新增或删除操作时,HMaster可以得到来自zookeeper的实时通知。因此一旦HRegion Server上线,HMaster能马上得到消息。

HRegion Server下线

当HRegion Server下线时,它和zookeeper的会话断开,zookeeper而自动释放代表这台server的文件上的独占锁。HMaster就可以确定:
HRegion Server和zookeeper之间的网络断开了。
HRegion Server挂了。
无论哪种情况,HRegion Server都无法继续为它的HRegion提供服务了,此时HMaster会删除server目录下代表这台HRegion Server的znode数据,并将这台HRegion Server的HRegion分配给其它还活着的节点

HMaster工作机制

master上线

master启动进行以下步骤:

  1. 从zookeeper上获取唯一一个代表active master的锁,用来阻止其它HMaster成为master
  2. 扫描zookeeper上的server父节点,获得当前可用的HRegion Server列表
  3. 和每个HRegion Server通信,获得当前已分配的HRegion和HRegion Server的对应关系
  4. 扫描.META.region的集合,计算得到当前还未分配的HRegion,将他们放入待分配HRegion列表。

master下线

由于HMaster只维护表和region的元数据,而不参与表数据IO的过程,HMaster下线仅导致所有元数据的修改被冻结(无法创建删除表,无法修改表的schema,无法进行HRegion的负载均衡,无法处理HRegion 上下线,无法进行HRegion的合并,唯一例外的是HRegion的split可以正常进行,因为只有HRegion Server参与),表的数据读写还可以正常进行。因此HMaster下线短时间内对整个HBase集群没有影响。
从上线过程可以看到,HMaster保存的信息全是可以冗余信息(都可以从系统其它地方收集到或者计算出来)
因此,一般HBase集群中总是有一个HMaster在提供服务,还有一个以上的‘HMaster’在等待时机抢占它的位置。

预分区

每一个 region 维护着 StartRow 与 EndRow,如果加入的数据符合某个 Region 维护的 RowKey
范围,则该数据交给这个 Region 维护。那么依照这个原则,我们可以将数据所要 投放的分区提前大致的规划好,以提高 HBase 性能。
1.手动设定预分区

Hbase> create 'staff1','info','partition1',SPLITS => 
['1000','2000','3000','4000']

划了四刀,所以是分成了五个区。之后根据rowkey与Start key和end key比较,来看将数据放在哪个分区。比较是按位比较。

2.按照文件中设置的规则预分区 创建 splits.txt 文件内容如下:
aaaa
bbbb
cccc
dddd 然后执行:
create 'staff3','partition3',SPLITS_FILE => 'splits.txt'

3.使用 JavaAPI 创建预分区 //自定义算法,产生一系列 hash
散列值存储在二维数组
中。因为数组里的每个元素其实也是字节数组形式的。

byte[ ][ ] splitKeys = 某个散列值函数
//创建 HbaseAdmin 实例
HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create());
//创建 HTableDescriptor 实例
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
//通过 HTableDescriptor 实例和散列值二维数组创建带有预分区的 Hbase 表
hAdmin.createTable(tableDesc, splitKeys);

RowKey 设计

一条数据的唯一标识就是 RowKey,那么这条数据存储于哪个分区,取决于 RowKey 处 于哪个一个预分区的区间内,设计 RowKey 的主要目的 ,就是让数据均匀的分布于所有的 region 中,在一定程度上防止数据倾斜。接下来我们就谈一谈 RowKey 常用的设计方案。
三个原则:

  1. 散列性
  2. 唯一性
  3. 长度原则

1.生成随机数、hash、散列值
比如:
原 本 rowKey 为 1001 的 , SHA1 后 变 成 :
dd01903921ea24941c26a48f2cec24e0bb0e8cc7
原 本 rowKey 为 3001 的 , SHA1 后 变 成 :
49042c54de64a1e9bf0b33e00245660ef92dc7bd
原 本 rowKey 为 5001 的 , SHA1 后 变 成 :
7b61dec07e02c188790670af43e717f0f46e8913
在做此操作之前,一般我们会选择从数据集中抽取样本,来决定什么样的 rowKey 来 Hash
后作为每个分区的临界值
2.字符串反转
20170524000001 转成 10000042507102
20170524000002 转成 20000042507102
这样也可以在一定程度上散列逐步 put 进来的数据。
3.字符串拼接
20170524000001_a12e
20170524000001_93i7

分区实例:
通话记录情况
在这里插入图片描述
设置预分区
在这里插入图片描述

  1. 确定多少个分区
  2. 确定分区键和rowkey的前缀。 |的位数比_大。所以可以将000_开头的数据划分在000|分区中。因为希望手机号可以放到同一个分区,所以划分区域的前缀是000-299,共三百个分区,所以该前缀的获取可直接使用手机号除300取取模得到
  3. 取模得到的前缀存在不同不同手机号分到同一个分区的情况,所以我们希望能够集中的读取一个分区中的手机号,手机号相同的防在一起。所
  4. 以之后拼接上手机号。
    在这里插入图片描述

但是不同人的通话记录次数也都差别很大,也有可能会造成数据倾斜的问题,所以我们可以再把每个人的通话次数按月份进行再划分,为了散列性。具体操作就是手机号加上年月再进行除以299进行取模。来得到前缀进行划分。
在这里插入图片描述
最重要的是要想以后分区什么数据能够在一起,就将什么数据的划分往前提,就会先按该标准进行划分。
在这里插入图片描述
例如求该手机号19年2月份的所有通话记录,那么

start key=xxx_13142542322_2019-02
 end key=xxx_13142542322_2019-03
 当然也可以写成
 start key=xxx_13142542322_2019-02
 end key=xxx_13142542322_2019-02|(因为|比任何其他值都大,用于拦截)

其中xxx前缀是在手机号加年月模299的基础上进行得到的。如果要取这个人一年的通话记录,那么需要进行12次这样的操作,因为是按手机号和年月进行分区的。不同手机号还要依据年月的不同放在不同分区。

总结

所以其实分区前缀的获得要看你要把数据怎么进行散列。例如上例中是希望将手机号按照年月进行散列放在不同的分区中的,因为不同手机号的的童话记录次数也会有很大不一样,是为了负载均衡进行合理的分区操作。
但如果你希望在一个分区中有些数据相近的应该靠在一起,那就应该将它接在rowkey后面,并合理安排它的优先级。如一天的,那么就应该将它拼接上作为rowkey,在这里当然先是同一个手机号,然后同年月日,然后同时间进行聚合在一起,自己看需要可以进行合理安排。

内存优化

HBase 操作过程中需要大量的内存开销,毕竟 Table 是可以缓存在内存中的,一般会分 配整个可用内存的 70%给 HBase 的 Java 堆。但是不建议分配非常大的堆内存,因为 GC 过 程持续太久会导致 RegionServer 处于长期不可用状态,一般 16~48G 内存就可以了,如果因 为框架占用内存过高导致系统内存不足,框架一样会被系统服务拖死。
因为内存有个RegionServer 级别的刷写,限制值是堆大小 * 0.4 。如果它比较大,那么在进行阻塞时,会一直把读写阻塞到低于堆大小0.40.38。如果堆内存比较大,那么这个值也会比较大,那么阻塞的时间就会比较久。
1.允许在 HDFS 的文件中追加内容

hdfs-site.xml、hbase-site.xml
属性:dfs.support.append

解释:开启 HDFS 追加同步,可以优秀的配合 HBase 的数据同步和持久化。默认值为 true。
2.优化 DataNode 允许的最大文件打开数

hdfs-site.xml
属性:dfs.datanode.max.transfer.threads

解释:HBase 一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为 4096 或者更高。默认值:4096。因为有RegionServer 级别的刷写,同时会刷写多个文件。
3.优化延迟高的数据操作的等待时间

hdfs-site.xml
属性:dfs.image.transfer.timeout

解释:如果对于某一次数据操作来讲,延迟非常高,socket 需要等待更长的时间,建议把该值设置为更大的值(默认 60000 毫秒),以确保 socket 不会被 timeout 掉。为了确保有些进行慢的任务也能正常进行(也即是延迟高)
4.优化数据的写入效率
mapred-site.xml
属性:
mapreduce.map.output.compress
mapreduce.map.output.compress.codec
解释:开启这两个数据可以大大提高文件的写入效率,减少写入时间。第一个属性值修改为
true,第二个属性值修改为:org.apache.hadoop.io.compress.GzipCodec 或者其
他压缩方式。通过压缩文件来提高存储效率例如storeFile就是以HFile的文件格式进行存储的,可以进行文件压缩。
5.设置 RPC 监听数量

hbase-site.xml
属性:Hbase.regionserver.handler.count

解释:默认值为 30,用于指定 RPC 监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。(客户端和服务端之间的通信使用的是RPC)
6.优化 HStore 文件大小
hbase-site.xml
属性:hbase.hregion.max.filesize
解释:默认值 10737418240(10GB),如果需要运行 HBase 的 MR 任务,可以减小此值,因为一个 region 对应一个 map 任务,如果单个 region 过大,会导致 map 任务执行时间过长。该值的意思就是,如果 HFile 的大小达到这个数值,则这个 region 会被切分为两个 Hfile
7.优化 HBase 客户端缓存
hbase-site.xml
属性:hbase.client.write.buffer
解释:用于指定 Hbase 客户端缓存,增大该值可以减少 RPC 调用次数但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少 RPC 次数的目的。
8.指定 scan.next 扫描 HBase 所获取的行数
hbase-site.xml
属性:hbase.client.scanner.caching
解释:用于指定 scan.next 方法获取的默认行数,值越大,消耗内存越大。
上面两个都是客户端的优化。
9.flush、compact、split 机制
当 MemStore 达到阈值,将 Memstore 中的数据 Flush 进 Storefile;compact 机制则是把 flush出来的小文件合并成大的 Storefile 文件。split 则是当 Region 达到阈值,会把过大的 Region一分为二

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值