分布式跟蹤系統(tǒng)(一):Zipkin的背景和設(shè)計

  • 2010年谷歌發(fā)表了其內(nèi)部使用的分布式跟蹤系統(tǒng)Dapper的論文講述了Dapper在谷歌內(nèi)部兩年的演變和設(shè)計、運維經(jīng)驗,Twitter也根據(jù)該論文開發(fā)了自己的分布式跟蹤系統(tǒng)Zipkin士飒,并將其開源,但不知為啥沒有貢獻(xiàn)給Apache米辐。其實還有很多的分布式跟蹤系統(tǒng)于樟,比如naver的Pinpoint、Apache的HTrace硼身,阿里的鷹眼Tracing硅急、京東的Hydra、新浪的Watchman等佳遂。
  • 大型互聯(lián)網(wǎng)公司為什么需要分布式跟蹤系統(tǒng)营袜?為了支撐日益增長的龐大業(yè)務(wù)量,我們會把服 務(wù)進(jìn)行整合丑罪、拆分荚板,使我們的服務(wù)不僅能通過集群部署抵擋流量的沖擊,又能根據(jù)業(yè)務(wù)在其上進(jìn)行靈活的擴(kuò)展吩屹。一次請求少則經(jīng)過三四次服務(wù)調(diào)用完成跪另,多則跨越幾十個甚至是上百個服務(wù)點。如何動態(tài)展示服務(wù)的鏈路煤搜?如何分析服務(wù)鏈路的瓶頸并對其進(jìn)行調(diào)優(yōu)罚斗?如何快速進(jìn)行服務(wù)鏈路的故障發(fā)現(xiàn)?這就是服務(wù)跟蹤系統(tǒng)存在的目的和意義宅楞。
  • 即使作為分布式系統(tǒng)的開發(fā)者针姿,也很難清楚的說出某個服務(wù)的調(diào)用鏈路,況且服務(wù)調(diào)用鏈路還是動態(tài)變化的厌衙,這時候只能咬咬牙翻代碼了距淫。接下來,我們看看Zipkin是如何做到這一點的婶希。在這之前榕暇,我們先來簡單討論一下分布式跟蹤系統(tǒng)的設(shè)計要點,第一點:對應(yīng)用透明、低侵入彤枢。為什么說這一點最重要狰晚?因為分布式系統(tǒng)面對的客戶是開發(fā)者,如果他們的系統(tǒng)需要花費較大的改造才能接入你的分布式跟蹤系統(tǒng)缴啡,除非你是他的老板壁晒,否則他會直接和你說:No!业栅!沒人用是最慘的結(jié)果秒咐。那么怎么才能做到對業(yè)務(wù)系統(tǒng)最低的侵入性呢?Dapper給出的建議是在公共庫和中間件上做文章碘裕。沒錯携取,分布式系統(tǒng)之間的通訊靠的都是RPC、MQ等中間件系統(tǒng)帮孔,即使是內(nèi)部使用的線程池或者數(shù)據(jù)庫連接池雷滋,大多也是使用經(jīng)過公司包裝公共庫,這就給服務(wù)跟蹤帶來了機會文兢,我只要對中間件和公共庫進(jìn)行改造晤斩,就幾乎可以做到全方位跟蹤,當(dāng)然禽作,這也是有難度的尸昧;第二點:低開銷、高穩(wěn)定旷偿。大多數(shù)應(yīng)用不愿意接入監(jiān)控系統(tǒng)的原因是怕影響線上服務(wù)器的性能烹俗,特別是那些對性能特別敏感的應(yīng)用,所以萍程,分布式跟蹤系統(tǒng)一定要輕量級幢妄,不能有太復(fù)雜的邏輯和外部依賴,甚至需要做到根據(jù)服務(wù)的流量來動態(tài)調(diào)整采集密度茫负。第三點:可擴(kuò)展蕉鸳。隨著接入的分布式系統(tǒng)的增多,壓力也將不斷增長忍法,分布式跟蹤系統(tǒng)是否能動態(tài)的擴(kuò)展來支撐不斷接入的業(yè)務(wù)系統(tǒng)潮尝,這也是設(shè)計時需要考慮的《鲂颍可以看出勉失,這三點并沒有什么特別,對于服務(wù)降級系統(tǒng)原探、分布式跟蹤系統(tǒng)和業(yè)務(wù)監(jiān)控系統(tǒng)等乱凿,這三點都是必須的顽素。
    回到主題,Zipkin的設(shè)計徒蟆,一般的分布式跟蹤系統(tǒng)數(shù)據(jù)流主要分為三個步驟:采集胁出、發(fā)送和落盤分析,我們來看Zipkin官網(wǎng)給出的設(shè)計圖
9bdf758d-4242-3bcc-ad2a-2b95964d00ed.png

這里埋怨一下段审,Zipkin官網(wǎng)的內(nèi)容太過簡單(難道是因為懶才懶得去Apache孵化全蝶?),也許Twitter認(rèn)為有谷歌Dapper那邊文章就足夠了吧戚哎。我們看上圖裸诽,其中的S表示的是發(fā)送跟蹤數(shù)據(jù)的客戶端SDK還是Scribe的客戶端(因為Twitter內(nèi)部采用的就是Scribe來采集跟蹤數(shù)據(jù))嫂用?效果都一樣型凳,總而言之我們看到的就是各個應(yīng)用、中間件甚至是數(shù)據(jù)庫將跟蹤數(shù)據(jù)發(fā)送到Zipkin服務(wù)器嘱函。

總體設(shè)計沒什么特別甘畅,我們看下內(nèi)部的數(shù)據(jù)模型是怎么設(shè)計的。一般的調(diào)用鏈都可以展現(xiàn)成一顆樹往弓,比如下面的簡單調(diào)用:

2ef46adb-93e2-38f0-aae9-b8dda39fe7d2.png

上圖描述的服務(wù)調(diào)用場景應(yīng)該是很常見也很簡單的調(diào)用場景了疏唾,一個請求通過Gateway服務(wù)路由到下游的Service1,然后Service1先調(diào)用服務(wù)Service2函似,拿到結(jié)果后再調(diào)用服務(wù)Service3槐脏,最后組合Service2和Service3服務(wù)的結(jié)果,通過Gateway返回給用戶撇寞。我們用①②③④⑤⑥表示了RPC的順序顿天,那么,什么是span蔑担?span直譯過來是"跨度"牌废,在谷歌的Dapper論文中表示跟蹤樹中樹節(jié)點引用的數(shù)據(jù)結(jié)構(gòu)體,span是跟蹤系統(tǒng)中的基本數(shù)據(jù)單元啤握,Dapper的論文中鸟缕,并沒有具體介紹span中的全部細(xì)節(jié),但在Zipkin中排抬,每個span中一般包含如下字段:

traceId:全局跟蹤ID懂从,用它來標(biāo)記一次完整服務(wù)調(diào)用,所以和一次服務(wù)調(diào)用相關(guān)的span中的traceId都是相同的蹲蒲,Zipkin將具有相同traceId的span組裝成跟蹤樹來直觀的將調(diào)用鏈路圖展現(xiàn)在我們面前番甩。這里直接給出Zipkin官網(wǎng)中的一張Zipkin界面的圖:

eff1e978-414f-3b77-821f-cd4098f41fc0.png
  • id:span的id,理論上來說悠鞍,span的id只要做到一個traceId下唯一就可以对室,比如說阿里的鷹眼系統(tǒng)巧妙用span的id來體現(xiàn)調(diào)用層次關(guān)系(例如0模燥,0.1,0.2掩宜,0.1.1等)蔫骂,但Zipkin中的span的id則沒有什么實際含義。

  • parentId:父span的id牺汤,調(diào)用有層級關(guān)系辽旋,所以span作為調(diào)用節(jié)點的存儲結(jié)構(gòu),也有層級關(guān)系檐迟,就像圖3所示补胚,跟蹤鏈?zhǔn)遣捎酶櫂涞男问絹碚宫F(xiàn)的,樹的根節(jié)點就是調(diào)用調(diào)用的頂點追迟,從開發(fā)者的角度來說溶其,頂級span是從接入了Zipkin的應(yīng)用中最先接觸到服務(wù)調(diào)用的應(yīng)用中采集的。所以敦间,頂級span是沒有parentId字段的瓶逃,拿圖2所展現(xiàn)的例子來說,頂級span由Gateway來采集廓块,Service1的span是它的子span厢绝,而Service2和Service3的span是Service1的span的子span,很顯然Service2和Service3的span是平級關(guān)系带猴。

  • name:span的名稱昔汉,主要用于在界面上展示,一般是接口方法名拴清,name的作用是讓人知道它是哪里采集的span靶病,不然某個span耗時高我都不知道是哪個服務(wù)節(jié)點耗時高。

  • timestamp:span創(chuàng)建時的時間戳贷掖,用來記錄采集的時刻嫡秕。

  • duration:持續(xù)時間,即span的創(chuàng)建到span完成最終的采集所經(jīng)歷的時間苹威,除去span自己邏輯處理的時間昆咽,該時間段可以理解成對于該跟蹤埋點來說服務(wù)調(diào)用的總耗時。

  • annotations:基本標(biāo)注列表牙甫,一個標(biāo)注可以理解成span生命周期中重要時刻的數(shù)據(jù)快照掷酗,比如一個標(biāo)注中一般包含發(fā)生時刻(timestamp)、事件類型(value)窟哺、端點(endpoint)等信息泻轰,這里給出一個標(biāo)注的json結(jié)構(gòu):

{
 
            "timestamp": 1476197069680000,
 
            "value": "cs",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
 }

那么,有哪些事件類型呢且轨?答案是四種:cs(客戶端/消費者發(fā)起請求)浮声、cr(客戶端/消費者接收到應(yīng)答)虚婿、sr(服務(wù)端/生產(chǎn)者接收到請求)和ss(服務(wù)端/生產(chǎn)者發(fā)送應(yīng)答)∮净樱可以看出然痊,這四種事件類型的統(tǒng)計都應(yīng)該是Zipkin提供客戶端來做的,因為這些事件和業(yè)務(wù)無關(guān)屉符,這也是為什么跟蹤數(shù)據(jù)的采集適合放到中間件或者公共庫來做的原因剧浸。

binaryAnnotations:業(yè)務(wù)標(biāo)注列表,如果某些跟蹤埋點需要帶上部分業(yè)務(wù)數(shù)據(jù)(比如url地址矗钟、返回碼和異常信息等)唆香,可以將需要的數(shù)據(jù)以鍵值對的形式放入到這個字段中。

說到這里吨艇,大家對span的印象可能還是有點模糊不清躬它,于是我們繼續(xù)拿圖2的服務(wù)調(diào)用來舉例,如果我們將圖2的應(yīng)用接入Zipkin秸应,將會是下圖的效果:

10865dce-3eb0-3b0d-a3c1-92ca6194561d.png
  • 這里我們看到虑凛,Gateway碑宴、Service1软啼、Service2和Service3都在往Zipkin發(fā)送跟蹤數(shù)據(jù),你一定會感覺奇怪延柠,Gateway作為服務(wù)調(diào)用的起點祸挪,難道不是由Service1、Service2和Service3把各自的跟蹤數(shù)據(jù)傳回Gateway然后再由Gateway統(tǒng)計并整理好一并發(fā)往Zipkin服務(wù)端嗎贞间?認(rèn)真想想就知道這種設(shè)計的弊端贿条,如果一次完整的服務(wù)請求調(diào)用鏈路特長,比如設(shè)計上百個服務(wù)節(jié)點的通訊增热,那么將各服務(wù)節(jié)點的span信息傳回給頂級span和將跟蹤數(shù)據(jù)匯總并發(fā)送到Zipkin將帶來巨大的網(wǎng)絡(luò)開銷整以,這是不值當(dāng)?shù)模€不如將跟蹤數(shù)據(jù)組裝的任務(wù)直接交給Zipkin來做峻仇,這樣Zipkin的客戶端SDK不需要有過于復(fù)雜的邏輯公黑,也節(jié)省了大量的網(wǎng)絡(luò)帶寬資源,可擴(kuò)展性大大提高摄咆。

  • 需要注意的是凡蚜,并不是每個span上都會完整的發(fā)生cs、cr吭从、sr和ss這四種事件朝蜘,比如圖4中Gateway上的span只會有cs和cr,因為Gateway沒有上游應(yīng)用涩金,Service2和Service3上的span有sr和ss谱醇,但不會有cs和cr暇仲,因為對于此次服務(wù)調(diào)用來說,Service2和Service3并不依賴下游任何應(yīng)用服務(wù)副渴。但對于Service1來說就復(fù)雜得多熔吗,它將產(chǎn)生三個Span,接收和應(yīng)答Gateway是一個span佳晶,調(diào)用和接收Service2是一個span桅狠,調(diào)用和接收Service3是第三個span,注意轿秧,一個span只能用于記錄兩個應(yīng)用之間的服務(wù)調(diào)用中跌,所以不能將這三個span信息合成一個。由cs菇篡、cr漩符、sr和ss事件的時間,可以得出很多時間數(shù)據(jù)驱还,例如:

  • 請求總耗時 = Gateway.cr - Gateway.cs

  • ①的網(wǎng)絡(luò)耗時 = Service1.sr - Gateway.cs

  • Service1的調(diào)用Service2的耗時 = Service1.cr - Service1.cs (圖4中Service1節(jié)點上的第二個span中的cr和cs)

  • Service1的調(diào)用Service3的耗時 = Service1.cr - Service1.cs (圖4中Service1節(jié)點上的第三個span中的cr和cs)

  • ④的網(wǎng)絡(luò)耗時 = Service3.sr - Service1.cs (圖4中Service1節(jié)點上的第三個span中的cs)

  • 可以這樣說嗜暴,如果采集到這些span,幾乎所有階段的耗時都可以計算出來议蟆。

  • 如果要推廣Zipkin闷沥,除了Zipkin服務(wù)端要有出色的擴(kuò)展性和友好豐富的數(shù)據(jù)展示界面外,提供多種類型的客戶端SDK也是很重要的咐容,因為跟蹤數(shù)據(jù)的采集都是有中間件和公共庫做的舆逃,所以SDK不應(yīng)該太過復(fù)雜,最理想的做法是官方給一些著名開發(fā)語言和中間件提供默認(rèn)的SDK實現(xiàn)戳粒,目前根據(jù)Zipkin的官方說明路狮,已經(jīng)給Go(zipkin-go-opentracing)、Java(brave)蔚约、JavaScript(zipkin-js)奄妨、Ruby(zipkin-ruby)和Scala(zipkin-finagle)提供了官方的庫,社區(qū)方面也很給力苹祟,提供了多種方案的庫實現(xiàn)砸抛,詳見:http://zipkin.io/pages/existing_instrumentations.html

分布式跟蹤系統(tǒng)(二):Zipkin的Span模型:http://manzhizhen.iteye.com/blog/2347153

   最后苔咪,給出圖4四個服務(wù)采集的span數(shù)據(jù)樣例:
# Gateway的span
 
{
 
    "traceId": "daaed0921874ebc3",
 
    "id": "daaed0921874ebc3",
 
    "name": "get",
 
    "timestamp": 1476197067420000,
 
    "duration": 4694000,
 
    "annotations": [
 
        {
 
            "timestamp": 1476197067420000,
 
            "value": "cs",
 
            "endpoint": {
 
                "serviceName": "gateway",
 
                "ipv4": "xxx.xxx.xxx.110"
 
            }
 
        },
 
        {
 
            "timestamp": 1476197072114000,
 
            "value": "cr",
 
            "endpoint": {
 
                "serviceName": "gateway",
 
                "ipv4": "xxx.xxx.xxx.110"
 
            }
 
        }
 
    ],
 
    "binaryAnnotations": [
 
        {
 
            "key": "http.url",
 
            "value": "[http://localhost:8080/service1](http://localhost:8080/service1)",
 
            "endpoint": {
 
                "serviceName": "gateway",
 
                "ipv4": "xxx.xxx.xxx.110"
 
            }
 
        }
 
    ]
 
}
 
 
 
# Service1的三個span
 
{
 
    "traceId": "daaed0921874ebc3",
 
    "id": "411d4c32c102a974",
 
    "name": "get",
 
    "parentId": "daaed0921874ebc3",
 
    "timestamp": 1476197069680000,
 
    "duration": 1168000,
 
    "annotations": [
 
        {
 
            "timestamp": 1476197069680000,
 
            "value": "cs",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        },
 
        {
 
            "timestamp": 1476197070848000,
 
            "value": "cr",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        }
 
    ],
 
    "binaryAnnotations": [
 
        {
 
            "key": "http.url",
 
            "value": "[http://localhost:8089/service2](http://localhost:8089/service2)",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        }
 
    ]
 
}
 
 
 
{
 
    "traceId": "daaed0921874ebc3",
 
    "id": "7c0d7d897a858217",
 
    "name": "get",
 
    "parentId": "daaed0921874ebc3",
 
    "timestamp": 1476197070850000,
 
    "duration": 1216000,
 
    "annotations": [
 
        {
 
            "timestamp": 1476197070850000,
 
            "value": "cs",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        },
 
        {
 
            "timestamp": 1476197072066000,
 
            "value": "cr",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        }
 
    ],
 
    "binaryAnnotations": [
 
        {
 
            "key": "http.url",
 
            "value": "[http://localhost:8090/service3](http://localhost:8090/service3)",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        }
 
    ]
 
}
 
 
 
{
 
    "traceId": "daaed0921874ebc3",
 
    "id": "daaed0921874ebc3",
 
    "name": "get",
 
    "timestamp": 1476197067623000,
 
    "duration": 4479000,
 
    "annotations": [
 
        {
 
            "timestamp": 1476197067623000,
 
            "value": "sr",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        },
 
        {
 
            "timestamp": 1476197072102000,
 
            "value": "ss",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        }
 
    ],
 
    "binaryAnnotations": [
 
        {
 
            "key": "http.status_code",
 
            "value": "200",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        },
 
        {
 
            "key": "http.url",
 
            "value": "/service1",
 
            "endpoint": {
 
                "serviceName": "service1",
 
                "ipv4": "xxx.xxx.xxx.111"
 
            }
 
        }
 
    ]
 
}
 
 
 
# Service2 的span
 
{
 
    "traceId": "daaed0921874ebc3",
 
    "id": "411d4c32c102a974",
 
    "name": "get",
 
    "parentId": "daaed0921874ebc3",
 
    "timestamp": 1476197069806000,
 
    "duration": 1040000,
 
    "annotations": [
 
        {
 
            "timestamp": 1476197069806000,
 
            "value": "sr",
 
            "endpoint": {
 
                "serviceName": "service2",
 
                "ipv4": "xxx.xxx.xxx.112"
 
            }
 
        },
 
        {
 
            "timestamp": 1476197070846000,
 
            "value": "ss",
 
            "endpoint": {
 
                "serviceName": "service2",
 
                "ipv4": "xxx.xxx.xxx.112"
 
            }
 
        }
 
    ],
 
    "binaryAnnotations": [
 
        {
 
            "key": "http.status_code",
 
            "value": "200",
 
            "endpoint": {
 
                "serviceName": "service2",
 
                "ipv4": "xxx.xxx.xxx.112"
 
            }
 
        },
 
        {
 
            "key": "http.url",
 
            "value": "/service2",
 
            "endpoint": {
 
                "serviceName": "service2",
 
                "ipv4": "xxx.xxx.xxx.112"
 
            }
 
        }
 
    ]
 
}
 
 
 
# Service3的span
 
{
 
    "traceId": "daaed0921874ebc3",
 
    "id": "7c0d7d897a858217",
 
    "name": "get",
 
    "parentId": "daaed0921874ebc3",
 
    "timestamp": 1476197071011000,
 
    "duration": 1059000,
 
    "annotations": [
 
        {
 
            "timestamp": 1476197071011000,
 
            "value": "sr",
 
            "endpoint": {
 
                "serviceName": "service3",
 
                "ipv4": "xxx.xxx.xxx.113"
 
            }
 
        },
 
        {
 
            "timestamp": 1476197072070000,
 
            "value": "ss",
 
            "endpoint": {
 
                "serviceName": "service3",
 
                "ipv4": "xxx.xxx.xxx.113"
 
            }
 
        }
 
    ],
 
    "binaryAnnotations": [
 
        {
 
            "key": "http.status_code",
 
            "value": "200",
 
            "endpoint": {
 
                "serviceName": "service3",
 
                "ipv4": "xxx.xxx.xxx.113"
 
            }
 
        },
 
        {
 
            "key": "http.url",
 
            "value": "/service3",
 
            "endpoint": {
 
                "serviceName": "service3",
 
                "ipv4": "xxx.xxx.xxx.113"
 
            }
 
        }
 
    ]
 
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锰悼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子团赏,更是在濱河造成了極大的恐慌箕般,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舔清,死亡現(xiàn)場離奇詭異丝里,居然都是意外死亡曲初,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門杯聚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來臼婆,“玉大人,你說我怎么就攤上這事幌绍“涔樱” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵傀广,是天一觀的道長颁独。 經(jīng)常有香客問我,道長伪冰,這世上最難降的妖魔是什么誓酒? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮贮聂,結(jié)果婚禮上靠柑,老公的妹妹穿的比我還像新娘。我一直安慰自己吓懈,他們只是感情好歼冰,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骄瓣,像睡著了一般停巷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榕栏,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音蕾各,去河邊找鬼扒磁。 笑死,一個胖子當(dāng)著我的面吹牛式曲,可吹牛的內(nèi)容都是我干的妨托。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼吝羞,長吁一口氣:“原來是場噩夢啊……” “哼兰伤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钧排,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤敦腔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后恨溜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體符衔,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡找前,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了判族。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躺盛。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖形帮,靈堂內(nèi)的尸體忽然破棺而出槽惫,到底是詐尸還是另有隱情,我是刑警寧澤辩撑,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布躯枢,位于F島的核電站,受9級特大地震影響槐臀,放射性物質(zhì)發(fā)生泄漏锄蹂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一水慨、第九天 我趴在偏房一處隱蔽的房頂上張望得糜。 院中可真熱鬧,春花似錦晰洒、人聲如沸朝抖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽治宣。三九已至,卻和暖如春砌滞,著一層夾襖步出監(jiān)牢的瞬間侮邀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工贝润, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绊茧,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓打掘,卻偏偏與公主長得像华畏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子尊蚁,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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