ZooKeeper

一、宏觀

image.png

1.1 是什么

zookeeper是用于分布式中一致性處理的框架,簡單的說 zookeeper = 文件系統(tǒng) (保證集群內(nèi)數(shù)據(jù)一致性)+監(jiān)聽通知機。

1.2 重要概念

  • ZooKeeper 本身就是一個分布式程序(只要半數(shù)以上節(jié)點存活,ZooKeeper 就能正常服務(wù))。
  • 為了保證高可用,最好是以集群形態(tài)來部署 ZooKeeper,這樣只要集群中大部分機器是可用的(能夠容忍一定的機器故障),那么 ZooKeeper 本身仍然是可用的。
  • ZK 將數(shù)據(jù)保存在內(nèi)存中,這也就保證了 高吞吐量和低延遲(但是內(nèi)存限制了能夠存儲的容量不太大,此限制也是保持 Znode 中存儲的數(shù)據(jù)量較小的進一步原因)。
  • ZK 的讀是高性能的。在“讀”多于“寫”的應(yīng)用程序中尤其地高性能,因為“寫”會導(dǎo)致所有的服務(wù)器間同步狀態(tài)。(“讀”多于“寫”是協(xié)調(diào)服務(wù)的典型場景。)
  • ZK 有臨時節(jié)點的概念。當(dāng)創(chuàng)建臨時節(jié)點的客戶端會話一直保持活動,瞬時節(jié)點就一直存在。
    而當(dāng)會話終結(jié)時,瞬時節(jié)點被刪除。持久節(jié)點是指一旦這個 ZNode 被創(chuàng)建了,除非主動進行 ZNode 的移除操作,否則這個 ZNode 將一直保存在 Zookeeper 上。
  • ZooKeeper 底層其實只提供了兩個功能:
    ①管理(存儲、讀?。┯脩舫绦蛱峤坏臄?shù)據(jù);
    ②為用戶程序提交數(shù)據(jù)節(jié)點監(jiān)聽服務(wù)。

1.3 架構(gòu)圖

image.png

1.4 有哪些應(yīng)用場景

分布式應(yīng)用程序可以基于 ZooKeeper 實現(xiàn)一下功能:

  • 數(shù)據(jù)發(fā)布/訂閱
  • 負載均衡
  • 命名服務(wù)
  • 分布式協(xié)調(diào)/通知
  • 集群管理
  • Master 選舉
  • 分布式鎖
  • 分布式隊列

1.5 有哪些缺點/限制

1. ZK不是為高可用性設(shè)計的
由于zookeeper對于網(wǎng)絡(luò)隔離的極度敏感,導(dǎo)致zookeeper對于網(wǎng)絡(luò)的任何風(fēng)吹草動都會做出激烈反應(yīng)。這使得zookeeper的‘不可用’時間比較多,我們不能讓zookeeper的‘不可用’,變成系統(tǒng)的不可用。
2. ZK的選舉過程速度很慢
而zookeeper對那種情況非常敏感。一旦出現(xiàn)網(wǎng)絡(luò)隔離,zookeeper就要發(fā)起選舉流程。zookeeper的選舉流程通常耗時30到120秒,期間zookeeper由于沒有master,都是不可用的。對于網(wǎng)絡(luò)里面偶爾出現(xiàn)的,比如半秒一秒的網(wǎng)絡(luò)隔離,zookeeper會由于選舉過程,而把不可用時間放大幾十倍。
3. ZK的性能有限
典型的zookeeper的tps大概是一萬多,無法覆蓋系統(tǒng)內(nèi)部每天動輒幾十億次的調(diào)用。因此每次請求都去zookeeper獲取業(yè)務(wù)系統(tǒng)master信息是不可能的。因此zookeeper的client必須自己緩存業(yè)務(wù)系統(tǒng)的master地址。

1.6 ZK與Eureka的對比

從CAP原則來看,ZooKeeper選擇了CP,Eureka選擇了AP

Eureka為了最大化保證可用性,犧牲了數(shù)據(jù)的強一致性,僅保證弱一致性。
ZooKeeper為了最大化保證數(shù)據(jù)強一致性,犧牲了可用性(選主期間不可用)。

image.png

二、中觀

2.1 數(shù)據(jù)模型

ZK的數(shù)據(jù)結(jié)構(gòu)與linux文件系統(tǒng)很類似,和文件系統(tǒng)不同的是,zk的數(shù)據(jù)存儲是是結(jié)構(gòu)化存儲,沒有文件和目錄的概念,文件和目錄被抽象成了節(jié)點(node),也叫znode。節(jié)點有永久和臨時兩種類型,永久節(jié)點不會隨著該節(jié)點的session的結(jié)束而被刪除,除非顯示delete才會被刪除。臨時節(jié)點在session結(jié)束后,會被自動刪除。

每個znode由三個部分組成:

  • stat, 描述該znode的版本權(quán)限等信息。
  • data,與該znode關(guān)聯(lián)的數(shù)據(jù)。
  • children, 該znode下的子節(jié)點。
image.png

在 ZK 中,“節(jié)點"分為兩類:
第一類同樣是指構(gòu)成集群的機器,我們稱之為機器節(jié)點。
第二類則是指數(shù)據(jù)模型中的數(shù)據(jù)單元,我們稱之為數(shù)據(jù)節(jié)點一ZNode

2.2 通知機制

ZooKeeper允許用戶在指定節(jié)點上注冊一些 Watcher,并在特定事件觸發(fā)的時候,將事件通知到感興趣的客戶端上去??蛻舳私邮盏竭@個消息通知后,需要主動到服務(wù)端獲取最新的數(shù)據(jù)。


image.png

2.3 保證機制

ZK提供的保證機制:

  • 順序一致性-來自客戶端的更新將按照發(fā)送的順序應(yīng)用。
  • 原子性-更新成功或失敗。 沒有部分結(jié)果。
  • 統(tǒng)一映像-無論客戶端連接到哪個服務(wù)器,客戶端都將看到相同的服務(wù)視圖。 即,即使客戶端故障轉(zhuǎn)移到具有相同會話的其他服務(wù)器,客戶端也永遠不會看到系統(tǒng)的較舊視圖。
  • 可靠性-應(yīng)用更新后,此更新將一直持續(xù)到客戶端覆蓋更新為止。
  • 及時性-確保系統(tǒng)的客戶視圖在特定時間范圍內(nèi)是最新的。

2.4 數(shù)據(jù)一致性

集群中的角色

Leader(只能有1個): 服務(wù)器為客戶端提供讀和寫服務(wù)。
Follower和Observer:
- 共同點: 只提供讀服務(wù)
- 區(qū)別: Observer不參與leader選舉,和寫操作的『過半寫成功』策略。因此它可在不影響寫性能的情況下提升集群的讀性能。


image.png

如何保證數(shù)據(jù)一致性

ZooKeeper通過ZAB協(xié)議來保證數(shù)據(jù)一致性。

只有當(dāng)服務(wù)端的ZK存在多臺時,才會出現(xiàn)數(shù)據(jù)一致性的問題, 服務(wù)端存在多臺服務(wù)器,他們被劃分成了不同的角色,只有一臺Leader,多臺Follower和多臺Observer。他們中的任意一臺都能響應(yīng)客戶端的讀請求,任意一臺也都能接收寫請求, 不同的是,Follower和Observer接收到客戶端的寫請求后不能直接處理這個請求而是將這個請求轉(zhuǎn)發(fā)給Leader,由Leader發(fā)起原子廣播完成數(shù)據(jù)一致性.

理論上ZK集群中的每一個節(jié)點的作用都是相同的,他們應(yīng)該和單機時一樣,各個節(jié)點存放的數(shù)據(jù)保持一致才行

Leader接收到Follower轉(zhuǎn)發(fā)過來的寫請求后發(fā)起提議,要求每一個Follower都對這次寫請求進行投票O(jiān)bserver不參加投票,繼續(xù)響應(yīng)client的讀請求),Follower收到請求后,如果認為可以執(zhí)行寫操作,就發(fā)送給leader確認ack, 這里存在一個過半機制,就是說,在Leader發(fā)起的這次請求中如果存在一半以上的Follower響應(yīng)了ack,Leader就認為這次的寫操作通過了決議,向Follower發(fā)送commit,讓它們把最新的操作寫進自己的文件系統(tǒng)。

三、微觀

3.1 ZAB協(xié)議

Zookeeper的核心是原子廣播,保證各server的同步,實現(xiàn)該機制的協(xié)議是Zab協(xié)議。Zab協(xié)議有兩種模式,恢復(fù)模式和廣播模式。

  • 恢復(fù)模式
    leader崩潰后,Zab進入恢復(fù)模式,開始選舉leader,選好后且大多數(shù)server完成了和leader的同步,恢復(fù)模式結(jié)束。
  • 廣播模式
    一旦leader和多數(shù)的follower狀態(tài)同步后,就進入廣播狀態(tài)。Zookeeper會維持在Broadcast狀態(tài),直到leader崩潰了或者失去了大部分的followers支持。

3.2 選舉機制

Leader選取規(guī)則

1. 優(yōu)先檢查zxid(遞增的事務(wù)id),zxid大的作為leader服務(wù)器。
2. zxid相同就比較server id,server id大的作為leader服務(wù)器(越晚啟動serverid越大)。
3. 只有獲取過半server的支持才能成為leader。

注意: zxid是一個64位的數(shù)字,它高32位是epoch用來標(biāo)識leader關(guān)系是否改變,每次一個leader被選出來,它都會有一個新的epoch,低32位是個遞增計數(shù)。

選舉算法

Zk的選舉算法有兩種:一種基于basic paxos實現(xiàn),另外一種基于fast paxos算法實現(xiàn)。系統(tǒng)默認的選舉算法為fast paxos。

fast paxos算法

fast paxos過程,每個Server會向所有其他Server提議自己要成為leader, 選舉過程如下。
(1) 全新集群選舉(無數(shù)據(jù))
有5臺服務(wù)器均無數(shù)據(jù),按編號1,2,3,4,5,依次啟動:

  1. 服務(wù)器1啟動,給自己投票,然后發(fā)投票信息,由于其它機器還沒有啟動所以它收不到反饋信息,服務(wù)器1的狀態(tài)一直屬于Looking。
  2. 服務(wù)器2啟動,給自己投票,同時與之前啟動的服務(wù)器1交換結(jié)果,由于服務(wù)器2的編號大所以服務(wù)器2勝出,但此時投票數(shù)沒有大于半數(shù),所以兩個服務(wù)器的狀態(tài)依然是LOOKING。
  3. 服務(wù)器3啟動,給自己投票,同時與之前啟動的服務(wù)器1,2交換信息,由于服務(wù)器3的編號最大所以服務(wù)器3勝出,此時投票數(shù)正好大于半數(shù),所以服務(wù)器3成為領(lǐng)導(dǎo)者,服務(wù)器1,2成為小弟。
  4. 服務(wù)器4啟動,給自己投票,同時與之前啟動的服務(wù)器1,2,3交換信息,盡管服務(wù)器4的編號大,但之前服務(wù)器3已經(jīng)勝出,所以服務(wù)器4只能成為小弟。

(2) 非全新集群選舉(有數(shù)據(jù))
對于運行正常的zookeeper集群,中途有機器down掉,需要重新選舉時,選舉過程就需要加入數(shù)據(jù)ID、服務(wù)器ID、和邏輯時鐘。

  1. 邏輯時鐘小的選舉結(jié)果被忽略,重新投票;(除去選舉次數(shù)不完整的服務(wù)器)
  2. 統(tǒng)一邏輯時鐘后,數(shù)據(jù)id大的勝出;(選出數(shù)據(jù)最新的服務(wù)器)
  3. 數(shù)據(jù)id相同的情況下,服務(wù)器id大的勝出。(數(shù)據(jù)相同的情況下, 選擇服務(wù)器id最大,即權(quán)重最大的服務(wù)器)

3.3 應(yīng)用場景

3.3.1 分布式鎖

鎖的定義

ZooKeeper 上的一個 節(jié)點(node)可以表示一個鎖。


image.png
排它鎖

如果事務(wù) T1 對數(shù)據(jù)對象 O1 加上了排他鎖,那么加鎖期間,只允許事務(wù) T1 對 O1 進行讀取和更新操作。核心是保證當(dāng)前有且僅有一個事務(wù)獲得鎖,并且鎖釋放后,所有正在等待獲取鎖的事務(wù)都能夠被通知到。

  • 定義鎖
    通過 ZooKeeper 上的 Znode 可以表示一個鎖,/x_lock/lock。

  • 獲取鎖
    所有客戶端都會通過調(diào)用 create() 接口嘗試在 /x_lock 創(chuàng)建臨時子節(jié)點 /x_lock/lock。最終只有一個客戶端創(chuàng)建成功,那么該客戶端就獲取了鎖。同時沒有獲取到鎖的其他客戶端,注冊一個子節(jié)點變更的 Watcher 監(jiān)聽。

  • 釋放鎖
    獲取鎖的客戶端發(fā)生宕機或者正常完成業(yè)務(wù)邏輯后,就會把臨時節(jié)點刪除。臨時子節(jié)點刪除后,其他客戶端又開始新的一輪獲取鎖的過程。

共享鎖

如果事務(wù) T1 對數(shù)據(jù)對象 O1 加上了共享鎖,那么當(dāng)前事務(wù) T1 只能對 O1 進行讀取操作,其他事務(wù)也只能對這個數(shù)據(jù)對象加共享鎖,直到數(shù)據(jù)對象上的所有共享鎖都被釋放。

  • 定義鎖
    通過 ZooKeeper 上的 Znode 表示一個鎖,/s_lock/[HOSTNAME]-請求類型-序號。
/
├── /host1-R-000000001
├── /host2-R-000000002
├── /host3-W-000000003
├── /host4-R-000000004
├── /host5-R-000000005
├── /host6-R-000000006
└── /host7-W-000000007
  • 獲取鎖
    需要獲得共享鎖的客戶端都會在 s_lock 這個節(jié)點下面創(chuàng)建一個臨時順序節(jié)點,如果當(dāng)前是讀請求,就創(chuàng)建類型為 R 的臨時節(jié)點,如果是寫請求,就創(chuàng)建類型為 W 的臨時節(jié)點。
    判斷讀寫順序 共享鎖下不同事務(wù)可以同時對同一個數(shù)據(jù)對象進行讀取操作,而更新操作必須在當(dāng)前沒有任何事務(wù)進行讀寫操作的情況下進行。
    • 2.1 創(chuàng)建完節(jié)點后,獲取 s_lock 的所有子節(jié)點,并對該節(jié)點注冊子節(jié)點變更的 Watcher 監(jiān)聽
    • 2.2 然后確定自己的節(jié)點序號在所有的子節(jié)點中的順序
    • 2.3 對于讀請求,如果沒有比自己小的子節(jié)點,那么表名自己已經(jīng)成功獲取到了共享鎖,同時開始執(zhí)行讀取邏輯,如果有比自己序號小的寫請求,那么就需要進行等待。對于寫請求,如果有比自己小的子節(jié)點,就需要進行等待。
    • 2.4 接收到 Watcher 通知后重復(fù) 2.1
  • 釋放鎖
    獲取鎖的客戶端發(fā)生宕機或者正常完成業(yè)務(wù)邏輯后,就會把臨時節(jié)點刪除。臨時子節(jié)點刪除后,其他客戶端又開始新的一輪獲取鎖的過程。

3.3.3 負載均衡

負載均衡是一種手段,用來把對某種資源的訪問分攤給不同的設(shè)備,從而減輕單點的壓力。
實現(xiàn)的思路:

  • 首先建立 Servers 節(jié)點,并建立監(jiān)聽器監(jiān)視 Servers 子節(jié)點的狀態(tài)(用于在服務(wù)器增添時及時同步當(dāng)前集群中服務(wù)器列表)。
  • 在每個服務(wù)器啟動時,在 Servers 節(jié)點下建立臨時子節(jié)點 Worker Server,并在對應(yīng)的字節(jié)點下存入服務(wù)器的相關(guān)信息,包括服務(wù)的地址,IP,端口等等。
  • 可以自定義一個負載均衡算法,在每個請求過來時從 ZooKeeper 服務(wù)器中獲取當(dāng)前集群服務(wù)器列表,根據(jù)算法選出其中一個服務(wù)器來處理請求。
image.png

3.3.3 命名服務(wù)

命名服務(wù)就是提供名稱的服務(wù)。ZooKeeper 的命名服務(wù)有兩個應(yīng)用方面。

提供類 JNDI 功能,可以把系統(tǒng)中各種服務(wù)的名稱、地址以及目錄信息存放在 ZooKeeper,需要的時候去 ZooKeeper 中讀取

制作分布式的序列號生成器
利用 ZooKeeper 順序節(jié)點的特性,制作分布式的序列號生成器,或者叫 id 生成器。(分布式環(huán)境下使用作為數(shù)據(jù)庫 id,另外一種是 UUID(缺點:沒有規(guī)律)),ZooKeeper 可以生成有順序的容易理解的同時支持分布式環(huán)境的編號。
在創(chuàng)建節(jié)點時,如果設(shè)置節(jié)點是有序的,則 ZooKeeper 會自動在你的節(jié)點名后面加上序號,上面說容易理解,是比如說這樣,你要獲得訂單的 id,你可以在創(chuàng)建節(jié)點時指定節(jié)點名為 order_[日期]_xxxxxx,這樣一看就大概知道是什么時候的訂單。

/
└── /order
    ├── /order-date1-000000000000001
    ├── /order-date2-000000000000002
    ├── /order-date3-000000000000003
    ├── /order-date4-000000000000004
    └── /order-date5-000000000000005

3.3.4 分布式協(xié)調(diào)/通知

一種典型的分布式系統(tǒng)機器間的通信方式是心跳。好處就是檢測系統(tǒng)和被檢系統(tǒng)不需要直接相關(guān)聯(lián),而是通過 ZooKeeper 節(jié)點來關(guān)聯(lián),大大減少系統(tǒng)的耦合。

心跳檢測是指分布式環(huán)境中,不同機器之間需要檢測彼此是否正常運行。傳統(tǒng)的方法是通過主機之間相互 PING 來實現(xiàn),又或者是建立長連接,通過 TCP 連接固有的心跳檢測機制來實現(xiàn)上層機器的心跳檢測。

如果使用 ZooKeeper,可以基于其臨時節(jié)點的特性,不同機器在 ZooKeeper 的一個指定節(jié)點下創(chuàng)建臨時子節(jié)點,不同機器之間可以根據(jù)這個臨時節(jié)點來判斷客戶端機器是否存活。

3.3.5 集群管理

利用 ZooKeeper 實現(xiàn)集群管理監(jiān)控

在管理機器上線/下線的場景中,為了實現(xiàn)自動化的線上運維,我們必須對機器的上/下線情況有一個全局的監(jiān)控。通常在新增機器的時候,需要首先將指定的 Agent 部署到這些機器上去。Agent 部署啟動之后,會首先向 ZooKeeper 的指定節(jié)點進行注冊,具體的做法就是在機器列表節(jié)點下面創(chuàng)建一個臨時子節(jié)點,例如 /machine/[Hostname](下文我們以“主機節(jié)點”代表這個節(jié)點),如下圖所示。

image

當(dāng) Agent 在 ZooKeeper 上創(chuàng)建完這個臨時子節(jié)點后,對 /machines 節(jié)點關(guān)注的監(jiān)控中心就會接收到“子節(jié)點變更”事件,即上線通知,于是就可以對這個新加入的機器開啟相應(yīng)的后臺管理邏輯。另一方面,監(jiān)控中心同樣可以獲取到機器下線的通知,這樣便實現(xiàn)了對機器上/下線的檢測,同時能夠很容易的獲取到在線的機器列表,對于大規(guī)模的擴容和容量評估都有很大的幫助。

3.3.6 Master 選舉

分布式系統(tǒng)中 Master 是用來協(xié)調(diào)集群中其他系統(tǒng)單元,具有對分布式系統(tǒng)狀態(tài)更改的決定權(quán)。比如一些讀寫分離的應(yīng)用場景,客戶端寫請求往往是 Master 來處理的。

利用常見關(guān)系型數(shù)據(jù)庫中的主鍵特性來實現(xiàn)也是可以的,集群中所有機器都向數(shù)據(jù)庫中插入一條相同主鍵 ID 的記錄,數(shù)據(jù)庫會幫助我們自動進行主鍵沖突檢查,可以保證只有一臺機器能夠成功。

但是有一個問題,如果插入成功的和護短機器成為 Master 后掛了的話,如何通知集群重新選舉 Master?

利用 ZooKeeper 創(chuàng)建節(jié)點 API 接口,提供了強一致性,能夠很好保證在分布式高并發(fā)情況下節(jié)點的創(chuàng)建一定是全局唯一性。

集群機器都嘗試創(chuàng)建節(jié)點,創(chuàng)建成功的客戶端機器就會成為 Master,失敗的客戶端機器就在該節(jié)點上注冊一個 Watcher 用于監(jiān)控當(dāng)前 Master 機器是否存活,一旦發(fā)現(xiàn) Master 掛了,其余客戶端就可以進行選舉了。

3.3.7 分布式隊列

FIFO

使用 ZooKeeper 實現(xiàn) FIFO 隊列,入隊操作就是在 queue_fifo 下創(chuàng)建自增序的子節(jié)點,并把數(shù)據(jù)(隊列大?。┓湃牍?jié)點內(nèi)。出隊操作就是先找到 queue_fifo 下序號最下的那個節(jié)點,取出數(shù)據(jù),然后刪除此節(jié)點。

/queue_fifo
|
├── /host1-000000001
├── /host2-000000002
├── /host3-000000003
└── /host4-000000004

創(chuàng)建完節(jié)點后,根據(jù)以下步驟確定執(zhí)行順序:

  1. 通過 get_children() 接口獲取 /queue_fifo 節(jié)點下所有子節(jié)點
  2. 通過自己的節(jié)點序號在所有子節(jié)點中的順序
  3. 如果不是最小的子節(jié)點,那么進入等待,同時向比自己序號小的最后一個子節(jié)點注冊 Watcher 監(jiān)聽
  4. 接收到 Watcher 通知后重復(fù) 1
Barrier

Barrier就是柵欄或者屏障,適用于這樣的業(yè)務(wù)場景:當(dāng)有些操作需要并行執(zhí)行,但后續(xù)操作又需要串行執(zhí)行,此時必須等待所有并行執(zhí)行的線程全部結(jié)束,才開始串行,于是就需要一個屏障,來控制所有線程同時開始,并等待所有線程全部結(jié)束。

image

利用 ZooKeeper 的實現(xiàn),開始時 queue_barrier 節(jié)點是一個已經(jīng)存在的默認節(jié)點,并且將其節(jié)點的數(shù)據(jù)內(nèi)容賦值為一個數(shù)字 n 來代表 Barrier 值,比如 n=10 代表只有當(dāng) /queue_barrier 節(jié)點下的子節(jié)點個數(shù)達到10才會打開 Barrier。之后所有客戶端都會在 queue_barrier 節(jié)點下創(chuàng)建一個臨時節(jié)點,如 queue_barrier/host1

如何控制所有線程同時開始? 所有的線程啟動時在 ZooKeeper 節(jié)點 /queue_barrier 下插入順序臨時節(jié)點,然后檢查 /queue/barrier 下所有 children 節(jié)點的數(shù)量是否為所有的線程數(shù),如果不是,則等待,如果是,則開始執(zhí)行。具體的步驟如下:

  1. getData() 獲取 /queue_barrier 節(jié)點的數(shù)據(jù)內(nèi)容
  2. getChildren() 獲取 /queue_barrier 節(jié)點下的所有子節(jié)點,同時注冊對子節(jié)點列表變更的 Watche 監(jiān)聽。
  3. 統(tǒng)計子節(jié)點的個數(shù)
  4. 如果子節(jié)點個數(shù)不足10,那么進入等待
  5. 接收 Watcher 通知后,重復(fù)2

如何等待所有線程結(jié)束? 所有線程在執(zhí)行完畢后,都檢查 /queue/barrier 下所有 children 節(jié)點數(shù)量是否為0,若不為0,則繼續(xù)等待。

用什么類型的節(jié)點? 根節(jié)點使用持久節(jié)點,子節(jié)點使用臨時節(jié)點,根節(jié)點為什么要用持久節(jié)點?首先因為臨時節(jié)點不能有子節(jié)點,所以根節(jié)點要用持久節(jié)點,并且在程序中要判斷根節(jié)點是否存在。 子節(jié)點為什么要用臨時節(jié)點?臨時節(jié)點隨著連接的斷開而消失,在程序中,雖然會刪除臨時節(jié)點,但可能會出現(xiàn)程序在節(jié)點被刪除之前就 crash了,如果是持久節(jié)點,節(jié)點不會被刪除。

三、參考

https://zhuanlan.zhihu.com/p/75161633
https://zhuanlan.zhihu.com/p/59669985

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