Redis 如何分布式,來看京東金融的設計與實踐

轉載:Redis 如何分布式,來看京東金融的設計與實踐


作者 | 李竟成

編輯 | 雨多田光

標簽 | 分布式緩存

前 ? 言

R2M 是京東金融線上大規模應用的分布式緩存系統,目前管理的機器總內存容量超過 60TB,近 600 個 Redis Cluster 集群,9200 多個 Redis 實例。

其主要功能包括:全 web 可視化運維緩存集群一鍵部署資源池統籌管理在線擴容及快速數據遷移多機房切換及容災完善的監控及告警Redis API 兼容等。

本文將從 R2M 系統架構、資源管理、集群擴容與遷移、數據冷熱交換、多機房容災等多方面進行深入剖析,希望讀者能有所收獲。

業務使用及運維上的優點

極簡化接入

R2M 接入簡單,以 Java 客戶端為例,只需在業務程序中引入客戶端 jar 包,配置好 appname 及 ZK 地址,即可使用。

配置自動下發

R2M 客戶端提供了諸如連接池、讀寫超時時間、重試次數等配置,有些情況下,需要對這些配置進行調優,比如 618、雙十一大促來臨時,有些業務需要減小客戶端讀寫超時時間,避免超時問題引發的連鎖反應。

為了修改配置,業務不得不重新上線所有的客戶端,不僅費時費力,還有可能引發故障。因此,為了避免這個問題,R2M 提供了配置自動下發功能,業務客戶端無需重新上線,管理端修改配置后,所有客戶端即時生效。

多種數據類型 API 支持

完全兼容 Redis 各數據類型 API 接口,提供包括哈希、集合、有序集合、列表、發布 / 訂閱等近百個接口。

支持數據冷熱交換

在保證高性能和數據一致性的前提下,實現了基于 LFU 熱度統計的數據動態冷熱交換,使得冷數據被交換到 SSD 上,熱數據被加載到 Redis 上,取得高性能和低成本的高平衡。

全 web 可視化運維

R2M 實現了包括集群部署、擴容、數據遷移、監控、集群下線、數據清理、故障節點替換及機器下線等在內的所有功能的可視化運維,運維效率及可用性大大提升。

多機房一鍵切換

通過改造 Redis Cluster 支持多機房災備、防止集群腦裂,以及各系統組件針對多機房切換選舉的支持,實現了在 Web 控制臺的多機房一鍵切換。

多種方式的集群同步及數據遷移工具

R2M 提供了專門的遷移工具組件,支持從原生 Redis 遷移至 R2M,實現了基于 Redis RDB 文件傳輸及增量同步的遷移機制。

同時,還可以指定規則比如按照前綴匹配或者反向匹配進行部分數據遷移。由于內部歷史原因,京東金融部分業務以前用的是京東商城的 Jimdb,R2M 同樣也支持了從 Jimdb 集群進行遷移。

R2M 遷移工具還支持數據實時同步的功能,包括 R2M 集群間的數據同步和 Jimdb 源集群的數據同步。

非 Java 語言代理

我們的業務開發人員主要用的是 Java,對于非 Java 語言的客戶端,比如 Python、C 等等,則通過 R2M Proxy 組件接入,各種運維操作在 Proxy 層進行,對業務方屏蔽。同時,Proxy 也提供了高可用保障方案。

系統架構

組件功能

Web console

是 R2M 緩存系統的可視化運維控制臺。所有運維操作均在 Web console 進行。

Manager

整個系統的管理組件。負責所有運維操作的下發、監控數據的收集等。運維操作包括集群創建、數據遷移、擴容、多機房切換等等。

Agent

每臺物理機上部署一個 Agent 組件,Agent 負責本機 Redis 實例的部署和監控,并進行數據上報。

緩存集群節點

每個集群的節點分布在不同機器上,若干個節點構成一個分布式集群,去中心化,無單點。

Client

客戶端由業務方引入,如:Java 通過 jar 包方式引入。

Proxy

對于非 Java 客戶端的業務,通過 Proxy 提供緩存接入和服務。

緩存集群一鍵部署

分布式集群的部署通常來說是比較麻煩的,涉及到多臺機器、多個節點及一系列的動作和配置,比如部署 Redis Cluster,就包括節點安裝與啟動、節點握手、主從分配、插槽分配、設置復制這些步驟。

雖然官方提供了構建集群的工具腳本,但機器推薦、節點安裝及配置仍然沒有自動化,對于需要大規模部署和運維 Redis Cluster 的企業來說,仍然不夠靈活和便捷。

因此,R2M 基于 Golang 實現了在 Web 控制臺一鍵完成從機器推薦、節點部署、集群構建、到節點配置的所有動作,這個過程中每臺機器上的 Agent 組件負責下載并安裝 RPM 包、在指定端口上啟動實例,Manager 組件則負責完成集群構建和節點配置過程。

自動部署過程中,還有一些必要的驗證條件和優先規則,主要是以下幾點:

檢查主節點數量和主備策略,是否滿足分布式選舉及高可用的最低配置條件:三個以上主節點、一主一從。

避免同一個集群多個節點部署在相同機器上,防止機器故障,優先推薦符合條件的機器。

根據機器可用內存,優先推薦剩余可用內存多的機器。

根據主節點數量,均衡分配插槽數量。

資源規劃與統籌管理

由于機房、機器、業務數量眾多,要做好平臺化管理,需要對資源進行合理的事先規劃,事先規劃包括:申請接入時業務方對容量進行預估,合理分配緩存實例大小和數量、機器的預留內存,為了方便管理和統計,通常還需要根據機房對機器進行分組、或者根據業務進行機器分組。

做好事先規劃的同時,還需要對資源使用情況做到一目了然,避免出現超用或嚴重超配的情況。

嚴重超配,就是實際使用量遠小于預估容量的情況,這種情況還是很多的,因為很多時候容量很難準確預估,或者有的業務開發為了保險起見或擔心不好擴容,申請的容量往往遠大于實際需要,對于這種情況,我們可以進行一鍵縮容,防止資源浪費。

對于超用,也就是機器實際資源使用量超過了標準,則是要非常注意的,緩存機器超用比如 Redis 機器超用可能導致非常嚴重的后果,比如 OOM、發生數據淘汰、性能急劇下降,為了避免超用,需要進行合理的資源預留、選擇合適的淘汰策略,同時平臺要有完善的監控和實時的報警功能。

R2M 通過對機房、分組、機器、實例的層級管理和監控,方便我們更好地對資源進行規劃,并最大限度的統籌和平衡資源利用,防止資源浪費和機器超用。

擴容及數據遷移

業務在申請緩存時,我們都會要求預估容量,根據預估值進行分配,但預估值經常是不準確的,計劃也永遠趕不上變化,業務場景拓展、業務量和數據的增長總是無法預測的。

因此,良好的擴容機制顯得尤為重要,擴容做得好不好,決定了系統的擴展性好不好。在 R2M 中,我們將水平擴容解耦為兩個步驟,添加新節點和數據遷移,添加新節點其實就是一個自動部署的過程,很多步驟與集群創建過程是相同的,那么關鍵就在于如何解決數據遷移問題了。

數據遷移主要解決以下問題:

如何做到不影響業務的正常讀寫,即業務方對遷移是基本無感知的?

如何保證遷移的速度?

當一條數據處于遷移中間狀態時,如果此時客戶端需要對該數據進行讀寫,如何處理?

遷移過程中收到讀操作,是讀源節點還是目標節點,如何確保客戶端不會讀到臟數據?

遷移過程中是寫源節點還是寫目標節點,如果確保不寫錯地方、不會由于遷移使得新值被舊值覆蓋?

遷移完成,如何通知客戶端,將讀寫請求路由到新節點上?

為了解決這些問題,我們充分吸取了 Redis Cluster 的優點,同時也解決了它的一些不足之處和缺點。

數據遷移原理

上圖就是 Redis Cluster 的數據遷移原理圖,遷移過程是通過源節點、目標節點、客戶端三者共同配合完成的。

Redis Cluster 將數據集分為 16384 個插槽,插槽是數據分割的最小單位,所以數據遷移時最少要遷移一個插槽,遷移的最小粒度是一個 key,對每個 key 的遷移可以看成是一個原子操作,會短暫阻塞源節點和目標節點上對該 key 的讀寫,這樣就使得不會出現遷移“中間狀態”,即 key 要么在源節點,要么在目標節點。

如上圖,假設正在遷移 9 號插槽,首先會在源節點中將 9 號插槽標記為“正在遷移”狀態,將目標節點中 9 號插槽標記為“正在導入”狀態,然后遍歷遷移該插槽中所有的 key。

此時,如果客戶端要對 9 號插槽的數據進行訪問,如果該數據還沒被遷移到目標節點,則直接讀寫并返回,如果該數據已經被遷移到目標節點,則返回 Ask 響應并攜帶目標節點的地址,告訴客戶端到目標節點上再請求一次。

如果 9 號插槽的數據被全部遷移完成,客戶端還繼續到源節點進行讀寫的話,則返回 Moved 響應給客戶端,客戶端收到 Moved 響應后可以重新獲取集群狀態并更新插槽信息,后續對 9 號插槽的訪問就會到新節點上進行。這樣,就完成了對一個插槽的遷移。

多節點并行數據遷移

Redis Cluster 是基于 CRC16 算法做 hash 分片的,在插槽數量差不多且沒有大 key 存在的情況下,各節點上數據的分布通常非常均衡,而由于數據遷移是以 key 為單位的,遷移速度較慢。

當數據量暴漲需要緊急擴容時,如果一個接一個地進行主節點數據遷移,有可能部分節點還沒來得及遷移就已經把內存“撐爆”了,導致發生數據淘汰或機器 OOM。

因此,R2M 實現了多節點并行數據遷移,防止此類問題發生,同時也使數據遷移耗時大大縮短,另外,結合 Redis 3.0.7 之后的 pipeline 遷移功能,可以進一步減少網絡交互次數,縮短遷移耗時。

可控的數據遷移

水平擴容添加新節點后,為了做數據 / 負載均衡,需要把部分數據遷移到新節點上,通常數據遷移過程是比較耗時的,根據網絡條件、實例大小和機器配置的不同,可能持續幾十分鐘至幾個小時。

而數據遷移時可能對網絡造成較大的壓力,另外,對于正在遷移的 slot 或 keys,Redis Cluster 通過 ASK 或 MOVED 重定向機制告訴客戶端將請求路由至新節點,使得客戶端與 Redis 多發生一次請求響應交互。

并且通常客戶端的緩存讀寫超時比較短 (通常在 100~500ms 以內),在多重因素的作用下,有可能造成大量讀寫超時情況,對在線業務造成較大的影響。

基于此,我們實現了遷移任務暫停和遷移任務繼續,當發現遷移影響業務時,隨時可以暫停遷移,待業務低峰期再繼續進行剩余的數據遷移,做到靈活可控。

自動擴容

R2M 還提供了自動擴容機制,開啟自動擴容后,當機器可用內存足夠時,如果實例已使用容量達到或超過了預設的閥值,則自動對容量進行擴大。

對于一些比較重要的業務,或不能淘汰數據的業務,可以開啟自動擴容。當然,自動擴容也是有條件的,比如不能無限制的自動擴容,實例大小達到一個比較高的值時,則拒絕自動擴容,還要預留出一部分內存進行 Fork 操作,避免機器發生 OOM。

數據冷熱交換存儲

由于我們線上存在很多大容量 (幾百 GB 或幾個 TB) 緩存集群,緩存機器內存成本巨大,線上機器總內存容量已達到 66TB 左右。

經過調研發現,主流 DDR3 內存和主流 SATA SSD 的單位成本價格差距大概在 20 倍左右,為了優化基礎設施 (硬件、機房機柜、耗電等) 綜合成本,因此,我們考慮實現基于熱度統計的數據分級存儲及數據在 RAM/FLASH 之間的動態交換,從而大幅度降低基礎設施綜合成本,并達到性能與成本的高平衡。

R2M 的冷熱交換存儲的基本思想是:基于 key 訪問次數 (LFU) 的熱度統計算法識別出熱點數據,并將熱點數據保留在 Redis 中,對于無訪問 / 訪問次數少的數據則轉存到 SSD 上,如果 SSD 上的 key 再次變熱,則重新將其加載到 Redis 內存中。

思想很簡單,但實際上做起來就不那么容易了,由于讀寫 SATA SSD 相對于 Redis 讀寫內存的速度還是有很大差距的,設計時為了避免這種性能上的不對等拖累整個系統的性能、導致響應時間和整體吞吐量的急劇下降,我們采用了多進程異步非阻塞模型來保證 Redis 層的高性能,通過精心設計的硬盤數據存儲格式、多版本 key 惰性刪除、多線程讀寫 SSD 等機制來最大限度的發揮 SSD 的讀寫性能。

多進程異步模型,主要是兩個進程,一個是 SSD 讀寫進程,用于訪問 SSD 中的 key,一個是深度改造過的 Redis 進程,用于讀寫內存 key,同時如果發現要讀寫的 key 是在 SSD 上,則會將請求轉發給 SSD 讀寫進程進行處理。

Redis 進程這一層,最開始我們其實是基于 Redis 3.2 做的,但 Redis 4 出了 RC 版本之后尤其是支持了 LFU、Psync2、內存碎片整理等功能,我們就果斷的切到 Redis 4 上進行改造開發了。

SSD 讀寫進程,起初是基于開源的 SSDB 進行開發,不過由于 SSDB 的主從復制實現性能很差,數據存儲格式設計還不夠好,與 Redis API 有很多的不兼容問題,最終除了基本的網絡框架外,基本重寫了 SSDB。

另外由于 SSDB 默認采用的存儲引擎是 leveldb,結合功能特性、項目活躍度等方面的原因,我們改成了比較流行的 RocksDB,當然,其實它也是發源于 leveldb 的。

目前我們內部已完成了該項目的開發,并進行了全面的功能、穩定性和性能測試,即將上線。由于冷熱交換存儲涉及的內容較多,由于篇幅原因,這里不再詳述。該項目已命名為 swapdb,并在 Github 開源

https://github.com/JRHZRD/swapdb

歡迎有興趣的同學關注,歡迎加 star~

多機房切換及容災支持

多機房切換是一個從上到下各組件協調聯動的過程,要考慮的因素非常多,在 R2M 中,主要包括緩存集群、路由服務 (如:ZooKeeper、etcd) 及各個組件 (Manager、Web console、客戶端) 的多機房切換。

數據層的多機房切換——即緩存服務的多機房切換

對于多機房支持,關鍵在于如何避免腦裂問題。我們先來看看腦裂是如何發生的。

正常情況下,一個緩存集群的節點部署在同一個機房,按最低三主、一主一從進行部署,每個主節點負責一部分數據,如果主節點掛了,剩余主節點通過選舉將它的從節點提升為新的主節點,即自動 failover。

如果要進行機房切換或對重要的業務進行多機房容災,則需要在另一個機房對每個主節點再添加一個從節點,那么每個主節點將有兩個從,運行過程中,如果集群中有節點發生自動 failover,主節點可能被 failover 到另一個機房,結果,就會出現同一個集群的主節點分布在不同機房的情況。

這種情況下,如果機房間網絡鏈路出現問題,A 機房的主節點與 B 機房的主節點會互相認為對方處于 fail 狀態,假設多數主節點都在 A 機房,那么 A 機房的主節點會從同機房的從節點中選出新的主節點來替代 B 機房的主節點,導致相同的分片同時被分屬兩個機房的主節點負責,A 機房的客戶端把這些分片的數據寫到了 A 機房新選出的主節點,B 機房的客戶端仍然把數據寫到了 B 機房的主節點上,從而造成腦裂導致數據無法合并。

熟悉 Redis Cluster 的同學可能知道,Redis Cluster 有一個cluster-require-full-coverage的參數,默認是開啟的,該參數的作用是:只要有節點宕機導致 16384 個分片沒被全覆蓋,整個集群就拒絕服務,大大降低可用性,所以實際應用中一定要關閉。但帶來的問題就是,如果出現上述問題,就會造成腦裂帶來的后果。

為了解決這個問題,我們在 Redis 的集群通信消息中加入了datacenter標識,收到自動 failover 請求時,主節點會將自己的 datacenter 標識與被提名做 failover 的從節點的 datacenter 標識進行比較,如果一致,則同意該節點的自動 failover 請求,否則,拒絕該請求。

保證自動 failover 只會發生在同機房從節點上,避免主節點分布在多個機房的情況。而對于手動 failover 或強制 failover,則不受此限制。針對 Redis 多機房支持的功能,已經向 Redis 官方提交了 pull request,作者 antirez 大神在 Redis 4.2 roadmap 中表示會加入這塊功能。

目前,R2M 的機房正常切換及容災切換都已經實現了在 Web console 的一鍵切換。當需要做機房正常維護或遷移時,就可以通過手動 failover 將主節點批量切到跨機房的從節點上。

值得一提的是,正常切換過程保證切換前后主從節點的數據一致。當機房由于斷電或其它原因出故障時,通過強制 failover 將主節點批量切到跨機房的從節點上,由于是突發事件,少量數據可能還未同步給從節點,但這里的主要目的是容災、及時恢復服務,可用性重要程度要遠大于少量的數據不一致或丟失。

系統組件的多機房切換

緩存集群路由服務 (ZK) 的多機房切換

業務客戶端通過路由服務拿到對應的緩存節點地址,在我們的生產環境中,每個機房的 ZK 都是獨立部署的,即不同機房的 ZK 實例屬于不同的 ZK 集群,同時每個機房的業務客戶端直接訪問本機房的 ZK 獲取緩存節點。

在 R2M 中,每個機房的 ZK 路由節點存儲的配置全部相同,我們保持 ZK 路由節點中的信息盡量簡單,所有集群狀態相關的東西都不在 ZK 上,基本是靜態配置,只有擴容或下線節點時才需要更改配置。所以,當機房切換時,不需要對 ZK 做任何變更。

客戶端的多機房切換

業務客戶端本身是多機房部署的,不存在多機房問題,但客戶端需要在緩存集群發生多機房切換后及時把服務路由到切換后的機房,這就需要通知分布于多個機房的各個客戶端,并與每個客戶端維持或建立連接,無疑是一大麻煩事。

在 R2M 中,由于客戶端是 smart client,當感知到異常時,可以從存活的節點中重新獲取集群狀態,自動感知節點角色變更并切換,也就不存在通知的問題了。

Manager 組件的多機房切換

Manager 是緩存集群的管理組件,運維操作包括機房切換操作都是通過它來進行,所以必須做到 Manager 本身的多機房才能保證可以隨時進行機房容災切換或正常切換。

需要注意的是,由于不同機房的 ZK 是獨立的,Manager 的多機房切換不能直接依賴于 ZK 來實現,因為有可能剛好被依賴的那個 ZK 所在的機房掛掉了,所以,我們實現了 Manager 的多機房選舉 (類 Raft 機制) 功能,多個 Manager 可以自行選舉 leader、自動 failover。

Web console 的多機房切換

對于 Web console 的多機房切換,這個就相對簡單了。由于 Web 是無狀態的,直接通過 Nginx 做負載均衡,只要有任意一個機房的 Web 組件可用就可以了。

監控、告警及問題排查

業務出現調用超時、性能指標出現抖動怎么辦?

一次業務調用可能涉及多個服務,比如消息隊列、數據庫、緩存、RPC,如何確認不是緩存的問題?

如果是緩存服務的問題,是機器問題、網絡問題、系統問題、還是業務使用不當問題?

當出現上述問題時,面對大量機器、集群以及無數的實例,如果沒有一套完善的監控與告警系統,沒有一個方便易用的可視化操作界面,那只能茫然無措、一籌莫展,耐心地一個一個實例的看日志、查 info 輸出,查網絡、查機器,所謂人肉運維。

因此,R2M 提供了各種維度的監控指標和告警功能,及時對異常情況進行預警,當問題出現時,也能夠快速定位排查方向。

機器和網絡指標

每臺機器的網絡 QoS(丟包率、包重傳次數、發送接收錯誤數)、流入流出帶寬、CPU、內存使用量、磁盤讀寫速率等。

系統參數指標

每個節點的內存使用量、網絡流入流出流量、TPS、查詢命中率、客戶端 TCP 連接數、key 淘汰數、慢查詢命令記錄、實例運行日志等。

實時監控及歷史統計圖表

實時和歷史統計圖表是對各項參數指標的實時反饋和歷史走勢的直觀展示,不僅能在出問題時快速給出定位的方向,還能夠對運維和業務開發提供非常有價值的參考數據,這些參考數據也反過來促進業務系統進行優化、促進更好地運維。

對于實例的歷史監控統計數據,由每個機器上部署的 Agent 組件負責收集并上報。由于實例數及監控項非常多,監控數據量可能會非常大。

為了避免監控數據占用大量數據庫空間,對于歷史統計數據,我們會保留展示最近 12 小時以分鐘為維度、最近一個月以小時為維度、以及最近一年以天為維度的數據,12 小時以前的分鐘數據自動合并為小時維度的數據,一個月以前的小時數據自動合并為天維度的數據,在合并時,保留這個時間段的指標最高值、最低值、以及累加后的平均值。

對于實時監控圖表,則是用戶請求查看時才與對應的緩存實例建立連接,直接從實例獲取實時信息。

客戶端性能指標

每個客戶端的 TP50、TP90、TP99、TP999 請求耗時統計,快速定位問題 IP。

告警項

容量告警、流入流出流量、TPS、實例阻塞、實例停止服務、客戶端連接數等。

總 ? 結

限于篇幅原因,這里只能對 R2M 緩存系統大致的設計思路和功能做一個簡要的介紹,很多細節和原理性的東西沒能一一詳述,比如數據的冷熱交換,實際上做這個東西的過程中我們遇到了很多的挑戰,也希望以后能對這塊做詳細的介紹。最后,也希望有更多的技術同仁擁抱和參與開源,讓大家有更多更好的輪子用。

作者介紹

李竟成(微信號:lijingcheng87),任職于京東金融杭州研發中心,京東金融 R2M 分布式緩存系統負責人,略通 Redis 內核,愛好開源,關注 KV 存儲、分布式架構及數據一致性相關領域。

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

推薦閱讀更多精彩內容