HBase row key設(shè)計(jì)得不好、頻度各異的查詢類型,會(huì)導(dǎo)致熱門數(shù)據(jù)集中坐落在某幾個(gè)Region上,造成Region熱點(diǎn),集群負(fù)載不均衡。
能采取哪些解決方案,首先要明確訪問(wèn)模式,然后針對(duì)性優(yōu)化:
犧牲有序性,散列化row key。
如果不需要數(shù)據(jù)的有序性:
在row key首部增加原始row key的hash code,使數(shù)據(jù)均勻散列。
或者,將原始row key的MD5作為實(shí)際的row key。
對(duì)整個(gè)row key散列犧牲了有序性和根據(jù)前綴匹配進(jìn)行范圍掃描的能力。
為此,我們也可以對(duì)row key的各個(gè)部分,分別求取MD5,再拼接起來(lái),作為新的row key。這樣雖然仍不支持有序查詢,但是支持根據(jù)前綴匹配進(jìn)行范圍掃描——根據(jù)row key前綴的MD5,范圍掃描匹配的行,返回的是無(wú)序的數(shù)據(jù)。
不同訪問(wèn)模式的數(shù)據(jù),不要混雜在一張表里。
一個(gè)店鋪有哪些商品(row key是store id + product id) 和 一種商品有哪些店鋪在出售(row key是product id + store id),這兩種行,不要放在一張表里。
因?yàn)闃I(yè)務(wù)應(yīng)用的以上兩種查詢,其執(zhí)行頻率會(huì)有很大差別。如果這兩種行,在一張表里,其中一種更頻繁的查詢,自然會(huì)導(dǎo)致整張表中的一類row key成為熱點(diǎn)數(shù)據(jù)。
所以,要拆成兩張表,讓HBase有自由度獨(dú)立管理兩張表的region,獨(dú)立進(jìn)行region的拆分,保持負(fù)載均衡。
二級(jí)索引的熱點(diǎn)
我們根據(jù)查詢條件有哪些字段,構(gòu)建出二級(jí)索引,二級(jí)索引的值就是數(shù)據(jù)表的row key。那么對(duì)于經(jīng)常執(zhí)行的查詢條件,會(huì)集中訪問(wèn)二級(jí)索引的一部分行,就造成了二級(jí)索引的熱點(diǎn)區(qū)域。
舉個(gè)例子,以時(shí)間戳作為二級(jí)索引的key,支持時(shí)間范圍查找,那么寫入最新的數(shù)據(jù)、查詢最新的數(shù)據(jù),很容易導(dǎo)致最后一個(gè)region成為熱點(diǎn)。
為此,我們要影響二級(jí)索引的分片策略。我學(xué)習(xí)到了兩種方案:
方案一:salting
在以時(shí)間戳作為二級(jí)索引的例子中,計(jì)算:
···
salt = timestamp.hashCode() % region server個(gè)數(shù)
···
將以上salt作為時(shí)間戳二級(jí)索引的前綴。這樣打亂了原先的二級(jí)索引分片策略,使得負(fù)載均衡。
salt的取值范圍是[0, region server個(gè)數(shù))。 因此,查詢時(shí),我們的應(yīng)用邏輯,需要對(duì)每一個(gè)salt的取值,發(fā)起一次查詢請(qǐng)求,以salt值作為scan的row key的前綴。然后,將這些查詢的結(jié)果合并返回。
salt技術(shù)有一個(gè)問(wèn)題——當(dāng)region server數(shù)量變化時(shí),row key前綴中的salt沒(méi)有相應(yīng)更新。
方案二 by 360
360公司(趙建博)提出的二級(jí)索引方案:http://blog.csdn.net/dhtx_wzgl/article/details/49069081
其核心思想是,索引和數(shù)據(jù)保證在同一張表的同一個(gè)region里。這是通過(guò)將region的start row key作為索引row key的首部前綴實(shí)現(xiàn)的。索引和數(shù)據(jù),在同一行的不同column family中。當(dāng)region分裂以平衡負(fù)載時(shí),索引和數(shù)據(jù)共同分裂。二級(jí)索引的訪問(wèn)負(fù)載會(huì)和被索引的數(shù)據(jù)一樣均衡。因?yàn)閿?shù)據(jù)和它的二級(jí)索引**總是**在同一個(gè)region里的。
這種方案能處理region分裂、region server個(gè)數(shù)發(fā)生變化的情形。