MongoDB 復(fù)制集那點事兒

何以高可用?

我們以前用Mysql的時候水醋,經(jīng)常是一臺服務(wù)器走天下,如果只是用于學(xué)習(xí)蒜哀,是沒有問題的斩箫,但是在生產(chǎn)環(huán)境中,這樣的風(fēng)險是很大的撵儿,如果服務(wù)器因為網(wǎng)絡(luò)原因或者崩潰了乘客,就會導(dǎo)致數(shù)據(jù)庫一段時間了不可用,這樣的體驗很不好淀歇。

那么應(yīng)該怎么辦呢易核?既然一臺機器不行,我就多上幾臺機器總可以了吧浪默,比如我上個兩臺牡直,讓他們互為主備,相互同步數(shù)據(jù)纳决。想到這里我就只想說一個字井氢,穩(wěn)。

其實redis,mongodb,kafka等分布式應(yīng)用基本上都是這樣的思想

MongoDB也差不多是這樣的思想岳链。它通過復(fù)制集來解決這個問題,MongoDB復(fù)制集由一組Mongod進程組成,包含一個Primary節(jié)點和多個Secondary節(jié)點劲件,Mongodb Driver(客戶端)的所有數(shù)據(jù)都寫入Primary掸哑,Secondary從Primary同步寫入的數(shù)據(jù),以保持復(fù)制集內(nèi)所有成員存儲相同的數(shù)據(jù)集零远,提供數(shù)據(jù)的高可用苗分。

要想成為primary節(jié)點,你必須保證大多數(shù)節(jié)點都同意才行,大多數(shù)的節(jié)點就是副本中一半以上的成員牵辣。

成員總數(shù) 大多數(shù) 容忍失敗數(shù)
1 1 0
2 2 0
3 2 1
4 3 1
5 3 2
6 4 2
7 4 3

為什么要要求大多數(shù)呢摔癣?其實是為了避免出現(xiàn)兩個primary節(jié)點。比如一個五個節(jié)點的復(fù)制集纬向,其中3個成員不可用择浊,剩下的2個仍然正常工作。這兩個工作的節(jié)點由于不能滿足復(fù)制集大多數(shù)的要求(這個例子中要求要有3個節(jié)點才是大多數(shù))逾条,所以他們無法選擇主節(jié)點琢岩,即使其中有一個節(jié)點是primary節(jié)點,當(dāng)它注意到它無法獲取大多數(shù)節(jié)點的支持時师脂,它就會退位担孔,成為備份節(jié)點江锨。

如果讓這兩個節(jié)點可以選出primary節(jié)點,問題是另外3個節(jié)點可能不是真正掛了糕篇,而只是網(wǎng)絡(luò)不可達而已啄育。另外3個節(jié)點就一定可以選擇出primary節(jié)點,這樣就存在了兩個primary節(jié)點了拌消。
所以要求大多數(shù)就可以避免產(chǎn)生兩個primary節(jié)點的問題挑豌。

如果MongoDB副本集可以擁有多個primary節(jié)點,那么就會面臨寫入沖突的問題,在支持多線程寫入的系統(tǒng)中解決沖突的方式有手動解決和讓操作系統(tǒng)任選一個這兩種方式拼坎,但是這兩種方式都不易實現(xiàn)浮毯,無法保證寫入的數(shù)據(jù)不被其他節(jié)點修改,因此mongodb只支持單一的primary節(jié)點泰鸡,這樣使得開發(fā)更容易债蓝。

當(dāng)一個備份節(jié)點無法與主節(jié)點連通時,它會聯(lián)系并請求其他副本集成員將自己選舉為主節(jié)點盛龄,其他成員會做幾項理性的檢查:自身是否能夠與主節(jié)點連通饰迹?希望被選舉為主節(jié)點的備份節(jié)點的數(shù)據(jù)是否最新?有沒有其他更高優(yōu)先級的成員可以被選舉為主節(jié)點余舶?
如果競選節(jié)點成員能夠得到大多數(shù)投票啊鸭,就會成為主節(jié)點。但是一旦大多數(shù)成員中只有一個否決了本次選舉匿值,選舉就會取消赠制。

在日志中可以看到得票數(shù)為比較大的負數(shù)的情況,因為一張否決票相當(dāng)于10000張贊成票挟憔。如果有2張贊成票钟些,2張否決票,那么選舉結(jié)果就是-19998绊谭,依此類推政恍。

配置選項

我們一般在部署的時候,副本集節(jié)點個數(shù)至少是3個(因為它允許1個失敗),這也就意味著數(shù)據(jù)要被復(fù)制三份达传。


1-primary-2-secondary.png

仲裁者(arbiter)

很多人的應(yīng)用程序使用量比較小篙耗,不想保存三份數(shù)據(jù),只想要保存兩份就行了宪赶,保存第三份純粹是浪費宗弯。對于這種部署MongoDB也是支持的。它有一種特殊的成員叫做仲裁者(arbiter)搂妻,它唯一的作用就是參與選舉罕伯,它既不保存數(shù)據(jù)也不為客戶端提供服務(wù),只是為了幫助只有兩個成員的副本集滿足大多數(shù)這個條件而已叽讳。

arbiter.png

仲裁者其實也是有缺點的追他。如果真有一個節(jié)點掛了(數(shù)據(jù)無法恢復(fù)),另一個成員稱為主節(jié)點坟募。為了數(shù)據(jù)安全,就需要一個新的備份節(jié)點邑狸,并且將主節(jié)點的數(shù)據(jù)備份到備份節(jié)點懈糯。復(fù)制數(shù)據(jù)會對服務(wù)器造成很大的壓力,會拖慢應(yīng)用程序单雾。相反如果有三個數(shù)據(jù)成員即使其中一個掛了赚哗,仍有一個主節(jié)點和一個備份節(jié)點,不影響正常運作硅堆。這個時候還可以用剩下的那個備份節(jié)點來初始化一個新的備份節(jié)點服務(wù)器屿储,而不依賴于主節(jié)點。所以如果可能盡可能在副本集中使用奇數(shù)個數(shù)據(jù)成員渐逃,而不要使用仲裁者够掠。

優(yōu)先級(priority)

如果想讓一個節(jié)點有更大的機會成為primary的話這需要設(shè)置優(yōu)先級,比如我添加一個優(yōu)先級為2的成員(默認為1)

rs.add({"_id":4, "host": "10.17.28.190:27017", "priority" : 2});

假設(shè)其他都是默認優(yōu)先級茄菊,只要10.17.28.190擁有最新數(shù)據(jù)疯潭,那么當(dāng)前primary節(jié)點就會自動退位,10.17.28.190會被選舉為新的主節(jié)點面殖。如果它的數(shù)據(jù)不夠新竖哩,那么當(dāng)前主節(jié)點就會保持不變。

如果設(shè)置priority為0脊僚,表示不會被選為primary節(jié)點相叁。

投票權(quán)(vote)

由于復(fù)制集成員最多50個,而參與Primary成員投票的最多7個,所以其他成員的vote必須設(shè)置為0(priority也必須為0)。
盡管無投票權(quán)的成員不會在選舉中投票辽幌,但這些成員擁有副本集數(shù)據(jù)的副本增淹,并且可以接受來自客戶端應(yīng)用程序的讀取操作。

隱藏成員(hidden)

客戶端不會像隱藏成員發(fā)送請求舶衬,隱藏成員也不會作為復(fù)制源(盡管當(dāng)其他復(fù)制源不可用時隱藏成員)。因此很多人將不夠強大的服務(wù)器或者備份服務(wù)器隱藏起來赎离。通過設(shè)置hidden:true可以設(shè)置隱藏逛犹,只有優(yōu)先級為0的才能被隱藏。
可使用Hidden節(jié)點做一些數(shù)據(jù)備份梁剔、離線計算的任務(wù)虽画,不會影響復(fù)制集的服務(wù)

延遲備份節(jié)點(slaveDelay)

數(shù)據(jù)可能會因為人為錯誤而遭到毀滅性的破壞,為了防止這類問題荣病,可以使用slaveDelay設(shè)置一個延遲的備份節(jié)點码撰。

延遲備份節(jié)點的數(shù)據(jù)回比主節(jié)點延遲指定的時間(單位是秒),slaveDelay要求優(yōu)先級是0,如果應(yīng)用會將讀請求路由到備份節(jié)點个盆,應(yīng)該將延遲備份節(jié)點隱藏掉脖岛,以免讀請求被路由到延遲備份節(jié)點朵栖。

因Delayed節(jié)點的數(shù)據(jù)比Primary落后一段時間,當(dāng)錯誤或者無效的數(shù)據(jù)寫入Primary時柴梆,可通過Delayed節(jié)點的數(shù)據(jù)來恢復(fù)到之前的時間點陨溅。

修改副本集配置

比如我有個副本集叫做rs0,我想修改增加或者刪除成員,修改成員的配置(vote,hidden,priority等)可以通過reconfig命令

https://docs.mongodb.com/manual/reference/method/rs.reconfig/

cfg = rs.conf();
cfg.members[1].priority = 2;
rs.reconfig(cfg);

同步

Primary與Secondary之間通過oplog來同步數(shù)據(jù)绍在,Primary上的寫操作完成后门扇,會向特殊的local.oplog.rs特殊集合寫入一條oplog,Secondary不斷的從Primary取新的oplog并應(yīng)用偿渡。

因oplog的數(shù)據(jù)會不斷增加臼寄,local.oplog.rs被設(shè)置成為一個capped集合,當(dāng)容量達到配置上限時溜宽,會將最舊的數(shù)據(jù)刪除掉吉拳。由于復(fù)制操作的過程是先復(fù)制數(shù)據(jù)在寫入oplog,oplog必須具有冪等性坑质,即重復(fù)應(yīng)用也會得到相同的結(jié)果合武。

我向test庫的coll集合插入了一條數(shù)據(jù)之后(db.coll.insert({count:1})),調(diào)用db.isMaster()命令可以看到當(dāng)前節(jié)點的最后一次寫入時間戳

> db.isMaster()
{
  "ismaster" : true,
  "secondary" : false,
  "lastWrite" : {
    "opTime" : {
            "ts" : Timestamp(1572509087, 2),
            "t" : NumberLong(1)
    },
    "lastWriteDate" : ISODate("2019-10-31T08:04:47Z"),
    "majorityOpTime" : {
            "ts" : Timestamp(1572509087, 2),
            "t" : NumberLong(1)
    },
    "majorityWriteDate" : ISODate("2019-10-31T08:04:47Z")
  }
}

命令會返回很多數(shù)據(jù)涡扼,這里我只列出了小部分稼跳,可以看到我們當(dāng)前所在節(jié)點是master節(jié)點(primary),如果當(dāng)前節(jié)點不是primary,也會通過primary屬性告訴你當(dāng)前primary節(jié)點是哪個,同時最后一次寫入的時間戳是1572509087。

此時我們登錄另一臺secondary節(jié)點,切換到local數(shù)據(jù)庫,執(zhí)行命令db.oplog.rs.find()命令,會返回很多條數(shù)據(jù)吃沪,這里我們查看最后一條即可

{ 
  "ts" : Timestamp(1572509087, 2), 
  "t" : NumberLong(1), 
  "h" : NumberLong("6139682004250579847"), 
  "v" : 2, 
  "op" : "i", 
  "ns" : "test.coll", 
  "ui" : UUID("1be7f8d0-fde2-4d68-89ea-808f14b326da"), 
  "wall" : ISODate("2019-10-31T08:04:47.925Z"), 
  "o" : { 
    "_id" : ObjectId("5dba959fcf287dfd8727a1bf"), 
    "count" : 1 
  } 
}

可以看到oplog的ts和isMater()命令返回的lastTime.opTime.ts的值是一致的,證明我們的數(shù)據(jù)是最新的汤善,如果你這個時候訪問其他節(jié)點查看oplog.rs的數(shù)據(jù),會發(fā)現(xiàn)數(shù)據(jù)是一模一樣的票彪。
在來解釋下字段含義

  • ts : 操作時間红淡,當(dāng)前timestamp + 計數(shù)器,計數(shù)器每秒都被重置
  • h:操作的全局唯一標(biāo)識
  • v:oplog版本信息
  • op:操作類型
    • i:插入操作
    • u:更新操作
    • d:刪除操作
    • c:執(zhí)行命令(如createDatabase降铸,dropDatabase)
  • n:空操作在旱,特殊用途
  • ns:操作針對的集合
  • o:操作內(nèi)容,可以看到我這里插入的字段是count推掸,值是1
  • o2:操作查詢條件桶蝎,僅update操作包含該字段

初始化同步

副本集中的成員啟動之后,就會檢查自身狀態(tài)谅畅,確定是否可以從某個成員那里進行同步登渣。如果不行的話,它會嘗試從副本的另一個成員那里進行完整的數(shù)據(jù)復(fù)制毡泻。這個過程就是初始化同步(initial syncing)胜茧。

init sync過程包含如下步驟

  1. 準(zhǔn)備工作刪除所有已存在的數(shù)據(jù)庫,以一個全新的狀態(tài)開始同步
  2. 將同步源的所有記錄全部復(fù)制到本地(除了local)
  3. oplog同步第一步,克隆過程中的所有操作都會被記錄到oplog中仇味,如果有文檔在克隆過程中被移動了呻顽,就有可能會被遺漏雹顺,導(dǎo)致沒有被克隆,對于這樣的文檔芬位,可能需要重新克隆
  4. oplog同步過程第二步无拗,將第一個oplog同步中的操作記錄下來
  5. 創(chuàng)建索引
  6. 如果當(dāng)前節(jié)點的數(shù)據(jù)仍然遠遠落后于同步源,那么oplog同步過程的最后一步就是將創(chuàng)建索引期間的所有操作全部同步過來昧碉,防止該成員成為備份節(jié)點英染。
  7. 完成初始化同步之后,切換到普通同步狀態(tài)被饿,這時當(dāng)前成員就可以稱為備份節(jié)點了四康。

總結(jié)起來就是從其他節(jié)點同步全量數(shù)據(jù),然后不過從Primary的local.oplog.rs集合里查詢最新的oplog并應(yīng)用到自身狭握。

查詢固定集合使用的tailable cursor(https://docs.mongodb.com/manual/core/tailable-cursors/)

Primary選舉

Primary選舉除了在復(fù)制集初始化時發(fā)生闪金,還有如下場景

  1. 復(fù)制集reconfig
  2. Secondary節(jié)點檢測到Primary宕機時,會觸發(fā)新Primary的選舉
  3. 當(dāng)有Primary節(jié)點主動stepDown(主動降級為Secondary)時论颅,也會觸發(fā)新的Primary選舉

Primary的選舉受節(jié)點間心跳哎垦、優(yōu)先級、最新的oplog時間等多種因素影響恃疯。

節(jié)點間心跳

復(fù)制集成員間默認每2s會發(fā)送一次心跳信息漏设,如果10s未收到某個節(jié)點的心跳,則認為該節(jié)點已宕機今妄;如果宕機的節(jié)點為Primary郑口,Secondary(前提是可被選為Primary)會發(fā)起新的Primary選舉。

心跳是為了知道其他成員狀態(tài),哪個是主節(jié)點盾鳞,哪個可以作為同步源犬性,哪個掛掉了等等信息

成員狀態(tài):

  1. STARTUP : 剛啟動時處于這個狀態(tài),加載副本集成功后就進入STARTUP2狀態(tài)
  2. STARTUP2 : 整個初始化同步都處于這個狀態(tài)腾仅,這個狀態(tài)下乒裆,MongDB會創(chuàng)建幾個線程,用于處理復(fù)制和選舉推励,然后就會切換到RECOVERING狀態(tài)
  3. RECOVERING : 表示運行正常鹤耍,當(dāng)暫時不能處理讀取請求。如果有成員處于這個狀態(tài)吹艇,可能會造成輕微系統(tǒng)過載
  4. ARBITER : 仲裁者處于這個狀態(tài)
  5. DOWN : 一個正常運行的成員不可達惰蜜,就處于DOWN狀態(tài)昂拂。這個狀態(tài)有可能是網(wǎng)絡(luò)問題
  6. UNKNOWN : 成員無法到達其他任何成員受神,其他成員就知道無法它處于什么狀態(tài),就會處于UNKNOWN格侯。表明這個未知狀態(tài)的成員掛掉了鼻听〔浦或者兩個成員間存在網(wǎng)絡(luò)訪問問題。
  7. REMOVED : 被移除副本集時處于的狀態(tài),添加回來后撑碴,就會回到正常狀態(tài)
  8. ROLLBACK : 處于數(shù)據(jù)回滾時就處于ROLLBACK狀態(tài)撑教。回滾結(jié)束后醉拓,會換為RECOVERING狀態(tài)伟姐,然后成為備份節(jié)點。
  9. FATAL : 發(fā)生不可挽回錯誤亿卤,也不再嘗試恢復(fù)愤兵,就處于這個狀態(tài)。這個時候通常應(yīng)該重啟服務(wù)器

節(jié)點優(yōu)先級

  1. 每個節(jié)點都傾向于投票給優(yōu)先級最高的節(jié)點
  2. 優(yōu)先級為0的節(jié)點不會主動發(fā)起Primary選舉
  3. 當(dāng)Primary發(fā)現(xiàn)有優(yōu)先級更高Secondary排吴,并且該Secondary的數(shù)據(jù)落后在10s內(nèi)秆乳,則Primary會主動降級,讓優(yōu)先級更高的Secondary有成為Primary的機會钻哩。

OpTime

最新optime(最近一條oplog的時間戳)的節(jié)點才能被選為主,請看上面對oplog.rs的分析屹堰。

網(wǎng)絡(luò)分區(qū)

只有大多數(shù)投票節(jié)點間保持網(wǎng)絡(luò)連通,才有機會被選Primary街氢;如果Primary與大多數(shù)的節(jié)點斷開連接扯键,Primary會主動降級為Secondary。當(dāng)發(fā)生網(wǎng)絡(luò)分區(qū)時阳仔,可能在短時間內(nèi)出現(xiàn)多個Primary忧陪,故Driver在寫入時,最好設(shè)置大多數(shù)成功的策略近范,這樣即使出現(xiàn)多個Primary嘶摊,也只有一個Primary能成功寫入大多數(shù)。

復(fù)制集的讀寫設(shè)置

Read Preference

默認情況下评矩,復(fù)制集的所有讀請求都發(fā)到Primary叶堆,Driver可通過設(shè)置Read Preference來將讀請求路由到其他的節(jié)點。

  1. primary: 默認規(guī)則斥杜,所有讀請求發(fā)到Primary
  2. primaryPreferred: Primary優(yōu)先虱颗,如果Primary不可達,請求Secondary
  3. secondary: 所有的讀請求都發(fā)到secondary
  4. secondaryPreferred:Secondary優(yōu)先蔗喂,當(dāng)所有Secondary不可達時忘渔,請求Primary
  5. nearest:讀請求發(fā)送到最近的可達節(jié)點上(通過ping探測得出最近的節(jié)點)

Write Concern

默認情況下,Primary完成寫操作即返回缰儿,Driver可通過設(shè)置Write Concern來設(shè)置寫成功的規(guī)則畦粮。

如下的write concern規(guī)則設(shè)置寫必須在大多數(shù)節(jié)點上成功,超時時間為5s。

db.products.insert(
  { item: "envelopes", qty : 100, type: "Clasp" },
  { writeConcern: { w: majority, wtimeout: 5000 } }
)

上面的設(shè)置方式是針對單個請求的宣赔,也可以修改副本集默認的write concern预麸,這樣就不用每個請求單獨設(shè)置。

cfg = rs.conf()
cfg.settings = {}
cfg.settings.getLastErrorDefaults = { w: "majority", wtimeout: 5000 }
rs.reconfig(cfg)

回滾(rollback)

Primary執(zhí)行了一個寫請求之后掛了儒将,但是備份節(jié)點還沒有來得及復(fù)制這次操作吏祸。新選舉出來的主節(jié)點結(jié)就會漏掉這次寫操作。當(dāng)舊Primary恢復(fù)之后钩蚊,就要回滾部分操作贡翘。

比如一個復(fù)制集存在兩個數(shù)據(jù)中心,DC1中存在A(primary),B兩個節(jié)點,DC2中存在C,D,E這三個節(jié)點。
如果DC1出現(xiàn)了故障砰逻。其中DC1這個數(shù)據(jù)中心的最后的操作是126,但是126沒有被復(fù)制到另外的數(shù)據(jù)中心床估。所以DC2中服務(wù)器最新的操作是125

DC2的數(shù)據(jù)中心仍然滿足副本集大多數(shù)的要求(5臺,DC2有3臺),因此其中一個會被選舉成為新的主節(jié)點诱渤,這個節(jié)點會繼續(xù)處理后續(xù)的寫入操作丐巫。
當(dāng)網(wǎng)絡(luò)恢復(fù)之后,DC1中心的服務(wù)器就會從其他服務(wù)器同步126之后的操作勺美,但是無法找到递胧。這種時候DC1中的A,B就會進入回滾過程。

回滾回將失敗之前未復(fù)制的操作撤銷赡茸。擁有126操作的服務(wù)器會在DC2的服務(wù)器的oplog尋找共同的操作點缎脾。這里會定位125,這是兩個數(shù)據(jù)中心相匹配的最后一個操作占卧。

這時遗菠,服務(wù)器會查看這些沒有被復(fù)制的操作,將受這些操作影響的文檔寫入一個.bson文件华蜒,保存在數(shù)據(jù)目錄下的rollback目錄中辙纬。

如果126是一個更新操作,服務(wù)器回將126更新的文檔寫入collectionName.bson文件叭喜。如果想要恢復(fù)被回滾的操作贺拣,可以使用mongorestore命令。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捂蕴,一起剝皮案震驚了整個濱河市譬涡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌啥辨,老刑警劉巖涡匀,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異溉知,居然都是意外死亡陨瘩,警方通過查閱死者的電腦和手機腊嗡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拾酝,“玉大人,你說我怎么就攤上這事卡者≥锒冢” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵崇决,是天一觀的道長材诽。 經(jīng)常有香客問我,道長恒傻,這世上最難降的妖魔是什么脸侥? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮盈厘,結(jié)果婚禮上睁枕,老公的妹妹穿的比我還像新娘。我一直安慰自己沸手,他們只是感情好外遇,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著契吉,像睡著了一般跳仿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捐晶,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天菲语,我揣著相機與錄音,去河邊找鬼惑灵。 笑死山上,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的英支。 我是一名探鬼主播胶哲,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼潭辈!你這毒婦竟也來了鸯屿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤把敢,失蹤者是張志新(化名)和其女友劉穎寄摆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體修赞,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡婶恼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年桑阶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勾邦。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚣录,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出眷篇,到底是詐尸還是另有隱情萎河,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布蕉饼,位于F島的核電站虐杯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏昧港。R本人自食惡果不足惜擎椰,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望创肥。 院中可真熱鬧达舒,春花似錦、人聲如沸叹侄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圈膏。三九已至塔猾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間稽坤,已是汗流浹背丈甸。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尿褪,地道東北人睦擂。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像杖玲,于是被迫代替她去往敵國和親顿仇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

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