用Java構(gòu)建響應(yīng)式微服務(wù)5-OpenShift上部署響應(yīng)式微服務(wù)

到目前為止,我們僅僅在本地機器上部署了我們的微服務(wù)碎捺。當我們部署一個微服務(wù)在云端會發(fā)生什么距糖?大多數(shù)云平臺提供了讓你部署和運行更容易的服務(wù)玄窝。伸縮能力、負載均衡是常見特性悍引,這些是與部署響應(yīng)式微服務(wù)尤其相關(guān)的恩脂。在這一章節(jié),我們將看到這些特性怎樣被用來開發(fā)和部署響應(yīng)式微服務(wù)趣斤。

為了展示這些優(yōu)勢俩块,我們將使用OpenShift(https://www.openshift.org/)。然而浓领,大多數(shù)現(xiàn)代的云平臺包含我們在這兒所用的這些特性玉凯。這一章的最后,你將看到云是怎樣讓響應(yīng)式變得容易联贩。


OpenShift是什么漫仆?

RedHat OpenShift v3是一個開源的容器平臺。用OpenShift部署運行在容器中的應(yīng)用泪幌,OpenShift使得構(gòu)建和管理變得容易盲厌。OpenShift構(gòu)建在Kubernetes(https://kubernetes.io/)之上。

Kubernetes(圖5-1藍色部分)是一個項目祸泪,擁有在大規(guī)模Linux容器里運行微服務(wù)集群的許多功能吗浩。Google打包十多年的容器經(jīng)驗到Kubernetes。OpenShift構(gòu)建在這個經(jīng)驗之上没隘,在構(gòu)建和部署自動化(圖5-1綠色部分)方面擴展它懂扼,比如提供開箱即用的滾動更新、金絲雀部署右蒲、持續(xù)交付管道阀湿。


圖5-1 OpenShift容器平臺?

OpenShift有一些簡單的實體(Entity),如圖5-2所描述瑰妄,投入到工作之前我們需要理解他們:


圖5-2 OpenShift實體?

構(gòu)建配置

構(gòu)建是創(chuàng)建容器鏡像的過程炕倘,鏡像被OpenShift用來實例化構(gòu)成應(yīng)用的不同的容器。OpenShift構(gòu)建可以使用不同的策略:

. Docker: 從dockerfile文件構(gòu)建一個鏡像

. 源代碼到鏡像(S2I):基于OpenShift構(gòu)建鏡像(builder

image)翰撑,從應(yīng)用源代碼構(gòu)建一個鏡像

. Jenkins管道:用Jenkins管道(https://jenkins.io/doc/book/pipeline)構(gòu)建一個鏡像罩旋,潛在地包含多個步驟比如構(gòu)建、測試和部署

構(gòu)建配置能夠被git push自動地觸發(fā)眶诈,配置變化或者依賴的鏡像發(fā)生更新涨醋;顯示地,手工觸發(fā)逝撬。


部署配置

部署配置了構(gòu)建生成的鏡像的實例化浴骂,它定義了哪一個鏡像被用來創(chuàng)建容器、需要保持活著的實例的數(shù)量宪潮。它也描述了什么時候部署應(yīng)該被觸發(fā)溯警。一個部署也作為一個復(fù)制控制器趣苏,負責保持容器活著。為了達到這個目的梯轻,你設(shè)定了期望的實例數(shù)量食磕。期望的實例數(shù)量能隨時間或者基于負載波動而調(diào)整(自動伸縮)。部署也能夠指定健康檢查喳挑、管理滾動更新彬伦、監(jiān)測死容器。


Pods

一個Pod是包含一個或更多容器的容器組伊诵,然而单绑,通常是一個單一的容器構(gòu)成。Pod的編排曹宴、計劃搂橙、管理被委托給Kubernetes。Pods是可代替的笛坦,能夠在任何時候被另一個實例所代替区转。舉個例子,如果容器崩潰弯屈,另一個實例將被生成。


服務(wù)和路由

因為Pod是動態(tài)實體(實例的數(shù)量隨時間而變化)恋拷,我們不能依賴他們直接的IP地址(每個pod有它自己的IP地址)资厉。服務(wù)允許我們和Pod通訊,不依賴于Pod的地址蔬顾、而是使用service虛擬地址宴偿。一個服務(wù)作為一組Pods的前端代理,它也實現(xiàn)了負載均衡策略诀豁。

運行在OpenShift上的別的應(yīng)用能夠用服務(wù)訪問Pods提供的功能窄刘,但是OpenShift外面的應(yīng)用需要一個路由。一個路由暴露一個服務(wù)在一個象www.myservice.com這樣的主機名上舷胜,因此外面的客戶端能夠通過主機名訪問它娩践。

在你的機器上安裝OpenShift

這些是足夠抽象的概念。現(xiàn)在是時候動手了烹骨。我們將在你的機器上安裝MiniShift(https://github.com/minishift/minishift)翻伺。或者沮焕,你可以用OpenShiftOnline(https://www.openshift.com/devpreview/)吨岭,或者RedHat容器開發(fā)套件V3(https://developers.redhat.com/products/cdk/download/)。

安裝MiniShift(https://github.com/minishift/minishift#installation)需要hypervisor來運行容納OpenShift的虛擬機峦树。取決于你的主機的操作系統(tǒng)辣辫,你可以選擇hypervisor旦事,查看MiniShift安裝向?qū)б粤私饧毠?jié)。

為了安裝MiniShift急灭,僅僅從MiniShift發(fā)布頁(https://github.com/minishift/minishift/releases)下載最近的適合你操作系統(tǒng)的壓縮包姐浮,解壓它到你指定的位置,加minishift執(zhí)行目錄到你的PATH環(huán)境變量化戳。一旦安裝完成单料,啟動MiniShift:

minishift start

一旦啟動,你應(yīng)該能夠訪問https://192.168.64.12:8443連接到你的OpenShift實例点楼。你可能不得不確認SSL認證扫尖。用developer/developer登錄。

我們還需要OpenShift客戶端oc掠廓,一個命令行工具用來與你的OpenShift實例交互换怖。從https://github.com/openshift/origin/releases/latest下載最近OpenShift客戶端版本。解壓它到你指定的位置蟀瞧,加oc執(zhí)行目錄到你的PATH環(huán)境變量沉颂。

然后,連接你的OpenShift實例:

oc login https://192.168.64.12:8443 -u developer -pdeveloper

OpenShift有一個命名空間的概念稱之為project悦污。為了創(chuàng)建我們打算部署的例子的project铸屉,執(zhí)行:

oc new-project reactive-microservices

oc policy add-role-to-user admin developer –n reactive-microservices

oc policy add-role-to-user view -n reactive-microservices-z default

用你的瀏覽器,打開https://192.168.64.12:8443/console/project/reactive-microservices/切端。你應(yīng)該能夠看到這個project彻坛,這時它是沒什么東西的,因為我們還沒有部署任何東西(圖5-3):


圖5-3?

OpenShift部署微服務(wù)

是時候部署一個微服務(wù)到OpenShift踏枣。我們打算部署的代碼放在代碼倉庫的openshift/hello-

microservice-openshift目錄昌屉。Verticle是與我們前面部署的hello微服務(wù)很接近:

package io.vertx.book.openshift;

import io.vertx.core.AbstractVerticle;

import io.vertx.core.http.HttpHeaders;

import io.vertx.core.json.JsonObject;

import io.vertx.ext.web.*;

public class HelloHttpVerticle extends AbstractVerticle {

static finalString HOSTNAME = System.getenv("HOSTNAME");

@Override

public voidstart() {

Router router =Router.router(vertx);

router.get("/").handler(this::hello);

router.get("/:name").handler(this::hello);

vertx.createHttpServer()

.requestHandler(router::accept)

.listen(8080);

}

private voidhello(RoutingContext rc) {

String message= "hello";

if(rc.pathParam("name") != null) {

message += " " + rc.pathParam("name");

}

JsonObject json= new JsonObject()

.put("message",message)

.put("served-by",HOSTNAME);

rc.response()

.putHeader(HttpHeaders.CONTENT_TYPE,"application/json")

.end(json.encode());

}

}

代碼沒有依賴特定的OpenShift API或者是結(jié)構(gòu)。它與你部署在你的機器的應(yīng)用一樣茵瀑。Java代碼與部署選擇分離必須是一個深思熟慮的設(shè)計選擇间驮,讓代碼能夠在任何云平臺上運行。

我們將手工地創(chuàng)建所有OpenShift實體马昨,但是讓我們使用Fabric8提供的Maven插件(https://maven.fabric8.io/)竞帽,一個為Kubernetes提供的端到端的的開發(fā)平臺。如果你打開pom.xml文件鸿捧,你將看到這個插件被配置在openshift profile抢呆,與Vert.X Maven插件協(xié)作一起創(chuàng)建OpenShift實體。

打包和部署微服務(wù)到OpenShift笛谦,執(zhí)行:

mvnfabric8:deploy –Popenshift

這個命令與你用oc登錄的OpenShift實例交互抱虐,創(chuàng)建一個構(gòu)建(用源代碼到鏡像策略)并觸發(fā)它。首次構(gòu)建會花一些時間因為它需要獲得builder鏡像饥脑。不用擔心---一旦被緩存恳邀,構(gòu)建將很快被創(chuàng)建懦冰。構(gòu)建的輸出(鏡像)被部署配置使用,部署配置也是被Fabric8 Maven插件創(chuàng)建谣沸,缺省地刷钢,它創(chuàng)建一個Pod。一個Service也被這個插件創(chuàng)建乳附。你可以在OpenShift儀表盤上找到這些信息内地,象圖5-4所顯示的那樣:


圖5-4?

Fabric8 Maven插件缺省地并不創(chuàng)建路由(route)。然而赋除,我們從它的定義文件(src/main/fabric8/

route.yml)中創(chuàng)建一個阱缓。

如果你在你的瀏覽器打開:http://hello-microservice-reactive-microservices.192.168.64.12.nip.io/Luke

你應(yīng)該看到像這樣的結(jié)果:

{"message":"helloLuke","served-by":"hello-microservice-1-9r8uv"}

hello-microservice-1-9r8uv即是為這個請求提供服務(wù)的pod的主機名。


服務(wù)發(fā)現(xiàn)

現(xiàn)在举农,我們部署了hello微服務(wù)荆针,讓我們用一個微服務(wù)消費它。在這一小節(jié)里我們將要部署的代碼放在代碼倉庫的openshift/hello-microservice-consumer-openshift目錄颁糟。

為了消費一個微服務(wù)航背,我們首先不得不找到它。OpenShift提供了一個服務(wù)發(fā)現(xiàn)機制棱貌。服務(wù)查找能夠用環(huán)境變量玖媚、DNS或者Vert.X服務(wù)發(fā)現(xiàn)來實現(xiàn),這們這里用Vert.X的服務(wù)發(fā)現(xiàn)婚脱。

項目的pom.xml配置了引入Vert.X服務(wù)發(fā)現(xiàn)今魔,Kubernetes服務(wù)引入,一個服務(wù)端的服務(wù)發(fā)現(xiàn)起惕。你不必在提供者側(cè)顯示地注冊服務(wù)涡贱,象Fabric8 Maven聲明一個服務(wù)那樣咏删。消費者將得到OpenShift服務(wù)而不是Pods惹想。

@Override

public voidstart() {

Router router = Router.router(vertx);

router.get("/").handler(this::invokeHelloMicroservice);

// Create the service discovery instance

ServiceDiscovery.create(vertx, discovery -> {

// Look for an HTTP endpoint named "hello-microservice"

// you can also filter on 'label'

Single single =HttpEndpoint.rxGetWebClient(discovery,

rec -> rec.getName().equals("hello-microservice"),

new JsonObject().put("keepAlive", false)

);

single.subscribe(client -> {

// the configured client to call the microservice

this.hello = client;

vertx.createHttpServer()

.requestHandler(router::accept)

.listen(8080);

},

err -> System.out.println("Oh no, no service")

);

});

}

在start方法里,我們用服務(wù)發(fā)現(xiàn)來找到hello微服務(wù)督函。然后嘀粱,如果服務(wù)可獲得,我們啟動http server辰狡、保持一個得到的web客戶端的引用锋叨。我們也傳遞了一個配置給web客戶端、keep-alive設(shè)為false(一會兒我們將明白原因)宛篇。在調(diào)用hello微服務(wù)里娃磺,我們沒必要象前面所做的那樣傳遞端口和主機給rxSend方法,實際上叫倍,web客戶端被配置為目標是hello服務(wù):

HttpRequestrequest1 = hello.get("/Luke").as(BodyCodec.jsonObject());

HttpRequestrequest2 = hello.get("/Leia").as(BodyCodec.jsonObject());

Singles1 = request1.rxSend().map(HttpResponse::body);

Singles2 = request2.rxSend().map(HttpResponse::body);

// ...

在終端控制臺偷卧,切換至openshift/hello-microservice-consumer-openshift目錄豺瘤,構(gòu)建和部署這個消費者:

mvnfabric8:deploy –Popenshift

在OpenShift儀表盤上,你應(yīng)該看到第二個服務(wù)和路由听诸。如果你打開與hello消費者服務(wù)關(guān)聯(lián)的路由坐求,你應(yīng)該會看到:

{

"luke": "hello Luke hello-microservice-1-sa5pf",

"leia": "hello Leia hello-microservice-1-sa5pf"

}

你可能看到503錯誤頁,因為pod仍然沒有起來晌梨。僅僅刷新直到你得到正確的頁面桥嗤。到現(xiàn)在為止,沒有什么令人吃驚的仔蝌。顯示的served-by值總是指向同一個pod(因為僅有一個)泛领。


伸縮

如果我們正在用一個云平臺,主要是因為可伸縮性的原因掌逛。我們希望能夠根據(jù)負載增加/減少我們的應(yīng)用的實例數(shù)量师逸。在OpenShift儀表盤上,我們可以調(diào)節(jié)pods的數(shù)量的多少豆混,正如圖5-5所顯示的:


圖5-5

你也可以用oc命令行來設(shè)置副本的數(shù)量:

# 增加至2個副本

oc scale --replicas=2 dc hello-microservice

# 減少到0個副本

oc scale --replicas=0 dc hello-microservice

讓我們創(chuàng)建hello微服務(wù)的第二個實例篓像。然后,等到第二個微服務(wù)實例正確地起來(等待是令人厭煩的皿伺,后面我們將解決這個問題)员辩,在瀏覽上返回至hello消費者頁,你應(yīng)該看到像這樣:

{

"luke" : "hello Luke hello-microservice-1-h6bs6",

"leia" : "hello Leia hello-microservice-1-keq8s"

}

如果你刷新幾次鸵鸥,你將看到OpenShift在兩個實例間均衡負載奠滑。你還記得keep-alive設(shè)置為false? 當http連接使用一個keep-alive連接時,OpenShift轉(zhuǎn)發(fā)請求到同一個pod妒穴。注意在實踐中宋税,keep-alive是非常值得有的頭,因為它允許重用連接讼油。


在前面的情形里存在一個小問題杰赛。當我們伸展(scale

up)時,OpenShift開始分發(fā)請求到新的pod矮台,并沒有檢查應(yīng)用是否就緒能夠服務(wù)這些請求乏屯。因此,消費者可能請求了一個還沒有就緒的微服務(wù)瘦赫、得到了一個失敗辰晕。解決這個有兩種方式:

[if !supportLists]1)??????[endif]在微服務(wù)里面用健康檢測;

[if !supportLists]2)??????[endif]在消費者代碼里準備應(yīng)對失敗确虱。


健康檢查和失敗轉(zhuǎn)移

在OpenShift里面你能夠定義兩種類型的檢測含友。就緒檢測(Readiness Check)用來避免更新一個微服務(wù)的時候出現(xiàn)停機。在滾動更新下,OpenShift直到新版本就緒才停掉前一個版本窘问,它ping新版本微服務(wù)的就緒檢測點直到它就緒扎唾、驗證微服務(wù)被成功地初始化∧匣海活著檢測(Liveness Check)用來判定一個容器是否活著胸遇,OpenShift周期地向活著檢測點發(fā)請求,如果一個容器沒有正確地應(yīng)答汉形,它將會被重啟纸镊。活著檢測聚焦在微服務(wù)所需求的關(guān)鍵資源上概疆。在下面的例子逗威,兩個檢測我們將使用同樣的檢測點,然而岔冀,最好是使用不同的檢測點凯旭。

這個例子的代碼放在openshift/hello-microservice-openshift-health-checks目錄。如果你打開verticle使套,你將看到驗證http服務(wù)是否起來的健康檢測處理器:

privateboolean started;

@Override

publicvoid start() {

Router router = Router.router(vertx);

router.get("/health").handler(

HealthCheckHandler.create(vertx)

.register("http-server-running",

future ->future.complete(started ? Status.OK() : Status.KO())

)

);

router.get("/").handler(this::hello);

router.get("/:name").handler(this::hello);

vertx.createHttpServer()

.requestHandler(router::accept)

.listen(8080, ar -> started =ar.succeeded());

}

Fabric8

Maven插件被配置為使用/health作為就緒和活著健康檢測罐呼。一旦這個版本的hello微服務(wù)被部署,所有后續(xù)的部署將使用就緒檢測來避免出現(xiàn)停機侦高,下如圖5-6所示:


圖5-6 滾動更新(Rolling Update)

當容器就緒時嫉柴,OpenShift路由請求到這個容器、停掉老版本的容器奉呛。當我們擴展時(scale up)计螺,OpenShift不會路由請求到一個尚未就緒的容器。


使用熔斷器

盡管健康檢測避免了請求一個未就緒瞧壮、重啟死掉的微服務(wù)登馒,我們?nèi)匀恍枰獜膭e的失敗比如超時、網(wǎng)絡(luò)中斷咆槽、微服務(wù)的bug等等中保護自己陈轿,在這一小節(jié)我們打算用熔斷器來保護hello消費者,這一小節(jié)的代碼放在openshift/hello-microservice-consumer-openshift-circuit-breaker目錄罗晕。

在verticle里济欢,我們用一個簡單的熔斷器來保護對hello微服務(wù)的兩個請求赠堵,下面的代碼使用這個設(shè)計小渊,然而,這僅僅是大量可行的途徑中的一種茫叭,比如每個請求獨立地用一個熔斷器酬屉、而不是用一個簡單的熔斷器保護兩個請求:

privatevoid invokeHelloMicroservice(RoutingContext rc) {

circuit.rxExecuteCommandWithFallback(

future -> {

HttpRequest request1= hello.get("/Luke").as(BodyCodec.jsonObject());

HttpRequest request2= hello.get("/Leia").as(BodyCodec.jsonObject());

Single s1 = request1.rxSend().map(HttpResponse::body);

Single s2 = request2.rxSend().map(HttpResponse::body);

Single.zip(s1, s2, (luke, leia) -> {

// We have the result of both requestin Luke and Leia

return new JsonObject()

.put("Luke",luke.getString("message") + " " +luke.getString("served-by"))

.put("Leia",leia.getString("message") + " " +leia.getString("served-by"));

})

.subscribe(future::complete,future::fail);

},

error -> newJsonObject().put("message", "hello (fallback, "+circuit.state().toString() + ")")

).subscribe(

x ->rc.response().end(x.encodePrettily()),

t ->rc.response().end(t.getMessage())

);

}

在error情況下,我們提供一個回退(fallback)消息,指示熔斷器的狀態(tài)呐萨。這將幫助我們理解發(fā)生了什么杀饵。部署這個工程:

mvnfabric8:deploy –Popenshift

現(xiàn)在讓我們收縮(scale

down)hello微服務(wù)到0,做這個谬擦,我們可以在OpenShift Web控制臺上點擊容器旁邊的向下箭頭或者運行:

oc scale--replicas=0 dc hello-microservice

現(xiàn)在如果你刷新消費者頁面(http://hello-consumer-reactive-microservices.192.168.64.12.nip.io/)切距,你應(yīng)該看到回退(fallback)消息。前面3個請求顯示:

{

"message": "hello (fallback, CLOSED)"

}

一旦失敗次數(shù)達到閥值惨远,它會返回:

{

"message": "hello (fallback, OPEN)"

}

如果你恢復(fù)hello微服務(wù)的副本(replicas)到1:

oc scale--replicas=1 dc hello-microservice

一旦微服務(wù)就緒你應(yīng)該會獲得正常的輸出谜悟。


等等,我們是響應(yīng)式的么北秽?

是的葡幸,我們是響應(yīng)式的了。讓我們看看為什么贺氓。

所有的交互是異步的蔚叨,使用異步的、非阻塞的http請求和響應(yīng)辙培。另外蔑水,感謝OpenShift的service,我們發(fā)送請求到一個虛擬地址扬蕊,這使得有彈性肤粱。Service在一組容器中均衡負載。我們能夠很容易擴展或收縮厨相,通過調(diào)整容器的數(shù)量或者使用自動伸縮领曼。我們也有了可恢復(fù)性。感謝健康檢測蛮穿,我們有了失敗轉(zhuǎn)移機制來確笔荆總是有正常數(shù)量的容器在運行。在消費者一側(cè)践磅,我們能夠使用幾種恢復(fù)模式比如超時单刁、重試、或者熔斷器來從失敗中保護微服務(wù)府适。因此羔飞,當處于負載且面對失敗的情況下,我們的系統(tǒng)能夠及時地處理請求檐春,我們是響應(yīng)式的逻淌!

任何使用非阻塞http、在云端提供負載均衡和可恢復(fù)特性的系統(tǒng)是響應(yīng)式的嗎疟暖?是的卡儒,但是不要忘記了成本田柔。Vert.X使用事件輪詢器(event loop)實現(xiàn)用少數(shù)線程來處理大量并發(fā)請求,展示了云的重要本質(zhì)骨望。當使用依賴于線程池的途徑時硬爆,你需要:1)調(diào)整線程池找到合適的大小擎鸠;2)在你的代碼里處理并發(fā)缀磕,這意味著調(diào)試死鎖、競爭劣光、瓶頸虐骑;3)監(jiān)控性能。云環(huán)境是基于虛擬機的赎线,當你有很多線程時廷没,線程安排可能變成一個大問題。

有許多非阻塞技術(shù)垂寥,并不是所有的用同樣的執(zhí)行模式來處理異步特性颠黎,我們可以把這些技術(shù)歸為三大類:

[if !supportLists]1.??????[endif]在后臺使用一個線程池的途徑---然后面臨著調(diào)整,安排滞项,運維時不斷變化的負荷的并發(fā)挑戰(zhàn)狭归;

[if !supportLists]2.??????[endif]使用回調(diào)線程的途徑---你仍然需要管理你代碼的線程安全,避免死鎖和瓶頸文判;

[if !supportLists]3.??????[endif]用同一個線程的途徑过椎,比如Vert.X---使用少數(shù)線程,從調(diào)試死鎖中解放出來戏仓。

我們可以在云端使用消息系統(tǒng)來實現(xiàn)響應(yīng)式微服務(wù)系統(tǒng)么疚宇?當然可以。在OpenShift里面我們能夠用Vert.X事件總線(event bus)來構(gòu)建我們的響應(yīng)式微服務(wù)赏殃,但是這將不會展示虛擬服務(wù)地址敷待、OpenShift提供的負載均衡,而是Vert.X它自己來處理仁热。這里我們決定用http榜揖,無限選擇中一種設(shè)計。按你所想的方式打造你的系統(tǒng)吧抗蠢!


小結(jié)

在這一章節(jié)举哟,我們在OpenShift里部署了微服務(wù),看到了Vert.X和OpenShift怎樣組合來構(gòu)建響應(yīng)式微服務(wù)迅矛。組合異步的http服務(wù)端和客戶端妨猩,OpenShift Services、負載均衡诬乞、失敗轉(zhuǎn)移以及消費側(cè)可恢復(fù)性給了我們響應(yīng)式特性册赛。

這本書聚焦在響應(yīng)式。然而震嫉,當構(gòu)建一個微服務(wù)系統(tǒng)森瘪,許多其它方面需要被管理比如安全、配置票堵、日志等等扼睬。大多數(shù)云平臺,包括OpenShift悴势,提供了處理這些方面的服務(wù)窗宇。

關(guān)于這些topic,如果你想了解更多特纤,查看下面的資源:

.OpenShift官網(wǎng)(http://openshift.org/)

.OpenShift核心概念(https://docs.openshift.com/enterprise/3.0/architecture/core_concepts/)

.Kubernetes官網(wǎng)(https://kubernetes.io/)

.OpenShift健康檢測文檔(https://docs.openshift.com/enterprise/3.0/dev_guide/application_health.html)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末军俊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子捧存,更是在濱河造成了極大的恐慌粪躬,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昔穴,死亡現(xiàn)場離奇詭異镰官,居然都是意外死亡,警方通過查閱死者的電腦和手機吗货,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門泳唠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宙搬,你說我怎么就攤上這事笨腥。” “怎么了勇垛?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵扇雕,是天一觀的道長。 經(jīng)常有香客問我窥摄,道長镶奉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任崭放,我火速辦了婚禮哨苛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘币砂。我一直安慰自己建峭,他們只是感情好,可當我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布决摧。 她就那樣靜靜地躺著亿蒸,像睡著了一般凑兰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上边锁,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天姑食,我揣著相機與錄音,去河邊找鬼茅坛。 笑死音半,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的贡蓖。 我是一名探鬼主播曹鸠,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼斥铺!你這毒婦竟也來了彻桃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤晾蜘,失蹤者是張志新(化名)和其女友劉穎叛薯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笙纤,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡耗溜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了省容。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抖拴。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖腥椒,靈堂內(nèi)的尸體忽然破棺而出阿宅,到底是詐尸還是另有隱情,我是刑警寧澤笼蛛,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布洒放,位于F島的核電站,受9級特大地震影響滨砍,放射性物質(zhì)發(fā)生泄漏往湿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一惋戏、第九天 我趴在偏房一處隱蔽的房頂上張望领追。 院中可真熱鬧,春花似錦响逢、人聲如沸绒窑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽些膨。三九已至蟀俊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間订雾,已是汗流浹背肢预。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留葬燎,地道東北人误甚。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓缚甩,卻偏偏與公主長得像谱净,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子擅威,可洞房花燭夜當晚...
    茶點故事閱讀 43,658評論 2 350

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