18.性能Performance

性能

隨著您應(yīng)用程序的擴(kuò)展,您需要確保它在負(fù)載和使用量增加的情況下運(yùn)行良好声离。本文檔提供了如何優(yōu)化應(yīng)用程序性能的指導(dǎo)宾娜。雖然您可以使用Parse Server進(jìn)行快速原型設(shè)計(jì),而不用擔(dān)心性能吩谦,但在最初設(shè)計(jì)應(yīng)用程序時(shí)鸳谜,您還是需要考慮性能指標(biāo)。我們強(qiáng)烈建議您在發(fā)布應(yīng)用程序之前遵循所有建議式廷。

您可以通過查看以下內(nèi)容來改善應(yīng)用程序的性能:

  • 編寫高效的查詢咐扭。
  • 寫限制性查詢。
  • 使用客戶端緩存。
  • 使用Cloud Code草描。
  • 避免計(jì)數(shù)查詢览绿。
  • 使用有效的搜索技術(shù)。

請(qǐng)記住穗慕,并不是所有的建議都適用于您的應(yīng)用程序饿敲。以下讓我們逐一研究他們的細(xì)節(jié)。

1.編寫高效查詢

Parse對(duì)象存儲(chǔ)在數(shù)據(jù)庫中逛绵。Parse查詢根據(jù)查詢條件檢索您感興趣的對(duì)象怀各。為了避免每個(gè)查詢都翻遍某個(gè)Parse類中的所有數(shù)據(jù),可在數(shù)據(jù)庫中使用索引术浪。索引是符合給定條件的有序列表瓢对。索引可幫助數(shù)據(jù)庫進(jìn)行高效的搜索并返回匹配結(jié)果,而不用查看所有數(shù)據(jù)胰苏。索引通常較小且在內(nèi)存中硕蛹,因此查找更快。

2.索引

使用Parse Server時(shí)硕并,需要自行負(fù)責(zé)管理數(shù)據(jù)庫和維護(hù)索引法焰。如果您的數(shù)據(jù)未建立索引,則每個(gè)查詢都必須遍歷類中的所有數(shù)據(jù)以返回查詢結(jié)果倔毙。另一方面埃仪,如果您的數(shù)據(jù)建立索引得當(dāng),為返回正確的查詢結(jié)構(gòu)陕赃,需掃描的文檔數(shù)量將很少卵蛉。

一些有用的查詢約束命令如下:

  • 等于(Equal to)
  • 包含在(Contained In)
  • 小于,小于或等于么库,大于傻丝,大于或等于(Less than, Less than or Equal to, Greater than, Greater than or Equal to)
  • 前綴字符串匹配(Prefix string matches)
  • 不等于(Not equal to)
  • 不包含在(Not contained in)
  • 其他一切(Everything else)

我們來看一下以下檢索GameScore對(duì)象的查詢:

var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("score", 50);
query.containedIn("playerName",
    ["Jonathan Walsh", "Dario Wunsch", "Shawn Simon"]);

在score字段創(chuàng)建索引查詢將會(huì)比在playerName字段上創(chuàng)建索引的搜索空間更小。

考慮數(shù)據(jù)類型廊散,布爾值的熵很低桑滩,因此它不會(huì)是好的索引≡识茫考慮以下查詢約束:

query.equalTo("cheatMode", false);

對(duì)于"cheatMode"运准,兩個(gè)可能的值是true和false。如果在此字段上添加索引將沒什么用處缭受,因?yàn)楹芸赡苓€是需要查看50%的記錄才能返回查詢結(jié)果胁澳。

數(shù)據(jù)類型按其鍵值值域的預(yù)期熵進(jìn)行排名:

  • GeoPoints
  • Array
  • Pointer
  • Date
  • String
  • Number
  • Other

即使最好的索引策略也比不上次優(yōu)的查詢。

3.高效查詢的設(shè)計(jì)

編寫高效的查詢可充分利用索引的優(yōu)勢(shì)米者。我們來看看一些使得索引無效的查詢約束:

  • 不等于(Not Equal To)
  • 不包含(Not Contained In)

此外韭畸,在某些情況下宇智,如果它們無法利用索引,以下查詢可能響應(yīng)緩慢:

  • 正則表達(dá)式
  • 排序(Ordered By)

1.不等于(NOT EQUAL TO)

例如胰丁,假設(shè)您在GameScore類中查找游戲的高分∷骈伲現(xiàn)在你想要檢索除了某個(gè)玩家外的所有玩家的分?jǐn)?shù)。您可以創(chuàng)建此查詢:

var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.notEqualTo("playerName", "Michael Yabuti");
query.find().then(function(results) {
  // Retrieved scores successfully
});

此查詢無法利用索引锦庸。數(shù)據(jù)庫必須檢查GameScore類中的所有對(duì)象以滿足約束并檢索結(jié)果机蔗。隨著類中條目數(shù)量的增長,查詢運(yùn)行時(shí)間更長甘萧。

幸運(yùn)的是萝嘁,大多數(shù)時(shí)候,“Not Equal To”查詢條件可以重寫為“Contained In”條件扬卷。您需要檢索匹配其他列值的值牙言,而不是去查詢?nèi)笔е怠_@樣做數(shù)據(jù)庫可使用索引怪得,查詢將更快咱枉。

例如,如果User類有一個(gè)名為state的列,它具有值“SignedUp”、“Verified”和“Invited”垢揩,那么查找所有至少使用過該應(yīng)用程序一次的用戶的緩慢方式是:

var query = new Parse.Query(Parse.User);
query.notEqualTo("state", "Invited");

而配置查詢時(shí)使用“Contained In”條件會(huì)更快:

query.containedIn("state", ["SignedUp", "Verified"]);

有時(shí)闹获,您可能需要完全重寫您的查詢⊙瞻茫回到這個(gè)"GameScore"例子财岔,假設(shè)我們正在查詢并顯示得分高于給定玩家的玩家。我們可以這樣做河爹,首先得到給定玩家的高分匠璧,然后使用以下查詢語句:

var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
// Previously retrieved highScore for Michael Yabuti
query.greaterThan("score", highScore);
query.find().then(function(results) {
  // Retrieved scores successfully
});

您使用的新查詢?nèi)Q于您的用例。有時(shí)這可能意味著要重新設(shè)計(jì)您的數(shù)據(jù)模型咸这。

2.不包含(NOT CONTAINED IN)

類似于“Not Equal To”夷恍,“Not Contained In”查詢約束不能使用索引。您應(yīng)該嘗試使用互補(bǔ)的“Contained In”約束媳维∧鹧基于之前的User示例,如果state列還有一個(gè)值“Blocked”侄刽,以表示被阻止的用戶指黎,則查找活動(dòng)用戶的慢查詢是:

var query = new Parse.Query(Parse.User);
query.notContainedIn("state", ["Invited", "Blocked"]);

而使用互補(bǔ)的“Contained In”查詢約束將始終更快:

query.containedIn("state", ["SignedUp", "Verified"]);

這意味著要相應(yīng)地重寫你的查詢。而查詢重寫取決于您的Schema設(shè)置州丹。這意味著可能要重做該Schema模式醋安。

3.正則表達(dá)式

由于性能考慮杂彭,應(yīng)避免使用正則表達(dá)式查詢。MongoDB對(duì)于局部字符串匹配效率不高吓揪,除了僅需要前綴匹配的特殊情況亲怠。因此,包含正則表達(dá)式限制的查詢代價(jià)高昂柠辞,特別是對(duì)于超過100,000條記錄的類团秽。在特定應(yīng)用程序上,應(yīng)該限制特定時(shí)間內(nèi)運(yùn)行這樣操作的次數(shù)钾腺。

您應(yīng)該避免運(yùn)行不能使用索引的正則表達(dá)式約束徙垫。例如,以下查詢?cè)?playerName"字段中查找具有給定字符串的數(shù)據(jù)放棒。字符串搜索不區(qū)分大小寫姻报,因此無法編入索引:

query.matches("playerName", "Michael", "i");

以下查詢?cè)诖笮懨舾械那闆r下,會(huì)查找字段中的任何字符串间螟,并且無法編入索引:

query.contains("playerName", "Michael");

這些查詢都很慢吴旋。事實(shí)上,我們的查詢指南中故意沒有包含matches和contains查詢限制方法厢破,因?yàn)槲覀儾煌扑]使用它們荣瑟。根據(jù)您的用例,您應(yīng)切換到以下可使用索引的約束摩泪,例如:

query.startsWith("playerName", "Michael");

這將查找以給定字符串開頭的數(shù)據(jù)笆焰。此查詢將使用后端索引,因此即使對(duì)于大型數(shù)據(jù)集也將更快见坑。

作為最佳實(shí)踐嚷掠,當(dāng)您使用正則表達(dá)式約束時(shí),您需要確保查詢中的其他約束將結(jié)果集減少到數(shù)百個(gè)對(duì)象的有序列表荞驴,以使查詢高效不皆。如果由于遺留原因,您必須使用matches或contains約束熊楼,請(qǐng)盡可能使用區(qū)分大小寫的固定查詢霹娄,例如:

query.matches("playerName", "^Michael");

大多數(shù)使用正則表達(dá)式的用例涉及到執(zhí)行搜索。執(zhí)行搜索更有效的方法將在后面詳細(xì)介紹鲫骗。

4.寫限制性查詢

寫限制性查詢使得您僅返回客戶端需要的數(shù)據(jù)犬耻。這在移動(dòng)環(huán)境中至關(guān)重要,數(shù)據(jù)使用可能受到限制挎峦,而且網(wǎng)絡(luò)連接不可靠香追。您還希望您的移動(dòng)應(yīng)用顯示響應(yīng)結(jié)果,這直接受發(fā)送回客戶端對(duì)象的影響坦胶⊥傅洌“查詢”章節(jié)介紹了可以添加到現(xiàn)有查詢中以限制返回?cái)?shù)據(jù)的約束類型晴楔。添加約束時(shí),您需要注意設(shè)計(jì)高效的查詢峭咒。

您可以使用skip和limit來瀏覽結(jié)果税弃,并根據(jù)需要加載數(shù)據(jù)。缺省情況下凑队,查詢限制為100:

query.limit(10); // limit to at most 10 results

如果您在GeoPoints上發(fā)出查詢则果,請(qǐng)確保指定合理的半徑:

var query = new Parse.Query(PlaceObject);
query.withinMiles("location", userGeoPoint, 10.0);
query.find().then(function(placesObjects) {
  // Get a list of objects within 10 miles of a user's location
});

您可以進(jìn)一步限制通過調(diào)用select返回的字段:

var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.select("score", "playerName");
query.find().then(function(results) {
  // each of results will only have the selected fields available.
});

5.客戶端緩存

對(duì)于從iOS和Android運(yùn)行的查詢,您可以打開查詢緩存漩氨。有關(guān)詳細(xì)信息西壮,請(qǐng)參閱iOSAndroid指南。緩存查詢將提高您移動(dòng)應(yīng)用程序的性能叫惊,特別是在您要從Parse獲取最新數(shù)據(jù)時(shí)顯示緩存數(shù)據(jù)的情況下款青。

6.使用Cloud Code

Cloud Code允許您在Parse Server上運(yùn)行自定義JavaScript邏輯,而不是在客戶端上運(yùn)行霍狰。

您可以利用它把處理分流到Parse服務(wù)器抡草,從而增加應(yīng)用程序端的感知性能。您可以創(chuàng)建保存或刪除對(duì)象時(shí)運(yùn)行的鉤子(hooks)蔗坯。這對(duì)于驗(yàn)證或清理數(shù)據(jù)很有用康震。您也可以使用Cloud Code修改相關(guān)對(duì)象或啟動(dòng)其他進(jìn)程,例如發(fā)送推送通知宾濒。

我們看到了約束查詢返回有限數(shù)據(jù)的例子腿短。您還可以使用Cloud Functions來減少返回到應(yīng)用程序的數(shù)據(jù)量。在以下示例中绘梦,我們使用Cloud Functions獲取電影的平均評(píng)分:

Parse.Cloud.define("averageStars", function(request, response) {
  var Review = Parse.Object.extend("Review");
  var query = new Parse.Query(Review);
  query.equalTo("movie", request.params.movie);
  query.find().then(function(results) {
    var sum = 0;
    for (var i = 0; i < results.length; ++i) {
      sum += results[i].get("stars");
    }
    response.success(sum / results.length);
  }, function(error) {
    response.error("movie lookup failed");
  });
});

您可以在客戶端上的Review類中運(yùn)行查詢答姥,僅返回stars字段數(shù)據(jù)并在客戶端上計(jì)算結(jié)果。隨著電影評(píng)論數(shù)量的增加谚咬,使用此方法返回到設(shè)備的數(shù)據(jù)也會(huì)增加。通過Cloud Functions實(shí)現(xiàn)該功能尚粘,如果成功择卦,則只返回一個(gè)結(jié)果。

查看優(yōu)化查詢時(shí)郎嫁,您會(huì)發(fā)現(xiàn)可能需要更改查詢 —— 有時(shí)即使將應(yīng)用程序發(fā)送到App Store或Google Play也是如此秉继。如果您使用Cloud Functions,則無需客戶端更新就可以更改查詢泽铛。即使您必須重新設(shè)計(jì)Schema尚辑,您依然可以在保持客戶端接口不變的情況下在Cloud Functions中更改,以避免應(yīng)用程序更新盔腔。從之前平均標(biāo)星數(shù)(average stars)的Cloud Functions示例中杠茬,從客戶端SDK調(diào)用它如下所示:

Parse.Cloud.run("averageStars", { "movie": "The Matrix" }).then(function(ratings) {
  // ratings is 4.5
});

如果以后月褥,您需要修改基礎(chǔ)數(shù)據(jù)模型,只要您返回一個(gè)表示評(píng)級(jí)結(jié)果的數(shù)字瓢喉,您的客戶端調(diào)用就可以保持不變宁赤。

7.避免計(jì)數(shù)操作

當(dāng)需要頻繁對(duì)對(duì)象計(jì)數(shù)時(shí),應(yīng)考慮在數(shù)據(jù)庫中保存一個(gè)計(jì)數(shù)變量栓票,每當(dāng)添加對(duì)象時(shí)計(jì)數(shù)變量就遞增决左。然后,可以簡單地通過檢索存儲(chǔ)的計(jì)數(shù)變量來快速獲得計(jì)數(shù)走贪。

假設(shè)您在應(yīng)用程序中顯示電影信息佛猛,數(shù)據(jù)模型由一個(gè)Movie類和一個(gè)包含指向相應(yīng)movie指針的Review類組成。您可能希望使用以下查詢?cè)陧敿?jí)導(dǎo)航屏幕上顯示每部電影的評(píng)論數(shù):

var Review = Parse.Object.extend("Review");
var query = new Parse.Query("Review");
query.equalTo(“movie”, movie);
query.count().then(function(count) {
  // Request succeeded
});

如果您為每個(gè)UI元素運(yùn)行計(jì)數(shù)查詢坠狡,則它們將無法在大型數(shù)據(jù)集上高效運(yùn)行继找。避免使用count()操作符的一種方法是在Movie類中添加一個(gè)字段,該字段表示該電影的評(píng)論數(shù)擦秽。在保存Review類的條目時(shí)码荔,需要在相應(yīng)影片的評(píng)論計(jì)數(shù)字段加一。這可以在一個(gè)afterSave處理方法中完成:

Parse.Cloud.afterSave("Review", function(request) {
  // Get the movie id for the Review
  var movieId = request.object.get("movie").id;
  // Query the Movie represented by this review
  var Movie = Parse.Object.extend("Movie");
  var query = new Parse.Query(Movie);
  query.get(movieId).then(function(movie) {
    // Increment the reviews field on the Movie object
    movie.increment("reviews");
    movie.save();
  }, function(error) {
    throw "Got an error " + error.code + " : " + error.message;
  });
});

新優(yōu)化的查詢使得您不需要查看Review類就可以獲取評(píng)論數(shù):

var Movie = Parse.Object.extend("Movie");
var query = new Parse.Query(Movie);
query.find().then(function(results) {
  // Results include the reviews count field
}, function(error) {
  // Request failed
});

您還可以使用單獨(dú)的Parse對(duì)象來跟蹤每次評(píng)論的計(jì)數(shù)感挥。每當(dāng)添加或刪除評(píng)論時(shí)缩搅,您可以在afterSave或afterDelete Cloud Code處理程序中增加或減少一個(gè)計(jì)數(shù)。您的方法取決于您的用例触幼。

8.實(shí)施高效的搜索

如前所述硼瓣,MongoDB對(duì)于局部字符串匹配效率不高。但是置谦,在產(chǎn)品中實(shí)現(xiàn)一個(gè)擴(kuò)展性很好的搜索功能堂鲤,這是一個(gè)重要的用例。

簡單的搜索算法直接掃描類中的所有數(shù)據(jù)媒峡,并對(duì)每個(gè)條目執(zhí)行查詢瘟栖。使搜索高效運(yùn)行的關(guān)鍵,是通過前述的索引來最小化每個(gè)查詢執(zhí)行時(shí)必須檢查的數(shù)據(jù)量谅阿。您需要為要搜索的數(shù)據(jù)設(shè)計(jì)一個(gè)容易構(gòu)建索引的數(shù)據(jù)模型半哟。例如,不匹配確切前綴的字符串匹配查詢由于無法使用索引签餐,隨著數(shù)據(jù)集增長將導(dǎo)致超時(shí)錯(cuò)誤寓涨。

我們來看一個(gè)如何構(gòu)建高效搜索的例子。您可以將此示例中的理念應(yīng)用于自己的用例氯檐。比如你的應(yīng)用程序有用戶發(fā)帖戒良,你想通過主題標(biāo)簽或特定的關(guān)鍵字搜索這些帖子。您將需要預(yù)處理帖子冠摄,并將主題標(biāo)簽(hashtags)和內(nèi)容(words)列表保存到數(shù)組中糯崎。您可以在應(yīng)用程序中保存帖子之前執(zhí)行此處理几缭,也可以使用Cloud Code的beforeSave鉤子:

var _ = require("underscore");
Parse.Cloud.beforeSave("Post", function(request, response) {
  var post = request.object;
  var toLowerCase = function(w) { return w.toLowerCase(); };
  var words = post.get("text").split(/\b/);
  words = _.map(words, toLowerCase);
  var stopWords = ["the", "in", "and"]
  words = _.filter(words, function(w) {
    return w.match(/^\w+$/) && !   _.contains(stopWords, w);
  });
  var hashtags = post.get("text").match(/#.+?\b/g);
  hashtags = _.map(hashtags, toLowerCase);
  post.set("words", words);
  post.set("hashtags", hashtags);
  response.success();
});

這可以將您的內(nèi)容和主題標(biāo)簽保存在數(shù)組中,MongoDB將使用多鍵索引存儲(chǔ)拇颅。這里要注意以下重要問題:首先奏司,將所有單詞轉(zhuǎn)換為小寫,以便我們可以使用小寫查詢查找它們樟插,并獲取不區(qū)分大小寫的匹配韵洋。其次,它會(huì)濾除很多帖子中出現(xiàn)的常見詞黄锤,如'the'搪缨,'in'和'and',以便在執(zhí)行查詢時(shí)進(jìn)一步減少對(duì)索引的無用掃描鸵熟。

一旦設(shè)置了關(guān)鍵字副编,您可以在查詢中使用“All”約束來高效地檢索:

var Post = Parse.Object.extend("Post");
var query = new Parse.Query(Post);
query.containsAll("hashtags", [“#parse”, “#ftw”]);
query.find().then(function(results) {
  // Request succeeded
}, function(error) {
  // Request failed
});

9.限制和其他注意事項(xiàng)

  • 這里有一些限制,以確保API可以高效提供您需要的數(shù)據(jù)流强。將來我們可能會(huì)調(diào)整這些限制痹届。請(qǐng)花點(diǎn)時(shí)間閱讀以下內(nèi)容:

對(duì)象

  • Parse對(duì)象的大小限制為128 KB。
  • 我們建議不要在單個(gè)Parse對(duì)象上創(chuàng)建超過64個(gè)字段打月,以確倍痈可以為查詢構(gòu)建高效的索引。
  • 我們建議不要使用超過1,024個(gè)字符的字段名稱奏篙,否則不會(huì)創(chuàng)建該字段的索引柴淘。

查詢

  • 默認(rèn)情況下,查詢返回100個(gè)對(duì)象秘通。使用limit參數(shù)來改變它为严。
  • skip和limit只能用于外部查詢。
  • 彼此沖突的約束將導(dǎo)致僅一個(gè)約束被執(zhí)行肺稀。例如:在equalTo約束條件上第股,為同一個(gè)鍵名設(shè)置了兩個(gè)不同的值,這兩個(gè)值是矛盾的(也許你正在尋找'contains')话原。
  • 地理查詢中沒有復(fù)合OR查詢炸茧。
  • 不建議使用$exists: false。
  • JavaScript SDK中的each查詢方法不能與地理位置約束的查詢結(jié)合使用稿静。
  • 一個(gè)containsAll查詢約束的比較數(shù)組中頂多只能包含9個(gè)項(xiàng)。

推送通知

Cloud Code

  • 傳遞到Cloud Code的參數(shù)有效載荷被限制為50 MB悬钳。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盐捷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子默勾,更是在濱河造成了極大的恐慌碉渡,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件母剥,死亡現(xiàn)場離奇詭異滞诺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)环疼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門习霹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人炫隶,你說我怎么就攤上這事淋叶。” “怎么了伪阶?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵煞檩,是天一觀的道長。 經(jīng)常有香客問我栅贴,道長斟湃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任筹误,我火速辦了婚禮桐早,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘厨剪。我一直安慰自己哄酝,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布祷膳。 她就那樣靜靜地躺著陶衅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪直晨。 梳的紋絲不亂的頭發(fā)上搀军,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音勇皇,去河邊找鬼罩句。 笑死,一個(gè)胖子當(dāng)著我的面吹牛敛摘,可吹牛的內(nèi)容都是我干的门烂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼屯远!你這毒婦竟也來了蔓姚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤慨丐,失蹤者是張志新(化名)和其女友劉穎坡脐,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體房揭,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡备闲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了崩溪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浅役。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖伶唯,靈堂內(nèi)的尸體忽然破棺而出觉既,到底是詐尸還是另有隱情,我是刑警寧澤乳幸,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布瞪讼,位于F島的核電站,受9級(jí)特大地震影響粹断,放射性物質(zhì)發(fā)生泄漏符欠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一瓶埋、第九天 我趴在偏房一處隱蔽的房頂上張望希柿。 院中可真熱鬧,春花似錦养筒、人聲如沸曾撤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挤悉。三九已至,卻和暖如春巫湘,著一層夾襖步出監(jiān)牢的瞬間装悲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工尚氛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诀诊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓阅嘶,卻偏偏與公主長得像属瓣,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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