Hbase使用Coprocessor構(gòu)建二級索引

最近在學習Hbase二級索引的構(gòu)建,雖然網(wǎng)上方案挺多瑞侮,代碼也并不復(fù)雜娜睛,但還是花了不少時間苞轿,主要是集群環(huán)境的調(diào)試踩了不少坑,畢竟新手... 這里將整個過程記錄下來金句,以便日后學習之用檩赢。

為什么需要二級索引

Hbase默認只支持對行鍵的索引,那么如果需要針對其它的列來進行查詢违寞,就只能全表掃描了贞瞒。表如果較大的話,代價是不可接受的趁曼,所以要提出二級索引的方案憔狞。網(wǎng)上的實現(xiàn)方法很多,華為彰阴,360等公司都有自己的方案,其中華為的已經(jīng)開源拍冠,但是貌似對源碼改動較大尿这,新手不容易接受,所以沒有選擇它們庆杜。而其它的像利用Phoenix射众,solr等外部框架構(gòu)建索引對Hbase的學習并沒有太大的幫助。綜上所述晃财,我使用了Hbase自帶的Cprocessor(協(xié)處理器)來實現(xiàn)叨橱。

Coprocessor

有關(guān)協(xié)處理器的講解,Hbase官方文檔是最好的断盛,這里大體說一下它的作用與使用方法罗洗。

  1. Coprocessor提供了一種機制可以讓開發(fā)者直接在RegionServer上運行自定義代碼來管理數(shù)據(jù)。
    通常我們使用get或者scan來從Hbase中獲取數(shù)據(jù)钢猛,使用Filter過濾掉不需要的部分伙菜,最后在獲得的數(shù)據(jù)上執(zhí)行業(yè)務(wù)邏輯。但是當數(shù)據(jù)量非常大的時候命迈,這樣的方式就會在網(wǎng)絡(luò)層面上遇到瓶頸贩绕。客戶端也需要強大的計算能力和足夠大的內(nèi)存來處理這么多的數(shù)據(jù)壶愤,客戶端的壓力就會大大增加淑倾。但是如果使用Coprocessor,就可以將業(yè)務(wù)代碼封裝征椒,并在RegionServer上運行娇哆,也就是數(shù)據(jù)在哪里,我們就在哪里跑代碼,這樣就節(jié)省了很大的數(shù)據(jù)傳輸?shù)木W(wǎng)絡(luò)開銷迂尝。
  2. Coprocessor有兩種:Observer和Endpoint
    EndPoint主要是做一些計算用的脱茉,比如計算一些平均值或者求和等等。而Observer的作用類似于傳統(tǒng)關(guān)系型數(shù)據(jù)庫的觸發(fā)器垄开,在一些特定的操作之前或者之后觸發(fā)琴许。學習過Spring的朋友肯定對AOP不陌生,想象一下AOP是怎么回事溉躲,就會很好的理解Observer了榜田。Observer Coprocessor在一個特定的事件發(fā)生前或發(fā)生后觸發(fā)。在事件發(fā)生前觸發(fā)的Coprocessor需要重寫以pre作為前綴的方法锻梳,比如prePut箭券。在事件發(fā)生后觸發(fā)的Coprocessor使用方法以post作為前綴,比如postPut疑枯。
    Observer Coprocessor的使用場景如下:
    2.1. 安全性:在執(zhí)行Get或Put操作前辩块,通過preGet或prePut方法檢查是否允許該操作;
    2.2. 引用完整性約束:HBase并不直接支持關(guān)系型數(shù)據(jù)庫中的引用完整性約束概念荆永,即通常所說的外鍵废亭。但是我們可以使用Coprocessor增強這種約束。比如根據(jù)業(yè)務(wù)需要具钥,我們每次寫入user表的同時也要向user_daily_attendance表中插入一條相應(yīng)的記錄豆村,此時我們可以實現(xiàn)一個Coprocessor,在prePut方法中添加相應(yīng)的代碼實現(xiàn)這種業(yè)務(wù)需求骂删。
    2.3. 二級索引:可以使用Coprocessor來維持一個二級索引掌动。正是我們需要的

索引設(shè)計思想

關(guān)鍵部分來了,既然Hbase并沒有提供二級索引宁玫,那如何實現(xiàn)呢粗恢?先看下面這張圖

1.png

我們的需求是找出滿足cf1:col2=c22這條記錄的cf1:col1的值,實現(xiàn)方法如圖撬统,首先根據(jù)cf1:col2=c22查找到該記錄的行鍵适滓,然后再通過行健找到對應(yīng)的cf1:col1的值。其中第二步是很容易實現(xiàn)的恋追,因為Hbase的行鍵是有索引的凭迹,那關(guān)鍵就是第一步,如何通過cf1:col2的值找到它對應(yīng)的行鍵苦囱。很容易想到建立cf1:col2的映射關(guān)系嗅绸,即將它們提取出來單獨放在一張索引表中,原表的值作為索引表的行鍵撕彤,原表的行鍵作為索引表的值鱼鸠,這就是Hbase的倒排索引的思想猛拴。

思想有了,工具有了Coprocessor蚀狰,就開始具體實現(xiàn)了愉昆。我們想實現(xiàn)的功能就是每在原表插入一條數(shù)據(jù),就相應(yīng)的在索引表中也插入一條數(shù)據(jù)麻蹋。也就是在Put數(shù)據(jù)到原表之前/之后使用Coprocessor提供的prePut/postPut方法向索引表中插入你想要的數(shù)據(jù)跛溉!

具體編碼和排坑過程

我使用的環(huán)境

工具 版本
hadoop 2.7.1
Hbase 1.2.4
zookeeper 3.4.9
Ubuntu 14.04
IDEA 2017.1.2

Hbase提供了JavaAPI以實現(xiàn)增刪改查,網(wǎng)上很多教程扮授,大家可以自己去找芳室,或者從我的github中down也行,我們直接來看Coprocessor中的代碼怎么寫

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

/**
 * Created by cwj on 17-10-26.
 *
 */
public class IndexObserver extends BaseRegionObserver {

    private static final byte[] TABLE_NAME = Bytes.toBytes("index_name_users");
    private static final byte[] COLUMN_FAMILY = Bytes.toBytes("personalDet");
    private static final byte[] COLUMN = Bytes.toBytes("name");

    private Configuration configuration = HBaseConfiguration.create();
    
    @Override
    public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability)
            throws IOException {

        HTable indexTable = new HTable(configuration, TABLE_NAME);

        List<Cell> cells = put.get(COLUMN_FAMILY, COLUMN);
        Iterator<Cell> cellIterator = cells.iterator();
        while (cellIterator.hasNext()) {
            Cell cell = cellIterator.next();
            Put indexPut = new Put(CellUtil.cloneValue(cell));
            indexPut.add(COLUMN_FAMILY, COLUMN, CellUtil.cloneRow(cell));
            indexTable.put(indexPut);
        }
    }
}

這里用的是Hbase官網(wǎng)在Coprocessor給的那個例子刹勃,表結(jié)構(gòu)是這樣的:

2.png

給personalDet:name列建立索引堪侯,代碼本身很簡單,大體說說吧荔仁,RegionObserver是基本接口伍宦,BaseRegionObserver是其實現(xiàn)類,一般繼承這個類就行了乏梁,然后在prePut方法中向索引表中插入數(shù)據(jù)雹拄。可以看到prePut方法的入?yún)⒂幸粋€put對象掌呜,這個對象就是你在主表插入數(shù)據(jù)時的那個put對象,所以你可以通過這個對象拿到之前主表插入的數(shù)據(jù)坪哄,這樣就可以實現(xiàn)自己的需求了质蕉。

之后將這個工程打成jar包(可以用IDEA自帶的打包方式,或者maven-assembly-plugin插件也行)翩肌,pom文件有這兩個依賴就行了

<dependencies>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>1.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>1.2.4</version>
        </dependency>
    </dependencies>
Coprocessor加載方式

要使用Coprocessor模暗,就需要先完成對其的裝載。這可以靜態(tài)實現(xiàn)(通過HBase配置文件)念祭,也可以動態(tài)完成(通過shell或Java API)兑宇。

靜態(tài)裝載和卸載Coprocessor

按以下如下步驟可以靜態(tài)裝載自定義的Coprocessor。需要注意的是粱坤,如果一個Coprocessor是靜態(tài)裝載的隶糕,要卸載它就需要重啟HBase。
靜態(tài)裝載步驟如下:

  1. 在hbase-site.xml中使用<property>標簽定義一個Coprocessor站玄。<property>的子元素<name>的值只能從下面三個中選一個:
    hbase.coprocessor.region.classes 對應(yīng) RegionObservers和Endpoints枚驻;
    hbase.coprocessor.wal.classes 對應(yīng) WALObservers;
    hbase.coprocessor.master.classes 對應(yīng)MasterObservers株旷。
    而<value>標簽的內(nèi)容則是自定義Coprocessor的全限定類名再登。
    下面演示了如何裝載一個自定義Coprocessor(這里是在SumEndPoint.java中實現(xiàn)的),需要在每個RegionServer的hbase-site.xml中創(chuàng)建如下的記錄:
<property>
    <name>hbase.coprocessor.region.classes</name>
    <value>org.cwj.hbase.coprocessor.observer.IndexObserver</value>
</property>

如果要裝載多個類,類名需要以逗號分隔锉矢。HBase會使用默認的類加載器加載配置中的這些類梯嗽,因此需要將相應(yīng)的jar文件上傳到HBase服務(wù)端的類路徑下。
使用這種方式加載的Coprocessor將會作用在HBase所有表的全部Region上沽损,因此這樣加載的Coprocessor又被稱為系統(tǒng)Coprocessor灯节。在Coprocessor列表中第一個Coprocessor的優(yōu)先級值為Coprocessor.Priority.SYSTEM,其后的每個Coprocessor的值將會按序加一(這意味著優(yōu)先級會減降低缠俺,因為優(yōu)先級是按整數(shù)的自然順序降序排列的)显晶。
當調(diào)用配置的Observer Coprocessor時,HBase將會按照優(yōu)先級順序依次調(diào)用它們的回調(diào)方法壹士。

  1. 將代碼放到HBase的類路徑下磷雇。一個簡單的方法是將封裝好的jar(包括代碼和依賴)放到HBase安裝路徑下的/lib目錄中。
  2. 重啟HBase躏救。

靜態(tài)卸載的步驟如下:

  1. 移除在hbase-site.xml中的配置唯笙。
  2. 重啟HBase。
  3. 這一步是可選的盒使,將上傳到HBase類路徑下的jar包移除崩掘。
動態(tài)裝載Coprocessor

動態(tài)裝載Coprocessor的一個優(yōu)勢就是不需要重啟HBase。不過動態(tài)裝載的Coprocessor只是針對某個表有效少办。因此苞慢,動態(tài)裝載的Coprocessor又被稱為表級Coprocessor。
此外英妓,動態(tài)裝載Coprocessor是對表的一次schema級別的調(diào)整挽放,因此在動態(tài)裝載Coprocessor時,目標表需要離線(disable)蔓纠。
動態(tài)裝載Coprocessor有兩種方式:通過HBase Shell和通過Java API辑畦。不管選擇哪一種,都要先將打好的jar包上傳到HDFS中

  1. Hbase Shell裝載/卸載
    1.1 先將表disable
    disable 'users'
    1.2 使用類似如下命令裝載
alter 'users', METHOD => 'table_att', 'Coprocessor'=>'hdfs://<namenode>:<port>/
user/<hadoop-user>/coprocessor.jar| org.cwj.hbase.Coprocessor.IndexObserver|1073741823|
arg1=1,arg2=2' 

簡單解釋下這個命令腿倚。這條命令在一個表的table_att中添加了一個新的屬性“Coprocessor”纯出。使用的時候Coprocessor會嘗試從這個表的table_attr中讀取這個屬性的信息。這個屬性的值用管道符“|”分成了四部分:
文件路徑:文件路徑中需要包含Coprocessor的實現(xiàn)敷燎,并且對所有的RegionServer都是可達的暂筝。這個路徑可以是每個RegionServer的本地磁盤路徑,也可以是HDFS上的一個路徑硬贯。通常建議是將Coprocessor實現(xiàn)存儲到HDFS乖杠。HBASE-14548允許使用一個路徑中包含的所有的jar,或者是在路徑中使用通配符來指定某些jar澄成,比如:hdfs://<namenode>:<port>/user/<hadoop-user>/ 或者 hdfs://<namenode>:<port>/user/<hadoop-user>/*.jar胧洒。需要注意的是如果是用路徑來指定要加載的Coprocessor畏吓,這個路徑下的所有jar文件都會被加載,不過該路徑下的子目錄中的jar不會被加載卫漫。另外菲饼,如果要用路徑指定Coprocessor時,就不要再使用通配符了列赎。這些特性在Java API中也得到了支持宏悦。
類名:Coprocessor的全限定類名。
優(yōu)先級:一個整數(shù)包吝。HBase將會使用優(yōu)先級來決定在同一個位置配置的所有Observer Coprocessor的執(zhí)行順序饼煞。這個位置可以留白,這樣HBase將會分配一個默認的優(yōu)先級诗越。
參數(shù)(可選的):這些值會被傳遞給要使用的Coprocessor實現(xiàn)砖瞧。這個項是可選的,可以不用填
  1.3 enable這個表
  enable 'users'
  1.4 查看是否加載成功
  describe 'users'

3.png

裝載過程就是這樣嚷狞,卸載過程和裝載大體一樣的块促,也是先將表disable,卸載之后在重新enable
卸載方式如下:

hbase> alter 'users', METHOD => 'table_att_unset', NAME => 'coprocessor$1'
  1. 使用JavaAPI裝載/卸載
    Hbase版本前后經(jīng)歷了很大的變化,JavaAPI也是床未,有些方法在這個版本過期了竭翠,下個版本可能又會拿回來,所以代碼根據(jù)自己的版本來薇搁,我這里提供的代碼在1.2.4下是可以用的
public class CoprocessorUtilTest {
    private String tableName;
    private String jarPath;
    private Class className;

    private Logger logger = LogManager.getLogger(CoprocessorUtilTest.class);

    @Before
    public void setUp() throws Exception {
        tableName = "users";
        jarPath = "hdfs://os-1:9000/HbaseTest.jar";
        className = ObserverExample.class;
//        className = SumEndPoint.class;
//        className = IndexObserver.class;
    }

    @Test
    public void loadCoprocessor() throws Exception {
        logger.info("load coprocessor...");

        TableName tName = TableName.valueOf(tableName);
        Path path = new Path(jarPath);
        Configuration configuration = HBaseConfiguration.create();
        Connection connection = ConnectionFactory.createConnection(configuration);
        Admin admin = connection.getAdmin();
        admin.disableTable(tName);
        HTableDescriptor hTableDescriptor = new HTableDescriptor(tName);

        HColumnDescriptor columnFamily1 = new HColumnDescriptor("personalDet");
        columnFamily1.setMaxVersions(3);
        hTableDescriptor.addFamily(columnFamily1);
        HColumnDescriptor columnFamily2 = new HColumnDescriptor("salaryDet");
        columnFamily2.setMaxVersions(3);
        hTableDescriptor.addFamily(columnFamily2);

        hTableDescriptor.addCoprocessor(className.getCanonicalName(), path, Coprocessor.PRIORITY_USER, null);

        admin.modifyTable(tName, hTableDescriptor);
        admin.enableTable(tName);

        logger.info("load coprocessor successful!");
    }

    @Test
    public void unloadCoprocessor() throws Exception {
        logger.info("unload coprocessor...");
        TableName tName = TableName.valueOf(tableName);
        Configuration configuration = HBaseConfiguration.create();
        Connection connection = ConnectionFactory.createConnection(configuration);
        Admin admin = connection.getAdmin();
        admin.disableTable(tName);
        HTableDescriptor hTableDescriptor = new HTableDescriptor(tName);

        HColumnDescriptor columnFamily1 = new HColumnDescriptor("personalDet");
        columnFamily1.setMaxVersions(3);
        hTableDescriptor.addFamily(columnFamily1);
        HColumnDescriptor columnFamily2 = new HColumnDescriptor("salaryDet");
        columnFamily2.setMaxVersions(3);
        hTableDescriptor.addFamily(columnFamily2);

        hTableDescriptor.removeCoprocessor(className.getCanonicalName());
        admin.modifyTable(tName, hTableDescriptor);
        admin.enableTable(tName);
        logger.info("unload coprocessor successful!");
    }
}

好了斋扰,這里有幾個注意的地方

  1. 首先遠程連接Hbase有兩種方式,第一是在客戶端代碼中設(shè)置地址:
conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum", "xxx.xxx.x.xx");
        conf.set("hbase.zookeeper.property.clientPort", "2181");

我的環(huán)境使用這種方式一直提示無法連接到Hbase啃洋,不知道什么原因褥实,這里推薦第二種方式,就是將的服務(wù)器的Hbase的配置文件hbase-site.xml,core-site.xml復(fù)制到客戶端的src目錄下裂允,這樣在加載的時候,首先它會從本地的配置文件讀取地址哥艇,這樣就可以連接到你的遠程Hbase了绝编。

  1. 表中有幾個列族就一定要new幾個HColumnDescriptor出來,當時以為只在personalDet上建立索引貌踏,所以就只new了一個出來十饥,果然沒有成功
  2. 這個問題就有點弱智了,看這句代碼
hTableDescriptor.addCoprocessor(className.getCanonicalName(), path, Coprocessor.PRIORITY_USER, null);

第一個入?yún)⒁欢ㄊ且粋€Class對象.getCanonicalName()祖乳,剛開始傻叉的String classname逗堵。。眷昆。關(guān)于這個問題蜒秤,我在另一篇帖子中說明了java中幾種獲取class的方式汁咏,有興趣請看這里
這個問題本身很弱智,但是引發(fā)的后果還是很嚴重的作媚,那就是加載之后攘滩,集群直接崩了,幾個RegionServer全部dead了纸泡,重啟之后也一樣漂问,10S之內(nèi),相繼掛掉女揭。蚤假。。毫無運維經(jīng)驗的我吧兔,看到這種情況一臉懵比磷仰,硬著頭皮翻log,發(fā)現(xiàn)這個錯誤 java.lang.RuntimeException: HRegionServer Aborted,各種搜索發(fā)現(xiàn)掩驱,默認當加載了錯誤的Coprocessor之后芒划,會導(dǎo)致RegionServer掛掉,原來如此欧穴,那就不慌了民逼,解決方法是修改hbase-site.xml文件

<property>
    <name>hbase.coprocessor.abortonerror</name>
    <value>false</value>
</property>

關(guān)于這個參數(shù),后續(xù)還會對它進行說明涮帘,這里設(shè)為false是指拼苍,哪怕加載了錯誤的Coprocessor,集群也不會崩潰
好了调缨,集群重新起來了疮鲫,修改了代碼,成功加載上去了弦叶,興沖沖的插入一條數(shù)據(jù)試試俊犯,然而再次懵比,索引表中并沒有插入相應(yīng)的索引數(shù)據(jù)

  1. 這又是什么鬼問題伤哺?log里并沒有什么錯誤燕侠,在Coprocessor中加了log輸出,發(fā)現(xiàn)并沒有打印出來立莉,看來是方法根本沒有被調(diào)用绢彤。又是一頓搜索,問題還是出在上面說的那個參數(shù)上蜓耻,
    hbase.coprocessor.abortonerror:如果coprocessor加載失敗或者初始化失敗或者拋出Throwable對象茫舶,則主機退出。設(shè)置為false會讓系統(tǒng)繼續(xù)運行刹淌,但是coprocessor的狀態(tài)會不一致饶氏,所以一般debug時才會設(shè)置為false讥耗,默認是true;.說的很清楚了嚷往,雖然我之后上傳了很多個版本的coprocessor葛账,但是在集群重啟之前它一直沿用著最早那個版本。將參數(shù)再調(diào)整為true,重新上傳jar包皮仁,重啟集群籍琳,這下沒問題了,索引表中出現(xiàn)了數(shù)據(jù)
  2. 還有一個問題贷祈,具體則怎么引起的給忘了趋急,錯誤log好像是說hbase.table.sanity.checks的問題,解決方法依然是更改配置文件
<property>
        <name>hbase.table.sanity.checks</name>
        <value>false</value>
 </property>

總結(jié)

代碼其實并不復(fù)雜势誊,但是集群的調(diào)試最麻煩呜达,沒事就去翻翻log,然后在根據(jù)錯誤找原因粟耻,今天就到此為止查近,之后再深入學習Hbase!
學習過程中參考的博客資料都在下面了
http://blog.itpub.net/12129601/viewspace-1690668/
http://blog.csdn.net/wwwxxdddx/article/details/50914667
http://blog.csdn.net/u013063153/article/details/72374974
http://blog.csdn.net/u011750989/article/details/50602373
http://blog.csdn.net/carl810224/article/details/52224441
http://hbasefly.com/2016/09/08/hbase-rit/
http://blog.itpub.net/12129601/viewspace-1690668/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挤忙,一起剝皮案震驚了整個濱河市霜威,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌册烈,老刑警劉巖戈泼,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赏僧,居然都是意外死亡大猛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門淀零,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挽绩,“玉大人,你說我怎么就攤上這事驾中“埃” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵哀卫,是天一觀的道長。 經(jīng)常有香客問我撬槽,道長此改,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任侄柔,我火速辦了婚禮共啃,結(jié)果婚禮上占调,老公的妹妹穿的比我還像新娘。我一直安慰自己移剪,他們只是感情好究珊,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纵苛,像睡著了一般剿涮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上攻人,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天取试,我揣著相機與錄音,去河邊找鬼怀吻。 笑死瞬浓,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蓬坡。 我是一名探鬼主播猿棉,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼屑咳!你這毒婦竟也來了萨赁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤乔宿,失蹤者是張志新(化名)和其女友劉穎位迂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體详瑞,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡坝橡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年计寇,在試婚紗的時候發(fā)現(xiàn)自己被綠了番宁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖茎截,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情榆浓,我是刑警寧澤撕攒,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布打却,位于F島的核電站柳击,受9級特大地震影響捌肴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜秽五,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一坦喘、第九天 我趴在偏房一處隱蔽的房頂上張望瓣铣。 院中可真熱鬧棠笑,春花似錦禽绪、人聲如沸印屁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至牺勾,卻和暖如春阵漏,著一層夾襖步出監(jiān)牢的瞬間履怯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蝗柔,地道東北人民泵。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓栈妆,卻偏偏與公主長得像鳞尔,于是被迫代替她去往敵國和親铅檩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 該文檔是用Hbase默認配置文件生成的,文件源是Hbase-default.xml hbase.rootdir 這...
    我是嘻哈大哥閱讀 4,762評論 0 7
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)额衙,斷路器窍侧,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 入門指南 1. 簡介 Quickstart會讓你啟動和運行一個單節(jié)點單機HBase伟件。 2. 快速啟動 – 單點HB...
    和心數(shù)據(jù)閱讀 4,570評論 1 41
  • 摘自:http://debugo.com/hbase-params/ 通用和master配置hbase.rootd...
    wangliang938閱讀 2,717評論 1 5
  • 早晨起床 陽光灑滿窗口 伸著懶腰發(fā)呆(′-ι_-`) 又是美好的一天扒捶怠嗓袱! 感謝床頭那只泰迪熊 陪我度過無數(shù)個日日夜...
    foorghT閱讀 139評論 0 0