netty權威指南學習

什么是nio?

nio 本質就是多路復用碍脏,內核告訴你那些句柄可讀可寫

jdk的selector就是對操作系統(tǒng)的io多路復用的一個封裝窃蹋,在linux中就是對epoll的封裝准潭;epoll的本質就是讓內核直接處理句柄者铜,不需要再復制到用戶空間腔丧,這個要整理不能簡單介紹

================>傳送門(后續(xù)整理)


同步與異步
阻塞和非阻塞

非nio的io復用的使用:

客戶端:

打開socketchannel 設置 socketchannel為非阻塞 異步鏈接server ,向reactor注冊多路復用器作烟,reactor線程創(chuàng)建selector啟動線程愉粤,輪詢就緒的key 異步讀請求到bytebuffer (異步寫請求到socketchannel)

服務端:

打開serversocketchannel 綁定端口,Reactor創(chuàng)建selector 將serversocketchannel注冊到selector selector輪詢key拿撩。判斷是否是新接入衣厘,新接入設置為accept。不是新接入的可讀狀態(tài) 異步請求到byuteBuffer(異步寫butebuffer到socketchannel)

如果是netty不用這么麻煩(首先啟動bootstrapt 注入兩個線程組压恒,創(chuàng)建channel為nioServerSocketChannel影暴,然后配置nioserverSocketChannel的tcp參數,設置為backlog探赫,最后綁定iohandler 處理類(包含處理類型宙,編解碼,記錄日志等)伦吠,上面配置完成以后妆兑,綁定監(jiān)聽端口即可)

tcp拆包粘包:

如上幾種情況魂拦,第二種粘了,第三種拆了

產生原因:1.進行了mss大小的tcp分段? 2.超mtu進行ip分段 3.程序寫的數據超過緩沖期大小

解決策略:

1.定長消息

2.在包尾部進行分割符

換行:LineBasedFrameDecoder
分隔符:DelimiterBasedFrameDecoder?
定長(固定長度):FixLengthFrameFecoder?

3.在表頭表名消息的總長度

netty解決粘包的第一種方法:LineBasedFrameDecoder解決:

(通過addLast()添加編解碼器)

(服務端)

一:bootstrap.group(boss搁嗓,work).channel(NioserversocketChannel.class).OPTION( tcp參數).childHandler(子處理器

二:子處理器(pipeline).addLast(LineBasedFrameDecoder編解碼).addLast(StringDecoder).addLast(真正的業(yè)務處理器handler)

三:真正的處理器子處理器handler需要繼承ChannelHandlerAdaptr父類實現 channelActive芯勘、channelRead,exceptionCaught方法

(客戶端)

與服務端類似:bootstrap.group().channel().option().handler(new ChannerlInitializer(){

實現initChannel(socketChannel)方法{

ch.pipeline.addLast(new LineBasedFrameDecoder()).addLast(StringDecoder()); addLast(客戶端處理類)}

})

:如此解決的問題:不會出現粘包的問題

為什么可以解決該問題:

原理很簡單LineBasedFrameDecoder的作用是依次遍歷bytebuf的可讀字節(jié)腺逛,讀到/N /R/N 換行符的時候結束荷愕,從可讀索引到結束位置的區(qū)間字節(jié)組成一行

而StringDecoder將接受的對象轉成字符串然后調用后來的handler,這兩個東西就是做按行切換的的文本解碼器

另外的處理方法:DelimiterBasedFrameDecoder 和 FixLengthFrameFecoder 這兩種的實現第一個是自動完成以分隔符做結束標志的消息的解碼

第二個是自動完成對定長消息的解碼

什么是netty的編解碼屉来?

當遠程調用的時候路翻,需要把本地的java對象編碼為字節(jié)數組或者bytebuffer對象,當遠程讀取到bytebuffer對象或者字節(jié)數組的時候茄靠,需要將其解碼位發(fā)送時的java對象

java序列化:僅僅是java編解碼技術的一種

為什么rpc框架很少使用jdk的serializable序列化:第一個缺點:因為rpc通常用到的是調用非java對象茂契,而jdk的serializable只是適用于java語言;第二個缺點:因為序列化的后碼流很大慨绳,占用網絡傳輸空間大掉冶;第三個缺點,序列化的性能比二進制編碼的性能差

編解碼技術二:google的protbuf

特點:結構化數據存儲格式(xml json) 脐雪;高校的編解碼技術厌小;語言無關;支持java.c python

使用二進制編碼有益于網絡傳輸

序列化和反序列化


字節(jié)數

Thrift:

弱勢:必須先確定好對象的數據結構战秋。當數據結構發(fā)生變化了璧亚,需要重新定義idl(接口描述)文件

優(yōu)點:適用于大型數據的交換及存儲的工具。性能遠優(yōu)于json和xml

thrift主要由5部分組成:

1.語言系統(tǒng)及idl編譯器脂信,由用戶給定額idl文件生成相應的接口代碼

2.Tprotocol:Rpc的協議層癣蟋,選擇多種不同的序列化方式。如json和binary

3.TTransport:rpc的傳輸層狰闪,可以選擇不同的傳輸層實現疯搅。如socket。NIO埋泵。MemoryBuffer

4.Tprocessor:作為協議層和用戶提供的服務實現之間的紐帶幔欧,負責調用服務實現的接口

5.TServer:聚合上面的2.3.4

Thrift支持三種典型的編解碼:通用的二進制編解碼。壓縮的二進制編解碼丽声。優(yōu)化的可選字段壓縮編解碼

Netty使用Protobuf作為編解碼框架實現

優(yōu)點:跨語言礁蔗,編解碼后消息更小,編解碼性能高雁社,支持定義可選和必選字段

特點:支持數據結構化一次到處使用瘦麸,包括跨語言使用

netty實現protobuf:

前面配置一樣,bootstrap.group.channel.option.childHandler(pipeline.addlast(protobuVarine32FrameDecoder(半包處理)).addLast(new protobufEncoder()).addLast(new SubReqServerHandler()))

因為使用了Decoder所以消息直接自動解碼歧胁,收到的消息可以直接使用滋饲;由于使用了Encoder我們做響應的時候不需要手動進行編碼

resp構造數據厉碟,writeAndFlush可以直接編碼發(fā)送

客戶端:類似,pipeline.addLast(new protobufVarint32FrameDecoder).addLast(new ProtobufDecoder()).addLast(ProtobufVarint32LengthFieldPrepender).addLast(new ProtobufEncoder).addLast(handler)

支持http場景

netty天生的異步事件驅動框架屠缭,因此箍鼓,niotcp協議棧開發(fā)的http協議也是異步非阻塞的

WEBSOCKET協議開發(fā)

websocket的出現解決了http的弊端,1.http是個半雙工的協議呵曹,數據只能單一方向傳遞

2.http消息榮譽繁雜款咖,包含消息頭,消息體奄喂,換行符等铐殃,相比于其余二進制冗雜

照著寫一份代碼試一下懶得解釋了

netty的基本組件及源碼學習

ByteBuf:

bytebuf繼承類

首先我們數據傳輸用到緩沖區(qū),使用的最多主要是bytebuffer跨新,8中基本數據類型都用各自的bytebuffer富腊,這個是jdknio類庫提供使用的

缺點是
bytebuffer的長度是固定死的,出現了編碼的pojo大于bytebuffer的時候就會出現索引越界的異常
2.bytebuffer只有一個標志位置的指針position 讀寫的時候需要手動調用filp()和rewind()等要正確調用否則會出現異常

光明出現了:Netty提供了新的緩沖區(qū)bytebuf數組緩沖區(qū)

提供一下幾個基本功能:
1.支持7種劇本類型byte數組域帐,bytebuffer
等的讀寫
2.緩沖區(qū)自身的copy和slice
3.設置網絡字節(jié)序
4.構造緩沖區(qū)實例
5.操作位置指針等方法

BYTEBUFFER的實現:如果用的是jdk的bytebuffer赘被,要正確使用filp,如果寫入數據后不調用flip的話肖揣。讀取的內容不正確

會讀到從position - capality(當前的limit)的位置
調用flip之后才會讀取position到limit的距離

所以得出結論 : flip()做的是將position與初始位置交換民假,limit移動到position的位置

bytebuf的實現
采用了readIndex和writeIndex兩個指針

初始狀態(tài)
前面是可讀數據,后面是可寫數據

clear以后數據都兩個指針都回到0位置

Bytebuffer進行擴容龙优,他不能自動擴容羊异,put數據的時候會判斷剩余空間是否足夠,如果不夠的話會進行重新開辟新的空間彤断,將老數據移入野舶,并清理老的bytebuffer對象;而netty提供的新的bytebuf會自動擴容不需要人為進行手動擴容

clear:將讀寫指針移會到初始位置

Mark+Reset:

bytebuffer用的是這兩個瓦糟,主要的用處是mark將當前指針記錄筒愚,reset將指針恢復為備份在mark中的值

bytebuf因為有兩個指針赴蝇,所以對應的mark和reset有四個菩浙,分別是讀mark讀reset寫mark寫reset

已知:nio的socketchannel進行網絡讀寫。操作的對象是bytebuffer句伶。
但是:netty所用的是bytebuf他不能操作
所以:要在接口層進行兩者互換劲蜻,

詳解bytebuffer與bytebuf轉換:

1.nioBuffer()將bytebuf轉換成bytebuffer,兩者公用一個緩沖區(qū)內容考余,對bytebuffer的讀寫操作先嬉,不會修改原bytebuf的動態(tài)拓展操作

2.niobuffer(int index , int length)也是將bytebuf轉換成buffer楚堤,是在起始位置為index疫蔓,長度為length進行轉換

支持隨機讀寫(set / get)

但是問題在set和write的區(qū)別是set必須確認長度大小是否符合可寫入的大小含懊,不能支持動態(tài)擴容,而write是支持動態(tài)擴容的


Bytebuf分類
按照內存分配的角度衅胀,可以分為兩類:堆內存和直接內存

堆內存:
分配及回收速度快岔乔,可以被jvm自動回收,但是缺點是io讀寫的時候要額外做一次內存復制滚躯,將堆內存的緩沖區(qū)復制到內核的channel中

直接內存
非堆內存雏门,在堆外進行內存分配,他的分配和回收會比堆內存比較慢掸掏,但是io操作的時候可以直接從socketchannel中讀取

最佳實踐:
io通信線程讀寫緩沖區(qū)使用直接內存茁影。后端業(yè)務編解碼模塊使用堆內存

按照內存回收的角度區(qū)分bytebuf可以以分為兩類,基于對象池的bytebuf 普通的bytebuf

區(qū)別在于對象池的bytebuf可以復用bytebuf對象丧凤,可以在netty的高負載大并發(fā)的沖擊下使得gc更加的穩(wěn)定

Channel是個啥

是jdk的NIO的組成部分募闲,netty重新實現

主要的api還是進行網絡io

channel在netty中是網絡操作抽象類、他聚合了一組功能息裸,包含但不限于網絡的讀寫客戶端發(fā)起鏈接主動關閉鏈接蝇更,獲取通信雙方餓網絡地址等;同時也可以獲取eventloop呼盆,獲取緩沖分配器年扩,和pipeline等

netty用自己的channel主要是要能夠跟netty的整體架構融合, 例如io模型访圃,基于channelpipeline的定制模型厨幻,以及基于元數據描述配置化的tcp參數等

channel的一些常用api

1.channel read:從channel中讀取數據到第一個inbound緩沖區(qū),讀取完以后會調用channelReadComplete這樣決定是否需要繼續(xù)讀取數據
2.channelFuture write:將數據通過channelpipeline寫入到channel中腿时,該操作只是將消息發(fā)送到環(huán)形數組中况脆,只有當調用到flush才會真正的發(fā)送數據
3.channelfuture writeandflush 將write和flush組合
4.channel flush將之前寫入到發(fā)送環(huán)形數組的消息全部寫入channel 并發(fā)送給通信方
5.channelfure connect 指定服務器地址發(fā)起鏈接請求
6.channelfuture bind 綁定指定的本地socket地址
7.is open:判斷是否channel已經打開;isRegistered:判斷channel是否注冊到evenloop上

8.eventLoop():channel需要注冊到evenloop的多路復用器批糟;通過該方法格了,可以獲取到channel注冊的evenloop (evenloop本質上是吃力網絡讀寫的reactor線程)

netty網絡傳播的本質是,當有網絡io的操作時候會發(fā)生channelPipeline中對應的事件方法徽鼎;channel在io操作中產生的io事件盛末,驅動事件在channelpieline中傳播。由對應的channelhandler進行事件處理否淤。不關心的事件直接忽略悄但。功能等價于aop像切面一樣

兩個重要的channel介紹一下 nioServerSocketChannel 和 nioSocketChannel

nioServerSocketChannel

對于nioserversocketchannel來說,他的讀取操作就是接受客戶端的鏈接石抡,然后創(chuàng)建niosocketChannel對象

nioSocketChannel

1.鏈接操作 socket.bind + socketchannel.connect檐嚣;如果鏈接success將niosocketChannel中的selectionKey設置為OP_CONNECT

什么是ChannelPipeline 和 ChannelHandler

就是一種責任鏈模式

Netty將channel的數據管道抽象為channelpipeline ,消息在channelPipeline中傳遞啰扛。channelHandler為事件攔截器嚎京,被channelpipeline持有(pipeline是handler的容器)嗡贺,用戶可以通過新增和刪除channelhandler進行不同的業(yè)務處理,不需要對已有的handler進行修改鞍帝。

本章三個概念:channelpipeline channelhandler channelhandlerContext

pipeline的流程圖

pipeline的流程圖詳解

左邊一列:數據讀取的流程暑刃,底層的socketchannel 調用read()讀取bytebuf -----> 觸發(fā)io線程eventloop調用channelpipeline的fireChannelRead的方法闷供。將消息(bytebuf)傳輸到channelPipeline中 --------->依次被channelhandler(1.2.3.4)一直到tailHandler(任何一個channelhandler都可以攔截和處理當前的消息結束消息傳遞

右邊一列:調用channelContext的write方法粟关,從tailHandler開始,途徑channelHandler(N...1)將消息發(fā)送到緩沖區(qū)中等待刷新向臀,也可以中斷流程如編碼失敗的時候宵膨,需要中斷消息構造future返回

Netty的事件:inbound事件架谎。outbound事件(參看上面的流程圖)這兩個事件只是netty根據事件在pipeline中流向抽象出來的術語

inbound事件:(流程圖左邊)(都是執(zhí)行的channelHandlerContext的 方法)(從io線程流向用戶業(yè)務的handler)
1.channel注冊 》?channelHandlerContext.fireChannelRegistered()
2.TCP鏈路建立成功,Channel激活事件
3.讀事件
4.讀完之后的通知事件
5.異常通知事件
6.Channel的可寫狀態(tài)變化通知事件
7.TCP關閉

outbound事件(流程圖右邊)(都是執(zhí)行的channelHandlerContext的 方法)(由用戶線程或者代碼發(fā)起的io操作)
1.bind 綁定本地地址事件
2.鏈接服務端事件
3.write發(fā)送事件
4.flush刷新事件
5.read讀事件
6.關閉當前channel事件

pipeline的構成>使用ServerBootStrap 或者 bootStrap啟動服務端和客戶端 netty為每一個channel都會單獨的創(chuàng)建一個獨立的pipeline

channelhandler是線程不安全的辟躏,channelpipeline是線程安全的谷扣,channelhandler支持動態(tài)的添加和刪除,:使用場景在業(yè)務高峰期的時候要對系統(tǒng)進行阻塞保護的時候捎琐,就可以動態(tài)的增減阻塞的channelhandler

channelpipeline維護了channlerhandler 名和 channelHandlerContext實例的映射關系

ChannelHandler支持注解:
1.sharable 多個channelPipeline公用一個channlehandler
2.skip被注釋的方法会涎,直接跳過

解碼的處理流程:


messageToMessageDecoder? 》 byteTomessageDecoder(都是實現channelHandler接口)

NETTY 提供的半包解碼器:

1.lineBaseFrameDecoder
2.DelimiterBasedFrameDecoder
3.LengthFieldBasedFrameDecoder :通過長度區(qū)分? 與其對應的是LengthFieldPrepender將消息編碼為 : 長度字段+原消息

如何區(qū)分整包:固定長度∪鸫眨回車換行符末秃。分隔符。指定長度

到此為止前面的問題到底是啥籽御?知道了pipeline 和 channelhandler的聯系(容器)练慕,但是channelhandlerContext和他們的聯系是啥呢?技掏?铃将??哑梳?

以下是通過資料查詢這三者的關系:

三者的關系

pipeline是handler的通道劲阎,context表示ChannelHandler和ChannelPipeline之間的關系

注意:一個ChannelHandler可以屬于多個ChannelPipeline,它也可以綁定多個ChannelHandlerContext實例鸠真,但是要使用注解sharable

注意二:handler線程不安全的所以要注意

什么是EventLoop和EventLoopGroup悯仙?

netty我們會創(chuàng)建boss和woker線程組帶著問題看一下?

netty框架主要的線程就是IO線程

Netty線程模型本質上遵循了Reactor的基礎線程模型弧哎,但是實現與Reactor存在差異.首先我們回顧一下Reactor的線程模型雁比,這地方我應該整理 傳送=======>
http://www.reibang.com/writer#/notebooks/48158437/notes/79347965

回顧完以后看下netty

雖然netty官方的demo是主從reactor模式但是也是支持netty用單或者多線程的模型

Netty的最佳實踐

1.創(chuàng)建兩個NioEventLoopGroup用于隔離nio Acceptor 和 nio 的io線程 (理解為一個是鏈接線程一個是讀數據的線程)
2.不要在ChannelHandler中啟動用戶線程稚虎,可以啟用線程可以將解碼后的消息發(fā)送到業(yè)務線程
3.解碼操作要在nio的解碼handler中操作撤嫩,不要切換到用戶線程中完成消息解碼
4.如果業(yè)務處理簡單可以直接在nio線程上完成業(yè)務邏輯編排
5.如果業(yè)務復雜,不要在nio線程上完成業(yè)務蠢终,要將解碼的消息封裝成task交付給業(yè)務線程中執(zhí)行序攘,盡快將nio線程釋放茴她,

推薦線程數量計算公式

線程數量 = (線程總時間/瓶頸資源時間) * 瓶頸資源的線程并行數

NioEventLoop:不單單是一個io線程,除了負責io的讀寫程奠,可以實現定時任務丈牢,可以處理系統(tǒng)task。(當io線程和用戶線程都要操作網絡資源的時候瞄沙,為防止并發(fā)操作導致的鎖競爭己沛,將用戶線程的操作task放到隊列中,有io線程同一處理距境,實現局部無鎖化)

Netty解決了空輪詢

空輪詢的bug:正常情況下selector的select操作是阻塞的申尼,只有被監(jiān)聽的fd有讀寫的時候才會被喚醒,但是空輪詢的bug是沒有 讀寫的時候也會被喚醒垫桂,所以會出現空輪詢的異常师幕,

產生的原因:linux2.6內核中, poll和epoll突然中斷連接的socket的場景下诬滩,會將exenset集合設置為pollup霹粥。或者是poerr 疼鸟。這樣就造成了evenset事件集合發(fā)生了變化后控。將selector被喚醒就出現了空輪詢

代碼如下:

Netty解決空輪詢的方式:

1.對selector的select的操作周期進行統(tǒng)計
2.每次出現空輪詢都記錄數
3.如果再某個周期內出現了n次空輪詢則證明出現了空輪詢的bug

Netty會通過重建selector進行系統(tǒng)恢復

ChannelFuture是異步獲取io操作結果的,分為兩種狀態(tài)uncompleted 和 completed 空镜。再其剛創(chuàng)建的時候處于第一種狀態(tài)忆蚀,在其完成之后會處于第二種狀態(tài),第三種狀態(tài)也分為操作成功姑裂,失敗馋袜,取消三種

Netty的架構剖析

Netty的行業(yè)應用

多線程編程在netty中的應用

拓展知識:

主流的操作系統(tǒng)提供了線程的實現,主要有三種

內核線程:這種線程有內核來完成線程的切換舶斧,內核通過線程調度器來對線程進行調度欣鳖,并負責將線程任務映射到不同的處理器上

用戶線程實現:完全建立在用戶空間的線程庫上,用戶線程的創(chuàng)建茴厉,啟動泽台,運行完全在用戶態(tài)中完成,不需要內核的幫助矾缓,因此執(zhí)行性能更改

混合實現:顧名思義

sun-jdk:在內核線程實現
solaris-jdk:可以設置參數選擇在哪里實現

Netty的邏輯架構

又上向下?
service
? ? |
pipeline
? ? |
Reactor

解釋:
Reactor通信調度層:包含ReactornioeventLoop怀酷。niosocketChannel , bytebuf嗜闻,主要負責監(jiān)聽網絡的讀寫和鏈接操作蜕依,負責將網絡層數據讀取到內存中,例如創(chuàng)建連接,讀寫事件样眠,并將事件觸發(fā)到pipeline等

ChannelPipeline職責鏈:負責動態(tài)的編排職責連友瘤。職責鏈選擇監(jiān)聽和處理自己關心的事件,可以將外部的消息轉換成自己內部的pojo對象檐束,這樣上層業(yè)務只關心業(yè)務處理即可

service業(yè)務編排層辫秧,對于業(yè)務開發(fā)人只需要關心業(yè)務邏輯制定即可,這種分層架構設計理念實現了nio框架各層之間的解耦被丧,便于上層協議棧的開發(fā)和業(yè)務邏輯定制

NETTY優(yōu)化的地方:

1.非阻塞的io庫盟戏,基于reactor實現,解決同步阻塞io模式下甥桂,服務端無法平滑增長客戶端的問題
2.tcp接收發(fā)送緩沖區(qū)用直接內存抓半,避免內存復制
3.通過內存池方式循環(huán)利用bytebuf,避免頻繁常見和銷毀bytebuf
4.環(huán)形數組緩沖區(qū)實現無鎖化并發(fā)編程
5.關鍵資源的單線程串行處理格嘁,避免多線程并發(fā)帶來的所競爭和額外的cpu資源消耗
6.通過引用計數器及時釋放不在引用的對象笛求,鎖粒度的內存管理降低了gc的頻率

netty的可靠性

檢測鏈路的有效性,由于長鏈接每次發(fā)送消息都要創(chuàng)建鏈路糕簿,性能相比于短連接性能更高探入,netty提供了兩種心跳檢測(空閑時檢測機制)
讀空閑超時機制
當連續(xù)T周期沒有消息可讀,觸發(fā)超時handler懂诗,并發(fā)送心跳消息蜂嗽,進行鏈路檢測,當n個周期沒有收到心跳則關閉鏈路

寫空閑超時機制
當有T個周期沒有數據要發(fā)的情況下殃恒,用戶可以基于寫空閑超時發(fā)送心跳消息植旧,進行鏈路檢測,如果連續(xù)n個周期沒有收到對方心跳离唐,主動關閉

netty的可制定性

1.責任鏈模式病附,channelpipeline基于責任鏈開發(fā),便于業(yè)務邏輯的攔截亥鬓,定制和拓展
2.基于接口的開發(fā):關鍵的類庫都提供了接口或者抽象類完沪,如果netty無法滿足用戶需求,可以由用戶自定義實現類
3.提供了工廠類嵌戈,通過重載這些工廠類可以按需創(chuàng)建出用戶實現的對象
4.提供大量系統(tǒng)參數覆积,供用戶按需設置,增強系統(tǒng)的場景定制性

Dubbo與Netty

流程圖:

DUBBO的RPC框架熟呛,通過dubbo encode方式將pojo對象編碼為dubbo協議的二進制字節(jié)流宽档,通過netty client發(fā)送給服務提供者,服務提供者的netty server從niosocketChannel讀取二進制碼流庵朝,將bytebuf解碼為dubbo請求消息并調用服務提供者吗冤,處理完后返回

netty位dubbo提供的了高性能nio框架又厉,主要職責在:
1.提供了異步高性能的nio框架
2.nio客戶端和服務端
3.心跳檢測能力
4.斷鏈重試機制
5.流量控制
6.dubbo協議的編解碼handler

NETTY CLIENT 的主要實現:

nettyhandler 持有了dubbo的自定義的channelhandler ,通過channelhandler 回調dubbo的filter欣孤,實現rpc的服務調用

學習高性能
https://www.cnblogs.com/flgb/p/13122281.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市昔逗,隨后出現的幾起案子降传,更是在濱河造成了極大的恐慌,老刑警劉巖勾怒,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婆排,死亡現場離奇詭異,居然都是意外死亡笔链,警方通過查閱死者的電腦和手機段只,發(fā)現死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鉴扫,“玉大人赞枕,你說我怎么就攤上這事∑捍矗” “怎么了炕婶?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長莱预。 經常有香客問我柠掂,道長,這世上最難降的妖魔是什么依沮? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任涯贞,我火速辦了婚禮,結果婚禮上危喉,老公的妹妹穿的比我還像新娘宋渔。我一直安慰自己,他們只是感情好辜限,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布傻谁。 她就那樣靜靜地躺著,像睡著了一般列粪。 火紅的嫁衣襯著肌膚如雪审磁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天岂座,我揣著相機與錄音态蒂,去河邊找鬼。 笑死费什,一個胖子當著我的面吹牛钾恢,可吹牛的內容都是我干的手素。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼瘩蚪,長吁一口氣:“原來是場噩夢啊……” “哼泉懦!你這毒婦竟也來了?” 一聲冷哼從身側響起疹瘦,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤崩哩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后言沐,有當地人在樹林里發(fā)現了一具尸體邓嘹,經...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年险胰,在試婚紗的時候發(fā)現自己被綠了汹押。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡起便,死狀恐怖棚贾,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情榆综,我是刑警寧澤鸟悴,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站奖年,受9級特大地震影響细诸,放射性物質發(fā)生泄漏。R本人自食惡果不足惜陋守,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一震贵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧水评,春花似錦猩系、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至疗涉,卻和暖如春拿霉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咱扣。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工绽淘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人闹伪。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓沪铭,卻偏偏與公主長得像壮池,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子杀怠,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內容