高并發(fā)之 API 接口,分布式巷燥,防刷限流赡盘,如何做?

以下文章部分出自網(wǎng)絡(luò)缰揪,參考鏈接如下:

https://blog.csdn.net/fanrenxiang/article/details/80683378

https://blog.csdn.net/top_code/article/details/53242262

https://blog.csdn.net/u010889390/article/details/82151903

  • 相關(guān)概念:
  • 應(yīng)用級(jí)限流
  • 分布式限流
  • 接入層限流

在開發(fā)分布式高并發(fā)系統(tǒng)時(shí)有三把利器用來保護(hù)系統(tǒng):緩存陨享、降級(jí)、限流

緩存

緩存的目的是提升系統(tǒng)訪問速度和增大系統(tǒng)處理容量

降級(jí)

降級(jí)是當(dāng)服務(wù)出現(xiàn)問題或者影響到核心流程時(shí)钝腺,需要暫時(shí)屏蔽掉抛姑,待高峰或者問題解決后再打開

限流

限流的目的是通過對并發(fā)訪問/請求進(jìn)行限速,或者對一個(gè)時(shí)間窗口內(nèi)的請求進(jìn)行限速來保護(hù)系統(tǒng)艳狐,一旦達(dá)到限制速率則可以拒絕服務(wù)定硝、排隊(duì)或等待、降級(jí)等處理

問題描述

1毫目、 某天A君突然發(fā)現(xiàn)自己的接口請求量突然漲到之前的10倍喷斋,沒多久該接口幾乎不可使用,并引發(fā)連鎖反應(yīng)導(dǎo)致整個(gè)系統(tǒng)崩潰蒜茴。如何應(yīng)對這種情況呢星爪?生活給了我們答案:比如老式電閘都安裝了保險(xiǎn)絲,一旦有人使用超大功率的設(shè)備粉私,保險(xiǎn)絲就會(huì)燒斷以保護(hù)各個(gè)電器不被強(qiáng)電流給燒壞顽腾。同理我們的接口也需要安裝上“保險(xiǎn)絲”,以防止非預(yù)期的請求對系統(tǒng)壓力過大而引起的系統(tǒng)癱瘓诺核,當(dāng)流量過大時(shí)抄肖,可以采取拒絕或者引流等機(jī)制。

2窖杀、 緩存的目的是提升系統(tǒng)訪問速度和增大系統(tǒng)能處理的容量漓摩,可謂是抗高并發(fā)流量的銀彈;而降級(jí)是當(dāng)服務(wù)出問題或者影響到核心流程的性能則需要暫時(shí)屏蔽掉入客,待高峰或者問題解決后再打開管毙;而有些場景并不能用緩存和降級(jí)來解決腿椎,比如稀缺資源(秒殺、搶購)夭咬、寫服務(wù)(如評論啃炸、下單)、頻繁的復(fù)雜查詢(評論的最后幾頁)卓舵,因此需有一種手段來限制這些場景的并發(fā)/請求量南用,即限流。

3掏湾、 系統(tǒng)在設(shè)計(jì)之初就會(huì)有一個(gè)預(yù)估容量裹虫,長時(shí)間超過系統(tǒng)能承受的TPS/QPS閾值,系統(tǒng)可能會(huì)被壓垮融击,最終導(dǎo)致整個(gè)服務(wù)不夠用恒界。為了避免這種情況,我們就需要對接口請求進(jìn)行限流砚嘴。

4十酣、 限流的目的是通過對并發(fā)訪問請求進(jìn)行限速或者一個(gè)時(shí)間窗口內(nèi)的的請求數(shù)量進(jìn)行限速來保護(hù)系統(tǒng),一旦達(dá)到限制速率則可以拒絕服務(wù)际长、排隊(duì)或等待耸采。

5、 一般開發(fā)高并發(fā)系統(tǒng)常見的限流模式有控制并發(fā)和控制速率工育,一個(gè)是限制并發(fā)的總數(shù)量(比如數(shù)據(jù)庫連接池虾宇、線程池),一個(gè)是限制并發(fā)訪問的速率(如nginx的limitconn模塊如绸,用來限制瞬時(shí)并發(fā)連接數(shù))嘱朽,另外還可以限制單位時(shí)間窗口內(nèi)的請求數(shù)量(如Guava的RateLimiter、nginx的limitreq模塊怔接,限制每秒的平均速率)搪泳。其他還有如限制遠(yuǎn)程接口調(diào)用速率、限制MQ的消費(fèi)速率扼脐。另外還可以根據(jù)網(wǎng)絡(luò)連接數(shù)岸军、網(wǎng)絡(luò)流量、CPU或內(nèi)存負(fù)載等來限流瓦侮。

相關(guān)概念:

PV:

page view 頁面總訪問量艰赞,每刷新一次記錄一次。

UV:

unique view 客戶端主機(jī)訪問肚吏,指一天內(nèi)相同IP的訪問記為1次方妖。

QPS:

query per second,即每秒訪問量。qps很大程度上代表了系統(tǒng)的繁忙度罚攀,沒次請求可能存在多次的磁盤io党觅,網(wǎng)絡(luò)請求雌澄,多個(gè)cpu時(shí)間片,一旦qps超過了預(yù)先設(shè)置的閥值仔役,可以考量擴(kuò)容增加服務(wù)器,避免訪問量過大導(dǎo)致的宕機(jī)是己。

RT:

response time,每次請求的響應(yīng)時(shí)間,直接決定用戶體驗(yàn)性又兵。

本文主要介紹應(yīng)用級(jí)限流方法,分布式限流卒废、流量入口限流(接入層如NGINX limitconn和limitreq 模塊)沛厨。

應(yīng)用級(jí)限流

一、控制并發(fā)數(shù)量

屬于一種較常見的限流手段摔认,在實(shí)際應(yīng)用中可以通過信號(hào)量機(jī)制(如Java中的Semaphore)來實(shí)現(xiàn)逆皮。操作系統(tǒng)的信號(hào)量是個(gè)很重要的概念,Java 并發(fā)庫 的Semaphore 可以很輕松完成信號(hào)量控制参袱,Semaphore可以控制某個(gè)資源可被同時(shí)訪問的個(gè)數(shù)电谣,通過 acquire() 獲取一個(gè)許可饥悴,如果沒有就等待剪勿,而 release() 釋放一個(gè)許可攒磨。

舉個(gè)例子般码,我們對外提供一個(gè)服務(wù)接口蓖救,允許最大并發(fā)數(shù)為10谒亦,代碼實(shí)現(xiàn)如下:

public class DubboService {
    private final Semaphore permit = new Semaphore(10, true);
    public void process(){
        try{
            permit.acquire();
            //業(yè)務(wù)邏輯處理
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            permit.release();
        }
    }
}

在以上代碼中鹿响,雖然有30個(gè)線程在執(zhí)行周伦,但是只允許10個(gè)并發(fā)的執(zhí)行郑现。Semaphore的構(gòu)造方法Semaphore(int permits) 接受一個(gè)整型的數(shù)字湃崩,表示可用的許可證數(shù)量。Semaphore(10)表示允許10個(gè)線程獲取許可證接箫,也就是最大并發(fā)數(shù)是10攒读。Semaphore的用法也很簡單,首先線程使用Semaphore的acquire()獲取一個(gè)許可證辛友,使用完之后調(diào)用release()歸還許可證整陌,還可以用tryAcquire()方法嘗試獲取許可證,信號(hào)量的本質(zhì)是控制某個(gè)資源可被同時(shí)訪問的個(gè)數(shù)瞎领,在一定程度上可以控制某資源的訪問頻率泌辫,但不能精確控制,控制訪問頻率的模式見下文描述九默。

二震放、控制訪問速率

在工程實(shí)踐中,常見的是使用令牌桶算法來實(shí)現(xiàn)這種模式驼修,常用的限流算法有兩種:漏桶算法和令牌桶算法殿遂。

漏桶算法

漏桶算法思路很簡單诈铛,水(請求)先進(jìn)入到漏桶里,漏桶以一定的速度出水墨礁,當(dāng)水流入速度過大會(huì)直接溢出幢竹,可以看出漏桶算法能強(qiáng)行限制數(shù)據(jù)的傳輸速率。

image

對于很多應(yīng)用場景來說恩静,除了要求能夠限制數(shù)據(jù)的平均傳輸速率外焕毫,還要求允許某種程度的突發(fā)傳輸。這時(shí)候漏桶算法可能就不合適了驶乾,令牌桶算法更為適合邑飒。

令牌桶算法

如圖所示,令牌桶算法的原理是系統(tǒng)會(huì)以一個(gè)恒定的速度往桶里放入令牌级乐,而如果請求需要被處理疙咸,則需要先從桶里獲取一個(gè)令牌,當(dāng)桶里沒有令牌可取時(shí)风科,則拒絕服務(wù)撒轮,令牌桶算法通過發(fā)放令牌,根據(jù)令牌的rate頻率做請求頻率限制贼穆,容量限制等腔召。

image

在Wikipedia上,令牌桶算法是這么描述的:

1扮惦、 每過1/r秒桶中增加一個(gè)令牌臀蛛。

2、 桶中最多存放b個(gè)令牌崖蜜,如果桶滿了浊仆,新放入的令牌會(huì)被丟棄。

3豫领、 當(dāng)一個(gè)n字節(jié)的數(shù)據(jù)包到達(dá)時(shí)抡柿,消耗n個(gè)令牌,然后發(fā)送該數(shù)據(jù)包等恐。

4洲劣、 如果桶中可用令牌小于n,則該數(shù)據(jù)包將被緩存或丟棄课蔬。

令牌桶控制的是一個(gè)時(shí)間窗口內(nèi)通過的數(shù)據(jù)量囱稽,在API層面我們常說的QPS、TPS二跋,正好是一個(gè)時(shí)間窗口內(nèi)的請求量或者事務(wù)量战惊,只不過時(shí)間窗口限定在1s罷了。以一個(gè)恒定的速度往桶里放入令牌扎即,而如果請求需要被處理吞获,則需要先從桶里獲取一個(gè)令牌况凉,當(dāng)桶里沒有令牌可取時(shí),則拒絕服務(wù)各拷。令牌桶的另外一個(gè)好處是可以方便的改變速度刁绒,一旦需要提高速率,則按需提高放入桶中的令牌的速率烤黍。

在我們的工程實(shí)踐中知市,通常使用Google開源工具包Guava提供的限流工具類RateLimiter來實(shí)現(xiàn)控制速率,該類基于令牌桶算法來完成限流蚊荣,非常易于使用初狰,而且非常高效莫杈。如我們不希望每秒的任務(wù)提交超過1個(gè)

public class DubboService {
    private final Semaphore permit = new Semaphore(10, true);
    public void process(){
        try{
            permit.acquire();
            //業(yè)務(wù)邏輯處理
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            permit.release();
        }
    }
}

首先通過RateLimiter.create(1.0);創(chuàng)建一個(gè)限流器互例,參數(shù)代表每秒生成的令牌數(shù),通過limiter.acquire(i);來以阻塞的方式獲取令牌筝闹,令牌桶算法允許一定程度的突發(fā)(允許消費(fèi)未來的令牌)媳叨,所以可以一次性消費(fèi)i個(gè)令牌;當(dāng)然也可以通過tryAcquire(int permits, long timeout, TimeUnit unit)來設(shè)置等待超時(shí)時(shí)間的方式獲取令牌关顷,如果超timeout為0糊秆,則代表非阻塞,獲取不到立即返回议双,支持阻塞或可超時(shí)的令牌消費(fèi)痘番。

從輸出來看,RateLimiter支持預(yù)消費(fèi)平痰,比如在acquire(5)時(shí)汞舱,等待時(shí)間是4秒,是上一個(gè)獲取令牌時(shí)預(yù)消費(fèi)了3個(gè)兩排宗雇,固需要等待3*1秒昂芜,然后又預(yù)消費(fèi)了5個(gè)令牌,以此類推赔蒲。

RateLimiter通過限制后面請求的等待時(shí)間泌神,來支持一定程度的突發(fā)請求(預(yù)消費(fèi)),在使用過程中需要注意這一點(diǎn)舞虱,Guava有兩種限流模式欢际,一種為穩(wěn)定模式(SmoothBursty:令牌生成速度恒定,平滑突發(fā)限流)矾兜,一種為漸進(jìn)模式(SmoothWarmingUp:令牌生成速度緩慢提升直到維持在一個(gè)穩(wěn)定值幼苛,平滑預(yù)熱限流) 兩種模式實(shí)現(xiàn)思路類似,主要區(qū)別在等待時(shí)間的計(jì)算上焕刮。

SmoothBursty 模式:

RateLimiter limiter = RateLimiter.create(5); RateLimiter.create(5)表示桶容量為5且每秒新增5個(gè)令牌舶沿,即每隔200毫秒新增一個(gè)令牌墙杯;limiter.acquire()表示消費(fèi)一個(gè)令牌,如果當(dāng)前桶中有足夠令牌則成功(返回值為0)括荡,如果桶中沒有令牌則暫停一段時(shí)間高镐,比如發(fā)令牌間隔是200毫秒,則等待200毫秒后再去消費(fèi)令牌畸冲,這種實(shí)現(xiàn)將突發(fā)請求速率平均為了固定請求速率嫉髓。

SmoothWarmingUp模式:

RateLimiter limiter = RateLimiter.create(5,1000, TimeUnit.MILLISECONDS);

創(chuàng)建方式:

RateLimiter.create(doublepermitsPerSecond, long warmupPeriod, TimeUnit unit),permitsPerSecond表示每秒新增的令牌數(shù)邑闲,warmupPeriod表示在從冷啟動(dòng)速率過渡到平均速率的時(shí)間間隔算行。速率是梯形上升速率的,也就是說冷啟動(dòng)時(shí)會(huì)以一個(gè)比較大的速率慢慢到平均速率苫耸;然后趨于平均速率(梯形下降到平均速率)州邢。可以通過調(diào)節(jié)warmupPeriod參數(shù)實(shí)現(xiàn)一開始就是平滑固定速率褪子。

放在Controller中用Jemter壓測

image

注:RateLimiter控制的是速率量淌,Samephore控制的是并發(fā)量。RateLimiter的原理就是令牌桶嫌褪,它主要由許可發(fā)出的速率來定義呀枢,如果沒有額外的配置,許可證將按每秒許可證規(guī)定的固定速度分配笼痛,許可將被平滑地分發(fā)裙秋,若請求超過permitsPerSecond則RateLimiter按照每秒 1/permitsPerSecond 的速率釋放許可。注意:RateLimiter適用于單體應(yīng)用缨伊,且RateLimiter不保證公平性訪問摘刑。

使用上述方式使用RateLimiter的方式不夠優(yōu)雅,自定義注解+AOP的方式實(shí)現(xiàn)(適用于單體應(yīng)用)倘核,詳細(xì)見下面代碼:

自定義注解:

import java.lang.annotation.*;
/**
 * 自定義注解可以不包含屬性泣侮,成為一個(gè)標(biāo)識(shí)注解
 */
@Inherited
@Documented
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimitAspect {
}

自定義切面類

import com.google.common.util.concurrent.RateLimiter;
import com.test.cn.springbootdemo.util.ResultUtil;
import net.sf.json.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Scope
@Aspect
public class RateLimitAop {
    @Autowired
    private HttpServletResponse response;
    private RateLimiter rateLimiter = RateLimiter.create(5.0); //比如說,我這里設(shè)置"并發(fā)數(shù)"為5
    @Pointcut("@annotation(com.test.cn.springbootdemo.aspect.RateLimitAspect)")
    public void serviceLimit() {
    }
    @Around("serviceLimit()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Boolean flag = rateLimiter.tryAcquire();
        Object obj = null;
        try {
            if (flag) {
                obj = joinPoint.proceed();
            }else{
                String result = JSONObject.fromObject(ResultUtil.success1(100, "failure")).toString();
                output(response, result);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("flag=" + flag + ",obj=" + obj);
        return obj;
    }
    public void output(HttpServletResponse response, String msg) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(msg.getBytes("UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            outputStream.flush();
            outputStream.close();
        }
    }
}

測試controller

import com.test.cn.springbootdemo.aspect.RateLimitAspect;
import com.test.cn.springbootdemo.util.ResultUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestController {
    @ResponseBody
    @RateLimitAspect
    @RequestMapping("/test")
    public String test(){
        return ResultUtil.success1(1001, "success").toString();
    }

壓測結(jié)果:

image

三紧唱、控制單位時(shí)間窗口內(nèi)請求數(shù)

某些場景下活尊,我們想限制某個(gè)接口或服務(wù) 每秒/每分鐘/每天 的請求次數(shù)或調(diào)用次數(shù)。例如限制服務(wù)每秒的調(diào)用次數(shù)為50漏益,實(shí)現(xiàn)如下:

private LoadingCache < Long, AtomicLong > counter = CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.SECONDS).build(new CacheLoader < Long, AtomicLong > () {@
    Override
    public AtomicLong load(Long seconds) throws Exception {
        return new AtomicLong(0);
    }
});
public static long permit = 50;
public ResponseEntity getData() throws ExecutionException {
    //得到當(dāng)前秒
    long currentSeconds = System.currentTimeMillis() / 1000;
    if (counter.get(currentSeconds).incrementAndGet() > permit) {
        return ResponseEntity.builder().code(404).msg("訪問速率過快").build();
    }
    //業(yè)務(wù)處理
}

到此應(yīng)用級(jí)限流的一些方法就介紹完了蛹锰。假設(shè)將應(yīng)用部署到多臺(tái)機(jī)器,應(yīng)用級(jí)限流方式只是單應(yīng)用內(nèi)的請求限流绰疤,不能進(jìn)行全局限流铜犬。因此我們需要分布式限流和接入層限流來解決這個(gè)問題。

分布式限流

自定義注解+攔截器+Redis實(shí)現(xiàn)限流 (單體和分布式均適用,全局限流)

自定義注解:

@Inherited
@Documented
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {
    int limit() default 5;
    int sec() default 5;
}

攔截器:

public class AccessLimitInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisTemplate<String, Integer> redisTemplate;  //使用RedisTemplate操作redis
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            if (!method.isAnnotationPresent(AccessLimit.class)) {
                return true;
            }
            AccessLimit accessLimit = method.getAnnotation(AccessLimit.class);
            if (accessLimit == null) {
                return true;
            }
            int limit = accessLimit.limit();
            int sec = accessLimit.sec();
            String key = IPUtil.getIpAddr(request) + request.getRequestURI();
            Integer maxLimit = redisTemplate.opsForValue().get(key);
            if (maxLimit == null) {
                redisTemplate.opsForValue().set(key, 1, sec, TimeUnit.SECONDS);  //set時(shí)一定要加過期時(shí)間
            } else if (maxLimit < limit) {
                redisTemplate.opsForValue().set(key, maxLimit + 1, sec, TimeUnit.SECONDS);
            } else {
                output(response, "請求太頻繁!");
                return false;
            }
        }
        return true;
    }
    public void output(HttpServletResponse response, String msg) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(msg.getBytes("UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            outputStream.flush();
            outputStream.close();
        }
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

controller:

<@Controller
@RequestMapping("/activity")
public class AopController {
    @ResponseBody
    @RequestMapping("/seckill")
    @AccessLimit(limit = 4,sec = 10)  //加上自定義注解即可
    public String test (HttpServletRequest request,@RequestParam(value = "username",required = false) String userName){
        //TODO somethings……
        return   "hello world !";
    }
}

配置文件:

/*springmvc的配置文件中加入自定義攔截器*/
<mvc:interceptors>
   <mvc:interceptor>
      <mvc:mapping path="/**"/>
      <bean class="com.pptv.activityapi.controller.pointsmall.AccessLimitInterceptor"/>
   </mvc:interceptor>
</mvc:interceptors>

訪問效果如下癣猾,10s內(nèi)訪問接口超過4次以上就過濾請求敛劝,原理和計(jì)數(shù)器算法類似:

image

接入層限流

主要介紹nginx 限流,采用漏桶算法纷宇。

限制原理:可一句話概括為:“根據(jù)客戶端特征夸盟,限制其訪問頻率”,客戶端特征主要指IP像捶、UserAgent等上陕。使用IP比UserAgent更可靠,因?yàn)镮P無法造假拓春,UserAgent可隨意偽造释簿。

用limit_req模塊來限制基于IP請求的訪問頻率:

http://nginx.org/en/docs/http/ngxhttplimitreqmodule.html

也可以用tengine中的增強(qiáng)版:

http://tengine.taobao.org/documentcn/httplimitreqcn.html

1、并發(fā)數(shù)和連接數(shù)控制的配置:

nginx http配置:
    #請求數(shù)量控制硼莽,每秒20個(gè)
    limit_req_zone $binary_remote_addr zone=one:10m rate=20r/s;
    #并發(fā)限制30個(gè)
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    server塊配置
    limit_req zone=one burst=5;
    limit_conn addr 30;

2庶溶、ngxhttplimitconnmodule 可以用來限制單個(gè)IP的連接數(shù):

ngxhttplimitconnmodule模塊可以按照定義的鍵限定每個(gè)鍵值的連接數(shù)〕辽荆可以設(shè)定單一 IP 來源的連接數(shù)渐尿。

并不是所有的連接都會(huì)被模塊計(jì)數(shù)醉途;只有那些正在被處理的請求(這些請求的頭信息已被完全讀入)所在的連接才會(huì)被計(jì)數(shù)矾瑰。

http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    ...
    server {
        ...
        location /download/ {
            limit_conn addr 1;
        }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市隘擎,隨后出現(xiàn)的幾起案子殴穴,更是在濱河造成了極大的恐慌,老刑警劉巖货葬,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件采幌,死亡現(xiàn)場離奇詭異,居然都是意外死亡震桶,警方通過查閱死者的電腦和手機(jī)休傍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹲姐,“玉大人磨取,你說我怎么就攤上這事〔穸眨” “怎么了忙厌?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長江咳。 經(jīng)常有香客問我逢净,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任爹土,我火速辦了婚禮甥雕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘胀茵。我一直安慰自己犀农,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布宰掉。 她就那樣靜靜地躺著呵哨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轨奄。 梳的紋絲不亂的頭發(fā)上孟害,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天,我揣著相機(jī)與錄音挪拟,去河邊找鬼挨务。 笑死,一個(gè)胖子當(dāng)著我的面吹牛玉组,可吹牛的內(nèi)容都是我干的谎柄。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼惯雳,長吁一口氣:“原來是場噩夢啊……” “哼朝巫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起石景,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤劈猿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后潮孽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揪荣,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年往史,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仗颈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡椎例,死狀恐怖挨决,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粟矿,我是刑警寧澤凰棉,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站陌粹,受9級(jí)特大地震影響撒犀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一或舞、第九天 我趴在偏房一處隱蔽的房頂上張望荆姆。 院中可真熱鬧,春花似錦映凳、人聲如沸胆筒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仆救。三九已至,卻和暖如春矫渔,著一層夾襖步出監(jiān)牢的瞬間彤蔽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工庙洼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顿痪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓油够,卻偏偏與公主長得像蚁袭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子石咬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評論 2 351