第19節(jié):從庫(kù)MTS多線程并行回放(一)


本節(jié)包含一個(gè)筆記如下:
http://www.reibang.com/p/8706d7422d89


之所以將MTS的相關(guān)知識(shí)放到這里講解摔寨,是因?yàn)楹竺娴膸坠?jié)會(huì)用到這部分知識(shí)淑廊,如果不先講解后面幾節(jié)將沒(méi)有辦法進(jìn)行描述腻格。

一、綜述

與單SQL線程的回放不同旗闽,MTS包含多個(gè)工作線程酬核,原有的SQL線程蛻變?yōu)閰f(xié)調(diào)線程。SQL協(xié)調(diào)線程同時(shí)還承擔(dān)了檢查點(diǎn)的工作适室。我們知道并行回放的方式有兩種嫡意,包含LOGICAL_CLOCK和DATABASE,體現(xiàn)在判定哪些事物能夠并行回放的規(guī)則不同捣辆。實(shí)際上源碼對(duì)應(yīng)兩個(gè)不同的類:

  • Mts_submode_logical_clock
  • Mts_submode_database

這里只準(zhǔn)備討論基于LOGICAL_CLOCK的并發(fā)方式蔬螟,而不會(huì)討論老的基于DATABASE的方式,下面是我設(shè)置的參數(shù):

  • slave_parallel_type:LOGICAL_CLOCK
  • slave_parallel_workers :4

注意slave_parallel_workers設(shè)置的是工作線程的個(gè)數(shù)罪帖,且不包協(xié)調(diào)線程促煮,因此如果不想使用MTS應(yīng)該將這個(gè)參數(shù)設(shè)置為0,然后‘stop slave;start slave’才能生效整袁。因?yàn)楣ぷ骶€程在啟動(dòng)的時(shí)候已經(jīng)初始化完畢了菠齿。

因?yàn)槲覀冎涝?.7中即便不開啟GTID也包含的匿名的GTID Event,它攜帶了last commit和seq number坐昙,因此即便關(guān)閉GTID也可以使用MTS绳匀,但是不建議后面第26節(jié)可以找到原因。

在前面我們討論了MySQL層事務(wù)提交的流程和基于WRITESET的并行復(fù)制方式炸客,我們總共提到了三種生成last commit和seq number的方式:

  • ORDER_COMMIT
  • WRITESET
  • WRITESET_SESSION

它們控制的是生成last commit和seq number的規(guī)則疾棵。而從庫(kù)只要將參數(shù)slave_parallel_type設(shè)置為L(zhǎng)OGICAL_CLOCK,其能否并行的依據(jù)就是last commit和seq number痹仙。

我們下面的描述還是以一個(gè)正常的‘Delete’語(yǔ)句刪除一行數(shù)據(jù)的Event來(lái)描述是尔,那么這個(gè)事物Event的順序如下:

Event類型
GTID_LOG_EVENT
QUERY_EVENT
MAP_EVENT
DELETE_EVENT
XID_EVENT

同時(shí)在此之前我們先來(lái)明確一下MySQL中持久化MTS信息的三個(gè)場(chǎng)所,因?yàn)楹蛡鹘y(tǒng)的單SQL線程的主從不同开仰,MTS需要存儲(chǔ)更多的信息拟枚。注意我們只討論master_info_repository和relay_log_info_repository為TABLE的情況,如下:

  • slave_master_info表:由IO線程進(jìn)行更新众弓,超過(guò)sync_master_info設(shè)置更新恩溅,單位Event個(gè)數(shù)。
  • relay_log_info_repository表:由SQL協(xié)調(diào)線程執(zhí)行檢查點(diǎn)的時(shí)候進(jìn)行更新谓娃。
  • slave_worker_info表:由工作線程每次提交事務(wù)的時(shí)候更新脚乡。

更加詳細(xì)的解釋參考第25節(jié),同時(shí)會(huì)解釋為什么只考慮master_info_repository和relay_log_info_repository為TABLE的原因滨达。

二奶稠、協(xié)調(diào)線程的分發(fā)機(jī)制

協(xié)調(diào)線程在Event的分發(fā)中主要完成下面兩個(gè)工作:

  • 判定事務(wù)是否可以并行回放俯艰。
  • 判定事務(wù)由哪一個(gè)工作線程進(jìn)行回放。

和單SQL線程執(zhí)行的流程不同窒典,主要體現(xiàn)在函數(shù)apply_event_and_update_pos下面蟆炊,對(duì)于單線程而言會(huì)完成Event的應(yīng)用,而對(duì)用MTS而言就是只會(huì)完成Event的分發(fā)瀑志,具體的應(yīng)用將會(huì)由工作線程完成涩搓。
這里說(shuō)一下簡(jiǎn)化的流程,具體函數(shù)調(diào)用參考筆記劈猪。下面是一張流程圖(圖19-1):

19-1.png

三昧甘、步驟解析

下面對(duì)每一步進(jìn)行解析如下:

(1)如果是GTID_LOG_EVENT代表事物開始,將本事物加入到GAQ隊(duì)列中(下一節(jié)會(huì)詳細(xì)描述GAQ)战得〕浔撸可參考函數(shù)Log_event::get_slave_worker。

(2)將GTID_LOG_EVENT加入到curr_group_da隊(duì)列中暫存常侦〗奖可參考函數(shù)Log_event::get_slave_worker。

(3)獲取GTID_LOG_EVENT中的last commit和seq number值聋亡≈庀埃可參考函數(shù)Mts_submode_logical_clock::schedule_next_event。

(4)獲取current_lwm值坡倔,這個(gè)值代表的是所有在GAQ隊(duì)列上還沒(méi)有提交完成事務(wù)中最早的那個(gè)事務(wù)的前一個(gè)已經(jīng)提交事務(wù)的seq number漂佩,可能后面的事務(wù)已經(jīng)提交完成了,聽起來(lái)可能比較拗口但很重要罪塔,如果都提交完成了那么就是取最新提交的事務(wù)的seq number投蝉,下面的圖表達(dá)的就是這個(gè)意思,這個(gè)圖是源碼中的征堪。這個(gè)值的獲取可參考函數(shù)Mts_submode_logical_clock::get_lwm_timestamp瘩缆。

       the last time index containg lwm
               +------+
               | LWM  |
               |  |   |
               V  V   V
GAQ:x  xoooooxxxxxXXXXX...X
             ^   ^
             |   | LWM+1(LWM代表的是檢查點(diǎn)指向的位置)
             |
             + new current_lwm(這里就是current_lwm)

      <---- logical (commit) time ----
      
here `x' stands for committed, `X' for committed and discarded from
the running range of the queue, `o' for not committed.

我們可以先不看LWM部分,對(duì)于檢查點(diǎn)的LWM后面在討論佃蚜。seq number從右向左遞增庸娱,在GAQ中實(shí)際上有三種值:

  • X:已經(jīng)做了檢查點(diǎn),在GAQ中出隊(duì)的事物爽锥。
  • x:已經(jīng)提交完成的事物。
  • o:沒(méi)有提交完成的事物畔柔。

我們可以看到我們需要獲取的current_lwm并不是最新一次提交事物的seq number的值氯夷,而是最早未提交事物的前一個(gè)已經(jīng)提交事物的seq number。這一點(diǎn)很重要靶擦,因?yàn)槔斫夂缶蜁?huì)知道大事務(wù)是如何影響MTS的并行回放的腮考,同時(shí)中間的5個(gè)‘o’實(shí)際上就是所謂的‘gap’雇毫,關(guān)于‘gap’下一節(jié)還會(huì)詳細(xì)描述。

(5)將GTID_LOG_EVENT中的last commit和當(dāng)前current_lwm進(jìn)行比較踩蔚∨锓牛可以參考函數(shù)Mts_submode_logical_clock::schedule_next_event。下面是大概的規(guī)則:

  • 如果last commit小于等于current_lwm表示可以進(jìn)行并行回放馅闽,繼續(xù)飘蚯。
  • 如果last commit大于current_lwm則表示不能進(jìn)行并行回放。這個(gè)時(shí)候協(xié)調(diào)線程就需要等待了福也,直到小于等于的條件成立局骤。成立后協(xié)調(diào)線程會(huì)被工作線程喚醒。等待期間狀態(tài)被置為“Waiting for dependent transaction to commit”暴凑。

源碼處也比較簡(jiǎn)單如下:

    longlong lwm_estimate= estimate_lwm_timestamp(); 
//這個(gè)值 只有在 出現(xiàn) 下面等待的時(shí)候 才會(huì)設(shè)置 min_waited_timestamp 峦甩,
//設(shè)置了min_waited_timestamp才會(huì)更新lwm_estimate
    if (!clock_leq(last_committed, lwm_estimate) && 
//  @return   true  when a "<=" b,false otherwise  last_committed<=lwm_estimate
        rli->gaq->assigned_group_index != rli->gaq->entry) 
    {
      if (wait_for_last_committed_trx(rli, last_committed, lwm_estimate)) 
//等待上一次 組提交的完成 Waiting for dependent transaction to commit

(6)如果是QUERY_EVENT則加入到curr_group_da隊(duì)列中暫存。

(7)如果是MAP_EVENT進(jìn)行工作線程的分配现喳。參考函數(shù)Mts_submode_logical_clock::get_least_occupied_worker凯傲,分配工作線程如下:

  • 如果有空閑的工作線程則分配完成,繼續(xù)嗦篱。
  • 如果沒(méi)有空閑的工作線程則等待空閑的工作線程冰单。這種情況下狀態(tài)會(huì)置為“Waiting for slave workers to process their queues”。

下面是分配的標(biāo)準(zhǔn)默色,其實(shí)也很簡(jiǎn)單:

  for (Slave_worker **it= rli->workers.begin(); it != rli->workers.end(); ++it)
  {
    Slave_worker *w_i= *it;
    if (w_i->jobs.len == 0)
//任務(wù)隊(duì)列為0表示本W(wǎng)orker線程空閑可以分配
      return w_i;
  }
  return 0;

(8)將GTID_LOG_EVENT和QUERY_EVENT分配給工作線程球凰。可參考append_item_to_jobs函數(shù)腿宰。

前面工作線程已經(jīng)分配了呕诉,這里就可以開始將Event分配給這個(gè)工作線程了。分配的時(shí)候需要檢查工作線程的任務(wù)隊(duì)列是否已滿吃度,如果滿了需要等待甩挫,狀態(tài)置為“Waiting for Slave Worker queue”。因?yàn)榉峙涞膯挝皇荅vent椿每,對(duì)于一個(gè)事務(wù)而言可能包含很多Event伊者,如果工作線程應(yīng)用的速度趕不上協(xié)調(diào)線程入隊(duì)的速度,可能導(dǎo)致任務(wù)隊(duì)列的積壓间护,因此任務(wù)隊(duì)列被占滿是可能的亦渗。任務(wù)隊(duì)列的大小為16384如下:

mts_slave_worker_queue_len_max= 16384;  

下面是入隊(duì)的部分代碼:

  while (worker->running_status == Slave_worker::RUNNING && !thd->killed &&
         (ret= en_queue(&worker->jobs, job_item)) == -1)
//如果已經(jīng)滿了
  {
    thd->ENTER_COND(&worker->jobs_cond, &worker->jobs_lock,
                    &stage_slave_waiting_worker_queue, &old_stage);
//標(biāo)記等待狀態(tài)
    worker->jobs.overfill= TRUE;
    worker->jobs.waited_overfill++;
    rli->mts_wq_overfill_cnt++; //標(biāo)記隊(duì)列滿的次數(shù)
    mysql_cond_wait(&worker->jobs_cond, &worker->jobs_lock);
//等待喚醒
    mysql_mutex_unlock(&worker->jobs_lock);
    thd->EXIT_COND(&old_stage);
    mysql_mutex_lock(&worker->jobs_lock);
  }

(9)MAP_EVENT分配給工作線程,同上汁尺。
(10)DELETE_EVENT分配給工作線程法精,同上。
(11)XID_EVENT分配給工作線程,但是這里還需要額外的處理搂蜓,主要處理一些和檢查點(diǎn)相關(guān)的信息狼荞,這里關(guān)注一點(diǎn)如下:

ptr_group->checkpoint_log_name= my_strdup(key_memory_log_event, 
rli->get_group_master_log_name(), MYF(MY_WME));
ptr_group->checkpoint_log_pos= rli->get_group_master_log_pos();
ptr_group->checkpoint_relay_log_name=my_strdup(key_memory_log_event, 
rli->get_group_relay_log_name(), MYF(MY_WME));
ptr_group->checkpoint_relay_log_pos= rli->get_group_relay_log_pos();
ptr_group->ts= common_header->when.tv_sec + (time_t) exec_time; 
//Seconds_behind_master related .checkpoint
//的時(shí)候會(huì)將這個(gè)值再次傳遞 mts_checkpoint_routine()      
ptr_group->checkpoint_seqno= rli->checkpoint_seqno;
//獲取seqno 這個(gè)值會(huì)在chkpt后減去偏移量

如果檢查點(diǎn)處于這個(gè)事務(wù)上,那么這些信息會(huì)出現(xiàn)在表 slave_worker_info中帮碰,并且會(huì)出現(xiàn)在show slave status中相味。也就是說(shuō),show slave status中很多信息是來(lái)自MTS的檢查點(diǎn)殉挽。下一節(jié)將詳細(xì)描述檢查點(diǎn)丰涉。

(12)如果上面Event的分配過(guò)程大于2分鐘(120秒),可能會(huì)出現(xiàn)一個(gè)日志如下:

image.png

這個(gè)截圖也是一個(gè)朋友問(wèn)的問(wèn)題此再。實(shí)際上這個(gè)日志可以算一個(gè)警告昔搂。實(shí)際上對(duì)應(yīng)的源碼為:

sql_print_information("Multi-threaded slave statistics%s: "
                "seconds elapsed = %lu; "
                "events assigned = %llu; "
                "worker queues filled over overrun level = %lu; "
                "waited due a Worker queue full = %lu; "
                "waited due the total size = %lu; "
                "waited at clock conflicts = %llu "
                "waited (count) when Workers occupied = %lu "
                "waited when Workers occupied = %llu",
                rli->get_for_channel_str(),
                static_cast<unsigned long>
                (my_now - rli->mts_last_online_stat),
//消耗總時(shí)間 單位秒
                rli->mts_events_assigned,
//總的event分配的個(gè)數(shù)
                rli->mts_wq_overrun_cnt,
// worker線程分配隊(duì)列大于 90%的次數(shù) 當(dāng)前硬編碼  14746
                rli->mts_wq_overfill_cnt,    
//由于work 分配隊(duì)列已滿造成的等待次數(shù) 當(dāng)前硬編碼 16384
                rli->wq_size_waits_cnt, 
//大Event的個(gè)數(shù) 一般不會(huì)存在
                rli->mts_total_wait_overlap,
//由于上一組并行有大事物沒(méi)有提交導(dǎo)致不能分配worker線程的等待時(shí)間 單位納秒
                rli->mts_wq_no_underrun_cnt, 
//work線程由于沒(méi)有空閑的而等待的次數(shù)
                rli->mts_total_wait_worker_avail);
//work線程由于沒(méi)有空閑的而等待的時(shí)間   單位納秒

因?yàn)榻?jīng)常看到朋友問(wèn)這里詳細(xì)說(shuō)明一下它們的含義输拇,從前面的分析中我們一共看到三個(gè)等待點(diǎn):

  • “Waiting for dependent transaction to commit”

由于協(xié)調(diào)線程判定本事務(wù)由于last commit大于current_lwm因此不能并行回放摘符,協(xié)調(diào)線程處于等待,大事務(wù)會(huì)加劇這種情況策吠。

  • “Waiting for slave workers to process their queues”

由于沒(méi)有空閑的工作線程逛裤,協(xié)調(diào)線程會(huì)等待。這種情況說(shuō)明理論上的并行度是理想的猴抹,但是可能是參數(shù)slave_parallel_workers設(shè)置不夠带族。當(dāng)然設(shè)置工作線程的個(gè)數(shù)應(yīng)該和服務(wù)器的配置和負(fù)載相結(jié)合考慮,因?yàn)榈?9節(jié)我們會(huì)看到線程是CPU調(diào)度最小的單位蟀给。

  • “Waiting for Slave Worker queue”

由于工作線程的任務(wù)隊(duì)列已滿蝙砌,協(xié)調(diào)線程會(huì)等待。這種情況前面說(shuō)過(guò)是由于一個(gè)事務(wù)包含了過(guò)多的Event并且工作線程應(yīng)用Event的速度趕不上協(xié)調(diào)線程分配Event的速度跋理,導(dǎo)致了積壓并且超過(guò)了16384個(gè)Event择克。

另外實(shí)際上還有一種等待如下:
“Waiting for Slave Workers to free pending events”:由所謂的‘big event’造成的,什么是‘big event’呢前普,源碼中描述為:event size is greater than slave_pending_jobs_size_max but less than slave_max_allowed_packet肚邢。我個(gè)人認(rèn)為出現(xiàn)的可能性不大,因此沒(méi)做過(guò)多考慮拭卿÷夂可以在函數(shù)append_item_to_jobs中找到答案。

我們下面對(duì)應(yīng)日志中的輸出進(jìn)行詳細(xì)解釋峻厚,如下:

指標(biāo) 解釋
seconds elapsed 整個(gè)分配過(guò)程消耗的時(shí)間响蕴,單位秒,超過(guò)120秒會(huì)出現(xiàn)這個(gè)日志惠桃。
events assigned 本工作線程分配的Event數(shù)量浦夷。
worker queues filled over overrun level 本工作線程任務(wù)隊(duì)列中Event個(gè)數(shù)大于90%的次數(shù)懊渡。當(dāng)前硬編碼大于14746。
waited due a Worker queue full 本工作線程任務(wù)隊(duì)列已滿的次數(shù)军拟。當(dāng)前硬編碼大于16384。和前面第三點(diǎn)對(duì)應(yīng)誓禁。
waited due the total size ‘big event’的出現(xiàn)的次數(shù)懈息。
waited at clock conflicts 由于不能并行回放,協(xié)調(diào)線程等待的時(shí)間摹恰,單位納秒辫继。和前面第一點(diǎn)對(duì)應(yīng)。
waited (count) when Workers occupied 由于沒(méi)有空閑的工作線程而等待的次數(shù)俗慈。對(duì)應(yīng)前面第二點(diǎn)姑宽。
waited when Workers occupied 由于沒(méi)有空閑的工作線程而等待的時(shí)間。對(duì)應(yīng)前面第二點(diǎn)闺阱。

我們可以看到這個(gè)日志還是記錄很全的炮车,基本覆蓋了前面我們討論的全部可能性。那么我們?cè)倏纯窗咐械娜罩竞ɡ#瑆aited at clock conflicts=91895169800 大約91秒瘦穆。120秒鐘大約91秒都因?yàn)椴荒懿⑿谢胤哦斐傻牡却苊黠@應(yīng)該考慮是否有大事物的存在赊豌。

四扛或、并行回放判定的列子

下面是我主庫(kù)使用WRITESET方式生成的一段binary log片段,我們主要觀察lastcommit和seq number碘饼,通過(guò)分析來(lái)熟悉這種過(guò)程熙兔。

image.png

我們根據(jù)剛才說(shuō)的并行判斷規(guī)則,即:

  • 如果last commit小于等于current_lwm表示可以進(jìn)行并行回放艾恼,繼續(xù)住涉。
  • 如果last commit大于current_lwm則表示不能進(jìn)行并行回放,需要等待蒂萎。
具體解析如下:

(last commit:22 seq number:23)這個(gè)事務(wù)會(huì)在(last commit:21 seq number:22)事務(wù)執(zhí)行完成后執(zhí)行因?yàn)椋╨ast commit:22<= seq number:22)秆吵,后面的事務(wù)直到(last_commit:22 seq number:30),實(shí)際上都可以并行執(zhí)行五慈,我們先假設(shè)他們都執(zhí)行完成了纳寂。我們繼續(xù)觀察隨后的三個(gè)事務(wù)如下:

  • last_committed:29 sequence_number:31
  • last_committed:30 sequence_number:32
  • last_committed:27 sequence_number:33

我們注意到到這是基于WRITESET的并行復(fù)制下明顯的特征息罗。 last commit可能比上一個(gè)事務(wù)更小鸟召,這就是我們前面說(shuō)的根據(jù)Writeset的歷史MAP信息計(jì)算出來(lái)的。因此還是根據(jù)上面的規(guī)則它們?nèi)齻€(gè)是可以并行執(zhí)行的窒朋。因?yàn)楹苊黠@:

  • last_committed:29 <= current_lwm:30
  • last_committed:30 <= current_lwm:30
  • last_committed:27 <= current_lwm:30

但是如果(last commit:22 seq number:30)這個(gè)事務(wù)之前有一個(gè)大事務(wù)沒(méi)有執(zhí)行完成的話争拐,那么current_lwm的取值將不會(huì)是30腋粥。比如(last commit:22 seq number:27)這個(gè)事務(wù)是大事務(wù)那么current_lwm將會(huì)標(biāo)記為26晦雨,上面的三個(gè)事務(wù)將會(huì)被堵塞,并且分配(last commit:29 seq number:31)的時(shí)候就已經(jīng)堵塞了隘冲,原因如下:

  • last_committed:29 > current_lwm:26
  • last_committed:30 > current_lwm:26
  • last_committed:27 > current_lwm:26

我們?cè)倏紤]一下基于WRITESET的并行復(fù)制下(last commit:27 seq number:33)這個(gè)事務(wù)闹瞧,因?yàn)樵谖覀儾⑿幸?guī)則下last commit越小獲得并發(fā)的可能性越高。因此基于WRITESET的并行復(fù)制確實(shí)提高了從庫(kù)回放的并行度展辞,但正如第16節(jié)所講主庫(kù)會(huì)有一定的開銷奥邮。


第19節(jié)結(jié)束

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市罗珍,隨后出現(xiàn)的幾起案子洽腺,更是在濱河造成了極大的恐慌,老刑警劉巖覆旱,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蘸朋,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡扣唱,警方通過(guò)查閱死者的電腦和手機(jī)藕坯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)噪沙,“玉大人堕担,你說(shuō)我怎么就攤上這事∏簦” “怎么了霹购?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)朋腋。 經(jīng)常有香客問(wèn)我齐疙,道長(zhǎng),這世上最難降的妖魔是什么旭咽? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任贞奋,我火速辦了婚禮,結(jié)果婚禮上穷绵,老公的妹妹穿的比我還像新娘轿塔。我一直安慰自己,他們只是感情好仲墨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布勾缭。 她就那樣靜靜地躺著,像睡著了一般目养。 火紅的嫁衣襯著肌膚如雪俩由。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天癌蚁,我揣著相機(jī)與錄音幻梯,去河邊找鬼兜畸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛碘梢,可吹牛的內(nèi)容都是我干的咬摇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼煞躬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼菲嘴!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起汰翠,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎昭雌,沒(méi)想到半個(gè)月后复唤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烛卧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年佛纫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片总放。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呈宇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出局雄,到底是詐尸還是另有隱情甥啄,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布炬搭,位于F島的核電站蜈漓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宫盔。R本人自食惡果不足惜融虽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灼芭。 院中可真熱鬧有额,春花似錦、人聲如沸彼绷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寄悯。三九已至句狼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間热某,已是汗流浹背腻菇。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工胳螟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筹吐。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓糖耸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親丘薛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘉竟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

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