如何優雅的理解HBase和BigTable

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"學習 HBase 最難的地方在於要讓你的腦子真正理解它是什麼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HBase:Google BigTable 的開源實現"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們經常會把關係型數據庫(RDBMS,比如 MySQL)和 HBase 搞混,因爲在這兩個系統中都包含 table 和 base(HBase,Database)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這篇文章的目標是從概念上來說清楚 HBase 這個分佈式的數據存儲系統。讀完後,你應該可以很清楚的知道什麼情況下 HBase 更好,什麼情況下傳統的關係型數據庫更好。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"關於一些術語"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"幸運的是,"},{"type":"link","attrs":{"href":"https://static.googleusercontent.com/media/research.google.com/zh-CN//archive/bigtable-osdi06.pdf","title":""},"content":[{"type":"text","text":"Google 的 BigTable論文"}]},{"type":"text","text":"清楚的解釋了 BigTable 到底是什麼。下面是論文中數據模型章節的第一句話:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"BigTable 是一個稀疏的、分佈式的、可持久化的多維有序 map。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這個節骨眼上,我想給讀者一個機會,讓他們在讀到最後一行字時,能夠收集到他們腦殼裏的活動信息(這可能是個笑話,但我沒懂^v^)。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"論文中,繼續解釋如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"map 通過 rowKey,columnKey 和時間戳進行索引,map 中的每個值都是一個連續的字節數組。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注:rowKey 是記錄的主鍵,唯一標識一行記錄"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 "},{"type":"link","attrs":{"href":"https://hadoop.apache.org/","title":""},"content":[{"type":"text","text":"Hadoop"}]},{"type":"text","text":" 的官方文檔中,也對 HBase 的架構做了說明:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"HBase 使用了與 BigTable 非常類似的數據模型。用戶存儲數據行到特定的表中。一個數據行有一個可排序的 rowKey 和數量不定的列。這個表是稀疏的,只要用戶願意,這個表不同行可以有完全不同的列。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些話看起來相當費解,讓人摸不着頭腦,但如果你把這些話拆成一個個詞,意思就慢慢變的清晰了。我將按照以下的順序來討論這些詞:map,持久化,分佈式,有序的,多維的,稀疏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我發現循序漸進地建立一個思維框架要比一次性勾畫一個完整的系統更加容易。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"map"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從根本來上來,HBase/BigTable 是一個 map。map 在不同的編程語言中有不同的叫法,比如 PHP 中的 array,Python 的 dictionary,Ruby 中的 Hash,或者 JavaScript 中的 Object。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"維基百科上對於 map 的定義是:map 是一個抽象的數據類型,包含了一組 key 和一組 value,每個 key 關聯一個 value。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果用 JavaScript 的對象來表示 map,這裏有一個簡單的例子,其中所有的 value 都是字符串:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"json"},"content":[{"type":"text","text":"{\n \"zzzzz\" : \"woot\",\n \"xyz\" : \"hello\",\n \"aaaab\" : \"world\",\n \"1\" : \"x\",\n \"aaaaa\" : \"y\"\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"持久化的"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"持久化的意思僅僅是指你放進這個特殊 map 的數據會在你的程序執行完成之後被保存下來。它和其他的持久化存儲系統中持久化的概念沒有任何區別,比如存一個文件到一個文件系統。我們繼續..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"分佈式的"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HBase 和 BigTable 都建立在分佈式文件系統上,所以底層文件可以被分散存儲到不同的機器上。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HBase 可以存儲到 HDFS(Hadoop's Distributed File System)上,也可以存儲到 亞馬遜的 S3(Simple Storage Service)上,而 BigTable 使用的是 GFS(Google File System)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同一份數據會被複制存儲到多個節點上,類似於 RAID(獨立冗餘磁盤陣列,利用冗餘存儲的數據使損壞數據得以恢復,從而保護數據不丟失)系統中數據在磁盤上的複製存儲到多塊磁盤的方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這篇文章中,我們不關心具體使用哪種分佈式文件系統。重要的是,要理解這個文件系統是分佈式的,即使集羣中某個節點出現故障,也可以保證數據的完整性和安全性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"有序的"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"和其他大多數 map 的實現不同,HBase 和 BigTable 的鍵值對的順序嚴格按照字母順序來排列。所以 rowKey 爲 \"aaaaa\" 的下一條記錄的 rowKey 就是 \"aaaab\",並且會離 “zzzz” 非常遠。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"繼續看上面的那個 JSON 例子,排行序之後是下面這樣的:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"json"},"content":[{"type":"text","text":"{\n \"1\" : \"x\",\n \"aaaaa\" : \"y\",\n \"aaaab\" : \"world\",\n \"xyz\" : \"hello\",\n \"zzzzz\" : \"woot\"\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲這個系統是分佈式的,而且會越來越大,因此排序這個特性非常重要。這樣就會把 rowKey 相近的記錄放在一起,在某些情況下,如果你必須要掃描表(通常不推薦),那就能保證你需要獲取的記錄都在一塊。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼如何選擇 rowKey 就非常重要。比如說,一個表的 rowKey 就是域名。一個比較好的方式就是將域名進行反轉來作爲 rowKey(使用 “com.jimbojw.www”,而不要使用 “www.jimbojw.com”),這樣,同一個域名下的記錄就可以存儲在相鄰的位置。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"繼續上面的域名例子,rowKey 爲 “mail.jimbojw.com” 行應該與 “www.jimbojw.com” 行更近,而不是 “mail.xyz.com”,如果不把域名反轉存儲,就會發生這種情況。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"需要注意的是,在 HBase / BigTable 中,有序並不意味着值是有序的。除了 rowKey 以外,沒有任內容會被排序,在這點上和普通 map 的實現一致。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"多維的"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到目前爲止,我們還沒有提過任何關於"},{"type":"text","marks":[{"type":"strong"}],"text":"列"},{"type":"text","text":"的概念,而是將"},{"type":"text","marks":[{"type":"strong"}],"text":"表"},{"type":"text","text":"在概念上當做常規的 map。我是故意這麼做的。列和表、base 等詞一樣,都帶有傳統關係型數據庫多年的情感包袱。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然而,我發現把 HBase 理解爲一個多維的 map 會容易很多,map 的 map。給上面的 JSON 再加上一列:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"json"},"content":[{"type":"text","text":"{\n \"1\" : {\n \"A\" : \"x\",\n \"B\" : \"z\"\n },\n \"aaaaa\" : {\n \"A\" : \"y\",\n \"B\" : \"w\"\n },\n \"aaaab\" : {\n \"A\" : \"world\",\n \"B\" : \"ocean\"\n },\n \"xyz\" : {\n \"A\" : \"hello\",\n \"B\" : \"there\"\n },\n \"zzzzz\" : {\n \"A\" : \"woot\",\n \"B\" : \"1337\"\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上面的例子中你可以看到每個 key 都指向了另一個 map,其中包含着 A 和 B 兩個 key。在這裏,我們將最上面那層鍵值對稱爲"},{"type":"text","marks":[{"type":"strong"}],"text":"行"},{"type":"text","text":"。並且在 HBase / BigTable 的術語表中,A 和 B 的映射稱之爲"},{"type":"text","marks":[{"type":"strong"}],"text":"列族"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個表的列族在表創建的時候就會被創建好,而且後續修改很困難,添加一個新列族的開銷同樣也很大,所以在創建表的時候應當將後續會用到的所有列族創建好。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"好在一個列族可以有任意數量的列。稱之爲爲列限定符(qualifier)或者標籤(label)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是我們上面 JSON 例子的子集,這次加入了 qualifier 的維度:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"json"},"content":[{"type":"text","text":"{\n // ...\n \"aaaaa\" : {\n \"A\" : {\n \"foo\" : \"y\",\n \"bar\" : \"d\"\n },\n \"B\" : {\n \"\" : \"w\"\n }\n },\n \"aaaab\" : {\n \"A\" : {\n \"foo\" : \"world\",\n \"bar\" : \"domination\"\n },\n \"B\" : {\n \"\" : \"ocean\"\n }\n },\n // ...\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意在上面的兩行數據中,A 列族有兩列:foo 和 bar,B 列族只有一列,而且 qualifier 是一個空字符串。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當訪問 HBase / BigTable 中的數據時,你需要提供完整的列名:"},{"type":"codeinline","content":[{"type":"text","text":":"}]},{"type":"text","text":"。舉個例子,上面總共有三列,分別是:"},{"type":"codeinline","content":[{"type":"text","text":"A:foo"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"A:bar"}]},{"type":"text","text":" 和 "},{"type":"codeinline","content":[{"type":"text","text":"B:"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"列族雖然基本固定不變,但是列不是,來看下面的例子:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"json"},"content":[{"type":"text","text":"{\n // ...\n \"zzzzz\" : {\n \"A\" : {\n \"catch_phrase\" : \"woot\",\n }\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這個例子中,"},{"type":"codeinline","content":[{"type":"text","text":"zzzzz"}]},{"type":"text","text":" 行有一個列 A:catch_phrase。因爲每一行可以有任意數量的列,所以沒有內置方法可以從所有行中的所有列中查詢出一個列表。爲了獲取到那些信息,你需要做全表掃描。但是你可以查詢所有的列族,因爲它們是不變的(基本不變)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HBase / BigTable 中最後的一個維度是時間。所有數據默認通過時間戳(1970年以來的秒數)來表示版本,或者你也可以指定一個其他的整數。客戶端在插入數據的時候可以指定這個時間戳。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在最新的例子中,我們使用任意的整數來作爲版本標識:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"json"},"content":[{"type":"text","text":"{\n // ...\n \"aaaaa\" : {\n \"A\" : {\n \"foo\" : {\n 15 : \"y\",\n 4 : \"m\"\n },\n \"bar\" : {\n 15 : \"d\",\n }\n },\n \"B\" : {\n \"\" : {\n 6 : \"w\"\n 3 : \"o\"\n 1 : \"w\"\n }\n }\n },\n // ...\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每個列族可以自己指定一個 cell 中的數據可以保留多少個版本(cell 由 rowKey 和列進行標識)。在大多數情況下,應用會直接訪問一個 cell 中的數據,而不會指定一個時間戳(版本),HBase / BigTable 會直接返回最近版本(時間戳最大的那個)的數據,因爲它是按照時間倒序來存儲數據的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果應用在請求數據的時候指定了一個時間戳,那麼 HBase 就會返回時間戳小於或者等於指定時間戳的一個 cell 中的數據。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果查詢上面例子中的 HBase 表,查詢 "},{"type":"codeinline","content":[{"type":"text","text":"aaaaa A:foo"}]},{"type":"text","text":",就會返回 y,如果帶時間戳查詢 "},{"type":"codeinline","content":[{"type":"text","text":"aaaaa A:foo 10"}]},{"type":"text","text":",就會返回 m,如果查詢 "},{"type":"codeinline","content":[{"type":"text","text":"aaaaa A:foo 2"}]},{"type":"text","text":",就會返回 null。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"稀疏的"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後的一個關鍵詞是"},{"type":"text","marks":[{"type":"strong"}],"text":"稀疏的"},{"type":"text","text":"。就如上面所說的,一個給定的行在每個列族中可以有任意數量的列,0 或者任意大。行之間可以存在間隙,這也是另一種稀疏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你一直跟着本文在 map 的基礎上來理解 HBase / BigTable,而沒有與關係型數據庫(RDBMS)的概念混淆,這樣就很好了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"就這些了"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我希望上面說的那些可以幫助你在概念上理解 HBase 的數據模型是什麼樣的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"像往常一樣,我期待你們的想法、評論和建議。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}}],"text":"譯 / Rayjun"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文地址:https://dzone.com/articles/understanding-HBase-and-bigtab"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文首發於我的公衆號 Rayjun,歡迎關注公衆號,查看更多內容。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/af/aff0781fde8a41d0b23e298cc79993c7.jpeg","alt":null,"title":"歡迎關注微信公衆號","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章