2021-Java后端工程師面試指南-(消息隊列)

前言

文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/bin392328206/six-finger
種一棵樹最好的時間是十年前,其次是現在

Tips

面試指南系列,很多情況下不會去深挖細節,是小六六以被面試者的角色去回顧知識的一種方式,所以我默認大部分的東西,作為面試官的你,肯定是懂的。

https://www.processon.com/view/link/600ed9e9637689349038b0e4

上面的是腦圖地址

叨絮

消息隊列,在互聯網企業級開發是一個必不可少的中間件,今天來看看我們的MQ吧

然后下面是前面的文章匯總

小六六接觸的MQ呢?也不算太多,我就具體說說我們經常用的rabbitmq和rocketmq

說說什么是消息隊列

我們可以把消息隊列看作是一個存放消息的容器,當我們需要使用消息的時候,直接從容器中取出消息供自己使用即可。
消息隊列是分布式系統中重要的組件之一。使用消息隊列主要是為了通過異步處理提高系統性能和削峰、降低系統耦合性。
我們知道隊列 Queue 是一種先進先出的數據結構,所以消費消息時也是按照順序來消費的。

那你的系統為啥要使用消息隊列

  • 通過異步處理提高系統性能(減少響應所需時間)
  • 削峰/限流:先將短時間高并發產生的事務消息存儲在消息隊列中,然后后端服務再慢慢根據自己的能力去消費這些消息,這樣就避免直接把后端服務打垮掉。
  • 降低系統耦合性:使用消息隊列還可以降低系統耦合性。我們知道如果模塊之間不存在直接調用,那么新增模塊或者修改模塊就對其他模塊影響較小,這樣系統的可擴展性無疑更好一些

那你說說引入消息隊列的優缺點是什么

優點:

  • 解耦
  • 削峰
  • 異步數據分發

缺點

  • 系統可用性降低
  • 系統復雜度提高
  • 一致性問題

說說你接觸過的mq,說說他們的特點和使用場景唄

image

那你聊聊JMS和AMQP

JMS
JMS(JAVA Message Service,Java消息服務)API是一個消息服務的標準或者說是規范,允許應用程序組件基于JavaEE平臺創建、發送、接收和讀取消息。它使分布式通信耦合度更低,消息服務更加可靠以及異步性。
ActiveMQ 就是基于 JMS 規范實現的。

AMQP
AMQP,即Advanced Message Queuing Protocol,一個提供統一消息服務的應用層標準 高級消息隊列協議(二進制應用層協議),是應用層協議的一個開放標準,為面向消息的中間件設計,兼容 JMS。基于此協議的客戶端與消息中間件可傳遞消息,并不受客戶端/中間件同產品,不同的開發語言等條件的限制。

  • AMQP 為消息定義了線路層(wire-level protocol)的協議,而JMS所定義的是API規范。在 Java 體系中,多個client均可以通過JMS進行交互,不需要應用修改代碼,但是其對跨平臺的支持較差。而AMQP天然具有跨平臺、跨語言特性。
  • JMS 支持TextMessage、MapMessage 等復雜的消息類型;而 AMQP 僅支持 byte[] 消息類型(復雜的類型可序列化后發送)。
  • 由于Exchange 提供的路由算法,AMQP可以提供多樣化的路由方式來傳遞消息到消息隊列,而 JMS 僅支持 隊列 和 主題/訂閱 方式兩種。

如何保證消息隊列的高可用?

這個的話其實就是看你自己公司使用哪個隊列你就回答哪個隊列,小六六這邊說rabbit 和rocket

RabbitMQ
RabbitMQ 有三種模式:單機模式、普通集群模式、鏡像集群模式。

  • 單機模式,就是 Demo 級別的,一般就是你本地啟動了玩玩兒的??,沒人生產用單機模式。
  • 普通集群模式(無高可用性)這種方式確實很麻煩,也不怎么好,沒做到所謂的分布式,就是個普通集群。因為這導致你要么消費者每次隨機連接一個實例然后拉取數據,要么固定連接那個 queue 所在實例消費數據,前者有數據拉取的開銷,后者導致單實例性能瓶頸。
  • 鏡像集群模式(高可用性)這種模式,才是所謂的 RabbitMQ 的高可用模式。跟普通集群模式不一樣的是,在鏡像集群模式下,你創建的 queue,無論元數據還是 queue 里的消息都會存在于多個實例上,就是說,每個 RabbitMQ 節點都有這個 queue 的一個完整鏡像,包含 queue 的全部數據的意思。然后每次你寫消息到 queue 的時候,都會自動把消息同步到多個實例的 queue 上。

RocketMQ
RocketMQ集群模式: 單Master模式 多Master模式 多Master多Slave模式(異步) 多Master多Slave模式(同步)

  • 單Master模式:這種方式風險較大,一旦Broker重啟或者宕機時,會導致整個服務不可用。不建議線上環境使用,可以用于本地測試
  • 多Master模式:一個集群無Slave,全是Master,例如2個Master或者3個Master,這種模式的優缺點如下:
    • 優點:配置簡單,單個Master宕機或重啟維護對應用無影響,在磁盤配置為RAID10時,即使機器宕機不可恢復情況下,由于RAID10磁盤非 常可靠,消息也不會丟(異步刷盤丟失少量消息,同步刷盤一條不丟),性能最高;
    • 缺點:單臺機器宕機期間,這臺機器上未被消費的消息在機器恢復之前不可訂閱,消息實時性會受到影響。
  • 多Master多Slave模式(異步):每個Master配置一個Slave,有多對Master-Slave,HA采用異步復制方式,主備有短暫消息延遲(毫秒級),這種模式的優缺點如下:
    • 優點:即使磁盤損壞,消息丟失的非常少,且消息實時性不會受影響,同時Master宕機后,消費者仍然可以從Slave消費,而且此過程對應用透明,不需要人工干預,性能同多Master模式幾乎一樣;
    • 缺點:Master宕機,磁盤損壞情況下會丟失少量消息。
  • 多Master多Slave模式(同步):每個Master配置一個Slave,有多對Master-Slave,HA采用同步雙寫方式,即只有主備都寫成功,才向應用返回成功,這種模式的優缺點如下:
    • 優點:數據與服務都無單點故障,Master宕機情況下,消息無延遲,服務可用性與數據可用性都非常高;
    • 缺點:性能比異步復制模式略低(大約低10%左右),發送單個消息的RT會略高,且目前版本在主節點宕機后,備機不能自動切換為主機。

說說rocketmq的各個組件唄

  • Producer:消息的發送者;舉例:發信者
  • Consumer:消息接收者;舉例:收信者
  • Broker:暫存和傳輸消息;舉例:郵局
  • NameServer:管理Broker;舉例:各個郵局的管理機構
  • Topic:區分消息的種類;一個發送者可以發送消息給一個或者多個Topic;一個消息的接收者可以訂閱一個或者多個Topic消息
  • Message Queue:相當于是Topic的分區;用于并行發送和接收消息

說說rocketmq組件的特別唄

  • NameServer是一個幾乎無狀態節點,可集群部署,節點之間無任何信息同步。意味著每個節點都包含全部的數據。
  • Broker部署相對復雜,Broker分為Master與Slave,一個Master可以對應多個Slave,但是一個Slave只能對應一個Master,Master與Slave的對應關系通過指定相同的BrokerName,不同的BrokerId來定義,BrokerId為0表示Master,非0表示Slave。Master也可以部署多個。每個Broker與NameServer集群中的所有節點建立長連接,定時注冊Topic信息到所有NameServer。
  • Producer與NameServer集群中的其中一個節點(隨機選擇)建立長連接,定期從NameServer取Topic路由信息,并向提供Topic服務的Master建立長連接,且定時向Master發送心跳。Producer完全無狀態,可集群部署。
  • Consumer與NameServer集群中的其中一個節點(隨機選擇)建立長連接,定期從NameServer取Topic路由信息,并向提供Topic服務的Master、Slave建立長連接,且定時向Master、Slave發送心跳。Consumer既可以從Master訂閱消息,也可以從Slave訂閱消息,訂閱規則由Broker配置決定。

既然你說你用rocketmq,那么我問你當集群啟動的時候它的工作流程是怎么樣的

  • 啟動NameServer,NameServer起來后監聽端口,等待Broker、Producer、Consumer連上來,相當于一個路由控制中心。
  • Broker啟動,跟所有的NameServer保持長連接,定時發送心跳包。心跳包中包含當前Broker信息(IP+端口等)以及存儲所有Topic信息。注冊成功后,NameServer集群中就有Topic跟Broker的映射關系。
  • 收發消息前,先創建Topic,創建Topic時需要指定該Topic要存儲在哪些Broker上,也可以在發送消息時自動創建Topic。
  • Producer發送消息,啟動時先跟NameServer集群中的其中一臺建立長連接,并從NameServer中獲取當前發送的Topic存在哪些Broker上,輪詢從隊列列表中選擇一個隊列,然后與隊列所在的Broker建立長連接從而向Broker發消息。
  • Consumer跟Producer類似,跟其中一臺NameServer建立長連接,獲取當前訂閱Topic存在哪些Broker上,然后直接跟Broker建立連接通道,開始消費消息。

如何保證消息不被重復消費?或者說,如何保證消息消費的冪等性?

首先我們來看看在消息隊列的各個組件中,有哪些組件會出現不冪等

  • 生產者已把消息發送到mq,在mq給生產者返回ack的時候網絡中斷,故生產者未收到確定信息,生產者認為消息未發送成功,但實際情況是,mq已成功接收到了消息,在網絡重連后,生產者會重新發送剛才的消息,造成mq接收了重復的消息
  • 消費者在消費mq中的消息時,mq已把消息發送給消費者,消費者在給mq返回ack時網絡中斷,故mq未收到確認信息,該條消息會重新發給其他的消費者,或者在網絡重連后再次發送給該消費者,但實際上該消費者已成功消費了該條消息,造成消費者消費了重復的消息;

解決方案

  • 第一個就是生產者,我們必須保證我們只有一個消息發送到了隊列中,可以通過一個唯一的id來保證,當然這種情況是非常小的
  • 第二個就是消費者,也可利用mq的該id來判斷,或者可按自己的規則生成一個全局唯一id,每次消費消息時用該id先判斷該消息是否已消費過,至于實現方式有很多,redis 數據庫等等都行

如何保證消息的順序消費

  • 生產者必須要將所有的消息順序的寫入到一個隊列中。
  • 然后消費者的話,就只能保證一個消費者,這樣的話就能實現順序消費了,但是順序消費的壞處就是我們的吞吐量要下降

如何保證消息的可靠性傳輸?或者說,如何處理消息丟失的問題?

數據的丟失問題,可能出現在生產者、MQ、消費者中,咱們從 RabbitMQ 和 RocketMQ 分別來分析一下吧。

RabbitMQ


image
  • 生產者弄丟了數據
    生產者將數據發送到 RabbitMQ 的時候,可能數據就在半路給搞丟了,因為網絡問題啥的,都有可能。
    此時可以選擇用 RabbitMQ 提供的事務功能或者是confirm 機制 事務機制和 confirm 機制最大的不同在于,事務機制是同步的,你提交一個事務之后會阻塞在那兒,但是 confirm 機制是異步的,你發送個消息之后就可以發送下一個消息,然后那個消息 RabbitMQ 接收了之后會異步回調你的一個接口通知你這個消息接收到了。
  • RabbitMQ 弄丟了數據
    就是 RabbitMQ 自己弄丟了數據,這個你必須開啟 RabbitMQ 的持久化,就是消息寫入之后會持久化到磁盤,哪怕是 RabbitMQ 自己掛了,恢復之后會自動讀取之前存儲的數據,一般數據不會丟。除非極其罕見的是,RabbitMQ 還沒持久化,自己就掛了,可能導致少量數據丟失,但是這個概率較小。
  • 消費端弄丟了數據
    RabbitMQ 如果丟失了數據,主要是因為你消費的時候,剛消費到,還沒處理,結果進程掛了,比如重啟了,那么就尷尬了,RabbitMQ 認為你都消費了,這數據就丟了。
    這個時候得用 RabbitMQ 提供的 ack 機制,簡單來說,就是你必須關閉 RabbitMQ 的自動 ack,可以通過一個 api 來調用就行,然后每次你自己代碼里確保處理完的時候,再在程序里 ack 一把。這樣的話,如果你還沒處理完,不就沒有 ack 了?那 RabbitMQ 就認為你還沒處理完,這個時候 RabbitMQ 會把這個消費分配給別的 consumer 去處理,消息是不會丟的。

RocketMQ

可以從三個方面來分析rocket的消息可靠性

  • Producer端消息丟失

    • producer端防止消息發送失敗,可以采用同步阻塞式的發送(也就是發送同步消息),同步的檢查Brocker返回的狀態是否持久化成功,發送超時或者失敗,則會默認重試2次,rocker選擇了確保消息一定發送成功,但有可能發生重復投遞
    • 如果是異步發送消息,會有一個回調接口,當brocker存儲成功或者失敗的時候,也可以在這里根據返回狀態來決定是否需要重試(當然這個是需要我們自己來實現的)
  • Brocker端消息丟失

    • rocketmq一般都是先把消息寫到PageCache中,然后再持久化到磁盤上,數據從pagecache刷新到磁盤有兩種方式,同步和異步
    • 同步刷盤方式:消息寫入內存的 PageCache后,立刻通知刷盤線程刷盤,然后等待刷盤完成,刷盤線程執行完成后喚醒等待的線程,返回消息寫成功的狀態。這種方式可以保證數據絕對安全,但是吞吐量不大。
    • 異步刷盤方式(默認):消息寫入到內存的 PageCache中,就立刻給客戶端返回寫操作成功,當 PageCache中的消息積累到一定的量時,觸發一次寫操作,將 PageCache中的消息寫入到磁盤中。這種方式吞吐量大,性能高,但是 PageCache中的數據可能丟失,不能保證數據絕對的安全。
  • Cousmer端消息丟失

    • cousmer端默認是消息之后自動返回消費成功確認ack,但是這時如果我們的程序執行失敗了,數據不就丟失了嗎?
    • 所以我們可以將自動提交(AutoCommit)消費響應,設置為在代碼中手動提交,只有真正消費成功之后再通知brocker消費成功,然后更新消費唯一offset或者刪除brocker中的消息

大量消息在 mq 里積壓了幾個小時了還沒解決此時應該怎么辦

  • 第一條,為啥會出現消息大量積壓,是本身我們的生產者的消息產多了,還是我們的消費者出現問題了,先弄清楚原因先
  • 第二 如果是我們生產的消息多了,那么我們可以多加幾個消費者去消費消息
  • 第三,如果說是我們的消費者出現了問題,那么我首先肯定是要修復消費者的bug,但是有一點就是就算我們修復了bug,但是要到生產的流程來說還要花幾個小時才能消費完,這時候,我們要零時寫一個邏輯,把消費者的耗時邏輯直接確認,然后把消息轉到另外一個隊列,另外一個隊列用10背速度去消費,等轉發完成之后,換成正常的消費邏輯,這樣就可以盡快的使業務得到正常的使用了。

說說延時隊列唄

延時隊列,首先,它是一種隊列,隊列意味著內部的元素是有序的,元素出隊和入隊是有方向性的,元素從一端進入,從另一端取出。
其次,延時隊列,最重要的特性就體現在它的延時屬性上,跟普通的隊列不一樣的是,普通隊列中的元素總是等著希望被早點取出處理,而延時隊列中的元素則是希望被在指定時間得到取出和處理,所以延時隊列中的元素是都是帶時間屬性的,通常來說是需要被處理的消息或者任務。
簡單來說,延時隊列就是用來存放需要在指定時間被處理的元素的隊列。

RabbitMQ中的一個高級特性——TTL(Time To Live),當我們有一些特殊的場景,比如注冊幾天后,沒有購買就給他們發優惠卷,這些運營手段,就可以用到這個延時隊列了,在rabbitmq里面就是ttl+死信隊列來實現的。

image

然后RocketMQ的延時隊列的話用處就不大了,rocketmq實現的延時隊列只支持特定的延時時間段,1s,5s,10s,...2h,不能支持任意時間段的延時

深入聊聊RocketMQ唄,因為rabbitmq的源碼不是Java,所以不好問,但是RocketMQ的源碼還是要大致了解了解

聊聊消息的存儲和發送

  • 消息存儲

磁盤如果使用得當,磁盤的速度完全可以匹配上網絡 的數據傳輸速度。目前的高性能磁盤,順序寫速度可以達到600MB/s, 超過了一般網卡的傳輸速度。但是磁盤隨機寫的速度只有大概100KB/s,和順序寫的性能相差6000倍!因為有如此巨大的速度差別,好的消息隊列系統會比普通的消息隊列系統速度快多個數量級。RocketMQ的消息用順序寫,保證了消息存儲的速度。

  • 消息發送

Linux操作系統分為【用戶態】和【內核態】,文件操作、網絡操作需要涉及這兩種形態的切換,免不了進行數據復制。

一臺服務器 把本機磁盤文件的內容發送到客戶端,一般分為兩個步驟:

1)read;讀取本地文件內容;

2)write;將讀取的內容通過網絡發送出去。

這兩個看似簡單的操作,實際進行了4 次數據復制,分別是:

  1. 從磁盤復制數據到內核態內存;
  2. 從內核態內存復 制到用戶態內存;
  3. 然后從用戶態 內存復制到網絡驅動的內核態內存;
  4. 最后是從網絡驅動的內核態內存復 制到網卡中進行傳輸。
image

通過使用mmap的方式,可以省去向用戶態的內存復制,提高速度。這種機制在Java中是通過MappedByteBuffer實現的

RocketMQ充分利用了上述特性,也就是所謂的“零拷貝”技術,提高消息存盤和網絡發送的速度。

這里需要注意的是,采用MappedByteBuffer這種內存映射的方式有幾個限制,其中之一是一次只能映射1.5~2G 的文件至用戶態的虛擬內存,這也是為何RocketMQ默認設置單個CommitLog日志數據文件為1G的原因了

聊聊分布式事務唄

如何解釋分布式事務呢?事務大家都知道吧?要么都執行要么都不執行 。在同一個系統中我們可以輕松地實現事務,但是在分布式架構中,我們有很多服務是部署在不同系統之間的,而不同服務之間又需要進行調用。比如此時我下訂單然后增加積分,如果保證不了分布式事務的話,就會出現A系統下了訂單,但是B系統增加積分失敗或者A系統沒有下訂單,B系統卻增加了積分。

如今比較常見的分布式事務實現有 2PC、TCC 和 事務最終一致性,一般我們除了強一致性的場景,一般用的可靠消息最終一致性,那么對于RocketMQ 它是怎么實現的呢?

在 RocketMQ 中使用的是 事務消息加上事務反查機制 來解決分布式事務問題的


image

在第一步發送的 half 消息 ,它的意思是 在事務提交之前,對于消費者來說,這個消息是不可見的 。

你可以試想一下,如果沒有從第5步開始的 事務反查機制 ,如果出現網路波動第4步沒有發送成功,這樣就會產生 MQ 不知道是不是需要給消費者消費的問題,他就像一個無頭蒼蠅一樣。在 RocketMQ 中就是使用的上述的事務反查來解決的

  • 事務消息發送及提交

    • 發送消息(half消息)。
    • 服務端響應消息寫入結果。
    • 根據發送結果執行本地事務(如果寫入失敗,此時half消息對業務不可見,本地邏輯不執行)。
    • 根據本地事務狀態執行Commit或者Rollback(Commit操作生成消息索引,消息對消費者可見)
  • 事務補償

    • 對沒有Commit/Rollback的事務消息(pending狀態的消息),從服務端發起一次“回查”
    • Producer收到回查消息,檢查回查消息對應的本地事務的狀態
    • 根據本地事務狀態,重新Commit或者Rollback
    • 其中,補償階段用于解決消息Commit或者Rollback發生超時或者失敗的情況。

聊聊RocketMQ的底層存儲機制

RocketMQ 是如何設計它的存儲結構了。我首先想大家介紹 RocketMQ 消息存儲架構中的三大角色——CommitLog 、ConsumeQueue 和 IndexFile 。

  • CommitLog: 消息主體以及元數據的存儲主體,存儲 Producer 端寫入的消息主體內容,消息內容不是定長的。單個文件大小默認1G ,文件名長度為20位,左邊補零,剩余為起始偏移量,比如00000000000000000000代表了第一個文件,起始偏移量為0,文件大小為1G=1073741824;當第一個文件寫滿了,第二個文件為00000000001073741824,起始偏移量為1073741824,以此類推。消息主要是順序寫入日志文件,當文件滿了,寫入下一個文件。
  • ConsumeQueue: 消息消費隊列,引入的目的主要是提高消息消費的性能,由于RocketMQ 是基于主題 Topic 的訂閱模式,消息消費是針對主題進行的,如果要遍歷 commitlog 文件中根據 Topic 檢索消息是非常低效的。Consumer 即可根據 ConsumeQueue 來查找待消費的消息。其中,ConsumeQueue(邏輯消費隊列)作為消費消息的索引,保存了指定 Topic 下的隊列消息在 CommitLog 中的起始物理偏移量 offset ,消息大小 size 和消息 Tag 的 HashCode 值。consumequeue 文件可以看成是基于 topic 的 commitlog 索引文件,故 consumequeue 文件夾的組織方式如下:topic/queue/file三層組織結構,具體存儲路徑為:$HOME/store/consumequeue/{topic}/{queueId}/{fileName}。同樣 consumequeue 文件采取定長設計,每一個條目共20個字節,分別為8字節的 commitlog 物理偏移量、4字節的消息長度、8字節tag hashcode,單個文件由30W個條目組成,可以像數組一樣隨機訪問每一個條目,每個 ConsumeQueue文件大小約5.72M;
  • IndexFile: IndexFile(索引文件)提供了一種可以通過key或時間區間來查詢消息的方法。

結束

接下來復習下ssm框架

日常求贊

好了各位,以上就是這篇文章的全部內容了,能看到這里的人呀,都是真粉

創作不易,各位的支持和認可,就是我創作的最大動力,我們下篇文章見

微信 搜 "六脈神劍的程序人生" 回復888 有我找的許多的資料送給大家

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,695評論 2 370

推薦閱讀更多精彩內容