人人都能看懂的 6 種限流實(shí)現(xiàn)方案攀甚!(純干貨)

作者 | 王磊
來源 | Java中文社群(ID:javacn666)

為了上班方便,去年我把自己在北郊的房子租出去了笛臣,搬到了南郊云稚,這樣離我上班的地方就近了,它為我節(jié)約了很多的時(shí)間成本沈堡,我可以用它來做很多有意義的事静陈,最起碼不會(huì)因?yàn)槎萝嚩[心了,幸福感直線上升诞丽。

但即使這樣鲸拥,生活也有其他的煩惱。南郊的居住密度比較大僧免,因此停車就成了頭痛的事刑赶,我租的是路兩邊的非固定車位,每次只要下班回來懂衩,一定是沒有車位停了撞叨,因此我只能和別人的車并排停著,但這樣帶來的問題是浊洞,我每天早上都要被挪車的電話給叫醒牵敷,心情自然就不用說了。

但后來幾天法希,我就慢慢變聰明了枷餐,我頭天晚上停車的時(shí)候,會(huì)找第二天限行的車并排停著苫亦,這樣我第二天就不用挪車了毛肋,這真是限行給我?guī)淼摹熬薮蠹t利”啊怨咪。

車輛限行就是一種生活中很常見的限流策略,他除了給我?guī)砹艘陨系暮锰幹馊蟪祝€給我們美好的生活環(huán)境帶來了一絲改善诗眨,并且快速增長的私家車已經(jīng)給我們的交通帶來了巨大的“負(fù)擔(dān)”,如果再不限行趁桃,可能所有的車都要被堵在路上辽话,這就是限流給我們的生活帶來的巨大好處。

從生活回到程序中卫病,假設(shè)一個(gè)系統(tǒng)只能為 10W 人提供服務(wù),突然有一天因?yàn)槟硞€(gè)熱點(diǎn)事件典徘,造成了系統(tǒng)短時(shí)間內(nèi)的訪問量迅速增加到了 50W蟀苛,那么導(dǎo)致的直接結(jié)果是系統(tǒng)崩潰,任何人都不能用系統(tǒng)了逮诲,顯然只有少人數(shù)能用遠(yuǎn)比所有人都不能用更符合我們的預(yù)期帜平,因此這個(gè)時(shí)候我們要使用「限流」了

限流分類

限流的實(shí)現(xiàn)方案有很多種梅鹦,磊哥這里稍微理了一下裆甩,限流的分類如下所示:

  1. 合法性驗(yàn)證限流:比如驗(yàn)證碼、IP 黑名單等齐唆,這些手段可以有效的防止惡意攻擊和爬蟲采集嗤栓;
  2. 容器限流:比如 Tomcat、Nginx 等限流手段箍邮,其中 Tomcat 可以設(shè)置最大線程數(shù)(maxThreads)茉帅,當(dāng)并發(fā)超過最大線程數(shù)會(huì)排隊(duì)等待執(zhí)行;而 Nginx 提供了兩種限流手段:一是控制速率锭弊,二是控制并發(fā)連接數(shù)堪澎;
  3. 服務(wù)端限流:比如我們?cè)诜?wù)器端通過限流算法實(shí)現(xiàn)限流,此項(xiàng)也是我們本文介紹的重點(diǎn)味滞。

合法性驗(yàn)證限流為最常規(guī)的業(yè)務(wù)代碼樱蛤,就是普通的驗(yàn)證碼和 IP 黑名單系統(tǒng),本文就不做過多的敘述了剑鞍,我們重點(diǎn)來看下后兩種限流的實(shí)現(xiàn)方案:容器限流和服務(wù)端限流昨凡。

容器限流

Tomcat 限流

Tomcat 8.5 版本的最大線程數(shù)在 conf/server.xml 配置中,如下所示:

<Connector port="8080" protocol="HTTP/1.1"
          connectionTimeout="20000"
          maxThreads="150"
          redirectPort="8443" />

其中 maxThreads 就是 Tomcat 的最大線程數(shù)攒暇,當(dāng)請(qǐng)求的并發(fā)大于此值(maxThreads)時(shí)土匀,請(qǐng)求就會(huì)排隊(duì)執(zhí)行,這樣就完成了限流的目的形用。

小貼士:maxThreads 的值可以適當(dāng)?shù)恼{(diào)大一些就轧,此值默認(rèn)為 150(Tomcat 版本 8.5.42)证杭,但這個(gè)值也不是越大越好,要看具體的硬件配置妒御,需要注意的是每開啟一個(gè)線程需要耗用 1MB 的 JVM 內(nèi)存空間用于作為線程棧之用解愤,并且線程越多 GC 的負(fù)擔(dān)也越重。最后需要注意一下乎莉,操作系統(tǒng)對(duì)于進(jìn)程中的線程數(shù)有一定的限制送讲,Windows 每個(gè)進(jìn)程中的線程數(shù)不允許超過 2000,Linux 每個(gè)進(jìn)程中的線程數(shù)不允許超過 1000惋啃。

Nginx 限流

Nginx 提供了兩種限流手段:一是控制速率哼鬓,二是控制并發(fā)連接數(shù)。

控制速率

我們需要使用 limit_req_zone 用來限制單位時(shí)間內(nèi)的請(qǐng)求數(shù)边灭,即速率限制异希,示例配置如下:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
server { 
    location / { 
        limit_req zone=mylimit;
    }
}

以上配置表示,限制每個(gè) IP 訪問的速度為 2r/s绒瘦,因?yàn)?Nginx 的限流統(tǒng)計(jì)是基于毫秒的称簿,我們?cè)O(shè)置的速度是 2r/s,轉(zhuǎn)換一下就是 500ms 內(nèi)單個(gè) IP 只允許通過 1 個(gè)請(qǐng)求惰帽,從 501ms 開始才允許通過第 2 個(gè)請(qǐng)求憨降。

我們使用單 IP 在 10ms 內(nèi)發(fā)并發(fā)送了 6 個(gè)請(qǐng)求的執(zhí)行結(jié)果如下:

image

從以上結(jié)果可以看出他的執(zhí)行符合我們的預(yù)期,只有 1 個(gè)執(zhí)行成功了该酗,其他的 5 個(gè)被拒絕了(第 2 個(gè)在 501ms 才會(huì)被正常執(zhí)行)授药。

速率限制升級(jí)版

上面的速率控制雖然很精準(zhǔn)但是應(yīng)用于真實(shí)環(huán)境未免太苛刻了,真實(shí)情況下我們應(yīng)該控制一個(gè) IP 單位總時(shí)間內(nèi)的總訪問次數(shù)垂涯,而不是像上面那么精確但毫秒烁焙,我們可以使用 burst 關(guān)鍵字開啟此設(shè)置,示例配置如下:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
server { 
    location / { 
        limit_req zone=mylimit burst=4;
    }
}

burst=4 表示每個(gè) IP 最多允許4個(gè)突發(fā)請(qǐng)求耕赘,如果單個(gè) IP 在 10ms 內(nèi)發(fā)送 6 次請(qǐng)求的結(jié)果如下:

image

從以上結(jié)果可以看出骄蝇,有 1 個(gè)請(qǐng)求被立即處理了,4 個(gè)請(qǐng)求被放到 burst 隊(duì)列里排隊(duì)執(zhí)行了操骡,另外 1 個(gè)請(qǐng)求被拒絕了九火。

控制并發(fā)數(shù)

利用 limit_conn_zonelimit_conn 兩個(gè)指令即可控制并發(fā)數(shù),示例配置如下:

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
    ...
    limit_conn perip 10;
    limit_conn perserver 100;
}

其中 limit_conn perip 10 表示限制單個(gè) IP 同時(shí)最多能持有 10 個(gè)連接册招;limit_conn perserver 100 表示 server 同時(shí)能處理并發(fā)連接的總數(shù)為 100 個(gè)岔激。

小貼士:只有當(dāng) request header 被后端處理后,這個(gè)連接才進(jìn)行計(jì)數(shù)是掰。

服務(wù)端限流

服務(wù)端限流需要配合限流的算法來執(zhí)行虑鼎,而算法相當(dāng)于執(zhí)行限流的“大腦”,用于指導(dǎo)限制方案的實(shí)現(xiàn)。

有人看到「算法」兩個(gè)字可能就暈了炫彩,覺得很深?yuàn)W匾七,其實(shí)并不是。算法就相當(dāng)于操作某個(gè)事務(wù)的具體實(shí)現(xiàn)步驟匯總江兢,其實(shí)并不難懂昨忆,不要被它的表象給嚇到哦~

限流的常見算法有以下三種:

  1. 時(shí)間窗口算法
  2. 漏桶算法
  3. 令牌算法

接下來我們分別看來。

1.時(shí)間窗口算法

所謂的滑動(dòng)時(shí)間算法指的是以當(dāng)前時(shí)間為截止時(shí)間杉允,往前取一定的時(shí)間邑贴,比如往前取 60s 的時(shí)間,在這 60s 之內(nèi)運(yùn)行最大的訪問數(shù)為 100叔磷,此時(shí)算法的執(zhí)行邏輯為拢驾,先清除 60s 之前的所有請(qǐng)求記錄,再計(jì)算當(dāng)前集合內(nèi)請(qǐng)求數(shù)量是否大于設(shè)定的最大請(qǐng)求數(shù) 100世澜,如果大于則執(zhí)行限流拒絕策略独旷,否則插入本次請(qǐng)求記錄并返回可以正常執(zhí)行的標(biāo)識(shí)給客戶端。

滑動(dòng)時(shí)間窗口如下圖所示:

image

其中每一小個(gè)表示 10s寥裂,被紅色虛線包圍的時(shí)間段則為需要判斷的時(shí)間間隔,比如 60s 秒允許 100 次請(qǐng)求案疲,那么紅色虛線部分則為 60s封恰。

我們可以借助 Redis 的有序集合 ZSet 來實(shí)現(xiàn)時(shí)間窗口算法限流,實(shí)現(xiàn)的過程是先使用 ZSet 的 key 存儲(chǔ)限流的 ID褐啡,score 用來存儲(chǔ)請(qǐng)求的時(shí)間诺舔,每次有請(qǐng)求訪問來了之后,先清空之前時(shí)間窗口的訪問量备畦,統(tǒng)計(jì)現(xiàn)在時(shí)間窗口的個(gè)數(shù)和最大允許訪問量對(duì)比低飒,如果大于等于最大訪問量則返回 false 執(zhí)行限流操作,負(fù)責(zé)允許執(zhí)行業(yè)務(wù)邏輯懂盐,并且在 ZSet 中添加一條有效的訪問記錄褥赊,具體實(shí)現(xiàn)代碼如下。

我們借助 Jedis 包來操作 Redis莉恼,實(shí)現(xiàn)在 pom.xml 添加 Jedis 框架的引用拌喉,配置如下:

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.3.0</version>
</dependency>

具體的 Java 實(shí)現(xiàn)代碼如下:

import redis.clients.jedis.Jedis;

public class RedisLimit {
    // Redis 操作客戶端
    static Jedis jedis = new Jedis("127.0.0.1", 6379);

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 15; i++) {
            boolean res = isPeriodLimiting("java", 3, 10);
            if (res) {
                System.out.println("正常執(zhí)行請(qǐng)求:" + i);
            } else {
                System.out.println("被限流:" + i);
            }
        }
        // 休眠 4s
        Thread.sleep(4000);
        // 超過最大執(zhí)行時(shí)間之后,再從發(fā)起請(qǐng)求
        boolean res = isPeriodLimiting("java", 3, 10);
        if (res) {
            System.out.println("休眠后俐银,正常執(zhí)行請(qǐng)求");
        } else {
            System.out.println("休眠后尿背,被限流");
        }
    }

    /**
     * 限流方法(滑動(dòng)時(shí)間算法)
     * @param key      限流標(biāo)識(shí)
     * @param period   限流時(shí)間范圍(單位:秒)
     * @param maxCount 最大運(yùn)行訪問次數(shù)
     * @return
     */
    private static boolean isPeriodLimiting(String key, int period, int maxCount) {
        long nowTs = System.currentTimeMillis(); // 當(dāng)前時(shí)間戳
        // 刪除非時(shí)間段內(nèi)的請(qǐng)求數(shù)據(jù)(清除老訪問數(shù)據(jù),比如 period=60 時(shí)捶惜,標(biāo)識(shí)清除 60s 以前的請(qǐng)求記錄)
        jedis.zremrangeByScore(key, 0, nowTs - period * 1000);
        long currCount = jedis.zcard(key); // 當(dāng)前請(qǐng)求次數(shù)
        if (currCount >= maxCount) {
            // 超過最大請(qǐng)求次數(shù)田藐,執(zhí)行限流
            return false;
        }
        // 未達(dá)到最大請(qǐng)求數(shù),正常執(zhí)行業(yè)務(wù)
        jedis.zadd(key, nowTs, "" + nowTs); // 請(qǐng)求記錄 +1
        return true;
    }
}

以上程序的執(zhí)行結(jié)果為:

正常執(zhí)行請(qǐng)求:0

正常執(zhí)行請(qǐng)求:1

正常執(zhí)行請(qǐng)求:2

正常執(zhí)行請(qǐng)求:3

正常執(zhí)行請(qǐng)求:4

正常執(zhí)行請(qǐng)求:5

正常執(zhí)行請(qǐng)求:6

正常執(zhí)行請(qǐng)求:7

正常執(zhí)行請(qǐng)求:8

正常執(zhí)行請(qǐng)求:9

被限流:10

被限流:11

被限流:12

被限流:13

被限流:14

休眠后,正常執(zhí)行請(qǐng)求

此實(shí)現(xiàn)方式存在的缺點(diǎn)有兩個(gè):

  • 使用 ZSet 存儲(chǔ)有每次的訪問記錄汽久,如果數(shù)據(jù)量比較大時(shí)會(huì)占用大量的空間鹤竭,比如 60s 允許 100W 訪問時(shí);
  • 此代碼的執(zhí)行非原子操作回窘,先判斷后增加诺擅,中間空隙可穿插其他業(yè)務(wù)邏輯的執(zhí)行,最終導(dǎo)致結(jié)果不準(zhǔn)確啡直。

2.漏桶算法

漏桶算法的靈感源于漏斗烁涌,如下圖所示:

image

滑動(dòng)時(shí)間算法有一個(gè)問題就是在一定范圍內(nèi),比如 60s 內(nèi)只能有 10 個(gè)請(qǐng)求酒觅,當(dāng)?shù)谝幻霑r(shí)就到達(dá)了 10 個(gè)請(qǐng)求撮执,那么剩下的 59s 只能把所有的請(qǐng)求都給拒絕掉,而漏桶算法可以解決這個(gè)問題舷丹。

漏桶算法類似于生活中的漏斗抒钱,無論上面的水流倒入漏斗有多大,也就是無論請(qǐng)求有多少颜凯,它都是以均勻的速度慢慢流出的谋币。當(dāng)上面的水流速度大于下面的流出速度時(shí),漏斗會(huì)慢慢變滿症概,當(dāng)漏斗滿了之后就會(huì)丟棄新來的請(qǐng)求;當(dāng)上面的水流速度小于下面流出的速度的話蕾额,漏斗永遠(yuǎn)不會(huì)被裝滿,并且可以一直流出彼城。

漏桶算法的實(shí)現(xiàn)步驟是诅蝶,先聲明一個(gè)隊(duì)列用來保存請(qǐng)求,這個(gè)隊(duì)列相當(dāng)于漏斗募壕,當(dāng)隊(duì)列容量滿了之后就放棄新來的請(qǐng)求察郁,然后重新聲明一個(gè)線程定期從任務(wù)隊(duì)列中獲取一個(gè)或多個(gè)任務(wù)進(jìn)行執(zhí)行翅睛,這樣就實(shí)現(xiàn)了漏桶算法。

上面我們演示 Nginx 的控制速率其實(shí)使用的就是漏桶算法,當(dāng)然我們也可以借助 Redis 很方便的實(shí)現(xiàn)漏桶算法末荐。

我們可以使用 Redis 4.0 版本中提供的 Redis-Cell 模塊灌诅,該模塊使用的是漏斗算法疏魏,并且提供了原子的限流指令倒信,而且依靠 Redis 這個(gè)天生的分布式程序就可以實(shí)現(xiàn)比較完美的限流了。

Redis-Cell 實(shí)現(xiàn)限流的方法也很簡單资溃,只需要使用一條指令 cl.throttle 即可武翎,使用示例如下:

> cl.throttle mylimit 15 30 60
1)(integer)0 # 0 表示獲取成功,1 表示拒絕
2)(integer)15 # 漏斗容量
3)(integer)14 # 漏斗剩余容量
4)(integer)-1 # 被拒絕之后溶锭,多長時(shí)間之后再試(單位:秒)-1 表示無需重試
5)(integer)2 # 多久之后漏斗完全空出來

其中 15 為漏斗的容量宝恶,30 / 60s 為漏斗的速率。

3.令牌算法

在令牌桶算法中有一個(gè)程序以某種恒定的速度生成令牌,并存入令牌桶中垫毙,而每個(gè)請(qǐng)求需要先獲取令牌才能執(zhí)行霹疫,如果沒有獲取到令牌的請(qǐng)求可以選擇等待或者放棄執(zhí)行,如下圖所示:

image

我們可以使用 Google 開源的 guava 包综芥,很方便的實(shí)現(xiàn)令牌桶算法丽蝎,首先在 pom.xml 添加 guava 引用,配置如下:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
</dependency>

具體實(shí)現(xiàn)代碼如下:

import com.google.common.util.concurrent.RateLimiter;

import java.time.Instant;

/**
 * Guava 實(shí)現(xiàn)限流
 */
public class RateLimiterExample {
    public static void main(String[] args) {
        // 每秒產(chǎn)生 10 個(gè)令牌(每 100 ms 產(chǎn)生一個(gè))
        RateLimiter rt = RateLimiter.create(10);
        for (int i = 0; i < 11; i++) {
            new Thread(() -> {
                // 獲取 1 個(gè)令牌
                rt.acquire();
                System.out.println("正常執(zhí)行方法膀藐,ts:" + Instant.now());
            }).start();
        }
    }
}

以上程序的執(zhí)行結(jié)果為:

正常執(zhí)行方法屠阻,ts:2020-05-15T14:46:37.175Z

正常執(zhí)行方法,ts:2020-05-15T14:46:37.237Z

正常執(zhí)行方法额各,ts:2020-05-15T14:46:37.339Z

正常執(zhí)行方法国觉,ts:2020-05-15T14:46:37.442Z

正常執(zhí)行方法,ts:2020-05-15T14:46:37.542Z

正常執(zhí)行方法虾啦,ts:2020-05-15T14:46:37.640Z

正常執(zhí)行方法麻诀,ts:2020-05-15T14:46:37.741Z

正常執(zhí)行方法,ts:2020-05-15T14:46:37.840Z

正常執(zhí)行方法傲醉,ts:2020-05-15T14:46:37.942Z

正常執(zhí)行方法蝇闭,ts:2020-05-15T14:46:38.042Z

正常執(zhí)行方法,ts:2020-05-15T14:46:38.142Z

從以上結(jié)果可以看出令牌確實(shí)是每 100ms 產(chǎn)生一個(gè)硬毕,而 acquire() 方法為阻塞等待獲取令牌丁眼,它可以傳遞一個(gè) int 類型的參數(shù),用于指定獲取令牌的個(gè)數(shù)昭殉。它的替代方法還有 tryAcquire(),此方法在沒有可用令牌時(shí)就會(huì)返回 false 這樣就不會(huì)阻塞等待了藐守。當(dāng)然 tryAcquire() 方法也可以設(shè)置超時(shí)時(shí)間挪丢,未超過最大等待時(shí)間會(huì)阻塞等待獲取令牌,如果超過了最大等待時(shí)間卢厂,還沒有可用的令牌就會(huì)返回 false乾蓬。

注意:使用 guava 實(shí)現(xiàn)的令牌算法屬于程序級(jí)別的單機(jī)限流方案,而上面使用 Redis-Cell 的是分布式的限流方案慎恒。

總結(jié)

本文提供了 6 種具體的實(shí)現(xiàn)限流的手段任内,他們分別是:Tomcat 使用 maxThreads 來實(shí)現(xiàn)限流;Nginx 提供了兩種限流方式融柬,一是通過 limit_req_zoneburst 來實(shí)現(xiàn)速率限流死嗦,二是通過 limit_conn_zonelimit_conn 兩個(gè)指令控制并發(fā)連接的總數(shù)。最后我們講了時(shí)間窗口算法借助 Redis 的有序集合可以實(shí)現(xiàn)粒氧,還有漏桶算法可以使用 Redis-Cell 來實(shí)現(xiàn)越除,以及令牌算法可以解決 Google 的 guava 包來實(shí)現(xiàn)。

需要注意的是借助 Redis 實(shí)現(xiàn)的限流方案可用于分布式系統(tǒng),而 guava 實(shí)現(xiàn)的限流只能應(yīng)用于單機(jī)環(huán)境摘盆。如果你嫌棄服務(wù)器端限流麻煩翼雀,甚至可以在不改代碼的情況下直接使用容器限流(Nginx 或 Tomcat),但前提是能滿足你的業(yè)務(wù)需求孩擂。

好了狼渊,文章到這里就結(jié)束了,期待我們下期再會(huì)~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末类垦,一起剝皮案震驚了整個(gè)濱河市狈邑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌护锤,老刑警劉巖官地,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異烙懦,居然都是意外死亡驱入,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門氯析,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亏较,“玉大人,你說我怎么就攤上這事掩缓⊙┣椋” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵你辣,是天一觀的道長巡通。 經(jīng)常有香客問我,道長舍哄,這世上最難降的妖魔是什么宴凉? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮表悬,結(jié)果婚禮上弥锄,老公的妹妹穿的比我還像新娘。我一直安慰自己蟆沫,他們只是感情好籽暇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饭庞,像睡著了一般戒悠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上但绕,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天救崔,我揣著相機(jī)與錄音惶看,去河邊找鬼。 笑死六孵,一個(gè)胖子當(dāng)著我的面吹牛纬黎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播劫窒,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼本今,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了主巍?” 一聲冷哼從身側(cè)響起冠息,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎孕索,沒想到半個(gè)月后逛艰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搞旭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年散怖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肄渗。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镇眷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出翎嫡,到底是詐尸還是另有隱情欠动,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布惑申,位于F島的核電站具伍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏圈驼。R本人自食惡果不足惜沿猜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碗脊。 院中可真熱鬧,春花似錦橄妆、人聲如沸衙伶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矢劲。三九已至,卻和暖如春慌随,著一層夾襖步出監(jiān)牢的瞬間芬沉,已是汗流浹背躺同。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丸逸,地道東北人蹋艺。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像黄刚,于是被迫代替她去往敵國和親捎谨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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