很久以前就看到过关于 Hbase 的相关信息, 那时以为这种需要大数据相关知识的数据库肯定是我这种业务开发程序员所接触不到的.
但是随着经历的公司多了, 发现其实对于大数据这个概念而言, 其实不过是 Java 开发的一个分支. 你可以看到在很多的 ToB 业务中, 都需要用到 Hive,HBase,Spark 等等这类常见的 Hadoop 系列的大数据操作工具. 相对与 ToC 的业务, ToB 需要看到数据的变化, 越多的数据对于客户具有越高的价值.
例如, 最近跑 Demo 的一个用户的店, 广告系统就有 60W 的关键词信息, 而且产品还要求每两个小时给用户跑一次. 所以对于一般的程序员, 大数据相关也是需要知道相关知识的.
有点扯远了, 回到 Hbase 这个话题, 这次通过这个项目对于 Hbase 有了一个完整的理解, 所以一起来分析给大家.
如何学习新的知识
看了上一期的《奇葩说》, 还是很有感触的. 知识是无限的, 而智慧才是有限的, 不断的归纳总结是对知识提升到智慧最好的途径.
我总结归纳了一下如何学习一块新软件的系统, 这里包括了语言, 包块了数据库这类开箱即用的系统.
学会使用
在 Hbase 中是没有数据结构的, 无论在那一行你都可以放下很长很长的列. 这就意味着它很适合做一些数据仓库的业务场景, 无须关注数据的结构, 拿到数据就往里面扔. 唯一需要设计的就是 ROWKEY. 简单的讲, 数据是按照字典序来排放的, 当你扫描相邻的数据就会很快. 当然, 它也是任使用者随意摆放的.
ROW KEY | 数据内容 |
---|---|
aabb | 。。。 |
abaa | 。。。 |
ba | 。。。 |
bbcc | 。。。 |
创建 Hbase 表
- create 'campaigns',
- {
- NAME =>'campaign', VERSIONS => 1, BLOCKCACHE => true, BLOCKSIZE => '65536', BLOOMFILTER => 'ROW'
- },
- {
- SPLITS => ['00','01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17',
- '18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37',
- '38','39','40','41','42','43','44','45','46','47','48','49','50','51','52','53','54','55','56','57',
- '58','59','60','61','62','63','64','65','66','67','68','69','70','71','72','73','74','75','76','77',
- '78','79','80','81','82','83','84','85','86','87','88','89','90','91','92','93','94','95','96','97','98','99']
- }
campaigns 表示表名, campaign 表示列族名字. 如果你不关注其他的信息, 这就是你创建一个表所需要的.
那么剩下的是什么意思呢? 容我一一道来.
BLOCKCACHE
开启 BLOCKCACHE, 我们都知道使用 Hbase 读取数据的时候往往是一块一块的读的, 那么可以从磁盘上一次性将所需要的容量读出来. 所以 BLOCKCACHE 一般设置为读取的量.
BLOOMFILTER
布隆过滤器, 它说有不一定有, 它说没有就一定没有.
使用一种数据结构来过滤大部分无效的读请求.
SPLITS
预分区, Hbase 是面向分布式设计的. 但是往往会出现热点数据, 出现的结果就是某台服务器读写被打爆, 发挥不出分布式的优点. 可以预先设计一些分区, 来提前规避一些热点问题, 也可以减少 region 分裂的时间.
为什么列族只有一个
在一个 Region 中会有多个 HStore, 每个 HStore 对应一个 Column Family.
HBase 会在 region 下所有的 StoreFile 中最大的 StoreFile 大小超过阀值进行 spliet.
而此时会出现一种情况, 存在一大一小的 HStore, 而小的那个就被迫进行了 spliet, 导致查询小表的时候需要大量扫描, 所有为的是对 Column Family 进行隔离.
https://www.cnblogs.com/gaopeng527/p/4967186.html
查询
- put "table","rowkey","columFamily:colum","value"
- get "table","rowkey","columFamily:colum"
- count "campaigns"
- scan "campaigns", {
- }
更多的请看: https://www.cnblogs.com/nexiyi/p/hbase_shell.html
有个小坑说下, 使用 truncate 删除正表数据的时候, 会将预分区都删除. 所以还是最好 drop, 重新 create.
最佳实践
最佳实践往往是踩坑过程中累计出来的.
Phoenix
背景是这样的, 业务部门使用的是 Python 来读取 Hbase, 然而直接使用 ROWKEY 无法做一些计算 (可以使用 Hbase coprossors), 同时需要二级索引. 然后调研了一下, 发现了 Phoenix 这个 "神器", 在 Hbase 上面再搭建一层 SQL 层, 同时 Phoenix 自带了 Hbase coprossors 节约编写代码的时间, 就决定是你了皮卡丘, 然后不断踩坑.
踩坑一: 字符类型
我们都知道在 MySQL 可以指定各种类型, 有 Integer,Bigdcimal. 然而放入 Hbase 我们使用的是 byte[] s= Bytes.toBytes("r1");
使用 Phoenix 指定类型之后就发现报错了, phoenix 无法识别, phoenix 是需要固定的字节长度来读取有类型的字段的. 你可以使用
来放入的时候固定类型长度. 或者 select SUM(TO_NUMBER("impressions")) from "data_report_campaigns", 在读取的时候使用 Phoenix 提供的函数.
踩坑二: 二级索引
原先单纯的以为二级索引和 MySQL 一样, 然而发现是我们太过天真了. Phoenix 的二级索引就是建立一个新的表, 将建立索引的表作为 ROWKEY, 类似于倒排索引的概念.
然而蛋疼的是如果你在查询的时候有包含非索引列, 那么他便不会走索引.
另外, 二级索引是 Phoenix 通过 Hbase 的 coprossor 生成的, 所以只有通过 phoenix 才能会生成 index 数据. 如果是通过 Hbase 来插入的数据, 还需要在 index 表里面插数据.
踩坑三: phoenix 4.7 的 bug
Hbase 的数据数量和 Phoenix 的数据量对不上了, Hbase 只有 60W 的数据, Phoenix 发现有 800W. 还以为是高并发导致数据错乱, 结果怎么试都没有复现. 怀疑是和时间相关的 bug, 手动触发 Hbase 的 Major compaction, 果然复现了.
解决方案: delete from system.stats where physical_name='CUST.PROFILE';
连接:
Hbase 定期进行 Major compaction 之后, Phoenix 并没有同步更新, 所以需要删除数据.
Hbase coprossors 使用
原本对于 coprossors 还是带有抵触心理, 因为将程序放在数据源觉得总会对数据造成影响. 后来发现包括 TiDB 以及其他针对大数据计算的框架, 都是有相同的思考, 将计算放在数据源. 这样能够减少大数据传输的带宽限制, 从而提升速度. coprossors 分为两种:
EndPoint 实现计算, 类似存储过程
Observer 观察者模式, 类似实现二级索引
使用的 Demo:
其他相关最佳实践
系统监控
这里包括的 Hbase 的容灾, 性能监控, 以及系统如何平稳升级
性能优化
HDFS 相关配置优化, HBase 服务端优化 (GC 优化, Compaction 优化, 硬件配置优化), 列族设计优化, 客户端优化
整体理解
对于系统监控和性能优化, 没有一个很好的实践也给不出啥有效的信息. 而通过学会使用和最佳实践之后, 一定是理解系统设计的理念, 包括整体的架构, 数据结构.
简单的讲就是理解:
一个 Hbase 的写过程是怎么样的?
一个 Hbase 的读过程是怎么样的?
感觉需要讲的有点多, 先放一个 Hbase 的整体架构图, 剩下的容我慢慢来讲.
来源: https://juejin.im/entry/5c033f2de51d45511f44825a