(三)使用Ribbon實現(xiàn)客戶端側(cè)負(fù)載均衡

文章目錄

1.Ribbon 簡介

1.1 Ribbon + Eureka 架構(gòu)

1.2 Ribbon 負(fù)載均衡器組件架構(gòu)

2 深入剖析Ribbon

2.1 Ribbon實現(xiàn)REST請求負(fù)載均衡邏輯

2.2 LoadBalancerInterceptor 的實現(xiàn)

2.3 LoadBalancerClient的實現(xiàn)

2.4ILoadBalancer負(fù)載均衡器的實現(xiàn)(結(jié)合Eureka)

2.5 IRule負(fù)載均衡策略

3 Ribbon實戰(zhàn):為服務(wù)消費者整合Ribbon

3.1需求場景

3.2編寫一個消費者

4 其他

4.1 配置項

4.2 **重試機制**

4.3 饑餓加載

5 參考文獻(xiàn)

1.Ribbon 簡介

Ribbon 是Netflix 發(fā)布的基于HTTP和TCP的客戶端負(fù)載均衡器凯楔,將我們服務(wù)間的REST模板請求進行攔截封裝嘹裂,轉(zhuǎn)發(fā)到合適的服務(wù)提供者實例上。

1.1 Ribbon + Eureka 架構(gòu)

Spring Cloud 中昆雀,Ribbon與Eureka 配合使用時焚廊,Ribbon可自動通過Eureka Client獲取服務(wù)提供者的地址列表,并基于某種負(fù)載均衡算法,請求其中一個服務(wù)提供實例妖碉。

Ribbon + Eureka 負(fù)載均衡架構(gòu)如下圖所示:

1.2 Ribbon 負(fù)載均衡器組件架構(gòu)

Rebbion 負(fù)載均衡器組件介紹:

ServerList:服務(wù)提供者實例列表,當(dāng)和Eureka結(jié)合時芥被,可以通過Eureka Client動態(tài)獲取可用的服務(wù)實例列表欧宜,也可以配置靜態(tài)的服務(wù)列表。

ServerListFilter:服務(wù)過濾器拴魄,通過該過濾器將會從serverList中過濾掉不符合規(guī)則的服務(wù)冗茸。

IPing:心跳檢查席镀,定時監(jiān)測ServerList服務(wù)列表中服務(wù)狀態(tài)。

IRule:均衡策略夏漱,將最終的ServerList按照某種負(fù)載均衡策略選擇要使用的服務(wù)實例豪诲。

通過上面的組件架構(gòu)流程我們可以為服務(wù)的每個請求選擇一個可用的服務(wù)DiscoveryEnabledServer。

Spring Cloud為每個服務(wù)提供者的Rebbion 負(fù)載均衡器 維護了一個子應(yīng)用上下文挂绰,我們可以為不同服務(wù)提供者配置不同的均衡策略屎篱,當(dāng)然也可以配置全局的均衡策略(詳見:配置項)。

2 深入剖析Ribbon

前面介紹了Ribbon是將我們服務(wù)間的REST請求通過封裝轉(zhuǎn)發(fā)葵蒂,來實現(xiàn)負(fù)載均衡芳室,那么具體是怎么實現(xiàn)的?

2.1 Ribbon實現(xiàn)REST請求負(fù)載均衡邏輯

當(dāng)服務(wù)啟動時刹勃,會為我們應(yīng)用中每個有@LoadBalanced 的RestTemplate實例堪侯,注入一個Ribbon負(fù)載均衡器的攔截器(LoadBalancerInterceptor ),當(dāng)服務(wù)在向某個服務(wù)提供者發(fā)起首次請求時荔仁,會初始化該服務(wù)提供者負(fù)載均衡器伍宦,這個加載過程也可以通過配置在服務(wù)啟動時被加載完成(詳見:《饑餓加載》章節(jié))

2.2 LoadBalancerInterceptor 的實現(xiàn)

LoadBalancerClient:負(fù)載均衡器客戶端,負(fù)載均衡入口乏梁,下一章節(jié)將詳解

LoadBalancerRequestFactory:負(fù)載均衡的請求創(chuàng)建工廠

在集成了Ribbon負(fù)載均衡之后不可能在使用IP:PORT 這樣的方式去發(fā)起請求次洼,而是將IP:PORT換成了每個服務(wù)提供者的ServerName。

2.3 LoadBalancerClient的實現(xiàn)

Spring Cloud 集成了Ribbion遇骑,使用RibbonLoadBalancerClient 實現(xiàn)了LoadBalancerClient 以下主要接口:

1.execute(String serviceId, LoadBalancerRequest request) throws IOException

主要流程:

代碼實現(xiàn):

2.URI reconstructURI(ServiceInstance instance, URI original);

前面在攔截器中介紹到卖毁,在集成了Ribbon負(fù)載均衡之后不可能在使用IP:PORT 這樣的方式去發(fā)起請求,而是將IP:PORT換成了每個服務(wù)提供者的ServerName落萎,但是最終還是轉(zhuǎn)成IP:PORT發(fā)起REST請求亥啦,reconstructURI實現(xiàn)了從RibbonServer服務(wù)實例向URI的轉(zhuǎn)化。

2.4ILoadBalancer負(fù)載均衡器的實現(xiàn)(結(jié)合Eureka)

接口組件:

ServerList:服務(wù)實例列表练链,當(dāng)Ribbon與Eureka聯(lián)合使用時翔脱,ServerList會被DiscoveryEnabledNIWSServerList重寫擴展成從Eureka注冊中心中獲取服務(wù)實例列表,并注冊媒鼓。當(dāng)Eureka Client定時從Eureka注冊中心獲取服務(wù)后會觸發(fā)DynamicServerListLoadBalancer 更新事件更新ServerList届吁。

1 )初始化Serverlist和啟動監(jiān)聽Eureker Client發(fā)送獲取服務(wù)(Get Register)的請求監(jiān)聽.

?

2 )注冊監(jiān)聽:EurekaNotificationServerListUpdater.start(final UpdateAction updateAction)

if(eurekaClient==null){eurekaClient=eurekaClientProvider.get();}if(eurekaClient!=null){eurekaClient.registerEventListener(updateListener);}

更新事件:com.netflix.loadbalancer.DynamicServerListLoadBalancer.updateListOfServers()

@VisibleForTesting

public void updateListOfServers() {

? ? List<T> servers = new ArrayList<T>();

? ? if (serverListImpl != null) {

? ? ? ? servers = serverListImpl.getUpdatedListOfServers();

? ? ? ? LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",

? ? ? ? ? ? ? ? getIdentifier(), servers);

? ? ? ? if (filter != null) {

? ? ? ? ? ? servers = filter.getFilteredListOfServers(servers);

? ? ? ? ? ? LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",

? ? ? ? ? ? ? ? ? ? getIdentifier(), servers);

? ? ? ? }

? ? }

? ? updateAllServerList(servers);

}

ServerListFilter:服務(wù)過濾器,通過該過濾器將會從serverList中過濾掉不符合規(guī)則的服務(wù)绿鸣。

org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter.getFilteredListOfServers()

@OverridepublicList<Server>getFilteredListOfServers(List<Server>servers){List<Server>output=super.getFilteredListOfServers(servers);if(this.zone!=null&&output.size()==servers.size()){List<Server>local=newArrayList<Server>();for(Server server:output){if(this.zone.equalsIgnoreCase(server.getZone())){local.add(server);}}if(!local.isEmpty()){returnlocal;}}returnoutput;}

IPing:檢測ServerList中的是否可用疚沐,當(dāng)Ribbon與Eureka聯(lián)合使用時,NIWSDiscoveryPing來取代IPing,它將職責(zé)委托給Eureka來確定服務(wù)端是否已經(jīng)啟動潮模。

1)啟動時開始定時任務(wù)(默認(rèn)10s):

BaseLoadBalancer.setupPingTask()

void setupPingTask() {

if (canSkipPing()) {

? ? ? ? return;

? ? }

? ? if (lbTimer != null) {

? ? ? ? lbTimer.cancel();

? ? }

? ? lbTimer = new ShutdownEnabledTimer("NFLoadBalancer-PingTimer-" + name,

? ? ? ? ? ? true);

? ? lbTimer.schedule(new PingTask(), 0, pingIntervalSeconds * 1000);

? ? forceQuickPing();

}

2)檢測NIWSDiscoveryPing.isAlive():

publicbooleanisAlive(Server server){booleanisAlive=true;if(server!=null&&serverinstanceofDiscoveryEnabledServer){DiscoveryEnabledServer dServer=(DiscoveryEnabledServer)server;InstanceInfo instanceInfo=dServer.getInstanceInfo();if(instanceInfo!=null){InstanceStatus status=instanceInfo.getStatus();if(status!=null){isAlive=status.equals(InstanceStatus.UP);}}}returnisAlive;}

IRule:均衡策略亮蛔,將最終的ServerList按照一定的策略選擇最終要使用的服務(wù)實例。

2.5 IRule負(fù)載均衡策略

隨機策略RandomRule

從ServerList中隨機選擇一個Server實例再登。

關(guān)鍵代碼:

intindex=rand.nextInt(serverCount);server=upList.get(index);

輪詢策略RoundRobinRule

輪詢Serverlist選擇下個Server實例

關(guān)鍵代碼:

intnextServerIndex=incrementAndGetModulo(serverCount);server=allServers.get(nextServerIndex);

incrementAndGetModulo():

privateintincrementAndGetModulo(intmodulo){for(;;){intcurrent=nextServerCyclicCounter.get();intnext=(current+1)%modulo;if(nextServerCyclicCounter.compareAndSet(current,next))returnnext;}}

權(quán)重策略WeightedResponseTimeRule

WeightedResponseTimeRule繼承了RoundRobinRule尔邓,開始時沒有權(quán)重列表晾剖,采用父類(RoundRobinRule)的輪詢方式;啟動一個定時任務(wù)(默認(rèn)30s)锉矢,定時任務(wù)會根據(jù)實例的響應(yīng)時間來更新權(quán)重列表梯嗽,choose方法中,用一個(0,1)的隨機double數(shù)乘以最大的權(quán)重得到randomWeight沽损,然后遍歷權(quán)重列表灯节,找出第一個比randomWeight大的實例下標(biāo),然后返回該實例绵估。

具體實現(xiàn)炎疆,請參考類:com.netflix.loadbalancer.WeightedResponseTimeRule

請求數(shù)最少策略BestAvailableRule

public Server choose(Object key) {

? ? if (loadBalancerStats == null) {

? ? ? ? return super.choose(key);

? ? }

? ? List<Server> serverList = getLoadBalancer().getAllServers();

? ? int minimalConcurrentConnections = Integer.MAX_VALUE;

? ? long currentTime = System.currentTimeMillis();

? ? Server chosen = null;

? ? for (Server server: serverList) {

? ? ? ? ServerStats serverStats = loadBalancerStats.getSingleServerStat(server);

? ? ? ? if (!serverStats.isCircuitBreakerTripped(currentTime)) {

? ? ? ? ? ? int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);

? ? ? ? ? ? if (concurrentConnections < minimalConcurrentConnections) {

? ? ? ? ? ? ? ? minimalConcurrentConnections = concurrentConnections;

? ? ? ? ? ? ? ? chosen = server;

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? if (chosen == null) {

? ? ? ? return super.choose(key);

? ? } else {

? ? ? ? return chosen;

? ? }

}

AvailabilityFilteringRule

過濾掉那些因為一直連接失敗的被標(biāo)記為circuit tripped的后端server,并過濾掉那些高并發(fā)的的后端server(active connections 超過配置的閾值)国裳,在使用RoundRobinRule 選擇一個服務(wù)

ZoneAvoidanceRule(Ribbon集合Eureka時形入,默認(rèn)IRule)

使用ZoneAvoidancePredicate過濾掉不可用的zone下的所有Server實例,再使用AvailabilityFiltering過濾掉過濾掉那些高并發(fā)的的后端server(active connections 超過配置的閾值)缝左,在輪詢選擇一個服務(wù)實例亿遂。

3 Ribbon實戰(zhàn):為服務(wù)消費者整合Ribbon

3.1需求場景

學(xué)生查詢已下單股票列表時,需要去股票服務(wù)中獲取股票詳情渺杉,補全股票信息蛇数。

3.2編寫一個消費者

1.創(chuàng)建一個ArtifactId是finace-training-student的Maven工程,并為項目添加以下依賴是越。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka-server</artifactId><exclusions><exclusion><artifactId>spring-retry</artifactId><groupId>org.springframework.retry</groupId></exclusion></exclusions></dependency>

2.在配置文件application.yml中添加如下內(nèi)容耳舅。

server:port:9000spring:application:name:finace-training-studenteureka:client:serviceUrl:defaultZone:http://localhost:8761/eureka/,http://localhost:8762/eureka/instance:prefer-ip-address:true

3.編寫啟動類,在啟動類上添加@EnableDiscoveryClient注解倚评,聲明這是一個Eureka Client,RestTemplate加上ribbon注解@LoadBalanced

packagecom.myhexin.finace.training.server.main;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.cloud.client.discovery.EnableDiscoveryClient;importorg.springframework.cloud.client.loadbalancer.LoadBalanced;importorg.springframework.context.annotation.Bean;importorg.springframework.web.client.RestTemplate;@SpringBootApplication(scanBasePackages="com.myhexin")@EnableDiscoveryClientpublicclassServierApplication{@Bean@LoadBalancedpublicRestTemplaterestTemplate(){returnnewRestTemplate();}publicstaticvoidmain(String[]args){SpringApplication.run(ServierApplication.class,args);}}

4.編寫消費者調(diào)用代碼:

packagecom.myhexin.finace.training.server.controller;importjava.util.ArrayList;importjava.util.List;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.cloud.client.ServiceInstance;importorg.springframework.cloud.client.discovery.DiscoveryClient;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.client.RestTemplate;importcom.myhexin.finace.training.api.stock.dto.StockDTO;@RestController@RequestMapping(value="/student",produces="application/json;charset=UTF-8")publicclassStudentController{@AutowiredprivateRestTemplate restTemplate;@AutowiredprivateDiscoveryClient discoveryClient;@GetMapping("/{id}/ownStcoks")publicList<StockDTO>ownStcoks(@PathVariableString id){String[]ownStockCodes={"300033","000001"};List<StockDTO>ownStocks=newArrayList<>(ownStockCodes.length);for(String code:ownStockCodes){// 補全股票信息//StockDTO stock = restTemplate.getForObject(this.getInstance("finace-training-stock") + "/stock/" + code, StockDTO.class);StockDTO stock=restTemplate.getForObject("http://finace-training-stock"+"/stock/"+code,StockDTO.class);ownStocks.add(stock);}returnownStocks;}privateStringgetInstance(String serviceId){List<ServiceInstance>instances=discoveryClient.getInstances(serviceId);if(instances.isEmpty()){returnnull;}returninstances.get(0).getUri().toString();}}

4 其他

4.1 配置項

全局默認(rèn)配置

Spring Cloud Ribbon自動化配置了默認(rèn)接口配置:

IClientConfig:Ribbon的客戶端配置浦徊,默認(rèn)采用DefaultClientConfigImpl。

IRule:Ribbon的負(fù)載均衡策略天梧,默認(rèn)采用ZoneAvoidanceRule辑畦,該策略能夠在多區(qū)域環(huán)境下選出最佳區(qū)域的實例進行訪問。

IPing:Ribbon的實例檢查策略腿倚,默認(rèn)采用DummyPing實現(xiàn)纯出,檢查實例狀態(tài)為UP,則返回true敷燎。

ServerList:服務(wù)實例清單的維護機制暂筝,默認(rèn)采用 ConfigurationBasedServerList實現(xiàn)。

ServerListFilter:服務(wù)實例清單過濾機制硬贯,默認(rèn)采用ZonePrefenceServerListFilter焕襟,優(yōu)先過濾出與請求調(diào)用方處于同區(qū)域的服務(wù)實例。

使用屬性自定義Ribbon配置

從Spring Cloud Netflix 1.2.0 (即從Spring Cloud Camden RELEASE開始)饭豹,Ribbon支持使用屬性自定義(即可定義在appplication.yml中)鸵赖。

配置前綴.ribbon.屬性务漩;是RibbonClient的名稱,如果省略則表示全部配置它褪。

屬性:

NFLoadBalancerClassName:配置ILoadBalancer的實現(xiàn)類

NFLoadBalancerPingClassName:配置IPing的實現(xiàn)類

NFLoadBalancerRuleClassName:配置IRule的實現(xiàn)類

NIWSServerListClassName:配置ServerList的實現(xiàn)類

NIWSServerListFilterClassName:配置ServerListFilter的實現(xiàn)類

例如:

finace-training-stock:ribbon:NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RandomRule

將finace-training-stock的Ribbon Client的負(fù)載均衡策略改為隨機策略饵骨。

?

例如:

ribbon:NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RandomRule

將所有的Ribbon Client的負(fù)載均衡策略改為隨機策略。

使用java代碼自定義Ribbon配置

4.2?重試機制

? 由于Spring Cloud Eureka實現(xiàn)的服務(wù)治理機制強調(diào)了CAP原理中的AP茫打,為了實現(xiàn)更高的服務(wù)可用性居触,犧牲了一定的一致性,在極端情況下它寧愿接受故障實例也不要丟掉“健康”實例老赤,比如轮洋,當(dāng)服務(wù)注冊中心的網(wǎng)絡(luò)繁盛故障斷開時,由于所有的服務(wù)實例無法維持持續(xù)心跳抬旺,在強調(diào)AP的服務(wù)治理中會把所有服務(wù)實例都踢出掉弊予,而Eureka則會因為超過85%的實例丟失心跳二回觸發(fā)保護機制,注冊中心江湖保留此時的所有節(jié)點开财,以實現(xiàn)服務(wù)間依然可以進行互相調(diào)用的場景汉柒,即使其中有部分故障節(jié)點,但這樣做可以繼續(xù)保障大多數(shù)服務(wù)正常消費床未。

? 所以服務(wù)調(diào)用的時候通常會加入一些重試機制竭翠。從Camden SR2版本開始,Spring Cloud整合了Spring Retry來增強RestTemplate的重試能力薇搁,對于開發(fā)者來說只需通過簡單的配置斋扰,原來那些通過RestTemplate實現(xiàn)的服務(wù)訪問就會自動根據(jù)配置來實現(xiàn)重試策略。

重試機制只有在引入了RetryTemplate才會生效啃洋。

<dependency>

<artifactId>spring-retry</artifactId>

<groupId>org.springframework.retry</groupId>

</dependency>

重試機制屬性配置策略:

spring.cloud.loadbalancer.retry.enabled:該參數(shù)用來開啟重試機制传货,它默認(rèn)是關(guān)閉的

hystrix.command.default.execution.isolation.thread.timeoutInMillseconds:斷路器的超時時間需要大于Ribbon的超時時間,不然不會觸發(fā)重試宏娄。

.ribbon.ConnectTimeout:請求連接的超時時間问裕。

.ribbon.ReadTimeout:請求處理的超時時間。

.ribbon.OkToRetryOnAllOperations:對所有操作請求都進行重試孵坚,默認(rèn)只對GET請求重試粮宛。

.ribbon.MaxAutoRetriesNextServer:切換實例的重試次數(shù)。

.ribbon.MaxAutoRetries:對當(dāng)前實例的重試次數(shù)卖宠。

具體可參考:

org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration.RetryAutoConfiguration

4.3 饑餓加載

前面Spring Cloud為每個服務(wù)提供者的Rebbion 負(fù)載均衡器 維護了一個子應(yīng)用上下文巍杈,通過代碼也分析出來了,這個上下文默認(rèn)是懶加載扛伍。只有在第一次請求時筷畦,對應(yīng)的上下文才會被加載,因此刺洒,首次請求往往會比較慢鳖宾,從Spring Cloud Dalston開始吼砂,我們可以配置饑餓加載。

例如:

ribbon:eager-load:enable:trueclients:finace-training-stock,finace-training-student

在啟動的時候就會加載 finace-training-stock和finace-training-student的Ribbon Client對應(yīng)的子應(yīng)用上下文鼎文,從而提高第一次的訪問速度渔肩。

5 參考文獻(xiàn)

[1] Ribbon的GitHub : https://github.com/Netflix/ribbon

[2] 周立. Spring Cloud與Docker微服務(wù)架構(gòu)實戰(zhàn)

[3] Spring Cloud中文網(wǎng).https://www.springcloud.cc/spring-cloud-dalston.html#spring-cloud-ribbon

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市漂问,隨后出現(xiàn)的幾起案子赖瞒,更是在濱河造成了極大的恐慌女揭,老刑警劉巖蚤假,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吧兔,居然都是意外死亡磷仰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門境蔼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灶平,“玉大人,你說我怎么就攤上這事箍土》晗恚” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵吴藻,是天一觀的道長瞒爬。 經(jīng)常有香客問我,道長沟堡,這世上最難降的妖魔是什么侧但? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮航罗,結(jié)果婚禮上禀横,老公的妹妹穿的比我還像新娘。我一直安慰自己粥血,他們只是感情好柏锄,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著复亏,像睡著了一般趾娃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜓耻,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天茫舶,我揣著相機與錄音,去河邊找鬼刹淌。 笑死饶氏,一個胖子當(dāng)著我的面吹牛讥耗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疹启,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼古程,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了喊崖?” 一聲冷哼從身側(cè)響起挣磨,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荤懂,沒想到半個月后茁裙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡节仿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年晤锥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片廊宪。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡矾瘾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出箭启,到底是詐尸還是另有隱情壕翩,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布傅寡,位于F島的核電站放妈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏赏僧。R本人自食惡果不足惜大猛,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淀零。 院中可真熱鬧挽绩,春花似錦、人聲如沸驾中。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肩民。三九已至唠亚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間持痰,已是汗流浹背灶搜。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人割卖。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓前酿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鹏溯。 傳聞我的和親對象是個殘疾皇子罢维,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

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