Hystrix技術(shù)解析(圖片版)

一、認識Hystrix

Hystrix是Netflix開源的一款容錯框架贺纲,包含常用的容錯方法:線程池隔離、信號量隔離褪测、熔斷猴誊、降級回退。在高并發(fā)訪問下侮措,系統(tǒng)所依賴的服務(wù)的穩(wěn)定性對系統(tǒng)的影響非常大懈叹,依賴有很多不可控的因素,比如網(wǎng)絡(luò)連接變慢分扎,資源突然繁忙澄成,暫時不可用,服務(wù)脫機等笆包。我們要構(gòu)建穩(wěn)定环揽、可靠的分布式系統(tǒng),就必須要有這樣一套容錯方法庵佣。
本文將逐一分析線程池隔離歉胶、信號量隔離、熔斷巴粪、降級回退這四種技術(shù)的原理與實踐通今。

二、線程隔離

2.1為什么要做線程隔離

比如我們現(xiàn)在有3個業(yè)務(wù)調(diào)用分別是查詢訂單肛根、查詢商品辫塌、查詢用戶,且這三個業(yè)務(wù)請求都是依賴第三方服務(wù)-訂單服務(wù)派哲、商品服務(wù)臼氨、用戶服務(wù)。三個服務(wù)均是通過RPC調(diào)用芭届。當查詢訂單服務(wù)储矩,假如線程阻塞了感耙,這個時候后續(xù)有大量的查詢訂單請求過來,那么容器中的線程數(shù)量則會持續(xù)增加直致CPU資源耗盡到100%持隧,整個服務(wù)對外不可用即硼,集群環(huán)境下就是雪崩。如下圖


訂單服務(wù)不可用.png

整個tomcat容器不可用.png
2.2屡拨、線程隔離-線程池
2.2.1只酥、Hystrix是如何通過線程池實現(xiàn)線程隔離的

Hystrix通過命令模式,將每個類型的業(yè)務(wù)請求封裝成對應(yīng)的命令請求呀狼,比如查詢訂單->訂單Command裂允,查詢商品->商品Command,查詢用戶->用戶Command哥艇。每個類型的Command對應(yīng)一個線程池叫胖。創(chuàng)建好的線程池是被放入到ConcurrentHashMap中,比如查詢訂單:

final static ConcurrentHashMap<String, HystrixThreadPool> threadPools = new ConcurrentHashMap<String, HystrixThreadPool>();
threadPools.put(“hystrix-order”, new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder));

當?shù)诙尾樵冇唵握埱筮^來的時候她奥,則可以直接從Map中獲取該線程池。具體流程如下圖:

hystrix線程執(zhí)行過程和異步化.png

創(chuàng)建線程池中的線程的方法怎棱,查看源代碼如下:

創(chuàng)建線程池中的線程.png

執(zhí)行Command的方式一共四種哩俭,直接看官方文檔(https://github.com/Netflix/Hystrix/wiki/How-it-Works),具體區(qū)別如下:

  • execute():以同步堵塞方式執(zhí)行run()拳恋。調(diào)用execute()后凡资,hystrix先創(chuàng)建一個新線程運行run(),接著調(diào)用程序要在execute()調(diào)用處一直堵塞著谬运,直到run()運行完成隙赁。

  • queue():以異步非堵塞方式執(zhí)行run()。調(diào)用queue()就直接返回一個Future對象梆暖,同時hystrix創(chuàng)建一個新線程運行run()伞访,調(diào)用程序通過Future.get()拿到run()的返回結(jié)果,而Future.get()是堵塞執(zhí)行的轰驳。

  • observe():事件注冊前執(zhí)行run()/construct()厚掷。第一步是事件注冊前,先調(diào)用observe()自動觸發(fā)執(zhí)行run()/construct()(如果繼承的是HystrixCommand级解,hystrix將創(chuàng)建新線程非堵塞執(zhí)行run()冒黑;如果繼承的是HystrixObservableCommand,將以調(diào)用程序線程堵塞執(zhí)行construct())勤哗,第二步是從observe()返回后調(diào)用程序調(diào)用subscribe()完成事件注冊抡爹,如果run()/construct()執(zhí)行成功則觸發(fā)onNext()和onCompleted(),如果執(zhí)行異常則觸發(fā)onError()芒划。

  • toObservable():事件注冊后執(zhí)行run()/construct()冬竟。第一步是事件注冊前欧穴,調(diào)用toObservable()就直接返回一個Observable<String>對象,第二步調(diào)用subscribe()完成事件注冊后自動觸發(fā)執(zhí)行run()/construct()(如果繼承的是HystrixCommand诱咏,hystrix將創(chuàng)建新線程非堵塞執(zhí)行run()苔可,調(diào)用程序不必等待run();如果繼承的是HystrixObservableCommand袋狞,將以調(diào)用程序線程堵塞執(zhí)行construct()焚辅,調(diào)用程序等待construct()執(zhí)行完才能繼續(xù)往下走),如果run()/construct()執(zhí)行成功則觸發(fā)onNext()和onCompleted()苟鸯,如果執(zhí)行異常則觸發(fā)onError()
    注:
    execute()和queue()是HystrixCommand中的方法同蜻,observe()和toObservable()是HystrixObservableCommand 中的方法。從底層實現(xiàn)來講早处,HystrixCommand其實也是利用Observable實現(xiàn)的(如果我們看Hystrix的源碼的話湾蔓,可以發(fā)現(xiàn)里面大量使用了RxJava),雖然HystrixCommand只返回單個的結(jié)果砌梆,但HystrixCommand的queue方法實際上是調(diào)用了toObservable().toBlocking().toFuture()默责,而execute方法實際上是調(diào)用了queue().get()。

2.2.2咸包、如何應(yīng)用到實際代碼中
線程池實際代碼使用.png

2.2.3桃序、線程隔離-線程池小結(jié)

執(zhí)行依賴代碼的線程與請求線程(比如Tomcat線程)分離,請求線程可以自由控制離開的時間烂瘫,這也是我們通常說的異步編程媒熊,Hystrix是結(jié)合RxJava來實現(xiàn)的異步編程。通過設(shè)置線程池大小來控制并發(fā)訪問量坟比,當線程飽和的時候可以拒絕服務(wù)芦鳍,防止依賴問題擴散。

線程隔離.png

線程池隔離的優(yōu)點:
[1]:應(yīng)用程序會被完全保護起來葛账,即使依賴的一個服務(wù)的線程池滿了柠衅,也不會影響到應(yīng)用程序的其他部分。
[2]:我們給應(yīng)用程序引入一個新的風(fēng)險較低的客戶端lib的時候籍琳,如果發(fā)生問題茄茁,也是在本lib中,并不會影響到其他內(nèi)容巩割,因此我們可以大膽的引入新lib庫裙顽。
[3]:當依賴的一個失敗的服務(wù)恢復(fù)正常時,應(yīng)用程序會立即恢復(fù)正常的性能宣谈。
[4]:如果我們的應(yīng)用程序一些參數(shù)配置錯誤了愈犹,線程池的運行狀況將會很快顯示出來,比如延遲、超時漩怎、拒絕等勋颖。同時可以通過動態(tài)屬性實時執(zhí)行來處理糾正錯誤的參數(shù)配置。
[5]:如果服務(wù)的性能有變化勋锤,從而需要調(diào)整饭玲,比如增加或者減少超時時間,更改重試次數(shù)叁执,就可以通過線程池指標動態(tài)屬性修改茄厘,而且不會影響到其他調(diào)用請求。
[6]:除了隔離優(yōu)勢外谈宛,hystrix擁有專門的線程池可提供內(nèi)置的并發(fā)功能次哈,使得可以在同步調(diào)用之上構(gòu)建異步的外觀模式,這樣就可以很方便的做異步編程(Hystrix引入了Rxjava異步框架)吆录。

盡管線程池提供了線程隔離窑滞,我們的客戶端底層代碼也必須要有超時設(shè)置,不能無限制的阻塞以致線程池一直飽和恢筝。

線程池隔離的缺點:
[1]:線程池的主要缺點就是它增加了計算的開銷哀卫,每個業(yè)務(wù)請求(被包裝成命令)在執(zhí)行的時候,會涉及到請求排隊撬槽,調(diào)度和上下文切換聊训。不過Netflix公司內(nèi)部認為線程隔離開銷足夠小,不會產(chǎn)生重大的成本或性能的影響恢氯。

The Netflix API processes 10+ billion Hystrix Command executions per day using thread isolation. Each API instance has 40+ thread-pools with 5–20 threads in each (most are set to 10).
Netflix API每天使用線程隔離處理10億次Hystrix Command執(zhí)行。 每個API實例都有40多個線程池鼓寺,每個線程池中有5-20個線程(大多數(shù)設(shè)置為10個)勋拟。

對于不依賴網(wǎng)絡(luò)訪問的服務(wù),比如只依賴內(nèi)存緩存這種情況下妈候,就不適合用線程池隔離技術(shù)敢靡,而是采用信號量隔離。

2.3苦银、線程隔離-信號量啸胧。

2.3.1、線程池和信號量的區(qū)別

上面談到了線程池的缺點幔虏,當我們依賴的服務(wù)是極低延遲的纺念,比如訪問內(nèi)存緩存,就沒有必要使用線程池的方式想括,那樣的話開銷得不償失陷谱,而是推薦使用信號量這種方式。下面這張圖說明了線程池隔離和信號量隔離的主要區(qū)別:線程池方式下業(yè)務(wù)請求線程和執(zhí)行依賴的服務(wù)的線程不是同一個線程;信號量方式下業(yè)務(wù)請求線程和執(zhí)行依賴服務(wù)的線程是同一個線程

信號量和線程池的區(qū)別.png

2.3.2烟逊、如何使用信號量來隔離線程

將屬性execution.isolation.strategy設(shè)置為SEMAPHORE 渣窜,象這樣 ExecutionIsolationStrategy.SEMAPHORE,則Hystrix使用信號量而不是默認的線程池來做隔離宪躯。

信號量使用.png

2.3.4乔宿、線程隔離-信號量小結(jié)

信號量隔離的方式是限制了總的并發(fā)數(shù),每一次請求過來访雪,請求線程和調(diào)用依賴服務(wù)的線程是同一個線程详瑞,那么如果不涉及遠程RPC調(diào)用(沒有網(wǎng)絡(luò)開銷)則使用信號量來隔離,更為輕量冬阳,開銷更小蛤虐。

三、熔斷

3.1肝陪、熔斷器(Circuit Breaker)介紹

熔斷器驳庭,現(xiàn)實生活中有一個很好的類比,就是家庭電路中都會安裝一個保險盒氯窍,當電流過大的時候保險盒里面的保險絲會自動斷掉饲常,來保護家里的各種電器及電路。Hystrix中的熔斷器(Circuit Breaker)也是起到這樣的作用狼讨,Hystrix在運行過程中會向每個commandKey對應(yīng)的熔斷器報告成功贝淤、失敗、超時和拒絕的狀態(tài)政供,熔斷器維護計算統(tǒng)計的數(shù)據(jù)播聪,根據(jù)這些統(tǒng)計的信息來確定熔斷器是否打開。如果打開布隔,后續(xù)的請求都會被截斷离陶。然后會隔一段時間默認是5s,嘗試半開衅檀,放入一部分流量請求進來招刨,相當于對依賴服務(wù)進行一次健康檢查,如果恢復(fù)哀军,熔斷器關(guān)閉沉眶,隨后完全恢復(fù)調(diào)用。如下圖:

熔斷器開關(guān)圖.png

說明杉适,上面說的commandKey谎倔,就是在初始化的時候設(shè)置的andCommandKey(HystrixCommandKey.Factory.asKey("testCommandKey"))

再來看下熔斷器在整個Hystrix流程圖中的位置,從步驟4開始猿推,如下圖:

Hystrix流程圖.png

Hystrix會檢查Circuit Breaker的狀態(tài)传藏。如果Circuit Breaker的狀態(tài)為開啟狀態(tài),Hystrix將不會執(zhí)行對應(yīng)指令,而是直接進入失敗處理狀態(tài)(圖中8 Fallback)毯侦。如果Circuit Breaker的狀態(tài)為關(guān)閉狀態(tài)哭靖,Hystrix會繼續(xù)進行線程池、任務(wù)隊列侈离、信號量的檢查(圖中5)

3.2试幽、如何使用熔斷器(Circuit Breaker)

由于Hystrix是一個容錯框架,因此我們在使用的時候卦碾,要達到熔斷的目的只需配置一些參數(shù)就可以了铺坞。但我們要達到真正的效果,就必須要了解這些參數(shù)洲胖。Circuit Breaker一共包括如下6個參數(shù)济榨。
1、circuitBreaker.enabled
是否啟用熔斷器绿映,默認是TURE擒滑。
2、circuitBreaker.forceOpen
熔斷器強制打開叉弦,始終保持打開狀態(tài)丐一。默認值FLASE。
3淹冰、circuitBreaker.forceClosed
熔斷器強制關(guān)閉库车,始終保持關(guān)閉狀態(tài)。默認值FLASE樱拴。
4柠衍、circuitBreaker.errorThresholdPercentage
設(shè)定錯誤百分比,默認值50%晶乔,例如一段時間(10s)內(nèi)有100個請求珍坊,其中有55個超時或者異常返回了,那么這段時間內(nèi)的錯誤百分比是55%瘪弓,大于了默認值50%,這種情況下觸發(fā)熔斷器-打開禽最。
5腺怯、circuitBreaker.requestVolumeThreshold
默認值20.意思是至少有20個請求才進行errorThresholdPercentage錯誤百分比計算。比如一段時間(10s)內(nèi)有19個請求全部失敗了川无。錯誤百分比是100%呛占,但熔斷器不會打開,因為requestVolumeThreshold的值是20. 這個參數(shù)非常重要懦趋,熔斷器是否打開首先要滿足這個條件晾虑,源代碼如下

熔斷器打開先后條件判斷.png

6、circuitBreaker.sleepWindowInMilliseconds
半開試探休眠時間,默認值5000ms帜篇。當熔斷器開啟一段時間之后比如5000ms糙捺,會嘗試放過去一部分流量進行試探,確定依賴服務(wù)是否恢復(fù)笙隙。

測試代碼(模擬10次調(diào)用洪灯,錯誤百分比為5%的情況下,打開熔斷器開關(guān)竟痰。):

熔斷器實際使用代碼1.png
熔斷器實際使用代碼2.png

測試結(jié)果:

call times:1 result:fallback: isCircuitBreakerOpen: false
call times:2 result:running: isCircuitBreakerOpen: false
call times:3 result:running: isCircuitBreakerOpen: false
call times:4 result:fallback: isCircuitBreakerOpen: false
call times:5 result:running: isCircuitBreakerOpen: false
call times:6 result:fallback: isCircuitBreakerOpen: false
call times:7 result:fallback: isCircuitBreakerOpen: false
call times:8 result:fallback: isCircuitBreakerOpen: false
call times:9 result:fallback: isCircuitBreakerOpen: false
call times:10 result:fallback: isCircuitBreakerOpen: false
熔斷器打開
call times:11 result:fallback: isCircuitBreakerOpen: true
call times:12 result:fallback: isCircuitBreakerOpen: true
call times:13 result:fallback: isCircuitBreakerOpen: true
call times:14 result:fallback: isCircuitBreakerOpen: true
call times:15 result:fallback: isCircuitBreakerOpen: true
call times:16 result:fallback: isCircuitBreakerOpen: true
call times:17 result:fallback: isCircuitBreakerOpen: true
call times:18 result:fallback: isCircuitBreakerOpen: true
call times:19 result:fallback: isCircuitBreakerOpen: true
call times:20 result:fallback: isCircuitBreakerOpen: true
5s后熔斷器關(guān)閉
call times:21 result:running: isCircuitBreakerOpen: false
call times:22 result:running: isCircuitBreakerOpen: false
call times:23 result:fallback: isCircuitBreakerOpen: false
call times:24 result:running: isCircuitBreakerOpen: false
call times:25 result:running: isCircuitBreakerOpen: false

3.3签钩、熔斷器(Circuit Breaker)源代碼HystrixCircuitBreaker.java分析
HystrixCircuitBreaker.java.png

Factory 是一個工廠類,提供HystrixCircuitBreaker實例

Factory源碼解析.png

HystrixCircuitBreakerImpl是HystrixCircuitBreaker的實現(xiàn)坏快,allowRequest()铅檩、isOpen()、markSuccess()都會在HystrixCircuitBreakerImpl有默認的實現(xiàn)莽鸿。

HystrixCircuitBreakerImpl-1.png
HystrixCircuitBreakerImpl-allowSingleTest().png
HystrixCircuitBreakerImpl-isOpen().png
3.4昧旨、熔斷器小結(jié)

每個熔斷器默認維護10個bucket,每秒一個bucket,每個blucket記錄成功,失敗,超時,拒絕的狀態(tài),默認錯誤超過50%且10秒內(nèi)超過20個請求進行中斷攔截富拗。下圖顯示HystrixCommand或HystrixObservableCommand如何與HystrixCircuitBreaker及其邏輯和決策流程進行交互臼予,包括計數(shù)器在斷路器中的行為。

四啃沪、回退降級

4.1粘拾、降級

所謂降級,就是指在在Hystrix執(zhí)行非核心鏈路功能失敗的情況下创千,我們?nèi)绾翁幚礴止停热缥覀兎祷啬J值等。如果我們要回退或者降級處理追驴,代碼上需要實現(xiàn)HystrixCommand.getFallback()方法或者是HystrixObservableCommand. HystrixObservableCommand()械哟。

CommandHelloFailure-降級.png
4.2、Hystrix的降級回退方式

Hystrix一共有如下幾種降級回退模式:

4.2.1殿雪、Fail Fast 快速失敗
 @Override
    protected String run() {
        if (throwException) {
            throw new RuntimeException("failure from CommandThatFailsFast");
        } else {
            return "success";
        }
    }

如果我們實現(xiàn)的是HystrixObservableCommand.java則 重寫 resumeWithFallback方法

@Override
    protected Observable<String> resumeWithFallback() {
        if (throwException) {
            return Observable.error(new Throwable("failure from CommandThatFailsFast"));
        } else {
            return Observable.just("success");
        }
    }
4.2.2暇咆、Fail Silent 無聲失敗

返回null,空Map丙曙,空List

fail silent.png
@Override
    protected String getFallback() {
        return null;
    }
@Override
    protected List<String> getFallback() {
        return Collections.emptyList();
    }
@Override
    protected Observable<String> resumeWithFallback() {
        return Observable.empty();
    }
4.2.3爸业、Fallback: Static 返回默認值

回退的時候返回靜態(tài)嵌入代碼中的默認值,這樣就不會導(dǎo)致功能以Fail Silent的方式被清楚亏镰,也就是用戶看不到任何功能了扯旷。而是按照一個默認的方式顯示。

@Override
    protected Boolean getFallback() {
        return true;
    }
@Override
    protected Observable<Boolean> resumeWithFallback() {
        return Observable.just( true );
    }
4.2.4索抓、Fallback: Stubbed 自己組裝一個值返回

當我們執(zhí)行返回的結(jié)果是一個包含多個字段的對象時钧忽,則會以Stubbed 的方式回退毯炮。Stubbed 值我們建議在實例化Command的時候就設(shè)置好一個值。以countryCodeFromGeoLookup為例耸黑,countryCodeFromGeoLookup的值桃煎,是在我們調(diào)用的時候就注冊進來初始化好的。CommandWithStubbedFallback command = new CommandWithStubbedFallback(1234, "china");主要代碼如下:

CommandWithStubbedFallback.png
4.2.5崎坊、Fallback: Cache via Network 利用遠程緩存

通過遠程緩存的方式备禀。在失敗的情況下再發(fā)起一次remote請求,不過這次請求的是一個緩存比如redis奈揍。由于是又發(fā)起一起遠程調(diào)用曲尸,所以會重新封裝一次Command,這個時候要注意,執(zhí)行fallback的線程一定要跟主線程區(qū)分開,也就是重新命名一個ThreadPoolKey衅谷。

Cache via Network.png
Cache via Network.png
4.2.6缤弦、Primary + Secondary with Fallback 主次方式回退(主要和次要)

這個有點類似我們?nèi)粘i_發(fā)中需要上線一個新功能,但為了防止新功能上線失敗可以回退到老的代碼,我們會做一個開關(guān)比如使用zookeeper做一個配置開關(guān),可以動態(tài)切換到老代碼功能。那么Hystrix它是使用通過一個配置來在兩個command中進行切換鹏倘。

Primary + Secondary with Fallback.png
CommandFacadeWithPrimarySecondary-1.png
CommandFacadeWithPrimarySecondary-2.png
CommandFacadeWithPrimarySecondary-3.png
4.3、回退降級小結(jié)

降級的處理方式顽爹,返回默認值纤泵,返回緩存里面的值(包括遠程緩存比如redis和本地緩存比如jvmcache)。
但回退的處理方式也有不適合的場景:
1镜粤、寫操作
2捏题、批處理
3、計算
以上幾種情況如果失敗肉渴,則程序就要將錯誤返回給調(diào)用者公荧。

總結(jié)

Hystrix為我們提供了一套線上系統(tǒng)容錯的技術(shù)實踐方法,我們通過在系統(tǒng)中引入Hystrix的jar包可以很方便的使用線程隔離同规、熔斷循狰、回退等技術(shù)。同時它還提供了監(jiān)控頁面配置券勺,方便我們管理查看每個接口的調(diào)用情況绪钥。像spring cloud這種微服務(wù)構(gòu)建模式中也引入了Hystrix,我們可以放心使用Hystrix的線程隔離技術(shù)朱灿,來防止雪崩這種可怕的致命性線上故障昧识。

轉(zhuǎn)載請注明出處钠四,并附上鏈接 http://www.reibang.com/p/3e11ac385c73

參考資料:
https://github.com/Netflix/Hystrix/wiki
《億級流量網(wǎng)站架構(gòu)核心技術(shù)》一書

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盗扒,一起剝皮案震驚了整個濱河市跪楞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌侣灶,老刑警劉巖甸祭,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異褥影,居然都是意外死亡池户,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門凡怎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來校焦,“玉大人,你說我怎么就攤上這事统倒≌洌” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵房匆,是天一觀的道長耸成。 經(jīng)常有香客問我,道長浴鸿,這世上最難降的妖魔是什么井氢? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮岳链,結(jié)果婚禮上花竞,老公的妹妹穿的比我還像新娘。我一直安慰自己宠页,他們只是感情好左胞,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著举户,像睡著了一般烤宙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俭嘁,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天躺枕,我揣著相機與錄音,去河邊找鬼供填。 笑死拐云,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的近她。 我是一名探鬼主播叉瘩,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粘捎!你這毒婦竟也來了薇缅?” 一聲冷哼從身側(cè)響起危彩,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎泳桦,沒想到半個月后汤徽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡灸撰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年谒府,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浮毯。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡完疫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出债蓝,到底是詐尸還是另有隱情趋惨,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布惦蚊,位于F島的核電站器虾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蹦锋。R本人自食惡果不足惜兆沙,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望莉掂。 院中可真熱鬧葛圃,春花似錦、人聲如沸憎妙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽厘唾。三九已至褥符,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抚垃,已是汗流浹背喷楣。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鹤树,地道東北人铣焊。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像罕伯,于是被迫代替她去往敵國和親曲伊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

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