Zuul 核心特性

服務(wù)發(fā)現(xiàn) Service Discovery

Zuul被構(gòu)建為可以無縫的和Eureka一起運(yùn)行佑刷,但是也可以通過配置來指定靜態(tài)服務(wù)列表或者使用其他的服務(wù)發(fā)現(xiàn)惶楼。
使用Eureka的標(biāo)準(zhǔn)方法如下:

### Load balancing backends with Eureka

eureka.shouldUseDns=true
eureka.eurekaServer.context=discovery/v2
eureka.eurekaServer.domainName=discovery${environment}.netflix.net
eureka.eurekaServer.gzipContent=true

eureka.serviceUrl.default=http://${region}.${eureka.eurekaServer.domainName}:7001/${eureka.eurekaServer.context}

api.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
api.ribbon.DeploymentContextBasedVipAddresses=api-test.netflix.net:7001

如上的配置狰腌,使用Eureka您宪,必須配置Eureka的上下文(context)和位置(location)痕惋,給出配置后号俐,Zuul會(huì)自動(dòng)從給出的VIP中選擇來自Eureka的服務(wù)列表,用于Ribbon client的api救欧。更多關(guān)于Ribbon的配置可以參考其官方文檔.
如果配置Zuul不使用Eureka衰粹,使用靜態(tài)服務(wù)列表或者服務(wù)發(fā)現(xiàn)提供者,需要保持配置屬性listOfServers是最新的值:

### Load balancing backends without Eureka

eureka.shouldFetchRegistry=false

api.ribbon.listOfServers=100.66.23.88:7001,100.65.155.22:7001
api.ribbon.client.NIWSServerListClassName=com.netflix.loadbalancer.ConfigurationBasedServerList
api.ribbon.DeploymentContextBasedVipAddresses=api-test.netflix.net:7001

注意颜矿,在這個(gè)配置中使用了靜態(tài)服務(wù)器列表寄猩,跟使用Eureka的配置相比,除了關(guān)閉了eureka骑疆,還有一個(gè)點(diǎn)是ServerListClassName的配置田篇,類是ConfigurationBasedServerList,而Eureka是DiscoveryEnabledNIWSServerList箍铭。

負(fù)載均衡 Load Balancing

默認(rèn)情況下泊柬,Zuul的負(fù)載均衡使用的是Ribbon的ZoneAwareLoadBalancer。該類的算法就是對(duì)在服務(wù)發(fā)現(xiàn)中可用實(shí)例的輪詢诈火,可用實(shí)例是成功追蹤到了響應(yīng)的可用區(qū)域(zone)兽赁。負(fù)載均衡器將對(duì)每個(gè)區(qū)域保持統(tǒng)計(jì),如果失敗比例超過配置閾值則丟棄該區(qū)域冷守。
如果你想要使用自己的負(fù)載均衡器刀崖,你需要為Ribbon client命名空間設(shè)置NFLoadBalancerClassName屬性或者是覆蓋DefaultClientChannelManager類的getLoadBalancerClass()方法。注意拍摇,此時(shí)你自己的類需要繼承DynamicServerListLoadBalancer亮钦。
Ribbon也允許用戶配置負(fù)載均衡規(guī)則。例如充活,可以將RoundRobinRule換成WeightedResponseTimeRule蜂莉,AvailabilityFilteringRule,或者你自己的規(guī)則混卵,更多細(xì)節(jié)參考官方文檔

連接池 Connecting Pool

Zuul沒有使用Ribbon來為響應(yīng)創(chuàng)建連接映穗,而是使用Netty client創(chuàng)建了自己的連接池。Zuul為每個(gè)主機(jī)每個(gè)事件循環(huán)創(chuàng)建一個(gè)連接池幕随。這樣做是為了降低線程上下文切換的成本蚁滋,確保了請(qǐng)求事件循環(huán)和響應(yīng)事件循環(huán)的完整性。帶來的結(jié)果就是無論請(qǐng)求是哪個(gè)事件循環(huán)在執(zhí)行合陵,但是整個(gè)請(qǐng)求過程都在同一個(gè)線程中執(zhí)行枢赔。
這種策略的一個(gè)副作用是當(dāng)有大量的Zuul實(shí)例并且每個(gè)實(shí)例都有大量的事件循環(huán)在運(yùn)行時(shí),最小數(shù)量的連接都可能會(huì)讓后端服務(wù)器的連接都很高拥知。在配置連接池時(shí)記住這一點(diǎn)是很重要的踏拜。
如下是一些有用的配置,默認(rèn)值低剔。
Ribbon Client config Properties

<originName>.ribbon.ConnectionTimeout                // default: 500 (ms)
<originName>.ribbon.MaxConnectionsPerHost            // default: 50
<originName>.ribbon.ConnIdleEvictTimeMilliSeconds    // default: 60000 (ms)
<originName>.ribbon.ReceiveBufferSize                // default: 32 * 1024
<originName>.ribbon.SendBufferSize                   // default: 32 * 1024
<originName>.ribbon.UseIPAddrForServer               // default: true

Zuul Properties

# Max amount of requests any given connection will have before forcing a close
<originName>.netty.client.maxRequestsPerConnection    // default: 1000

# Max amount of connection per server, per event loop
<originName>.netty.client.perServerWaterline          // default: 4

# Netty configuration connection
<originName>.netty.client.TcpKeepAlive                // default: false
<originName>.netty.client.TcpNoDelay                  // default: false
<originName>.netty.client.WriteBufferHighWaterMark    // default: 32 * 1024
<originName>.netty.client.WriteBufferLowWaterMark     // default: 8 * 1024
<originName>.netty.client.AutoRead                    // default: false

連接池也輸出一些度量指標(biāo)速梗,如果需要收集則可以參考Spectator

狀態(tài)分類 Status Categories

盡管HTTP狀態(tài)是通用的肮塞,但是并沒有提供更細(xì)粒度的狀態(tài)。為了指定更多的失敗模型姻锁,Zuul創(chuàng)建了可能失敗原因的枚舉枕赵,如下表。

StatusCategory Definition
SUCCESS Successful request
SUCCESS_NOT_FOUND Succesfully proxied but status was 404
SUCCESS_LOCAL_NOTSET Successful request but no StatusCategory was set
SUCCESS_LOCAL_NO_ROUTE Technically successful, but no routing found for the request
FAILURE_LOCAL Local Zuul failure (e.g. exception thrown)
FAILURE_LOCAL_THROTTLED_ORIGIN_SERVER_MAXCONN Request throttled due to max connection limit reached to origin server
FAILURE_LOCAL_THROTTLED_ORIGIN_CONCURRENCY Request throttled due to origin concurrency limit
FAILURE_LOCAL_IDLE_TIMEOUT Request failed due to idle connection timeout
FAILURE_CLIENT_CANCELLED Request failed because client cancelled
FAILURE_CLIENT_PIPELINE_REJECT Request failed because client attempted to send pipelined HTTP request
FAILURE_CLIENT_TIMEOUT Request failed due to read timeout from the client (e.g. truncated POST body)
FAILURE_ORIGIN The origin returned a failure (i.e. 500 status)
FAILURE_ORIGIN_READ_TIMEOUT The request to the origin timed out
FAILURE_ORIGIN_CONNECTIVITY Could not connect to origin
FAILURE_ORIGIN_THROTTLED Origin throttled the request (i.e. 503 status)
FAILURE_ORIGIN_NO_SERVERS Could not find any servers to connect to for the origin
FAILURE_ORIGIN_RESET_CONNECTION Origin reset the connection before the request could complete

可以通過StatusCategoryUtils類來設(shè)置或者獲得狀態(tài)位隶,例如:

// set
StatusCategoryUtils.setStatusCategory(request.getContext(), ZuulStatusCategory.SUCCESS)
// get
StatusCategoryUtils.getStatusCategory(response)

Zuul2中的類源碼有改動(dòng)拷窜,上文中的set不再是request獲取的RequestContext,而是RequestContext的替代類SessionContext涧黄,
get不再是response篮昧,而是ZuulMessage或者RequestContext的替代類SessionRequest,
源碼如下:

public class StatusCategoryUtils {
    private static final Logger LOG = LoggerFactory.getLogger(StatusCategoryUtils.class);

    public static StatusCategory getStatusCategory(ZuulMessage msg) {
        return getStatusCategory(msg.getContext());
    }

    public static StatusCategory getStatusCategory(SessionContext ctx) {
        return (StatusCategory) ctx.get(CommonContextKeys.STATUS_CATGEORY);
    }

    public static void setStatusCategory(SessionContext ctx, StatusCategory statusCategory) {
        ctx.set(CommonContextKeys.STATUS_CATGEORY, statusCategory);
    }

    public static StatusCategory getOriginStatusCategory(SessionContext ctx) {
        return (StatusCategory) ctx.get(CommonContextKeys.ORIGIN_STATUS_CATEGORY);
    }

    public static boolean isResponseHttpErrorStatus(HttpResponseMessage response) {
        boolean isHttpError = false;
        if (response != null) {
            int status = response.getStatus();
            isHttpError = isResponseHttpErrorStatus(status);
        }
        return isHttpError;
    }

    public static boolean isResponseHttpErrorStatus(int status) {
        return (status < 100 || status >= 500);
    }

    public static void storeStatusCategoryIfNotAlreadyFailure(final SessionContext context, final StatusCategory statusCategory) {
        if (statusCategory != null) {
            final StatusCategory nfs = (StatusCategory) context.get(CommonContextKeys.STATUS_CATGEORY);
            if (nfs == null || nfs.getGroup().getId() == ZuulStatusCategoryGroup.SUCCESS.getId()) {
                context.set(CommonContextKeys.STATUS_CATGEORY, statusCategory);
            }
        }
    }
}

重試機(jī)制 Retries

重試是保證彈性的關(guān)鍵特性之一笋妥。在Zuul中懊昨,重試會(huì)被認(rèn)真對(duì)待并且大量的使用了重試。重試請(qǐng)求的邏輯如下:

對(duì)錯(cuò)誤的重試 Retry on errors

  • 如果錯(cuò)誤是讀超時(shí)春宣,連接重置或者連接錯(cuò)誤酵颁,則zuul會(huì)重試

對(duì)狀態(tài)碼的重試 Retry on status codes

  • 如果狀態(tài)碼是503,則zuul會(huì)重試
  • 如果狀態(tài)碼配置為了冪等的月帝,并且方法是GET躏惋,HEADOPTIONS之一嚷辅,zuul會(huì)重試其掂。如何配置狀態(tài)碼為冪等使用屬性zuul.retry.allowed.statuses.idempotent,下文會(huì)列出潦蝇。
    Zuul在一個(gè)臨時(shí)狀態(tài)是不會(huì)重試的:
  • 如果已經(jīng)開始給client發(fā)送響應(yīng)
  • 如果丟失了內(nèi)容體(body),尤其是緩存或者刪除了內(nèi)容

相關(guān)配置屬性為:

# Sets a retry limit for both error and status code retries
<originName>.ribbon.MaxAutoRetriesNextServer            // default: 0

# This is a comma-delimited list of status codes
zuul.retry.allowed.statuses.idempotent                  // default: 500

<originName>.ribbon.MaxAutoRetriesNextServer設(shè)置重試次數(shù)
zuul.retry.allowed.statuses.idempotent是逗號(hào)分隔的列表深寥,如500,501,502,503

請(qǐng)求通行證/快照 Request Passport

在Zuul由1升級(jí)為2的過程中攘乒,Netflix開發(fā)并開源了一些好用的工具,Request Passport就是調(diào)試最好的工具惋鹅。它是基于納秒按照時(shí)間序列記錄的一個(gè)請(qǐng)求所有的瞬時(shí)狀態(tài)则酝。

成功請(qǐng)求示例 Example of successful request

如下是Netflix提供的一個(gè)示例,一個(gè)運(yùn)行多個(gè)filter的簡(jiǎn)單請(qǐng)求闰集,有一些IO操作沽讹,大理請(qǐng)求,對(duì)response執(zhí)行filter武鲁,然后將結(jié)果寫回的客戶端爽雄。

CurrentPassport {start_ms=1523578203359,
[+0=IN_REQ_HEADERS_RECEIVED,
+260335=FILTERS_INBOUND_START,
+310862=IN_REQ_LAST_CONTENT_RECEIVED,
+1053435=MISC_IO_START,
+2202112=MISC_IO_STOP,
+3917598=FILTERS_INBOUND_END,
+4157288=ORIGIN_CH_CONNECTING,
+4218319=ORIGIN_CONN_ACQUIRE_START,
+4443588=ORIGIN_CH_CONNECTED,
+4510115=ORIGIN_CONN_ACQUIRE_END,
+4765495=OUT_REQ_HEADERS_SENDING,
+4799545=OUT_REQ_LAST_CONTENT_SENDING,
+4820669=OUT_REQ_HEADERS_SENT,
+4822465=OUT_REQ_LAST_CONTENT_SENT,
+4830443=ORIGIN_CH_ACTIVE,
+20811792=IN_RESP_HEADERS_RECEIVED,
+20961148=FILTERS_OUTBOUND_START,
+21080107=IN_RESP_LAST_CONTENT_RECEIVED,
+21109342=ORIGIN_CH_POOL_RETURNED,
+21539032=FILTERS_OUTBOUND_END,
+21558317=OUT_RESP_HEADERS_SENDING,
+21575084=OUT_RESP_LAST_CONTENT_SENDING,
+21594236=OUT_RESP_HEADERS_SENT,
+21595122=OUT_RESP_LAST_CONTENT_SENT,
+21659271=NOW]}

超時(shí)示例 Example of a timeout

該示例是一個(gè)超時(shí)示例。跟前邊的實(shí)例相似沐鼠,但是并不是響應(yīng)請(qǐng)求的時(shí)間間隔和超時(shí)事件挚瘟。

CurrentPassport {start_ms=1523578490446,
[+0=IN_REQ_HEADERS_RECEIVED,
+139712=FILTERS_INBOUND_START,
+1364667=MISC_IO_START,
+2235393=MISC_IO_STOP,
+3686560=FILTERS_INBOUND_END,
+3823010=ORIGIN_CH_CONNECTING,
+3891023=ORIGIN_CONN_ACQUIRE_START,
+4242502=ORIGIN_CH_CONNECTED,
+4311756=ORIGIN_CONN_ACQUIRE_END,
+4401724=OUT_REQ_HEADERS_SENDING,
+4453035=OUT_REQ_HEADERS_SENT,
+4461546=ORIGIN_CH_ACTIVE,
+45004599181=ORIGIN_CH_READ_TIMEOUT,
+45004813647=FILTERS_OUTBOUND_START,
+45004920343=ORIGIN_CH_CLOSE,
+45004945985=ORIGIN_CH_CLOSE,
+45005052026=ORIGIN_CH_INACTIVE,
+45005246081=FILTERS_OUTBOUND_END,
+45005359480=OUT_RESP_HEADERS_SENDING,
+45005379978=OUT_RESP_LAST_CONTENT_SENDING,
+45005399999=OUT_RESP_HEADERS_SENT,
+45005401335=OUT_RESP_LAST_CONTENT_SENT,
+45005486729=NOW]}

你可以記錄通行證叹谁,把它添加到請(qǐng)求/響應(yīng)頭中或者輸出到一個(gè)存儲(chǔ)中以便接下來的調(diào)試〕烁牵可以通過通道(channel)或者回話上下文(session context)來取出passport焰檩。例如:

// from channel
CurrentPassport passport = CurrentPassport.fromChannel(channel);
// from context
CurrentPassport passport = CurrentPassport.fromSessionContext(context);

請(qǐng)求嘗試 Request Attempts

另一個(gè)非常有用的調(diào)試特性是記錄Zuul產(chǎn)生的請(qǐng)求嘗試。我們?cè)诿總€(gè)響應(yīng)中添加它僅僅作為內(nèi)部頭使用订框,它使跟蹤和調(diào)試請(qǐng)求對(duì)我們和內(nèi)部合作伙伴來說變的非常簡(jiǎn)單析苫。

成功請(qǐng)求示例 Example of successful request

[{"status":200,"duration":192,"attempt":1,"region":"us-east-1","asg":"simulator-v154","instanceId":"i-061db2c67b2b3820c","vip":"simulator.netflix.net:7001"}]

失敗請(qǐng)求的示例 Example of failed request

[{"status":503,"duration":142,"attempt":1,"error":"ORIGIN_SERVICE_UNAVAILABLE","exceptionType":"OutboundException","region":"us-east-1","asg":"simulator-v154","instanceId":"i-061db2c67b2b3820c","vip":"simulator.netflix.net:7001"},
{"status":503,"duration":147,"attempt":2,"error":"ORIGIN_SERVICE_UNAVAILABLE","exceptionType":"OutboundException","region":"us-east-1","asg":"simulator-v154","instanceId":"i-061db2c67b2b3820c","vip":"simulator.netflix.net:7001"}]

可以在outbound* filter中通過回話上下文(session context)來獲取請(qǐng)求嘗試(request attempts),例如:

// from context
RequestAttempts attempts = RequestAttempts.getFromSessionContext(context);

原始并發(fā)保護(hù) Origin Concurrency Protection

有些時(shí)候原始請(qǐng)求處理服務(wù)器會(huì)發(fā)生問題穿扳,尤其是請(qǐng)求量超過他們本身容量時(shí)衩侥。我們知道,Zuul作為一個(gè)代理纵揍,后端有問題的原始請(qǐng)求處理服務(wù)器會(huì)占滿連接和內(nèi)存從而潛在的影響其他的服務(wù)器顿乒。為了保護(hù)原始服務(wù)器和Zuul本身,我們?cè)O(shè)置了并發(fā)限制來平滑的實(shí)現(xiàn)服務(wù)中斷泽谨。
有兩種方式管理原始服務(wù)器并發(fā):

總體服務(wù)器并發(fā) Overall Origin Concurrency

zuul.origin.<originName>.concurrency.max.requests        // default: 200
zuul.origin.<originName>.concurrency.protect.enabled     // default: true

也就是對(duì)服務(wù)器請(qǐng)求總量超過設(shè)置最大值璧榄,不管后臺(tái)服務(wù)器是多少臺(tái)。

每個(gè)服務(wù)器的并發(fā) Per Server Concurrency

<originName>.ribbon.MaxConnectionsPerHost                // default: 50

也就是對(duì)后端每個(gè)服務(wù)器的最大請(qǐng)求量吧雹,超過則zuul限制請(qǐng)求骨杂。

如果請(qǐng)求超過總體并發(fā)或者每個(gè)服務(wù)器并發(fā),Zuul會(huì)返回503給請(qǐng)求端雄卷,而不會(huì)把請(qǐng)求繼續(xù)轉(zhuǎn)發(fā)給后端服務(wù)器處理搓蚪。

HTTP/2

Zuul可以在HTTP/2的模式下運(yùn)行。在這種模式中丁鹉,程序需要一個(gè)SSL證書,如果運(yùn)行在ELB之后揣钦,則必須使用TCP 監(jiān)聽器雳灾。具體示例餐參考sample app
HTTP/2相關(guān)配置屬性如下:

server.http2.max.concurrent.streams            // default: 100
server.http2.initialwindowsize                 // default: 5242880
server.http2.maxheadertablesize                // default: 65536
server.http2.maxheaderlistsize                 // default: 32768

相互的TLS Mutual TLS

Zuul可以運(yùn)行在相互的TLS模式,也就是雙方都提供證書認(rèn)證冯凹。在這種模式下谎亩,程序必須都有SSL證書,并有請(qǐng)求證書的信任存儲(chǔ)宇姚。作為HTTP/2匈庭,必須在ELB的TCP監(jiān)聽器后運(yùn)行。

代理協(xié)議 Proxy Protocol

代理協(xié)議在使用TCP監(jiān)聽器的時(shí)候是非常重要的特性浑劳,在Zuul中可以通過如下的服務(wù)端設(shè)置開啟:

// strip XFF headers since we can no longer trust them
channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER);

// prefer proxy protocol when available
channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, true);

// enable proxy protocol
channelConfig.set(CommonChannelConfigKeys.withProxyProtocol, true);

客戶端IP會(huì)在過濾器中被正確的寫入HttpRequestMessage,然后可以通過通道(channel)直接接收:

String clientIp = channel.attr(SourceAddressChannelHandler.ATTR_SOURCE_ADDRESS).get();

壓縮 GZip

Zuul自帶了GZipResponseFilter魔熏,可以對(duì)輸出的響應(yīng)進(jìn)行壓縮紊选。
是否壓縮啼止,取決于內(nèi)容類型、內(nèi)容大小以及請(qǐng)求頭Accept-Encoding中是否包含gzip兵罢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末献烦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子卖词,更是在濱河造成了極大的恐慌巩那,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件此蜈,死亡現(xiàn)場(chǎng)離奇詭異即横,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)裆赵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門东囚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人战授,你說我怎么就攤上這事页藻。” “怎么了植兰?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵份帐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我楣导,道長(zhǎng)废境,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任筒繁,我火速辦了婚禮噩凹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毡咏。我一直安慰自己栓始,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布血当。 她就那樣靜靜地躺著,像睡著了一般禀忆。 火紅的嫁衣襯著肌膚如雪臊旭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天箩退,我揣著相機(jī)與錄音离熏,去河邊找鬼。 笑死戴涝,一個(gè)胖子當(dāng)著我的面吹牛滋戳,可吹牛的內(nèi)容都是我干的钻蔑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼奸鸯,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼咪笑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起娄涩,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤窗怒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蓄拣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扬虚,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年球恤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辜昵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咽斧,死狀恐怖堪置,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情收厨,我是刑警寧澤晋柱,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站诵叁,受9級(jí)特大地震影響雁竞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拧额,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一碑诉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧侥锦,春花似錦进栽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至番挺,卻和暖如春唠帝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背玄柏。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工襟衰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粪摘。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓瀑晒,卻偏偏與公主長(zhǎng)得像绍坝,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子苔悦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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