热点现象(数据倾斜)怎么产生的,以及解决方法有哪些
热点现象:
某个小的时段内,对HBase 的读写请求集中到极少数的Region 上,导致这些region
所在的RegionServer 处理请求量骤增,负载量明显偏大,而其他的RgionServer
明显空闲。
热点现象出现的原因:
HBase 中的行是按照rowkey 的字典顺序排序的,这种设计优化了scan 操作,可以将相关的行以及会被一起读取的行存取在临近位置,便于scan。然而糟糕的rowkey 设计是热点的源头。
热点发生在大量的client 直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量访问会使热点region 所在的单个机器超出自身承受能力,引起性能下降甚至region 不可用,这也会影响同一个RegionServer 上的其他region,由于主机无法服务其他region 的请求。
热点现象解决办法:
为了避免写热点,设计rowkey 使得不同行在同一个region,但是在更多数据情况下,数据应该被写入集群的多个region,而不是一个。
常见的方法有以下这些:
加盐:
在rowkey 的前面增加随机数,使得它和之前的rowkey 的开头不同。分配的前缀种类数量应该和你想使用数据分散到不同的region 的数量一致。加盐之后的rowkey 就会根据随机生成的前缀分散到各个region 上,以避免热点。
哈希:
哈希可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get 操作准确获取某一个行数据
反转:
第三种防止热点的方法时反转固定长度或者数字格式的rowkey。这样可以使得rowkey 中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey 的有序性。反转rowkey 的例子以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题
时间戳反转:
一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为rowkey 的一部分对这个问题十分有用,可以用Long.Max_Value -timestamp 追加到key 的末尾,例如[key][reverse_timestamp],[key]的最新值可以通过scan [key]获得[key]的第一条记录,因为HBase 中rowkey 是有序的,第一条记录是最后录入的数据。
1. 比如需要保存一个用户的操作记录,按照操作时间倒序排序,在设计rowkey 的时候,可以这样设计[userId 反转][Long.Max_Value - timestamp],在查询用户的所有操作记录数据的时候,直接指定反转后的userId,startRow 是[userId 反转][000000000000],stopRow 是[userId 反转][Long.Max_Value - timestamp]
2. 如果需要查询某段时间的操作记录,startRow 是[user 反转][Long.Max_Value - 起始时间],stopRow 是[userId 反转][Long.Max_Value- 结束时间]
HBase 建表预分区:
创建HBase 表时,就预先根据可能的RowKey 划分出多个region 而不是默认的一个,从而可以将后续的读写操作负载均衡到不同的region 上,避免热点现象。