Redis入墳(二)高級(jí)特性灼舍,發(fā)布訂閱、事務(wù)涨薪、Lua腳本

目標(biāo)
1骑素、學(xué)習(xí) Redis 的一些高級(jí)特性,包括發(fā)布訂閱刚夺、事務(wù)砂豌、Lua 腳本

1、發(fā)布訂閱模式

1.1列表的局限

前面我們說(shuō)通過(guò)隊(duì)列的 rpush 和 lpop 可以實(shí)現(xiàn)消息隊(duì)列(隊(duì)尾進(jìn)隊(duì)頭出)光督,但是消費(fèi)者需要不停地調(diào)用 lpop 查看 List 中是否有等待處理的消息(比如寫一個(gè) while 循環(huán))。

為了減少通信的消耗塔粒,可以 sleep()一段時(shí)間再消費(fèi)结借,但是會(huì)有兩個(gè)問(wèn)題:

  1. 如果生產(chǎn)者生產(chǎn)消息的速度遠(yuǎn)大于消費(fèi)者消費(fèi)消息的速度,List 會(huì)占用大量的內(nèi)存卒茬。
  2. 消息的實(shí)時(shí)性降低
    list 還提供了一個(gè)阻塞的命令:blpop船老,沒(méi)有任何元素可以彈出的時(shí)候,連接會(huì)被阻塞圃酵。blpop queue 5柳畔,阻塞5秒。
    基于 list 實(shí)現(xiàn)的消息隊(duì)列郭赐,不支持一對(duì)多的消息分發(fā)薪韩。

1.2發(fā)布訂閱模式

除了通過(guò) list 實(shí)現(xiàn)消息隊(duì)列之外,Redis 還提供了一組命令實(shí)現(xiàn)發(fā)布/訂閱模式捌锭。

這種方式俘陷,發(fā)送者和接收者沒(méi)有直接關(guān)聯(lián)(實(shí)現(xiàn)了解耦),接收者也不需要持續(xù)嘗試獲取消息观谦。

1.2.1 訂閱頻道

可以訂閱一個(gè)或者多個(gè)頻道拉盾。消息的發(fā)布者(生產(chǎn)者)可以給指定的頻道發(fā)布消息。只要有消息到達(dá)了頻道豁状,所有訂閱了這個(gè)頻道的訂閱者都會(huì)收到這條消息捉偏。

需要注意的注意是倒得,發(fā)出去的消息不會(huì)被持久化,因?yàn)樗呀?jīng)從隊(duì)列里面移除了夭禽,所以消費(fèi)者只能收到它開始訂閱這個(gè)頻道之后發(fā)布的消息霞掺。

下面我們來(lái)看一下發(fā)布訂閱命令的使用方法。
訂閱者訂閱頻道:可以一次訂閱多個(gè)驻粟,比如這個(gè)客戶端訂閱了 3 個(gè)頻道根悼。

subscribe channel-1 channel-2 channel-3

發(fā)布者可以向指定頻道發(fā)布消息(并不支持一次向多個(gè)頻道發(fā)送消息):

publish channel-1 2673

取消訂閱(不能在訂閱狀態(tài)下使用):

unsubscribe channel-1

1.2.2 按規(guī)則(Pattern) 訂閱頻道

支持?和占位符。?代表一個(gè)字符蜀撑,代表 0 個(gè)或者多個(gè)字符挤巡。
消費(fèi)端 1,關(guān)注運(yùn)動(dòng)信息:

psubscribe *sport

消費(fèi)端 2酷麦,關(guān)注所有新聞:

psubscribe news*

消費(fèi)端 3矿卑,關(guān)注天氣新聞:

psubscribe news-weather

生產(chǎn)者,發(fā)布 3 條信息

publish news-sport yaoming
publish news-music jaychou
publish news-weather rain

java 代碼

package pubsub;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;

public class PublishSubscribe {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.0.224", 6379);
        jedis.subscribe(new Subscriber(),"channel");

    }
}
class Subscriber extends JedisPubSub{

    @Override
    public void onMessage(String channel, String message) {
        System.out.println("接收到的消息:"+message);
    }

    @Override
    public void onSubscribe(String channel, int subscribedChannels) {
        System.out.println("onSubscribe---channel:"+channel+",subscribedChannels:"+subscribedChannels);
    }

    @Override
    public void onPUnsubscribe(String pattern, int subscribedChannels) {
        System.out.println("onPUnsubscribe---pattern:"+pattern+",subscribedChannels:"+subscribedChannels);
    }

    @Override
    public void onPSubscribe(String pattern, int subscribedChannels) {
        System.out.println("onPSubscribe---pattern:"+pattern+",subscribedChannels:"+subscribedChannels);
    }

    @Override
    public void unsubscribe(String... channels) {
        super.unsubscribe(channels);
    }
}


package pubsub;

import redis.clients.jedis.Jedis;

public class PublishTest {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.0.224", 6379);
        jedis.publish("channel","你好呀");
        jedis.close();

    }
}

2 沃饶、Redis 事務(wù)

2.1 為什么要用事務(wù)

我們知道 Redis 的單個(gè)命令是原子性的(比如 get set mget mset)母廷,如果涉及到多個(gè)命令的時(shí)候,需要把多個(gè)命令作為一個(gè)不可分割的處理序列糊肤,就需要用到事務(wù)琴昆。

例如我們之前說(shuō)的用 setnx 實(shí)現(xiàn)分布式鎖,我們先 set馆揉,然后設(shè)置對(duì) key 設(shè)置 expire业舍,防止 del 發(fā)生異常的時(shí)候鎖不會(huì)被釋放,業(yè)務(wù)處理完了以后再 del升酣,這三個(gè)動(dòng)作我們就希望它們作為一組命令執(zhí)行舷暮。

Redis 的事務(wù)有兩個(gè)特點(diǎn):

  1. 按進(jìn)入隊(duì)列的順序執(zhí)行。
  2. 不會(huì)受到其他客戶端的請(qǐng)求的影響噩茄。
    Redis 的事務(wù)涉及到四個(gè)命令:multi(開啟事務(wù))下面,exec(執(zhí)行事務(wù)),discard(取消事務(wù))绩聘,watch(監(jiān)視)

2.2 事務(wù)的用法

案例場(chǎng)景:tom 和 mic 各有 1000 元沥割,tom 需要向 mic 轉(zhuǎn)賬 100 元。
tom 的賬戶余額減少 100 元君纫,mic 的賬戶余額增加 100 元驯遇。

127.0.0.1:6379> set tom 1000
OK
127.0.0.1:6379> set mic 1000
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby tom 100
QUEUED
127.0.0.1:6379> incrby mic 100
QUEUED
127.0.0.1:6379> exec
1) (integer) 900
2) (integer) 1100
127.0.0.1:6379> get tom
"900"
127.0.0.1:6379> get mic
"1100"

通過(guò) multi 的命令開啟事務(wù)。事務(wù)不能嵌套蓄髓,多個(gè) multi 命令效果一樣叉庐。
multi 執(zhí)行后,客戶端可以繼續(xù)向服務(wù)器發(fā)送任意多條命令会喝, 這些命令不會(huì)立即被執(zhí)行陡叠, 而是被放到一個(gè)隊(duì)列中玩郊, 當(dāng) exec 命令被調(diào)用時(shí), 所有隊(duì)列中的命令才會(huì)被執(zhí)行枉阵。

通過(guò) exec 的命令執(zhí)行事務(wù)译红。如果沒(méi)有執(zhí)行 exec,所有的命令都不會(huì)被執(zhí)行兴溜。如果中途不想執(zhí)行事務(wù)了侦厚,怎么辦?可以調(diào)用 discard 可以清空事務(wù)隊(duì)列拙徽,放棄執(zhí)行刨沦。

multi
set k1 1
set k2 2
set k3 3
discard

2.3 watch 命令

在 Redis 中還提供了一個(gè) watch 命令。
它可以為 Redis 事務(wù)提供 CAS 樂(lè)觀鎖行為(Check and Set / Compare and Swap)膘怕,也就是多個(gè)線程更新變量的時(shí)候想诅,會(huì)跟原值做比較,只有它沒(méi)有被其他線程修改的情況下岛心,才更新成新的值来破。

我們可以用 watch 監(jiān)視一個(gè)或者多個(gè) key,如果開啟事務(wù)之后忘古,至少有一個(gè)被監(jiān)視key 鍵在 exec 執(zhí)行之前被修改了徘禁, 那么整個(gè)事務(wù)都會(huì)被取消(key 提前過(guò)期除外)∷杩埃可以用 unwatch 取消晌坤。

2.4 事務(wù)可能遇到的問(wèn)題

我們把事務(wù)執(zhí)行遇到的問(wèn)題分成兩種,一種是在執(zhí)行 exec 之前發(fā)生錯(cuò)誤旦袋,一種是在執(zhí)行 exec 之后發(fā)生錯(cuò)誤。

2.4.1 在執(zhí)行 exec 之前發(fā)生錯(cuò)誤

比如:入隊(duì)的命令存在語(yǔ)法錯(cuò)誤它改,包括參數(shù)數(shù)量疤孕,參數(shù)名等等(編譯器錯(cuò)誤)。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set gupao 666
QUEUED
127.0.0.1:6379> hset qingshan 2673
(error) ERR wrong number of arguments for 'hset' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

在這種情況下事務(wù)會(huì)被拒絕執(zhí)行央拖,也就是隊(duì)列中所有的命令都不會(huì)得到執(zhí)行祭阀。

2.4.2 在執(zhí)行 exec 之后發(fā)生錯(cuò)誤

比如,類型錯(cuò)誤鲜戒,比如對(duì) String 使用了 Hash 的命令专控,這是一種運(yùn)行時(shí)錯(cuò)誤。

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> hset k1 a b
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get k1
"1"

最后我們發(fā)現(xiàn) set k1 1 的命令是成功的遏餐,也就是在這種發(fā)生了運(yùn)行時(shí)異常的情況下伦腐,只有錯(cuò)誤的命令沒(méi)有被執(zhí)行,但是其他命令沒(méi)有受到影響失都。

這個(gè)顯然不符合我們對(duì)原子性的定義柏蘑,也就是我們沒(méi)辦法用 Redis 的這種事務(wù)機(jī)制來(lái)實(shí)現(xiàn)原子性幸冻,保證數(shù)據(jù)的一致。

思考(作業(yè)):
為什么在一個(gè)事務(wù)中存在錯(cuò)誤咳焚,Redis 不回滾洽损?

3 Lua 腳本

Lua是一種輕量級(jí)腳本語(yǔ)言,它是用 C 語(yǔ)言編寫的革半,跟數(shù)據(jù)的存儲(chǔ)過(guò)程有點(diǎn)類似碑定。 使用 Lua 腳本來(lái)執(zhí)行 Redis 命令的好處:

  1. 一次發(fā)送多個(gè)命令,減少網(wǎng)絡(luò)開銷又官。
  2. Redis 會(huì)將整個(gè)腳本作為一個(gè)整體執(zhí)行延刘,不會(huì)被其他請(qǐng)求打斷,保持原子性赏胚。
  3. 對(duì)于復(fù)雜的組合命令访娶,我們可以放在文件中,可以實(shí)現(xiàn)程序之間的命令集復(fù)用觉阅。

3.1 在 Redis 中調(diào)用 Lua 腳本

使用 eval 方法崖疤,語(yǔ)法格式:

redis> eval lua-script key-num [key1 key2 key3 ....] [value1 value2 value3 ....]

? eval 代表執(zhí)行 Lua 語(yǔ)言的命令。
? lua-script 代表 Lua 語(yǔ)言腳本內(nèi)容典勇。
? key-num 表示參數(shù)中有多少個(gè) key劫哼, 需要注意的是 Redis 中 key 是從 1 開始的, 如果沒(méi)有 key 的參數(shù)割笙, 那么寫 0权烧。
? [key1 key2 key3…]是 key 作為參數(shù)傳遞給 Lua 語(yǔ)言, 也可以不填伤溉, 但是需要和 key-num 的個(gè)數(shù)對(duì)應(yīng)起來(lái)般码。
? [value1 value2 value3 ….]這些參數(shù)傳遞給 Lua 語(yǔ)言, 它們是可填可不填的乱顾。

示例板祝,返回一個(gè)字符串,0 個(gè)參數(shù):

redis> eval "return 'Hello World'" 0

3.2 在 Lua 腳本中調(diào)用 Redis 命令

使用 redis.call(command, key [param1, param2…])進(jìn)行操作走净。語(yǔ)法格式:

redis> eval "redis.call('set',KEYS[1],ARGV[1])" 1 lua-key lua-value

? command 是命令券时, 包括 set、 get伏伯、 del 等橘洞。
? key 是被操作的鍵。
? param1,param2…代表給 key 的參數(shù)说搅。

注意跟 Java 不一樣炸枣,定義只有形參,調(diào)用只有實(shí)參。
Lua 是在調(diào)用時(shí)用 key 表示形參抛虏,argv 表示參數(shù)值(實(shí)參)博其。

3.2.1 設(shè)置鍵值對(duì)

在 Redis 中調(diào)用 Lua 腳本執(zhí)行 Redis 命令
以上命令等價(jià)于 set gupao 2673
在 redis-cli 中直接寫 Lua 腳本不夠方便,也不能實(shí)現(xiàn)編輯和復(fù)用迂猴,通常我們會(huì)把腳本放在文件里面慕淡,然后執(zhí)行這個(gè)文件。

3.2.2 在 Redis 中調(diào)用 Lua 腳本文件中的命令沸毁, 操作 Redis

創(chuàng)建 Lua 腳本文件:

cd /usr/local/soft/redis5.0.5/src
vim gupao.lua

Lua 腳本內(nèi)容峰髓,先設(shè)置,再取值:

redis.call('set','gupao','lua666')
return redis.call('get','gupao')

在 Redis 客戶端中調(diào)用 Lua 腳本

cd /usr/local/soft/redis5.0.5/src
redis-cli --eval gupao.lua 0

得到返回值:

[root@localhost src]# redis-cli --eval gupao.lua 0
"lua666"

3.2.3 案例: 對(duì) IP 進(jìn)行限流

需求:某個(gè)IP息尺,在 X 秒內(nèi)只能訪問(wèn) Y 次携兵。
設(shè)計(jì)思路:用 key 記錄 IP,用 value 記錄訪問(wèn)次數(shù)搂誉。拿到 IP 以后徐紧,對(duì) IP+1。如果是第一次訪問(wèn)炭懊,對(duì) key 設(shè)置過(guò)期時(shí)間(參數(shù) 1)并级。否則判斷次數(shù),超過(guò)限定的次數(shù)(參數(shù) 2)侮腹,返回 0嘲碧。如果沒(méi)有超過(guò)次數(shù)則返回 1。超過(guò)時(shí)間父阻,key 過(guò)期之后愈涩,可以再次訪問(wèn)。KEY[1]是 IP加矛, ARGV[1]是過(guò)期時(shí)間 X履婉,ARGV[2]是限制訪問(wèn)的次數(shù) Y。

-- ip_limit.lua
-- IP 限流斟览, 對(duì)某個(gè) IP 頻率進(jìn)行限制 谐鼎, 6 秒鐘訪問(wèn) 10 次
local num=redis.call('incr',KEYS[1])
if tonumber(num)==1 then
  redis.call('expire',KEYS[1],ARGV[1])
  return 1
elseif tonumber(num)>tonumber(ARGV[2]) then
  return 0
else
  return 1
end

6 秒鐘內(nèi)限制訪問(wèn) 10 次,調(diào)用測(cè)試(連續(xù)調(diào)用 10 次):

./redis-cli --eval "ip_limit.lua" app:ip:limit:192.168.8.111 , 6 10

? app:ip:limit:192.168.8.111 是 key 值 趣惠,后面是參數(shù)值,中間要加上一個(gè)空格 和
一個(gè)逗號(hào)身害,再加上一個(gè) 空格 味悄。
即:./redis-cli –eval [lua 腳本] [key…]空格,空格[args…]
? 多個(gè)參數(shù)之間用一個(gè) 空格 分割

3.2.4 緩存 Lua 腳本

為什么要緩存
在腳本比較長(zhǎng)的情況下,如果每次調(diào)用腳本都需要把整個(gè)腳本傳給 Redis 服務(wù)端塌鸯,會(huì)產(chǎn)生比較大的網(wǎng)絡(luò)開銷侍瑟。為了解決這個(gè)問(wèn)題,Redis 提供了 EVALSHA 命令,允許開發(fā)者通過(guò)腳本內(nèi)容的 SHA1 摘要來(lái)執(zhí)行腳本涨颜。

如何緩存
Redis 在執(zhí)行 script load 命令時(shí)會(huì)計(jì)算腳本的 SHA1 摘要并記錄在腳本緩存中费韭,執(zhí)行 EVALSHA 命令時(shí) Redis 會(huì)根據(jù)提供的摘要從腳本緩存中查找對(duì)應(yīng)的腳本內(nèi)容,如果找到了則執(zhí)行腳本庭瑰,否則會(huì)返回錯(cuò)誤:"NOSCRIPT No matching script. Please use EVAL."

127.0.0.1:6379> script load "return 'Hello World'"
"470877a599ac74fbfda41caa908de682c5fc7d4b"
127.0.0.1:6379> evalsha "470877a599ac74fbfda41caa908de682c5fc7d4b" 0
"Hello World"

自乘案例
Redis 有 incrby 這樣的自增命令星持,但是沒(méi)有自乘,比如乘以 3弹灭,乘以 5督暂。
我們可以寫一個(gè)自乘的運(yùn)算,讓它乘以后面的參數(shù):

local curVal = redis.call("get", KEYS[1])
if curVal == false then
  curVal = 0
else
  curVal = tonumber(curVal)
end
curVal = curVal * tonumber(ARGV[1])
redis.call("set", KEYS[1], curVal)
return curVal

把這個(gè)腳本變成單行穷吮,語(yǔ)句之間使用分號(hào)隔開

local curVal = redis.call("get", KEYS[1]); if curVal == false then curVal = 0 else curVal = tonumber(curVal) end; curVal
= curVal * tonumber(ARGV[1]); redis.call("set", KEYS[1], curVal); return curVal

script load '命令'

127.0.0.1:6379> script load 'local curVal = redis.call("get", KEYS[1]); if curVal == false then curVal = 0 else curVal =
tonumber(curVal) end; curVal = curVal * tonumber(ARGV[1]); redis.call("set", KEYS[1], curVal); return curVal'

"be4f93d8a5379e5e5b768a74e77c8a4eb0434441"

調(diào)用:

127.0.0.1:6379> set num 2
OK
127.0.0.1:6379> evalsha be4f93d8a5379e5e5b768a74e77c8a4eb0434441 1 num 6
(integer) 12

3.2.5 腳本超時(shí)

Redis 的指令執(zhí)行本身是單線程的逻翁,這個(gè)線程還要執(zhí)行客戶端的 Lua 腳本,如果 Lua腳本執(zhí)行超時(shí)或者陷入了死循環(huán)捡鱼,是不是沒(méi)有辦法為客戶端提供服務(wù)了呢八回?

eval 'while(true) do end' 0

為 了防 止 某個(gè) 腳本 執(zhí) 行時(shí) 間 過(guò)長(zhǎng) 導(dǎo) 致 Redis 無(wú) 法提 供 服務(wù) , Redis 提 供 了lua-time-limit 參數(shù)限制腳本的最長(zhǎng)運(yùn)行時(shí)間驾诈,默認(rèn)為 5 秒鐘缠诅。
lua-time-limit 5000(redis.conf 配置文件中)

當(dāng)腳本運(yùn)行時(shí)間超過(guò)這一限制后,Redis 將開始接受其他命令但不會(huì)執(zhí)行(以確保腳本的原子性翘鸭,因?yàn)榇藭r(shí)腳本并沒(méi)有被終止)滴铅,而是會(huì)返回“BUSY”錯(cuò)誤。

Redis 提供了一個(gè) script kill 的命令來(lái)中止腳本的執(zhí)行就乓。新開一個(gè)客戶端:

script kill

如果當(dāng)前執(zhí)行的 Lua 腳本對(duì) Redis 的數(shù)據(jù)進(jìn)行了修改(SET汉匙、DEL 等),那么通過(guò)script kill 命令是不能終止腳本運(yùn)行的生蚁。

127.0.0.1:6379> eval "redis.call('set','gupao','666') while true do end" 0

因?yàn)橐WC腳本運(yùn)行的原子性噩翠,如果腳本執(zhí)行了一部分終止,那就違背了腳本原子性的要求邦投。最終要保證腳本要么都執(zhí)行伤锚,要么都不執(zhí)行。

127.0.0.1:6379> script kill
(error) UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.

遇到這種情況志衣,只能通過(guò) shutdown nosave 命令來(lái)強(qiáng)行終止 redis屯援。
shutdown nosave 和 shutdown 的區(qū)別在于 shutdown nosave 不會(huì)進(jìn)行持久化操作,意味著發(fā)生在上一次快照后的數(shù)據(jù)庫(kù)修改都會(huì)丟失念脯。

總結(jié):如果我們有一些特殊的需求狞洋,可以用 Lua 來(lái)實(shí)現(xiàn),但是要注意那些耗時(shí)的操作绿店。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吉懊,一起剝皮案震驚了整個(gè)濱河市庐橙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌借嗽,老刑警劉巖态鳖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異恶导,居然都是意外死亡浆竭,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門甲锡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)兆蕉,“玉大人,你說(shuō)我怎么就攤上這事缤沦』⒃希” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵缸废,是天一觀的道長(zhǎng)包蓝。 經(jīng)常有香客問(wèn)我,道長(zhǎng)企量,這世上最難降的妖魔是什么测萎? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮届巩,結(jié)果婚禮上硅瞧,老公的妹妹穿的比我還像新娘。我一直安慰自己恕汇,他們只是感情好腕唧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瘾英,像睡著了一般枣接。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缺谴,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天但惶,我揣著相機(jī)與錄音,去河邊找鬼湿蛔。 笑死膀曾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的阳啥。 我是一名探鬼主播添谊,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼苫纤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤卷拘,失蹤者是張志新(化名)和其女友劉穎喊废,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栗弟,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡污筷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乍赫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓣蛀。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖雷厂,靈堂內(nèi)的尸體忽然破棺而出惋增,到底是詐尸還是另有隱情,我是刑警寧澤改鲫,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布诈皿,位于F島的核電站,受9級(jí)特大地震影響像棘,放射性物質(zhì)發(fā)生泄漏稽亏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一缕题、第九天 我趴在偏房一處隱蔽的房頂上張望截歉。 院中可真熱鬧,春花似錦烟零、人聲如沸瘪松。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)凉逛。三九已至,卻和暖如春群井,著一層夾襖步出監(jiān)牢的瞬間状飞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工书斜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诬辈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓荐吉,卻偏偏與公主長(zhǎng)得像焙糟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子样屠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354