hbase-region split剖析

? ? hbase region 切分是hbases水平擴(kuò)展一個(gè)重要因素,將一個(gè)region切分為兩個(gè)小region,并將切分后的region放在不同的節(jié)點(diǎn)上埋凯,以達(dá)到將負(fù)載進(jìn)行均衡到其他節(jié)點(diǎn)。下面從split的策略、split流程以及split策略的設(shè)置三方面進(jìn)行講解region split雾棺。

split策略

????region split的策略分為如下幾種DisabledRegionSplitPolicy、ConstantSizeRegionSplitPolicy衬浑、IncreasingToUpperBoundRegionSplitPolicy捌浩、DelimitedKeyPrefixRegionSplitPolicy?、KeyPrefixRegionSplitPolicy以及SteppingSplitPolicy工秩。本節(jié)將從split的觸發(fā)條件尸饺、split切分的切分點(diǎn)以及相應(yīng)核心源碼三個(gè)方面進(jìn)行講解进统。

DisabledRegionSplitPolicy

? ? 禁用split策略,使用該策略浪听,region不會(huì)進(jìn)行自動(dòng)切分螟碎,可以進(jìn)行人為手動(dòng)的切分。

ConstantSizeRegionSplitPolicy

? ? 固定大小自動(dòng)split策略迹栓,在hbase?0.94.0之前使用的默認(rèn)策略?掉分。

split觸發(fā)條件

????當(dāng)region中存在一個(gè)store的大小大于desiredMaxFileSize值則觸發(fā)split。

????當(dāng)創(chuàng)建表時(shí)指定了MAX_FILESIZE屬性克伊,則desiredMaxFileSize =?MAX_FILESIZE * (1+浮動(dòng)率)酥郭,浮動(dòng)率由配置hbase.hregion.max.filesize.jitter計(jì)算得出。

????當(dāng)創(chuàng)建表時(shí)未指定MAX_FILESIZE屬性愿吹,則desiredMaxFileSize = hbase.hregion.max.filesize*1+浮動(dòng)率)不从,浮動(dòng)率由配置hbase.hregion.max.filesize.jitter計(jì)算得出。

? ? 核心觸發(fā)條件源碼如下:

protected boolean shouldSplit() {

? boolean force = region.shouldForceSplit();

? boolean foundABigStore = false;

//(1)逐個(gè)計(jì)算region中的store是否有大于desiredMaxFileSize的犁跪。

? for (Store store : region.getStores()) {

? ? if ((!store.canSplit())) {

? ? ? return false;

? ? }

? ? if (store.getSize() > desiredMaxFileSize) {

? ? ? foundABigStore = true;

? ? }

? }

? return foundABigStore || force;

}

//desiredMaxFileSize的賦值邏輯

protected void configureForRegion(HRegion region) {

? super.configureForRegion(region);

? Configuration conf = getConf();

//(1)當(dāng)表指定了MAX_FILESIZE屬性椿息,則desiredMaxFileSize 為該屬性的值

? HTableDescriptor desc = region.getTableDesc();

? if (desc != null) {

? ? this.desiredMaxFileSize = desc.getMaxFileSize();

? }

//(2)?表未指定MAX_FILESIZE屬性,則desiredMaxFileSize = hbase.hregion.max.filesize配置的值

? if (this.desiredMaxFileSize <= 0) {

? ? this.desiredMaxFileSize = conf.getLong(HConstants.HREGION_MAX_FILESIZE,

? ? ? HConstants.DEFAULT_MAX_FILE_SIZE);

? }

//(3)將desiredMaxFileSize 乘以浮動(dòng)系數(shù)耘拇。

? double jitter = conf.getDouble("hbase.hregion.max.filesize.jitter", 0.25D);

? this.jitterRate = (RANDOM.nextFloat() - 0.5D) * jitter;

? long jitterValue = (long) (this.desiredMaxFileSize * this.jitterRate);

? // make sure the long value won't overflow with jitter

? if (this.jitterRate > 0 && jitterValue > (Long.MAX_VALUE - this.desiredMaxFileSize)) {

? ? this.desiredMaxFileSize = Long.MAX_VALUE;

? } else {

? ? this.desiredMaxFileSize += jitterValue;

? }

}

split觸發(fā)點(diǎn)計(jì)算

? ? 本策略的切分點(diǎn)為該region上最大的store中最大的hfile的中間block的startkey作為splitpoint撵颊,如果該splitpoint等于該hfile的startkey或等于endkey則不進(jìn)行分割。

? ? 核心源碼如下:

protected byte[] getSplitPoint() {

//(1)是否有指定切分點(diǎn)惫叛,指定了切分點(diǎn)則使用指定的切分點(diǎn)進(jìn)行切分倡勇。

? byte[] explicitSplitPoint = this.region.getExplicitSplitPoint();

? if (explicitSplitPoint != null) {

? ? return explicitSplitPoint;

? }

? List<Store> stores = region.getStores();

? byte[] splitPointFromLargestStore = null;

? long largestStoreSize = 0;

? for (Store s : stores) {

? ? //(2)獲取該store中最大的hfile文件,選取該hfile的midkey作為splitpoint嘉涌,如果midkey等于該hfile的startkey或等于endkey則返回null妻熊。

? ? byte[] splitPoint = s.getSplitPoint();

? ? long storeSize = s.getSize();

? ? if (splitPoint != null && largestStoreSize < storeSize) {

? ? ? splitPointFromLargestStore = splitPoint;

? ? ? largestStoreSize = storeSize;

? ? }

? }

? return splitPointFromLargestStore;

}

public final byte[] getSplitPoint() throws IOException {

? if (this.storefiles.isEmpty()) {

? ? return null;

? }

//(1)獲取store上最大storefile,獲取該storefile的中間key作為切分點(diǎn)

? return StoreUtils.getLargestFile(this.storefiles).getFileSplitPoint(this.kvComparator);

}

byte[] getFileSplitPoint(KVComparator comparator) throws IOException {

? if (this.reader == null) {

? ? LOG.warn("Storefile " + this + " Reader is null; cannot get split point");

? ? return null;

? }

//(1)獲取該hfile的中間block的startkey作為midkey仑最,由于并不會(huì)遍歷block扔役,只是從block的元數(shù)據(jù)中獲取startkey,所以這個(gè)過(guò)程基本不耗時(shí)警医。

? byte [] midkey = this.reader.midkey();

//(2)判斷獲取的midkey是否與該hfile的startkey或endkey相同亿胸,相同則返回null即不進(jìn)行切分。

? if (midkey != null) {

? ? KeyValue mk = KeyValue.createKeyValueFromKey(midkey, 0, midkey.length);

? ? byte [] fk = this.reader.getFirstKey();

? ? KeyValue firstKey = KeyValue.createKeyValueFromKey(fk, 0, fk.length);

? ? byte [] lk = this.reader.getLastKey();

? ? KeyValue lastKey = KeyValue.createKeyValueFromKey(lk, 0, lk.length);

? ? if (comparator.compareRows(mk, firstKey) == 0 || comparator.compareRows(mk, lastKey) == 0) {

? ? ? if (LOG.isDebugEnabled()) {

? ? ? ? LOG.debug("cannot split because midkey is the same as first or last row");

? ? ? }

? ? ? return null;

? ? }

? ? return mk.getRow();

? }

? return null;

}

IncreasingToUpperBoundRegionSplitPolicy

? ? 動(dòng)態(tài)調(diào)整觸發(fā)切分大小策略预皇,從hbase0.94.0開(kāi)始默認(rèn)的自動(dòng)切分策略侈玄,繼承自ConstantSizeRegionSplitPolicy。

split觸發(fā)條件

一:指定表在當(dāng)前region對(duì)應(yīng)的regionserver上的region個(gè)數(shù)等于0或大于100吟温,則返回desiredMaxFileSize作為觸發(fā)大小序仙。

二:指定表在當(dāng)前region對(duì)應(yīng)的regionserver上的region個(gè)數(shù)大于0并且小于100,則動(dòng)態(tài)修改split觸發(fā)的大小鲁豪,計(jì)算公式: min(desiredMaxFileSize潘悼,initialSize*tableregioncount*tableregioncount*tableregioncount)

1)initialSize(初始大新赏骸):

如果配置文件指定了hbase.increasing.policy.initial.size,則使用該值治唤。

如果配置文件未指定hbase.increasing.policy.initial.size棒动,則使用創(chuàng)建表時(shí)指定的MEMSTORE_FLUSHSIZE屬性值*2,未指定表的MEMSTORE_FLUSHSIZE屬性則使用hbase.hregion.memstore.flush.size*2肝劲。

2)tableregioncount:指定表在當(dāng)前region對(duì)應(yīng)的regionserver上有多少個(gè)region迁客。

例如:

前提:

????1.分割之后的子region任然在父region的regionserver上

? ? 2.未指定hbase.increasing.policy.initial.size和表屬性MEMSTORE_FLUSHSIZE,指定hbase.hregion.memstore.flush.size為256M辞槐。

? ??3.desiredMaxFileSize為10G

第一次分割的觸發(fā)大兄朗:256*2*1*1*1 = 256M

第二次分割的觸發(fā)大小:256*2*2*2*2 = 2048M

第三次分割的觸發(fā)大虚省:256*2*4*4*4 =16384M >desiredMaxFileSize(10G)卜范,取desiredMaxFileSize(10G)

之后所有分割的觸發(fā)大小都是desiredMaxFileSize(10G)。

? ? 核心源碼如下:

protected boolean shouldSplit() {

? boolean force = region.shouldForceSplit();

? boolean foundABigStore = false;

? // (1)獲取指定表在當(dāng)前region對(duì)應(yīng)的regionserver上的region個(gè)數(shù)

? int tableRegionsCount = getCountOfCommonTableRegions();

? // (2)獲取檢查大小

? long sizeToCheck = getSizeToCheck(tableRegionsCount);

? for (Store store : region.getStores()) {

? ? if (!store.canSplit()) {

? ? ? return false;

? ? }

? ? // Mark if any store is big enough

? ? long size = store.getSize();

? ? if (size > sizeToCheck) {

? ? ? LOG.debug("ShouldSplit because " + store.getColumnFamilyName() + " size=" + size

? ? ? ? ? ? ? ? + ", sizeToCheck=" + sizeToCheck + ", regionsWithCommonTable="

? ? ? ? ? ? ? ? + tableRegionsCount);

? ? ? foundABigStore = true;

? ? }

? }

? return foundABigStore | force;

}

//計(jì)算check size
protected long getSizeToCheck(final int tableRegionsCount) {

? // (1)region個(gè)數(shù)等于0或大于100鹿榜,則返回desiredMaxFileSize作為觸發(fā)大小

//? (2)region個(gè)數(shù)大于0并且小于100海雪,則動(dòng)態(tài)修改split觸發(fā)的大小,計(jì)算公式: min(desiredMaxFileSize舱殿,initialSize*tableregioncount*tableregioncount*tableregioncount)

? return tableRegionsCount == 0 || tableRegionsCount > 100

? ? ? ? ? ? ? getDesiredMaxFileSize()

? ? ? ? ? ? : Math.min(getDesiredMaxFileSize(),

? ? ? ? ? ? ? ? ? ? ? ? initialSize * tableRegionsCount * tableRegionsCount * tableRegionsCount);

}

split觸發(fā)點(diǎn)計(jì)算

? ? 和ConstantSizeRegionSplitPolicy策略的split觸發(fā)點(diǎn)計(jì)算一致奥裸。

KeyPrefixRegionSplitPolicy

? ? 根據(jù)key的前綴進(jìn)行切分,繼承自IncreasingToUpperBoundRegionSplitPolicy沪袭。

split觸發(fā)條件

? ? split觸發(fā)條件和IncreasingToUpperBoundRegionSplitPolicy一致湾宙。

split觸發(fā)點(diǎn)計(jì)算

? ??根據(jù)rowKey的指定長(zhǎng)度的前綴對(duì)數(shù)據(jù)進(jìn)行分組,以便于將這些數(shù)據(jù)分到相同的Region中冈绊,長(zhǎng)度指定由創(chuàng)建表時(shí)的KeyPrefixRegionSplitPolicy.prefix_length屬性指定(舊版本的屬性為:prefix_split_key_policy.prefix_length)?比如rowKey都是8位的侠鳄,指定前3位是前綴,那么前3位相同的rowKey在進(jìn)行region split的時(shí)候會(huì)分到相同的region中死宣。

? ? 核心源碼如下:

protected byte[] getSplitPoint() {

//(1)調(diào)用父類(lèi)的方法伟恶,獲取該region上最大的store中最大的hfile的中間block的startkey作為splitpoint。

? byte[] splitPoint = super.getSplitPoint();

//(2)指定的前綴長(zhǎng)度大于0毅该,則獲取splitPoint的指定長(zhǎng)度作為最后split的切分點(diǎn)博秫。? ?

? if (prefixLength > 0 && splitPoint != null && splitPoint.length > 0) {

? ? // group split keys by a prefix

? ? return Arrays.copyOf(splitPoint,

? ? ? ? Math.min(prefixLength, splitPoint.length));

? } else {

? ? return splitPoint;

? }

}

//獲取前綴長(zhǎng)度
protected void configureForRegion(HRegion region) {

? super.configureForRegion(region);

? prefixLength = 0;

//(1)獲取表的KeyPrefixRegionSplitPolicy.prefix_length屬性為前綴長(zhǎng)度,舊版的為prefix_split_key_policy.prefix_length屬性眶掌。

? String prefixLengthString = region.getTableDesc().getValue(

? ? ? PREFIX_LENGTH_KEY);

? if (prefixLengthString == null) {

? ? prefixLengthString = region.getTableDesc().getValue(PREFIX_LENGTH_KEY_DEPRECATED);

? ? if (prefixLengthString == null) {

? ? ? return;

? ? }

? }

? try {

? ? prefixLength = Integer.parseInt(prefixLengthString);

? } catch (NumberFormatException nfe) {

? ? return;

? }

......

}

DelimitedKeyPrefixRegionSplitPolicy

? ? 根據(jù)分割符獲取前綴進(jìn)行切分台盯,繼承自IncreasingToUpperBoundRegionSplitPolicy。? ??

split觸發(fā)條件

? ? split觸發(fā)條件和IncreasingToUpperBoundRegionSplitPolicy一致畏线。

split觸發(fā)點(diǎn)計(jì)算

? ? 與KeyPrefixRegionSplitPolicy的split觸發(fā)點(diǎn)計(jì)算類(lèi)似也是使用rowkey的前綴作為splitpoint,不同點(diǎn)在于KeyPrefixRegionSplitPolicy使用固定長(zhǎng)度作為前綴良价,而DelimitedKeyPrefixRegionSplitPolicy指定分隔字符進(jìn)行拆分作為前綴寝殴。分隔字符由表的DelimitedKeyPrefixRegionSplitPolicy.delimiter屬性指定蒿叠。

? ? 核心源碼如下:

protected byte[] getSplitPoint() {

//(1)調(diào)用父類(lèi)的方法,獲取該region上最大的store中最大的hfile的中間block的startkey作為splitpoint蚣常。

? byte[] splitPoint = super.getSplitPoint();

//(2)獲取分隔符之前的字符作為splitpoint市咽。

? if (splitPoint != null && delimiter != null) {

? ? int index = com.google.common.primitives.Bytes.indexOf(splitPoint, delimiter);

? ? if (index < 0) {

? ? ? LOG.warn("Delimiter " + Bytes.toString(delimiter) + "? not found for split key "

? ? ? ? ? + Bytes.toString(splitPoint));

? ? ? return splitPoint;

? ? }

? ? return Arrays.copyOf(splitPoint, Math.min(index, splitPoint.length));

? } else {

? ? return splitPoint;

? }

}

//獲取分隔符號(hào)
protected void configureForRegion(HRegion region) {

? super.configureForRegion(region);

//(1)獲取表的DelimitedKeyPrefixRegionSplitPolicy.delimiter屬性作為分隔符

? String delimiterString = region.getTableDesc().getValue(DELIMITER_KEY);

? if (delimiterString == null || delimiterString.length() == 0) {

? ? LOG.error(DELIMITER_KEY + " not specified for table " + region.getTableDesc().getTableName() +

? ? ? ". Using default RegionSplitPolicy");

? ? return;

? }

? delimiter = Bytes.toBytes(delimiterString);}?

SteppingSplitPolicy

? ? 分階段進(jìn)行固定大小分割,繼承自IncreasingToUpperBoundRegionSplitPolicy抵蚊。? ?

split觸發(fā)條件

? ? 當(dāng)只有一個(gè)region的時(shí)候施绎,使用initialSize作為觸發(fā)split大小,否則使用desiredMaxFileSize作為觸發(fā)split大小贞绳。initialSize和desiredMaxFileSize都在前面進(jìn)行過(guò)描述谷醉。

? ? 核心代碼如下:

protected long getSizeToCheck(final int tableRegionsCount) {

? return tableRegionsCount == 1? ? this.initialSize : getDesiredMaxFileSize();

}

split觸發(fā)點(diǎn)計(jì)算

? ? 和ConstantSizeRegionSplitPolicy策略的split觸發(fā)點(diǎn)計(jì)算一致。

split流程

????當(dāng)split發(fā)生的時(shí)候冈闭,創(chuàng)建的子region并不會(huì)馬上把所有的數(shù)據(jù)寫(xiě)入新的文件俱尼,而是創(chuàng)建一個(gè)小的鏈接引用文件指向分割點(diǎn)的頭部和尾部。這些引用文件會(huì)在compactions操作逐漸被清除萎攒。只有當(dāng)region沒(méi)有引用文件的時(shí)候才可以進(jìn)行split操作遇八。

????regionserver在split開(kāi)始和結(jié)束都會(huì)通知hmaster去更新.META表,使客戶端可以知道新的子region耍休,重新組織hdfs上的文件路徑刃永。

split操作的流程如下圖所示:

split流程

1.在zookeeper的/hbase/region-in-transition/region-name路徑下創(chuàng)建znode并標(biāo)記狀態(tài)為SPLITTING.。

2.hmaster監(jiān)聽(tīng)/hbase/region-in-transition/region-name路徑得知該region正在進(jìn)行split

3.regionserver在hdfs的父region路徑下創(chuàng)建.splits路徑

4.regionserver上關(guān)閉父region羊精,此時(shí)父region為offline斯够,當(dāng)有客戶端訪問(wèn)該父region時(shí)會(huì)報(bào)NotServingRegionException錯(cuò)誤。

5.在hdfs的.splits路徑下創(chuàng)建子region A园匹、B的路徑雳刺,然后split,其實(shí)就是在子region A裸违、B的路徑下創(chuàng)建引用文件指向父region的文件掖桦。

6.創(chuàng)建實(shí)際的子region路徑(上面創(chuàng)建的文件都是在父region路徑下),并把引用文件移動(dòng)到該路徑下供汛。

7.該regionserver向擁有.META表的regionserver發(fā)送一條put請(qǐng)求枪汪,修改該spliting region的狀態(tài)offline,并且添加子region的regionname怔昨。在這個(gè)時(shí)候并沒(méi)有單獨(dú)的子region信息雀久,當(dāng)客戶端scan表.META時(shí)知道到父region在split,但是不知道子region的信息趁舀。當(dāng)put請(qǐng)求成功后父region會(huì)進(jìn)行快速的split赖捌。

8.該regionserver并發(fā)的打開(kāi)兩個(gè)子region。

9.該regionserver將兩個(gè)子region的信息(host)發(fā)送到擁有.META表的regionserver矮烹,添加到.META表中越庇。這時(shí)兩個(gè)子region上線罩锐,客戶端可以知道這兩個(gè)子region并向這兩個(gè)子region發(fā)送請(qǐng)求÷卑Γ客戶端會(huì)緩存.META表中的數(shù)據(jù)涩惑,當(dāng)使用緩存中的數(shù)據(jù)進(jìn)行訪問(wèn)regionserver時(shí)出現(xiàn)問(wèn)題,客戶端會(huì)重新請(qǐng)求.META表中的內(nèi)容進(jìn)行緩存桑驱。

10.將步驟1創(chuàng)建的znode竭恬,將該狀態(tài)轉(zhuǎn)為split,這時(shí)split操作完成熬的,hmaster得知split操作完成痊硕。

11.完成上述步驟后,hdfs仍然包含引用文件指向父region悦析,這些引用文件會(huì)在子region進(jìn)行compactions時(shí)進(jìn)行移除寿桨。hmaster中的gc任務(wù)會(huì)周期的檢查子region是否還有引用父region的文件,沒(méi)有的話會(huì)將父region進(jìn)行移除强戴。

split策略設(shè)置

? ? 分為兩種方式進(jìn)行設(shè)置

1)全局方式亭螟,通過(guò)修改配置文件中的hbase.regionserver.region.split.policy屬性進(jìn)行指定策略,未指定策略的表都使用該配置指定的策略骑歹。

2)表級(jí)別预烙,通過(guò)指定表的屬性進(jìn)行指定split策略,hbase shell中案例如下:

create 'test1', { NAME => 'cf',COMPRESSION => 'GZ'}, {METADATA => {'SPLIT_POLICY' => 'org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy',MAX_FILESIZE=> '10737418240'}}

? ??今天的分享就到這道媚,有看不明白的地方一定是我寫(xiě)的不夠清楚扁掸,所有歡迎提任何問(wèn)題以及改善方法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末最域,一起剝皮案震驚了整個(gè)濱河市谴分,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌镀脂,老刑警劉巖牺蹄,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異薄翅,居然都是意外死亡沙兰,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)翘魄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鼎天,“玉大人,你說(shuō)我怎么就攤上這事暑竟≌洌” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)绩鸣。 經(jīng)常有香客問(wèn)我怀大,道長(zhǎng),這世上最難降的妖魔是什么呀闻? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮潜慎,結(jié)果婚禮上捡多,老公的妹妹穿的比我還像新娘。我一直安慰自己铐炫,他們只是感情好垒手,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著倒信,像睡著了一般科贬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鳖悠,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天榜掌,我揣著相機(jī)與錄音,去河邊找鬼乘综。 笑死憎账,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卡辰。 我是一名探鬼主播胞皱,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼九妈!你這毒婦竟也來(lái)了反砌?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤萌朱,失蹤者是張志新(化名)和其女友劉穎宴树,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體嚷兔,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡森渐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冒晰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片同衣。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖壶运,靈堂內(nèi)的尸體忽然破棺而出耐齐,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布埠况,位于F島的核電站耸携,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏辕翰。R本人自食惡果不足惜夺衍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喜命。 院中可真熱鬧沟沙,春花似錦、人聲如沸壁榕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)牌里。三九已至颊咬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間牡辽,已是汗流浹背喳篇。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留催享,地道東北人杭隙。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像因妙,于是被迫代替她去往敵國(guó)和親痰憎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359