仿微博社交平臺系統(tǒng)設(shè)計[四]--使用springevent事件驅(qū)動模型(觀察者模式)結(jié)合redis bitmap 運用 實現(xiàn)每日數(shù)據(jù)統(tǒng)計

觀察者模式

當(dāng)對象間存在一對多關(guān)系時愤兵,則使用觀察者模式(Observer Pattern)。比如排吴,當(dāng)一個對象被修改時秆乳,則會自動通知它的依賴對象。觀察者模式屬于行為型模式钻哩。

主要解決:一個對象狀態(tài)改變給其他對象通知的問題屹堰,而且要考慮到易用和低耦合,保證高度的協(xié)作街氢。

何時使用:一個對象(目標(biāo)對象)的狀態(tài)發(fā)生改變扯键,所有的依賴對象(觀察者對象)都將得到通知,進(jìn)行廣播通知珊肃。

如何解決:使用面向?qū)ο蠹夹g(shù)荣刑,可以將這種依賴關(guān)系弱化扣泊。

優(yōu)點: 1、觀察者和被觀察者是抽象耦合的嘶摊。 2延蟹、建立一套觸發(fā)機(jī)制。

缺點: 1叶堆、如果一個被觀察者對象有很多的直接和間接的觀察者的話阱飘,將所有的觀察者都通知到會花費很多時間。 2虱颗、如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話沥匈,觀察目標(biāo)會觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,可能導(dǎo)致系統(tǒng)崩潰忘渔。 3高帖、觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化畦粮。

Spring Boot 之事件(Event)

Spring的事件通知機(jī)制是一項很有用的功能散址,使用事件機(jī)制我們可以將相互耦合的代碼解耦,從而方便功能的修改與添加宣赔。本文我來學(xué)習(xí)并分析一下Spring中事件的原理预麸。

舉個例子,假設(shè)有一個添加評論的方法儒将,在評論添加成功之后需要進(jìn)行修改redis緩存吏祸、給用戶添加積分等等操作。當(dāng)然可以在添加評論的代碼后面假設(shè)這些操作钩蚊,但是這樣的代碼違反了設(shè)計模式的多項原則:單一職責(zé)原則贡翘、迪米特法則、開閉原則砰逻。一句話說就是耦合性太大了鸣驱,比如將來評論添加成功之后還需要有另外一個操作,這時候我們就需要去修改我們的添加評論代碼了诱渤。

在以前的代碼中丐巫,我使用觀察者模式來解決這個問題。不過Spring中已經(jīng)存在了一個升級版觀察者模式的機(jī)制勺美,這就是監(jiān)聽者模式。通過該機(jī)制我們就可以發(fā)送接收任意的事件并處理碑韵。

Spring 官方文檔翻譯如下 :

ApplicationContext 通過 ApplicationEvent 類和 ApplicationListener 接口進(jìn)行事件處理赡茸。 如果將實現(xiàn) ApplicationListener 接口的 bean 注入到上下文中,則每次使用 ApplicationContext 發(fā)布 ApplicationEvent 時祝闻,都會通知該 bean占卧。 本質(zhì)上遗菠,這是標(biāo)準(zhǔn)的觀察者設(shè)計模式。

Spring的事件(Application Event)其實就是一個觀察者設(shè)計模式华蜒,一個 Bean 處理完成任務(wù)后希望通知其它 Bean 或者說 一個Bean 想觀察監(jiān)聽另一個Bean的行為辙纬。

Spring 事件只需要幾步:

自定義事件,繼承 ApplicationEvent
定義監(jiān)聽器叭喜,實現(xiàn) ApplicationListener 或者通過 @EventListener 注解到方法上
定義發(fā)布者贺拣,通過 ApplicationEventPublisher

實際代碼:

創(chuàng)建event文件夾

并創(chuàng)建event object類和handle類,一個handle類可以對應(yīng)多個object類捂蕴。


image.png
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EverydayStatisticEventObject {
 
  private Integer id;
 
  private String os;
 
  private String proxy;
 
  private StatisticEventType statisticEventType;
 
}

創(chuàng)建枚舉類 處理不同的事件類型譬涡,運用觀察者模式

public enum StatisticEventType {
   
  //注冊數(shù)統(tǒng)計
  REGISTER_COUNTER,
  //活躍數(shù)統(tǒng)計
  ACTIVE_COUNTER,
  //裂變數(shù)統(tǒng)計
  FISSION_COUNTER,
  //播放數(shù)統(tǒng)計
  PLAYED_COUNTER,
  //廣告點擊數(shù)統(tǒng)計
  ADCLICK_COUNTER;
 
  private StatisticEventType() {
  }
}

在事務(wù)service類中注入

@Autowired
  private ApplicationEventPublisher publisher;

處理完相應(yīng)的業(yè)務(wù)邏輯后,調(diào)取publish操作啥辨,將事務(wù)發(fā)布出去

其一

public LoginLog increaseLoginLog(String ip, int uid, String username) {
    User user = mixinsService.getUser(uid);
    LoginLog loginLog = new LoginLog();
    loginLog.setLoginIp(ip);
    loginLog.setLoginTime(new Date());
    loginLog.setUid(uid);
    loginLog.setUsername(username);
    loginLog.setProxy(user.getProxy());
    loginLog.setChannel(user.getChannel());
    loginLog.setUserType(user.getUserType());
    loginLog.setOs(user.getOs());
    LoginLog log = loginLogRepository.save(loginLog);
    
    //發(fā)布事件
    publisher.publishEvent(new EverydayStatisticEventObject(log.getUid(), log.getOs(), log.getProxy(),StatisticEventType.ACTIVE_COUNTER));
    ChannelDailyDataManager.fireEvent(new UserActiveEvent(user.getChannel()));
    return log;
  }

Google Guava Cache緩存

Google Guava Cache是一種非常優(yōu)秀本地緩存解決方案涡匀,提供了基于容量,時間和引用的緩存回收方式溉知≡纱瘢基于容量的方式內(nèi)部實現(xiàn)采用LRU算法,基于引用回收很好的利用了Java虛擬機(jī)的垃圾回收機(jī)制级乍。其中的緩存構(gòu)造器CacheBuilder采用構(gòu)建者模式提供了設(shè)置好各種參數(shù)的緩存對象拾酝,緩存核心類LocalCache里面的內(nèi)部類Segment與jdk1.7及以前的ConcurrentHashMap非常相似,都繼承于ReetrantLock卡者,還有六個隊列蒿囤,以實現(xiàn)豐富的本地緩存方案。

Guava Cache與ConcurrentMap的區(qū)別

Guava Cache與ConcurrentMap很相似崇决,但也不完全一樣材诽。最基本的區(qū)別是ConcurrentMap會一直保存所有添加的元素,直到顯式地移除恒傻。相對地脸侥,Guava Cache為了限制內(nèi)存占用,通常都設(shè)定為自動回收元素盈厘。在某些場景下睁枕,盡管LoadingCache 不回收元素,它也是很有用的沸手,因為它會自動加載緩存外遇。

//bitmap的偏移量offset生產(chǎn),offset越大,占用內(nèi)存越多契吉,所以以每日第一個id作為minid跳仿,作為被減數(shù)
//使用guava cache緩存機(jī)制獲取最小id,設(shè)置過期時間為每一天,每天清空一次
private LoadingCache<String, Integer> minId = CacheBuilder.newBuilder().expireAfterWrite(1L, TimeUnit.DAYS).build(new CacheLoader<String, Integer>() {
    @Override
    public Integer load(String s) throws Exception {
      Date date = LocalDate.parse(StringUtils.substringAfter(s, "@")).toDate();
      if (ACTIVE_COUNTER.startsWith(s)) {
        LoginLog loginLog = loginLogRepository.getTopByLoginTimeBeforeOrderByIdDesc(date);
        if (loginLog != null) {
          return loginLog.getId();
        }
      } else if (PLAYED_COUNTER.startsWith(s)) {
        ViewHistory viewHistory = viewHistoryRepository.getTopByViewtimeBeforeOrderByIdDesc(date);
        if (viewHistory != null) {
          return viewHistory.getId();
        }
      } else if (ADCLICK_COUNTER.startsWith(s)) {
        AdvClickHistory advClickHistory = advClickHistoryRepository.getTopByCreateTimeBeforeOrderByIdDesc(date);
        if (advClickHistory != null) {
          return advClickHistory.getId();
        }
      }
      return 0;
    }
  });

位圖的基本介紹

概念

什么是位圖?BitMap,大家直譯為位圖. 我的理解是:位圖是內(nèi)存中連續(xù)的二進(jìn)制位(bit),可以用作對大量整形做去重和統(tǒng)計.

引入一個小栗子來幫助理解一下:

假如我們要存儲三個int數(shù)字 (1,3,5),在java中我們用一個int數(shù)組來存儲,那么占用了12個字節(jié).但是我們申請一個bit數(shù)組的話.并且把相應(yīng)下標(biāo)的位置為1,也是可以表示相同的含義的,比如

截屏2021-06-10 下午5.42.57.png

可以看到,對應(yīng)于1,3,5為下標(biāo)的bit上的值為1,我們或者計算機(jī)也是可以get到1,3,5這個信息的.

優(yōu)勢

那么這么做有什么好處呢?感覺更麻煩了鴨,下面這種存儲方式,在申請了bit[8]的場景下才占用了一個字節(jié),占用內(nèi)存是原來的12分之一,當(dāng)數(shù)據(jù)量是海量的時候,比如40億個int,這時候節(jié)省的就是10幾個G的內(nèi)存了.

這就引入了位圖的第一個優(yōu)勢,占用內(nèi)存小.

再想一下,加入我們現(xiàn)在有一個位圖,保存了用戶今天的簽到數(shù)據(jù).下標(biāo)可以是用戶的ID.

A:


截屏2021-06-10 下午5.43.41.png

這代表了用戶(1,3,5)今天簽到了.

當(dāng)然還有昨天的位圖,

B:


截屏2021-06-10 下午5.44.00.png

這代表了用戶(1,2,3,7)昨天簽到了.

我們現(xiàn)在想求:

昨天和今天都簽到的用戶.
昨天或者今天簽到的用戶.
在關(guān)系型數(shù)據(jù)庫中存儲的話,這將是一個比較麻煩的操作,要么要寫一些表意不明的SQL語句,要么進(jìn)行兩次查詢,然后在內(nèi)存中雙重循環(huán)去判斷.

而使用位圖就很簡單了,A & B, A | B 即可.上面的操作明顯是一個集合的與或操作,而二進(jìn)制天然就支持邏輯操作,且眾所周知貓是液體.錯了,眾多周知是計算機(jī)進(jìn)行二進(jìn)制運算的效率很高.

這就是位圖的第二個優(yōu)點: 支持與或運算且效率高.

哇,這么完美,那么哪里可以買到呢?,那么有什么缺點呢?

不足

當(dāng)然有,位圖不能很方便的支持非運算,(當(dāng)然,關(guān)系型數(shù)據(jù)庫支持的也不好).這句話可能有點難理解.繼續(xù)舉個例子:

我們想查詢今天沒有簽到的用戶,直接對位圖進(jìn)行取非是不可以的.

對今天簽到的位圖取非得到的結(jié)果如下:


截屏2021-06-10 下午5.44.42.png

這意味著今天(0,2,4,6,7)用戶沒有簽到嗎?不是的,存在沒有7(任意數(shù)字)號用戶的情況,或者他注銷了呢.

這是因為位圖只能表示布爾信息,即true/false.他在這個位圖中,表示的是XX用戶今天有簽到或者沒有簽到,但是不能額外的表達(dá),xx用戶存在/不存在這個狀態(tài)了.

但是我們可以曲線救國,首先搞一個全集用戶的位圖.比如:

全集:


截屏2021-06-10 下午5.45.10.png

然后用全集的位圖和簽到的位圖做異或操作,相同則為0,不相同則為1.

在業(yè)務(wù)的邏輯為: 用戶存在和是否簽到兩個bool值,共四種組合.

用戶存在,且簽到了. 兩個集合的對應(yīng)位都為1,那么結(jié)果就為0.
用戶存在,但是沒簽到. 全集對應(yīng)位為1,簽到為0,所以結(jié)果是1.
用戶不存在,那么必然沒可能簽到, 兩個集合的對應(yīng)位都是0,結(jié)果為0.
所以結(jié)果中,為1的只有一種可能:用戶存在且沒有簽到,正好是我們所求的結(jié)果.

A ^ 全集:


截屏2021-06-10 下午5.45.36.png

此外,位圖對于稀疏數(shù)據(jù)的表現(xiàn)不是很好,(當(dāng)然聰明的大佬們已經(jīng)基本解決掉了這個問題).原生的位圖來講,如果我們只有兩個用戶,1號和100000000號用戶,那么直接存儲int需要8個字節(jié)也就是32個bit,而用位圖存儲需要1億個bit.當(dāng)數(shù)據(jù)量少,且跨度極大也就是稀疏的時候,原生的位圖不太適合.

點擊這里跳轉(zhuǎn)到稀疏數(shù)據(jù)的解決方案

總結(jié)
那么我們來做一下總結(jié):

位圖是用二進(jìn)制位來存儲整形數(shù)據(jù)的一種數(shù)據(jù)結(jié)構(gòu),在很多方面都有應(yīng)用,尤其是在大數(shù)據(jù)量的場景下,節(jié)省內(nèi)存及提高運算效率十分實用.

他的優(yōu)點有:

節(jié)省內(nèi)存.
-> 因此在大數(shù)據(jù)量的時候更加顯著.

與或運算效率高.
->可以快速求交集和并集.

缺點有:

不能直接進(jìn)行非運算.
-> 根本原因是位圖只能存儲一個布爾信息,信息多了就需要借助全量集合等數(shù)據(jù)輔助.

數(shù)據(jù)稀疏時浪費空間.
-> 這個不用很擔(dān)心,后面會講到大佬們的解法,基本可以解決掉.

只能存儲布爾類型.
-> 有限制,但是業(yè)務(wù)中很多數(shù)據(jù)都可以轉(zhuǎn)換為布爾類型.比如上面的例子中, 業(yè)務(wù)原意:用戶每天的簽到記錄,以用戶為維度. 我們可以轉(zhuǎn)換為: 每天的每個用戶是否簽到,就變?yōu)榱瞬紶栴愋偷臄?shù)據(jù).

應(yīng)用場景

應(yīng)用場景其實是很考驗人的,不能學(xué)以致用,在程序員行業(yè)里基本上就相當(dāng)于沒有學(xué)了吧…
經(jīng)過自己的摸索以及在網(wǎng)上的瀏覽,大致見到了一些應(yīng)用場景,粗略的寫出來,方便大家理解并且以后遇到類似的場景可以想到位圖并應(yīng)用他!

用戶簽到/搶購等唯一限制

用戶簽到每天只能一次,搶購活動中只能購買一件,這些需求導(dǎo)致的有一種查詢請求,給定的id做沒做過某事.而且一般這種需求都無法接受你去查庫的延遲.當(dāng)然你查一次庫之后在redis中寫入:key = 2345 , value = 簽到過了.也是可以實現(xiàn)的,但是內(nèi)存占用太大.

而使用位圖之后,當(dāng)2345用戶簽到過/搶購過之后,在redis中調(diào)用setbit 2019-07-01-簽到 2345 1即可,之后用戶的每次簽到/搶購請求進(jìn)來,只需要執(zhí)行相應(yīng)的getbit即可拿到是否放行的bool值.

這樣記錄,不僅可以節(jié)省空間,以及加快訪問速度之外,還可以提供一些額外的統(tǒng)計功能,比如調(diào)用bitcount來統(tǒng)計今天簽到總?cè)藬?shù)等等.統(tǒng)計速度一般是優(yōu)于關(guān)系型數(shù)據(jù)庫的,可以用來做實時的接口查詢等.

用戶標(biāo)簽等數(shù)據(jù)

大數(shù)據(jù)已經(jīng)很普遍了,用戶畫像大家也都在做,這時候需要根據(jù)標(biāo)簽分類用戶,進(jìn)行存儲.方便后續(xù)的推薦等操作.

而用戶及標(biāo)簽的數(shù)據(jù)結(jié)構(gòu)設(shè)計是一件比較麻煩的事情,且很容易造成查詢性能太低.同時,對多個標(biāo)簽經(jīng)常需要進(jìn)行邏輯操作,比如喜歡電子產(chǎn)品的00后用戶有哪些,女性且愛旅游的用戶有哪些等等,這在關(guān)系型數(shù)據(jù)庫中都會造成處理的困難.

可以使用位圖來進(jìn)行存儲,每一個標(biāo)簽存儲為一個位圖(邏輯上,實際上你還可以按照尾號分開等等操作),在需要的時間進(jìn)行快速的統(tǒng)計及計算. 如:


截屏2021-06-10 下午5.47.05.png

可以清晰的統(tǒng)計出,0,3,6用戶喜歡旅游.


截屏2021-06-10 下午5.47.19.png

用戶0,1,6是00后.

那么對兩個位圖取與即可得到愛旅游的00后用戶為0,6.

大家都知道的是一個字節(jié)用的是8個二進(jìn)制位來存儲的捐晶,也就是8個0或者1菲语,即一個字節(jié)可以存儲十進(jìn)制0~127的數(shù)字妄辩,也即包含了所有的數(shù)字、英文大小寫字母以及標(biāo)點符號山上。

1Byte=8bit

1KB=1024Byte

1MB=1024KB

1GB=1024MB

位數(shù)組在redis存儲世界里眼耀,每一個字節(jié)也是8位,初始都是:

0 0 0 0 0 0 0 0

而位操作就是在對應(yīng)的offset偏移量上設(shè)置0或者1佩憾,比如將第3位設(shè)置為1哮伟,即:

0 0 0 0 1 0 0 0
#對應(yīng)redis操作即:
setbit key 3 1
在此基礎(chǔ)上,如果要在偏移量為13的位置設(shè)置1鸯屿,即:

setbit key 13 1
#對應(yīng)redis中的存儲為:
0 0 1 0 | 0 0 0 0 | 0 0 0 0 | 1 0 0 0

Bitmaps介紹

Redis提供的Bitmaps這個“數(shù)據(jù)結(jié)構(gòu)”可以實現(xiàn)對位的操作澈吨。Bitmaps本身不是一種數(shù)據(jù)結(jié)構(gòu),實際上就是字符串寄摆,但是它可以對字符串的位進(jìn)行操作谅辣。
可以把Bitmaps想象成一個以位為單位數(shù)組,數(shù)組中的每個單元只能存0或者1婶恼,數(shù)組的下標(biāo)在bitmaps中叫做偏移量桑阶。
單個bitmaps的最大長度是512MB,即2^32個比特位勾邦。
bitmaps的最大優(yōu)勢是節(jié)省存儲空間蚣录。例如,在一個以自增id代表不同用戶的系統(tǒng)中眷篇,我們只需要512MB空間就可以記錄40億用戶的某個單一信息(比如萎河,用戶是否希望接收新聞郵件)。

Bitmaps使用場景

1.各種實時分析(Real time analytics of all kinds)蕉饼。
2.存儲與對象ID關(guān)聯(lián)的布爾信息虐杯,要求高效且高性能(Storing space efficient but high performance boolean information associated with object IDs.)。

Bitmaps常用命令

1.設(shè)置值

命令:setbit key offset value

setbit命令接收兩個參數(shù)昧港,

第一個參數(shù)表示你要操作的是第幾個bit位擎椰,第二個參數(shù)表示你要將這個位設(shè)為何值,可選值只有0,1兩個创肥。
如果所操作的bit位超過了當(dāng)前字串的長度达舒,reids會自動增大字串長度。

2 獲取值

命令:getbit key offset

getbit只是返回特定bit位的值叹侄。如果試圖獲取的bit位在當(dāng)前字串長度范圍外巩搏,該命令返回0。

3 獲取Bitmaps指定范圍值為1的個數(shù)

命令:bitcount key [start] [end]
查看某一天是否有打卡圈膏!


統(tǒng)計操作塔猾,統(tǒng)計打卡的天數(shù)!


image.png

用Redis bitmap統(tǒng)計活躍用戶稽坤、留存

對于個int型的數(shù)來說,若用來記錄id,則只能記錄一個,而若轉(zhuǎn)換為二進(jìn)制存儲,則可以表示32個,空間的利用率提升了32倍.對于海量數(shù)據(jù)的處理,這樣的存儲方式會節(jié)省很多內(nèi)存空間.對于未登陸的用戶,可以使用Hash算法,把對應(yīng)的用戶標(biāo)識哈希為一個數(shù)字id.對于一億個數(shù)據(jù)來說,我們也只需要1000000000/8/1024/1024大約12M空間左右.

而Redis已經(jīng)為我們提供了SETBIT的方法丈甸,使用起來非常的方便,我們在item頁面可以不停地使用SETBIT命令尿褪,設(shè)置用戶已經(jīng)訪問了該頁面睦擂,也可以使用GETBIT的方法查詢某個用戶是否訪問。最后通過BITCOUNT統(tǒng)計該網(wǎng)頁每天的訪問數(shù)量杖玲。


image.png

優(yōu)點: 占用內(nèi)存更小顿仇,查詢方便,可以指定查詢某個用戶摆马,對于非登陸的用戶臼闻,可能不同的key映射到同一個id,否則需要維護(hù)一個非登陸用戶的映射囤采,有額外的開銷述呐。

//使用觀察者模式,根據(jù)不同的type來判斷不同的事務(wù)
public String progressChanged(EverydayStatisticEventObject registerEventObject) {
    String Type = "";
    StatisticEventType eventType = registerEventObject.getStatisticEventType();
    switch (eventType) {
      case REGISTER_COUNTER:
        Type = REGISTER_COUNTER;
        break;
      case ACTIVE_COUNTER:
        Type = ACTIVE_COUNTER;
        break;
      case FISSION_COUNTER:
        Type = FISSION_COUNTER;
        break;
      case PLAYED_COUNTER:
        Type = PLAYED_COUNTER;
        break;
      case ADCLICK_COUNTER:
        Type = ADCLICK_COUNTER;
        break;
      default:
        break;
    }
    return Type;
  }
 
  //事件監(jiān)聽器
  //異步
  @EventListener
  @Async
  public void registerCountEvent(EverydayStatisticEventObject registerEventObject) {
 
 
    String date = LocalDate.now().toString(STATISTIC_DATE_FMT);
    String type = progressChanged(registerEventObject);
    
    //數(shù)據(jù)庫主鍵id 減去當(dāng)天第一個id 這樣每天的偏移量都是從一開始可以有效減少偏移量對內(nèi)存的占用蕉毯。
    int offset = registerEventObject.getId() + 1 - minId.getUnchecked(StringUtils.join(type, "@", date));
 
    String key = StringUtils.join(STATISTIC_CACHE_KEY_PREFIX, type,
      date, ":", registerEventObject.getOs());
 
 
    setBitmap(offset, key);
 
    String proxyKey = StringUtils.join(STATISTIC_CACHE_KEY_PREFIX, type,
      date, ":", registerEventObject.getProxy(), ":", registerEventObject.getOs());
 
    setBitmap(offset, proxyKey);
 
        
       /* redisTemplate.execute((RedisCallback) connection -> {
            Long count = connection.bitCount(key.getBytes());
            log.info("key={},count = {}乓搬,offset={}",key,count,offset);
            return true;
        });
        redisTemplate.execute((RedisCallback) connection -> {
            Long count = connection.bitCount(proxyKey.getBytes());
            log.info("proxyKey={},count = {},offset={}",proxyKey,count,offset);
            return true;
        });*/
  }
 
private void setBitmap(int offset, String key) {
 
    byte[] bitKey = key.getBytes();
 
    redisTemplate.execute((RedisCallback) connection -> {
      boolean exists = connection.getBit(bitKey, offset);
      if (!exists) {
        connection.setBit(bitKey, offset, true);
        //設(shè)置過期時間 每天的數(shù)據(jù)統(tǒng)計 只保留2天
        connection.expire(bitKey, 60L * 60 * 24 * 2);  //2 days
        return true;
      }
      return false;
    });
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市代虾,隨后出現(xiàn)的幾起案子进肯,更是在濱河造成了極大的恐慌,老刑警劉巖棉磨,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件江掩,死亡現(xiàn)場離奇詭異,居然都是意外死亡乘瓤,警方通過查閱死者的電腦和手機(jī)环形,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馅扣,“玉大人斟赚,你說我怎么就攤上這事〔钣停” “怎么了拗军?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蓄喇。 經(jīng)常有香客問我发侵,道長,這世上最難降的妖魔是什么妆偏? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任刃鳄,我火速辦了婚禮,結(jié)果婚禮上钱骂,老公的妹妹穿的比我還像新娘叔锐。我一直安慰自己挪鹏,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布愉烙。 她就那樣靜靜地躺著讨盒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪步责。 梳的紋絲不亂的頭發(fā)上返顺,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音蔓肯,去河邊找鬼遂鹊。 笑死,一個胖子當(dāng)著我的面吹牛蔗包,可吹牛的內(nèi)容都是我干的秉扑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼气忠,長吁一口氣:“原來是場噩夢啊……” “哼邻储!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起旧噪,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤吨娜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后淘钟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宦赠,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年米母,在試婚紗的時候發(fā)現(xiàn)自己被綠了勾扭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡铁瞒,死狀恐怖妙色,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慧耍,我是刑警寧澤身辨,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站芍碧,受9級特大地震影響煌珊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泌豆,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一定庵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦蔬浙、人聲如沸猪落。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽许布。三九已至兴革,卻和暖如春绎晃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杂曲。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工庶艾, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人擎勘。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓咱揍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親棚饵。 傳聞我的和親對象是個殘疾皇子煤裙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

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