关于Phoenix的使用
与Phoenix
带来的SQL on HBase
易用性相比,它带来的负面影响也是巨大的,
大表Join
大表,或者全表OrderBy
等消耗的资源随数据量呈至少线性增长,
并发直线下降,甚至低到只有百级别,扩容带来的收益下降很快。
另外,Phoenix表查询通过多个独立协调器(Query Server
),互相不管对方,
玩命占用HBase资源,在高并发的大查询下就会容易造成HBase整个集群过载。
而像Presto系统所有的请求都是走同一个协调器,可以总控资源使用,优雅的处理过载。
让现有HBase集群聚焦在线KV Store
,聚焦作为在线业务的温存储层。
Phoenix针对KV系统提供的 SaltBucket、SkipScan、Aggregation、列合并
等特性可以看做是对HBase的最佳实践。
云厂商今后可能从两个方面来改善Phoenix,一个是SQL的分离执行,Scale 无关的本地编译执行,Scale 相关的自动走DLA编译执行;另一个是像Presto那样资源调度的统一处理。
写入数据
HBase写入是先写WAL,然后写内存,如果宕机了,内存里的数据会丢失,需要回放log恢复数据之后,region才能上线,这个是需要时间的一般是3到5分钟。 而升级是不要这个过程的,region会先移走这个时间是百ms级别的。
phoniex 有自己的一套 编码格式, 列族、列名转化方式。 直接读phoenix原生的表, 需要自己去解析字段类型
连接数
hbase zk针对某个ip机器上连接有个上限:200,整体上HBase的连接数没有上限,据官方说是几十万级别的。
范围读
范围读说是的是 scan[startkey, endkey]
,在开始RK与结束RK顺之间按照字典顺序扫描数据。
一般一次扫描,不超过200为好,超过的话,可以设计为多次迭代的形式继续扫描。
删除表
执行删除表(disable->drop
操作),表并不是立即删除,而是先进archive目录
保留一小段时间,
所以,空间水位线不会立即下来。
Region Replica(HBASE-10070)特性
在HBase最初的架构中,一个Region
只能被部署在一个RegionServer
中,它的数据多副本交由HDFS
来保障。从1.0版本开始,HBase
有了Region Replica(HBASE-10070)
特性,该特性允许将一个Region
部署在多个RegionServer
中来提升读取的可用性,但多Region
副本之间的数据却不是实时同步的,因此不具备生产能力。
现存系统针对结构化数据存储与查询的一些痛点问题
结构化数据的存储,通常包含如下两种方式:
静态数据通常以Parquet/Carbon/Avro
形式直接存放在HDFS中,对于分析场景,这种存储通常是更加适合的。但无论以哪种方式存在于HDFS中,都难以支持单条记录级别的更新,随机读取也并不高效。
可变数据的存储通常选择HBase或者Cassandra
,因为它们能够支持记录级别的高效随机读写。但这种存储却并不适合离线分析场景,因为它们在大批量数据获取时的性能较差。
针对HBase
而言,有两方面的主要原因:
- 一、HFile本身的结构定义,它是按行组织数据的,这种格式针对大多数的分析场景,都会带来较大的IO消耗,因为可能会读取很多不必要的数据,相对而言
Parquet
格式针对分析场景就做了很多优化。 - 二、由于HBase本身的
LSM-Tree
架构决定的,HBase的读取路径中,不仅要考虑内存中的数据,同时要考虑HDFS中的一个或多个HFile
,较之于直接从HDFS
中读取文件而言,这种读取路径是过长的
如上两种存储方式,都存在明显的优缺点:
直接存放于HDFS
中,适合离线分析,却不利于记录级别的随机读写。
直接将数据存放于HBase/Cassandra
中,适合记录级别的随机读写,对离线分析却不友好。
ROWKEY设计
md5(car_Id).substring(0,4)_carid_timestamp md5的目的是打散,不是唯一
预分区
MD5Hash.getMD5AsHex hexString的假设数据范文是0000-fffff
建表时,指定分区算法,并且做了预分区
代码语言:javascript复制create 'prod:iov_passenger_location_history_5m','cf1',{NUMREGIONS => 30, SPLITALGO => 'HexStringSplit'}
NUMREGIONS
为 region的个数,一般按每个region 8~10GB
左右来计算region
数量,集群规模大,region
数量可以适当取大一些。
预分区
HBase可以支持100TB 的表,上万个分区, 建表时先估下数据量,然后指定好合适的分区数,分区数太多也不行,太少就会频繁的split,
SPLITALGO 为 rowkey分割的算法,HBase自带了三种pre-split的算法: HexStringSplit、DecimalStringSplit 和 UniformSplit
。
各种Split算法适用场景:
- HexStringSplit: rowkey是十六进制的字符串作为前缀的,这个配合md5前缀用的最多
- DecimalStringSplit: rowkey是10进制数字字符串作为前缀的
- UniformSplit: rowkey前缀完全随机
客户端的报错问题
代码语言:javascript复制Caused by: java.io.IOException: Call to press-001/10.30.93.78:16020 failed on local exception: org.apache.hadoop.hbase.ipc.FailedServerException: This server is in the failed servers list: press-001/10.30.93.78/10.30.93.78:16020
at org.apache.hadoop.hbase.ipc.IPCUtil.wrapException(IPCUtil.java:180)
at org.apache.hadoop.hbase.ipc.AbstractRpcClient.onCallFinished(AbstractRpcClient.java:390)
at org.apache.hadoop.hbase.ipc.AbstractRpcClient.access$100(AbstractRpcClient.java:95)
at org.apache.hadoop.hbase.ipc.AbstractRpcClient$3.run(AbstractRpcClient.java:410)
at org.apache.hadoop.hbase.ipc.AbstractRpcClient$3.run(AbstractRpcClient.java:406)
at org.apache.hadoop.hbase.ipc.Call.callComplete(Call.java:103)
at org.apache.hadoop.hbase.ipc.Call.setException(Call.java:118)
at org.apache.hadoop.hbase.ipc.AbstractRpcClient.callMethod(AbstractRpcClient.java:423)
hbase.regionserver.port:HBase RegionServer绑定的端口,默认16020