Redis數(shù)據(jù)類型簡介(十分鐘快速學(xué)習(xí)Redis)

  1. 如何在ubuntu18.04上安裝和保護(hù)redis
  2. 如何連接到Redis數(shù)據(jù)庫
  3. 如何管理Redis數(shù)據(jù)庫和Keys
  4. 如何在Redis中管理副本和客戶端
  5. 如何在Redis中管理字符串
  6. 如何在Redis中管理list
  7. 如何在Redis中管理Hashes
  8. 如何在Redis中管理Sets
  9. 如何在Redis中管理Sorted Sets
  10. 如何在Redis中運(yùn)行事務(wù)
  11. 如何使Redis中的Key失效
  12. 如何解決Redis中的問題
  13. 如何從命令行更改Redis的配置
  14. Redis數(shù)據(jù)類型簡介

Redis數(shù)據(jù)類型簡介

Redis不是簡單的鍵值存儲(chǔ)肋僧,它實(shí)際上是一個(gè)數(shù)據(jù)結(jié)構(gòu)服務(wù)器浑玛,支持不同類型的值读规。這意味著在傳統(tǒng)鍵值存儲(chǔ)中铃拇,您將字符串鍵與字符串值相關(guān)聯(lián)忠售,而在Redis中悔橄,該值不僅限于簡單的字符串缤底,還可以容納更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)扁耐。以下是Redis支持的所有數(shù)據(jù)結(jié)構(gòu)的列表潦蝇,本教程將分別進(jìn)行介紹:

  • 二進(jìn)制安全字符串款熬。
  • 列表:根據(jù)插入順序排序的字符串元素的集合。它們基本上是鏈表攘乒。
  • 集:唯一贤牛,未排序的字符串元素的集合。
  • 類似于Sets的排序集合则酝,但每個(gè)字符串元素都與一個(gè)稱為score的浮點(diǎn)值相關(guān)聯(lián)殉簸。元素總是按它們的分?jǐn)?shù)排序闰集,因此與Sets不同,可以檢索一系列元素(例如般卑,您可能會(huì)問:給我前10名或后10名)武鲁。
  • 哈希,是由與值關(guān)聯(lián)的字段組成的映射蝠检。字段和值都是字符串沐鼠。這與Ruby或Python哈希非常相似。
  • 位數(shù)組(或簡稱為位圖):可以使用特殊命令像位數(shù)組一樣處理字符串值:您可以設(shè)置和清除單個(gè)位叹谁,計(jì)數(shù)所有設(shè)置為1的位饲梭,找到第一個(gè)設(shè)置或未設(shè)置的位,等等焰檩。
  • HyperLogLogs:這是一個(gè)概率數(shù)據(jù)結(jié)構(gòu)憔涉,用于估計(jì)集合的基數(shù)。別害怕析苫,它比看起來更簡單...請(qǐng)參閱本教程的HyperLogLog部分兜叨。
  • 流:提供抽象日志數(shù)據(jù)類型的類地圖項(xiàng)的僅追加集合。在“ Redis流簡介”中對(duì)它們進(jìn)行了深入 介紹藤违。

命令參考中掌握這些數(shù)據(jù)類型的工作方式以及使用什么來解決給定問題并不總是那么容易浪腐,因此,本文檔是有關(guān)Redis數(shù)據(jù)類型及其最常見模式的速成課程顿乒。

對(duì)于所有示例议街,我們將使用該redis-cli實(shí)用程序(一個(gè)簡單但方便的命令行實(shí)用程序)對(duì)Redis服務(wù)器發(fā)出命令。

*Redis keys

Redis密鑰是二進(jìn)制安全的璧榄,這意味著您可以使用任何二進(jìn)制序列作為密鑰特漩,從“ foo”之類的字符串到JPEG文件的內(nèi)容」窃樱空字符串也是有效的鍵涂身。

有關(guān)密鑰的其他一些規(guī)則:

  • 太長的鍵不是一個(gè)好主意。例如搓蚪,1024字節(jié)的密鑰不僅是內(nèi)存方面的問題蛤售,也是一個(gè)壞主意,而且因?yàn)樵跀?shù)據(jù)集中查找密鑰可能需要進(jìn)行一些代價(jià)高昂的密鑰比較妒潭。即使手頭的任務(wù)是匹配一個(gè)大值的存在悴能,對(duì)它進(jìn)行散列(例如使用SHA1)也是一個(gè)更好的主意,尤其是從內(nèi)存和帶寬的角度來看雳灾。
  • 非常短的鍵通常不是一個(gè)好主意漠酿。如果您可以改寫“ user:1000:followers”,那么將“ u1000flw”寫為密鑰毫無意義谎亩。與鍵對(duì)象本身和值對(duì)象使用的空間相比炒嘲,后者更具可讀性宇姚,并且添加的空間較小。雖然短鍵顯然會(huì)消耗更少的內(nèi)存夫凸,但您的工作是找到合適的平衡浑劳。
  • 嘗試堅(jiān)持使用架構(gòu)。例如寸痢,“ object-type:id”是一個(gè)好主意呀洲,例如“ user:1000”。點(diǎn)或破折號(hào)通常用于多字字段啼止,例如“ comment:1234:reply.to”或“ comment:1234:reply-to”中道逗。
  • 允許的最大密鑰大小為512 MB。

*Redis Strings

Redis字符串類型是您可以與Redis鍵關(guān)聯(lián)的最簡單的值類型献烦。它是Memcached中唯一的數(shù)據(jù)類型滓窍,因此對(duì)于新手來說,在Redis中使用它也是很自然的巩那。

由于Redis鍵是字符串吏夯,因此當(dāng)我們也使用字符串類型作為值時(shí),我們會(huì)將一個(gè)字符串映射到另一個(gè)字符串即横。字符串?dāng)?shù)據(jù)類型對(duì)于許多用例很有用噪生,例如緩存HTML片段或頁面。

讓我們使用來處理字符串類型redis-cli(所有示例將redis-cli在本教程中通過來執(zhí)行)东囚。

> set mykey somevalue
OK
> get mykey
"somevalue"

如您所見跺嗽,使用SETGET命令是我們?cè)O(shè)置和檢索字符串值的方式。請(qǐng)注意页藻,即使鍵已與非字符串值相關(guān)聯(lián)桨嫁,SET仍將替換已存儲(chǔ)在鍵中的任何現(xiàn)有值。因此SET執(zhí)行分配份帐。

值可以是每種類型的字符串(包括二進(jìn)制數(shù)據(jù))璃吧,例如,您可以在值內(nèi)存儲(chǔ)jpeg圖像废境。值不能大于512 MB畜挨。

SET命令有有趣的選項(xiàng),這是作為附加參數(shù)噩凹。例如朦促,如果密鑰已經(jīng)存在,我可能會(huì)要求SET失敗栓始,或者相反,只有密鑰已經(jīng)存在時(shí)血当,它才會(huì)成功:

> set mykey newval nx
(nil)
> set mykey newval xx
OK

即使字符串是Redis的基本值幻赚,您也可以使用它們執(zhí)行一些有趣的操作禀忆。例如,一個(gè)是原子增量:

> set counter 100
OK
> incr counter
(integer) 101
> incr counter
(integer) 102
> incrby counter 50
(integer) 152

INCR命令由一個(gè)解析字符串值作為一個(gè)整數(shù)落恼,它的增量箩退,并最終將獲得的值作為新的值。還有其他類似的命令佳谦,例如INCRBY戴涝, DECRDECRBY。在內(nèi)部钻蔑,它始終是相同的命令啥刻,其執(zhí)行方式略有不同。

INCR是原子的意味著什么咪笑?即使使用相同密鑰發(fā)出INCR的多個(gè)客戶也永遠(yuǎn)不會(huì)進(jìn)入競爭狀態(tài)可帽。例如,客戶端1不會(huì)同時(shí)讀取“ 10”窗怒,客戶端2會(huì)同時(shí)讀取“ 10”映跟,都遞增為11,并將新值設(shè)置為11扬虚。最終值將始終為12努隙,而在所有其他客戶端未同時(shí)執(zhí)行命令時(shí)執(zhí)行增量設(shè)置操作。

有許多用于操作字符串的命令辜昵。例如荸镊,GETSET命令將鍵設(shè)置為新值,并返回舊值作為結(jié)果路鹰。例如贷洲,如果您的系統(tǒng)在 每次網(wǎng)站接收新訪客時(shí)使用INCR遞增Redis密鑰,則可以使用此命令晋柱。您可能希望每小時(shí)收集一次此信息优构,而又不會(huì)丟失任何增量。您可以GETSET鍵雁竞,為其分配新值“ 0”钦椭,然后回讀舊值。

在單個(gè)命令中設(shè)置或檢索多個(gè)鍵的值的功能對(duì)于減少延遲也很有用碑诉。因此彪腔,有MSETMGET命令:

> mset a 10 b 20 c 30
OK
> mget a b c
1) "10"
2) "20"
3) "30"

使用MGET時(shí),Redis返回一個(gè)值數(shù)組进栽。

*Altering and querying the key space

有些命令未在特定類型上定義德挣,但是在與鍵的空間進(jìn)行交互時(shí)很有用,因此可以與任何類型的鍵一起使用快毛。

例如格嗅,EXISTS命令返回1或0表示數(shù)據(jù)庫中是否存在給定的鍵番挺,而DEL命令則刪除鍵和關(guān)聯(lián)的值(無論該值是什么)。

> set mykey hello
OK
> exists mykey
(integer) 1
> del mykey
(integer) 1
> exists mykey
(integer) 0

從示例中屯掖,您還可以看到DEL本身如何返回1或0玄柏,具體取決于密鑰是否已刪除(存在)(不存在具有該名稱的此類密鑰)。

有許多與密鑰空間相關(guān)的命令贴铜,但是以上兩個(gè)命令與TYPE命令一起是必不可少的粪摘,TYPE命令返回存儲(chǔ)在指定密鑰處的值的類型:

> set mykey x
OK
> type mykey
string
> del mykey
(integer) 1
> type mykey
none

*Redis expires: keys with limited time to live

在繼續(xù)使用更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)之前,我們需要討論另一個(gè)功能绍坝,該功能不管值類型如何都可以工作徘意,并且稱為Redis expires∠葑欤基本上映砖,您可以為密鑰設(shè)置一個(gè)超時(shí)時(shí)間,這是有限的生存時(shí)間灾挨。生存時(shí)間過去后邑退,該密鑰將自動(dòng)銷毀,就像用戶使用該密鑰調(diào)用DEL命令一樣劳澄。

有關(guān)Redis的一些快速信息將過期:

  • 可以使用秒或毫秒精度進(jìn)行設(shè)置地技。
  • 但是,到期時(shí)間分辨率始終為1毫秒秒拔。
  • 有關(guān)過期的信息被復(fù)制并保留在磁盤上莫矗,實(shí)際上Redis服務(wù)器保持停止?fàn)顟B(tài)的時(shí)間已經(jīng)過去(這意味著Redis保存了密鑰過期的日期)。

設(shè)置過期時(shí)間很簡單:

> set key some-value
OK
> expire key 5
(integer) 1
> get key (immediately)
"some-value"
> get key (after some time)
(nil)

由于第二次呼叫延遲了5秒鐘以上砂缩,因此在兩次GET呼叫之間密鑰消失了作谚。在上面的示例中,我們使用EXPIRE來設(shè)置過期時(shí)間(也可以使用它來為已經(jīng)具有密鑰的密鑰設(shè)置不同的過期時(shí)間庵芭,例如可以使用PERSIST來刪除過期并使密鑰永久持久化)妹懒。但是,我們也可以使用其他Redis命令來創(chuàng)建具有過期密鑰双吆。例如眨唬,使用SET選項(xiàng):

> set key 100 ex 10
OK
> ttl key
(integer) 9

上面的示例使用一個(gè)字符串值設(shè)置一個(gè)密鑰,該密鑰100的到期時(shí)間為十秒鐘好乐。稍后調(diào)用TTL命令以檢查密鑰的剩余生存時(shí)間匾竿。

為了設(shè)置和檢查以毫秒為單位到期,檢查PEXPIRE熱釋光的命令蔚万,以及完整列表SET選項(xiàng)岭妖。

*Redis Lists

為了解釋List數(shù)據(jù)類型,最好從理論上入手,因?yàn)?em>List一詞經(jīng)常被信息技術(shù)人員以不正當(dāng)?shù)姆绞绞褂藐腔拧@缣蓿?Python列表”并不是名稱(鏈接列表)所建議的,而是數(shù)組(在Ruby中废离,相同的數(shù)據(jù)類型實(shí)際上稱為數(shù)組)。

從非常普遍的角度來看礁芦,列表只是一系列有序元素:10,20,1,2,3是一個(gè)列表蜻韭。但是,使用Array實(shí)現(xiàn)的List的屬性與使用Linked List實(shí)現(xiàn)的List的屬性非常不同 柿扣。

Redis列表是通過鏈接列表實(shí)現(xiàn)的肖方。這意味著即使您在列表中有數(shù)百萬個(gè)元素,在列表的開頭或結(jié)尾添加新元素的操作也會(huì)在固定時(shí)間內(nèi)執(zhí)行未状。使用LPUSH命令將新元素添加到具有10個(gè)元素的列表的開頭的速度與將元素添加到具有1000萬個(gè)元素的列表的開頭的速度相同俯画。

缺點(diǎn)是什么?在使用Array實(shí)現(xiàn)的列表中司草,按索引訪問元素速度非臣璐梗快(恒定時(shí)間索引訪問),而在通過鏈接列表實(shí)現(xiàn)的列表中訪問速度不是那么快(其中操作需要的工作量與所訪問元素的索引成比例)埋虹。

Redis列表是通過鏈接列表實(shí)現(xiàn)的猜憎,因?yàn)閷?duì)于數(shù)據(jù)庫系統(tǒng)而言,至關(guān)重要的是能夠以非成危快的方式將元素添加到很長的列表中胰柑。稍后您將看到,另一個(gè)強(qiáng)大的優(yōu)勢是Redis列表可以在恒定的時(shí)間內(nèi)以恒定的長度獲取爬泥。

當(dāng)快速訪問大量元素的中間位置很重要時(shí)柬讨,可以使用另一種稱為排序集的數(shù)據(jù)結(jié)構(gòu)。排序的集將在本教程的后面部分介紹袍啡。

*First steps with Redis Lists

所述LPUSH命令將一個(gè)新元素到一個(gè)列表踩官,在左側(cè)(在頭部),而RPUSH命令將一個(gè)新元素到一個(gè)列表葬馋,在右側(cè)(在尾部)卖鲤。最后, LRANGE命令從列表中提取元素范圍:

> rpush mylist A
(integer) 1
> rpush mylist B
(integer) 2
> lpush mylist first
(integer) 3
> lrange mylist 0 -1
1) "first"
2) "A"
3) "B"

請(qǐng)注意畴嘶,LRANGE需要兩個(gè)索引蛋逾,要返回的范圍的第一個(gè)和最后一個(gè)元素。兩個(gè)索引都可以為負(fù)窗悯,告訴Redis從末尾開始計(jì)數(shù):因此-1是列表的最后一個(gè)元素区匣,-2是列表的倒數(shù)第二個(gè)元素,依此類推。

如您所見亏钩,RPUSH在列表的右側(cè)附加了元素莲绰,而最后的LPUSH在列表的左側(cè)附加了元素。

這兩個(gè)命令都是可變參數(shù)命令姑丑,這意味著您可以在單個(gè)調(diào)用中隨意將多個(gè)元素推入列表中:

> rpush mylist 1 2 3 4 5 "foo bar"
(integer) 9
> lrange mylist 0 -1
1) "first"
2) "A"
3) "B"
4) "1"
5) "2"
6) "3"
7) "4"
8) "5"
9) "foo bar"

在Redis列表上定義的一項(xiàng)重要操作是彈出元素的能力蛤签。彈出元素是同時(shí)從列表中檢索元素并將其從列表中刪除的操作。您可以從左側(cè)和右側(cè)彈出元素栅哀,類似于在列表兩邊推送元素的方式:

> rpush mylist a b c
(integer) 3
> rpop mylist
"c"
> rpop mylist
"b"
> rpop mylist
"a"

我們添加了三個(gè)元素并彈出了三個(gè)元素震肮,因此在此命令序列的末尾,列表為空留拾,沒有其他要彈出的元素戳晌。如果我們嘗試彈出另一個(gè)元素,則會(huì)得到以下結(jié)果:

> rpop mylist
(nil)

Redis返回NULL值痴柔,以指示列表中沒有元素沦偎。

*Common use cases for lists

列表對(duì)于許多任務(wù)很有用,以下是兩個(gè)非常有代表性的用例:

  • 記住用戶發(fā)布到社交網(wǎng)絡(luò)上的最新更新咳蔚。
  • 使用生產(chǎn)者將項(xiàng)目推送到列表中的消費(fèi)者與生產(chǎn)者模式進(jìn)行流程之間的通信豪嚎,而消費(fèi)者(通常是worker)消耗這些項(xiàng)目和已執(zhí)行的動(dòng)作。Redis具有特殊的列表命令屹篓,以使此用例更加可靠和高效疙渣。

例如,流行的Ruby庫resquesidekiq都在后臺(tái)使用Redis列表堆巧,以實(shí)現(xiàn)后臺(tái)作業(yè)妄荔。

流行的Twitter社交網(wǎng)絡(luò) 用戶發(fā)布的最新推文放入Redis列表中。

為了逐步描述一個(gè)常見的用例谍肤,假設(shè)您的主頁顯示了在照片共享社交網(wǎng)絡(luò)中發(fā)布的最新照片你稚,并且您想加快訪問速度凄硼。

  • 每次用戶發(fā)布新照片時(shí)析恋,我們都會(huì)使用LPUSH將其ID添加到列表中画机。
  • 當(dāng)用戶訪問主頁時(shí),我們LRANGE 0 9為了獲取最新發(fā)布的10個(gè)項(xiàng)目系任。

*Capped lists

在許多用例中恳蹲,我們只想使用列表來存儲(chǔ)最新項(xiàng)目,無論它們是什么:社交網(wǎng)絡(luò)更新俩滥,日志或其他任何內(nèi)容嘉蕾。

Redis允許我們使用列表作為上限集合,僅使用LTRIM命令記住最新的N個(gè)項(xiàng)目并丟棄所有最舊的項(xiàng)目霜旧。

LTRIM命令類似于LRANGE错忱,但是,而不是顯示元件的規(guī)定的范圍內(nèi)將其設(shè)置在該范圍作為新的列表值。給定范圍之外的所有元素都將被刪除以清。

一個(gè)例子將使其更加清楚:

> rpush mylist 1 2 3 4 5
(integer) 5
> ltrim mylist 0 2
OK
> lrange mylist 0 -1
1) "1"
2) "2"
3) "3"

上面的LTRIM命令告訴Redis僅從索引0到2列出列表元素儿普,其他所有內(nèi)容都將被丟棄。這允許一個(gè)非常簡單但有用的模式:一起執(zhí)行List推操作+ List修剪操作掷倔,以便添加新元素并丟棄超出限制的元素:

LPUSH mylist <some element>
LTRIM mylist 0 999

上面的組合添加了一個(gè)新元素眉孩,并且僅將1000個(gè)最新元素納入列表。使用LRANGE勒葱,您可以訪問最重要的項(xiàng)目勺像,而無需記住非常舊的數(shù)據(jù)。

注意:雖然LRANGE從技術(shù)上講是O(N)命令错森,但朝列表的開頭或結(jié)尾訪問較小范圍是恒定時(shí)間操作。

*Blocking operations on lists

列表具有一項(xiàng)特殊功能篮洁,使其適合于實(shí)現(xiàn)隊(duì)列涩维,并且通常用作進(jìn)程間通信系統(tǒng)的構(gòu)建塊:阻止操作。

想象一下袁波,您想通過一個(gè)流程將項(xiàng)目推入列表瓦阐,然后使用不同的流程來對(duì)這些項(xiàng)目進(jìn)行某種工作。這是通常的生產(chǎn)者/使用者設(shè)置篷牌,可以通過以下簡單方式實(shí)現(xiàn):

  • 為了將項(xiàng)目推送到列表中睡蟋,生產(chǎn)者調(diào)用LPUSH
  • 為了從列表中提取/處理項(xiàng)目枷颊,消費(fèi)者調(diào)用RPOP戳杀。

但是,有時(shí)列表可能為空夭苗,沒有任何要處理的內(nèi)容信卡,因此RPOP僅返回NULL。在這種情況下题造,消費(fèi)者被迫等待一段時(shí)間傍菇,然后使用RPOP重試。這稱為輪詢界赔,在這種情況下不是一個(gè)好主意丢习,因?yàn)樗袔讉€(gè)缺點(diǎn):

  1. 強(qiáng)制Redis和客戶端處理無用的命令(列表為空時(shí)的所有請(qǐng)求將無法完成任何實(shí)際工作,它們只會(huì)返回NULL)淮悼。
  2. 由于工作人員在收到NULL之后會(huì)等待一段時(shí)間咐低,因此會(huì)增加項(xiàng)目處理的延遲。為了使延遲更小渊鞋,我們可以在兩次調(diào)用RPOP之間等待的時(shí)間更少,從而擴(kuò)大了問題編號(hào)1,即對(duì)Redis的調(diào)用更加無用锡宋。

所以儡湾,所謂的Redis命令工具BRPOPBLPOP它們的版本RPOPLPOP能夠阻止如果列表是空的:他們將回到只有當(dāng)新的元素添加到列表中的來電者,或在用戶指定的超時(shí)到達(dá)执俩。

這是我們可以在worker中使用的BRPOP調(diào)用的示例:

> brpop tasks 5
1) "tasks"
2) "do_something"

這意味著:“等待列表中的元素tasks徐钠,但如果5秒鐘后沒有可用元素,則返回”役首。

請(qǐng)注意尝丐,您可以將0用作超時(shí)來永遠(yuǎn)等待元素,還可以指定多個(gè)列表衡奥,而不僅僅是一個(gè)列表爹袁,以便同時(shí)等待多個(gè)列表,并在第一個(gè)列表收到一個(gè)元素時(shí)得到通知矮固。

有關(guān)BRPOP的幾點(diǎn)注意事項(xiàng)

  1. 客戶端以有序方式提供服務(wù):第一個(gè)阻塞等待列表的客戶端失息,在某個(gè)元素被其他客戶端推送時(shí)首先提供服務(wù),依此類推档址。
  2. 返回值與RPOP相比有所不同:它是一個(gè)包含兩個(gè)元素的數(shù)組盹兢,因?yàn)樗€包含鍵的名稱,因?yàn)?a href="/commands/brpop" target="_blank">BRPOP和BLPOP能夠阻止等待來自多個(gè)列表的元素守伸。
  3. 如果達(dá)到超時(shí)绎秒,則返回NULL。

關(guān)于列表和阻止操作尼摹,您應(yīng)該了解更多信息见芹。我們建議您閱讀以下內(nèi)容:

  • 使用RPOPLPUSH可以構(gòu)建更安全的隊(duì)列或輪換隊(duì)列。
  • 該命令還有一個(gè)阻塞變體蠢涝,稱為BRPOPLPUSH辆童。

*Automatic creation and removal of keys

到目前為止,在我們的示例中惠赫,我們無需在推入元素之前創(chuàng)建空列表把鉴,也無需在內(nèi)部不再包含元素時(shí)刪除空列表。Redis的責(zé)任是在列表為空時(shí)刪除鍵儿咱,或者在鍵不存在并且我們?cè)噲D向其添加元素(例如庭砍,使用LPUSH)時(shí)創(chuàng)建一個(gè)空列表。

這不是特定于列表的混埠,它適用于由多個(gè)元素組成的所有Redis數(shù)據(jù)類型-流怠缸,集合,排序集合和哈希钳宪。

基本上揭北,我們可以用三個(gè)規(guī)則來總結(jié)行為:

  1. 當(dāng)我們將元素添加到聚合數(shù)據(jù)類型時(shí)扳炬,如果目標(biāo)鍵不存在,則在添加元素之前會(huì)創(chuàng)建一個(gè)空的聚合數(shù)據(jù)類型搔体。
  2. 當(dāng)我們從聚合數(shù)據(jù)類型中刪除元素時(shí)恨樟,如果該值保持為空,則鍵將自動(dòng)銷毀疚俱。流數(shù)據(jù)類型是此規(guī)則的唯一例外劝术。
  3. 調(diào)用帶有空鍵的只讀命令(例如LLEN(返回列表的長度))或?qū)懨顒h除元素,總會(huì)產(chǎn)生與鍵保持空的聚合類型相同的結(jié)果呆奕。命令希望找到养晋。

規(guī)則1的示例:

> del mylist
(integer) 1
> lpush mylist 1 2 3
(integer) 3

但是,如果密鑰存在梁钾,我們將無法對(duì)錯(cuò)誤的類型執(zhí)行操作:

> set foo bar
OK
> lpush foo 1 2 3
(error) WRONGTYPE Operation against a key holding the wrong kind of value
> type foo
string

規(guī)則2的示例:

> lpush mylist 1 2 3
(integer) 3
> exists mylist
(integer) 1
> lpop mylist
"3"
> lpop mylist
"2"
> lpop mylist
"1"
> exists mylist
(integer) 0

彈出所有元素后绳泉,鍵不再存在。

規(guī)則3的示例:

> del mylist
(integer) 0
> llen mylist
(integer) 0
> lpop mylist
(nil)

*Redis Hashes

Redis散列與字段值對(duì)看起來完全一樣姆泻,可能是人們期望的“散列”外觀:

> hmset user:1000 username antirez birthyear 1977 verified 1
OK
> hget user:1000 username
"antirez"
> hget user:1000 birthyear
"1977"
> hgetall user:1000
1) "username"
2) "antirez"
3) "birthyear"
4) "1977"
5) "verified"
6) "1"

盡管哈先Ψ模可以方便地表示對(duì)象,但是實(shí)際上可以放入哈希中的字段數(shù)沒有實(shí)際限制(可用內(nèi)存除外)麦射,因此您可以在應(yīng)用程序內(nèi)部以多種不同方式使用哈希。

HMSET命令設(shè)置哈希的多個(gè)字段灯谣,而HGET檢索單個(gè)字段潜秋。HMGET類似于HGET但返回值的數(shù)組:

> hmget user:1000 username birthyear no-such-field
1) "antirez"
2) "1977"
3) (nil)

有些命令也可以對(duì)單個(gè)字段執(zhí)行操作,例如HINCRBY

> hincrby user:1000 birthyear 10
(integer) 1987
> hincrby user:1000 birthyear 10
(integer) 1997

您可以在文檔中找到哈希命令完整列表胎许。

值得注意的是峻呛,小哈希(即,一些具有較小值的元素)以特殊方式在內(nèi)存中進(jìn)行編碼辜窑,從而使它們具有很高的內(nèi)存效率钩述。

*Redis Sets

Redis集是字符串的無序集合。該 SADD命令添加新的元素穆碎,一組牙勘。還可以對(duì)集合進(jìn)行許多其他操作,例如測試給定元素是否已存在所禀,執(zhí)行多個(gè)集合之間的交集方面,并集或求差等等。

> sadd myset 1 2 3
(integer) 3
> smembers myset
1. 3
2. 1
3. 2

在這里色徘,我在集合中添加了三個(gè)元素恭金,并告訴Redis返回所有元素。如您所見褂策,它們沒有排序-Redis可以在每次調(diào)用時(shí)隨意以任何順序返回元素横腿,因?yàn)榕c用戶之間沒有關(guān)于元素順序的約定颓屑。

Redis具有用于測試成員資格的命令。例如耿焊,檢查元素是否存在:

> sismember myset 3
(integer) 1
> sismember myset 30
(integer) 0

“ 3”是集合的成員揪惦,而“ 30”不是集合的成員。

集合非常適合表示對(duì)象之間的關(guān)系搀别。例如丹擎,我們可以輕松地使用集合來實(shí)現(xiàn)標(biāo)簽。

對(duì)這個(gè)問題進(jìn)行建模的一種簡單方法是為我們要標(biāo)記的每個(gè)對(duì)象設(shè)置一個(gè)集合歇父。該集合包含與對(duì)象關(guān)聯(lián)的標(biāo)簽的ID蒂培。

一個(gè)例證是標(biāo)記新聞文章。如果商品ID 1000帶有標(biāo)簽1榜苫、2护戳、5和77進(jìn)行標(biāo)記,則集合可以將這些標(biāo)簽ID與新聞項(xiàng)相關(guān)聯(lián):

> sadd news:1000:tags 1 2 5 77
(integer) 4

我們可能還需要逆關(guān)系:用給定標(biāo)簽標(biāo)記的所有新聞的列表:

> sadd tag:1:news 1000
(integer) 1
> sadd tag:2:news 1000
(integer) 1
> sadd tag:5:news 1000
(integer) 1
> sadd tag:77:news 1000
(integer) 1

要獲取給定對(duì)象的所有標(biāo)簽很簡單:

> smembers news:1000:tags
1. 5
2. 1
3. 77
4. 2

注意:在示例中垂睬,我們假設(shè)您具有另一個(gè)數(shù)據(jù)結(jié)構(gòu)媳荒,例如Redis哈希,它將標(biāo)簽ID映射到標(biāo)簽名稱驹饺。

還有其他一些非常簡單的操作钳枕,使用正確的Redis命令仍然很容易實(shí)現(xiàn)。例如赏壹,我們可能需要包含標(biāo)簽1鱼炒、2、10和27的所有對(duì)象的列表蝌借。我們可以使用SINTER命令執(zhí)行此操作昔瞧,該命令執(zhí)行不同集合之間的交集。我們可以用:

> sinter tag:1:news tag:2:news tag:10:news tag:27:news
... results here ...

除了交集之外菩佑,您還可以執(zhí)行并集自晰,求差,提取隨機(jī)元素等等稍坯。

提取元素的命令稱為SPOP酬荞,對(duì)于建模某些問題非常方便。例如瞧哟,為了實(shí)現(xiàn)基于Web的撲克游戲袜蚕,您可能需要用一組來代表您的套牌。假設(shè)我們對(duì)(C)lubs绢涡,(D)鉆石牲剃,(H)耳釘,(S)墊使用一個(gè)單字符前綴:

>  sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK
   D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3
   H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6
   S7 S8 S9 S10 SJ SQ SK
   (integer) 52

現(xiàn)在我們要為每個(gè)玩家提供5張卡片雄可。該SPOP命令刪除一個(gè)隨機(jī)元素凿傅,將其返回到客戶端缠犀,所以在這種情況下完美運(yùn)行。

但是聪舒,如果我們直接在甲板上對(duì)其進(jìn)行稱呼辨液,那么在游戲的下一場比賽中,我們將需要再次填充紙牌箱残,這可能并不理想滔迈。因此,首先被辑,我們可以將存儲(chǔ)在deck密鑰中的集合復(fù)制到game:1:deck密鑰中燎悍。

這可以使用SUNIONSTORE來完成,SUNIONSTORE通常執(zhí)行多個(gè)集合之間的聯(lián)合盼理,并將結(jié)果存儲(chǔ)到另一個(gè)集合中谈山。但是,由于單個(gè)集合的并集本身宏怔,我可以使用以下命令復(fù)制我的卡組:

> sunionstore game:1:deck deck
(integer) 52

現(xiàn)在奏路,我準(zhǔn)備為第一位玩家提供五張牌:

> spop game:1:deck
"C6"
> spop game:1:deck
"CQ"
> spop game:1:deck
"D1"
> spop game:1:deck
"CJ"
> spop game:1:deck
"SJ"

一副千斤頂,不是很好...

現(xiàn)在是引入set命令的好時(shí)機(jī)臊诊,該命令提供集合中元素的數(shù)量鸽粉。 在集合理論的上下文中,這通常稱為集合基數(shù)抓艳,因此Redis命令稱為SCARD触机。

> scard game:1:deck
(integer) 47

數(shù)學(xué)原理:52-5 = 47。

當(dāng)您只需要獲取隨機(jī)元素而不將其從集合中刪除時(shí)壶硅,可以使用適合該任務(wù)的SRANDMEMBER命令。它還具有返回重復(fù)元素和非重復(fù)元素的功能销斟。

*Redis Sorted sets

排序集是一種數(shù)據(jù)類型庐椒,類似于集合和哈希之間的混合。像集合一樣蚂踊,排序集合由唯一的约谈,非重復(fù)的字符串元素組成,因此從某種意義上說犁钟,排序集合也是一個(gè)集合棱诱。

但是,雖然集內(nèi)的元素沒有排序涝动,但排序后的集合中的每個(gè)元素都與一個(gè)稱為得分的浮點(diǎn)值相關(guān)聯(lián) (這就是為什么該類型也類似于哈希的原因迈勋,因?yàn)槊總€(gè)元素都映射到一個(gè)值)。

此外醋粟,已排序集合中的元素是按順序進(jìn)行的(因此靡菇,它們不是應(yīng)請(qǐng)求而排序的重归,順序是用于表示已排序集合的數(shù)據(jù)結(jié)構(gòu)的特殊性)。它們按照以下規(guī)則排序:

  • 如果A和B是兩個(gè)分?jǐn)?shù)不同的元素厦凤,則如果A.score是> B.score鼻吮,則A>B。
  • 如果A和B的分?jǐn)?shù)完全相同较鼓,那么如果A字符串在字典上大于B字符串椎木,則A>B。A和B字符串不能相等博烂,因?yàn)榕判蚣瘍H具有唯一元素香椎。

讓我們從一個(gè)簡單的示例開始,添加一些選定的黑客名稱作為排序的集合元素脖母,并以其出生年份為“得分”士鸥。

> zadd hackers 1940 "Alan Kay"
(integer) 1
> zadd hackers 1957 "Sophie Wilson"
(integer) 1
> zadd hackers 1953 "Richard Stallman"
(integer) 1
> zadd hackers 1949 "Anita Borg"
(integer) 1
> zadd hackers 1965 "Yukihiro Matsumoto"
(integer) 1
> zadd hackers 1914 "Hedy Lamarr"
(integer) 1
> zadd hackers 1916 "Claude Shannon"
(integer) 1
> zadd hackers 1969 "Linus Torvalds"
(integer) 1
> zadd hackers 1912 "Alan Turing"
(integer) 1

如您所見,ZADDSADD相似谆级,但是使用一個(gè)額外的參數(shù)(放置在要添加的元素之前)作為得分烤礁。 ZADD也是可變參數(shù),因此即使上面的示例中未使用它肥照,您也可以自由指定多個(gè)得分-值對(duì)脚仔。

使用排序集,返回按其出生年份排序的黑客列表很簡單舆绎,因?yàn)閷?shí)際上他們已經(jīng)被排序了鲤脏。

實(shí)施說明:排序集是通過包含跳過列表和哈希表的雙端口數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,因此吕朵,每次添加元素時(shí)猎醇,Redis都會(huì)執(zhí)行O(log(N))操作。很好努溃,但是當(dāng)我們要求排序元素時(shí)硫嘶,Redis根本不需要做任何工作,它已經(jīng)全部排序了:

> zrange hackers 0 -1
1) "Alan Turing"
2) "Hedy Lamarr"
3) "Claude Shannon"
4) "Alan Kay"
5) "Anita Borg"
6) "Richard Stallman"
7) "Sophie Wilson"
8) "Yukihiro Matsumoto"
9) "Linus Torvalds"

注意:0和-1表示從元素索引0到最后一個(gè)元素(-1的工作方式與LRANGE命令的情況相同)梧税。

如果我想按相反的順序訂購(最小到最大)怎么辦沦疾?使用ZREVRANGE而不是ZRANGE

> zrevrange hackers 0 -1
1) "Linus Torvalds"
2) "Yukihiro Matsumoto"
3) "Sophie Wilson"
4) "Richard Stallman"
5) "Anita Borg"
6) "Alan Kay"
7) "Claude Shannon"
8) "Hedy Lamarr"
9) "Alan Turing"

也可以使用以下WITHSCORES參數(shù)返回分?jǐn)?shù):

> zrange hackers 0 -1 withscores
1) "Alan Turing"
2) "1912"
3) "Hedy Lamarr"
4) "1914"
5) "Claude Shannon"
6) "1916"
7) "Alan Kay"
8) "1940"
9) "Anita Borg"
10) "1949"
11) "Richard Stallman"
12) "1953"
13) "Sophie Wilson"
14) "1957"
15) "Yukihiro Matsumoto"
16) "1965"
17) "Linus Torvalds"
18) "1969"

*Operating on ranges

排序集比這更強(qiáng)大。它們可以在范圍內(nèi)操作第队。讓我們獲取所有在1950年(含)之前出生的人哮塞。我們使用ZRANGEBYSCORE命令來做到這一點(diǎn):

> zrangebyscore hackers -inf 1950
1) "Alan Turing"
2) "Hedy Lamarr"
3) "Claude Shannon"
4) "Alan Kay"
5) "Anita Borg"

我們要求Redis返回分?jǐn)?shù)在負(fù)無窮大和1950之間的所有元素(包括兩個(gè)極端)。

也可以刪除元素范圍凳谦。讓我們從排序集中刪除所有1940年至1960年之間出生的黑客:

> zremrangebyscore hackers 1940 1960
(integer) 4

ZREMRANGEBYSCORE可能不是最好的命令名稱忆畅,但是它可能非常有用,并返回已刪除元素的數(shù)量尸执。

為排序的集合元素定義的另一個(gè)極其有用的操作是get-rank操作邻眷∶呤海可以問一個(gè)元素在有序元素集合中的位置是什么。

> zrank hackers "Anita Borg"
(integer) 4

ZREVRANK命令也可以為了獲得軍銜肆饶,考慮的要素排序的下降方式改衩。

*Lexicographical scores

在最新版本的Redis 2.8中,引入了一項(xiàng)新功能驯镊,該功能允許按字典順序獲取范圍葫督,假設(shè)已排序集中的元素都以相同的相同分?jǐn)?shù)插入(將元素與C memcmp函數(shù)進(jìn)行比較 ,因此可以確保沒有排序規(guī)則) 板惑,并且每個(gè)Redis實(shí)例將以相同的輸出進(jìn)行回復(fù))橄镜。

用于按字典順序操作的主要命令是ZRANGEBYLEXZREVRANGEBYLEX冯乘,ZREMRANGEBYLEXZLEXCOUNT洽胶。

例如,讓我們?cè)俅翁砑游覀兊闹诳土斜眈陕沁@次對(duì)所有元素使用零分:

> zadd hackers 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0
  "Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon"
  0 "Linus Torvalds" 0 "Alan Turing"

由于排序集的排序規(guī)則姊氓,它們已經(jīng)按字典順序排序:

> zrange hackers 0 -1
1) "Alan Kay"
2) "Alan Turing"
3) "Anita Borg"
4) "Claude Shannon"
5) "Hedy Lamarr"
6) "Linus Torvalds"
7) "Richard Stallman"
8) "Sophie Wilson"
9) "Yukihiro Matsumoto"

使用ZRANGEBYLEX我們可以要求詞典范圍:

> zrangebylex hackers [B [P
1) "Claude Shannon"
2) "Hedy Lamarr"
3) "Linus Torvalds"

范圍可以是包含(inclusive)或排除(exclusive)(取決于第一個(gè)字符),字符串無限和負(fù)無限分別用+-字符串指定喷好。有關(guān)更多信息翔横,請(qǐng)參見文檔。

此功能非常重要梗搅,因?yàn)樗试S我們將排序后的集合用作通用索引禾唁。例如,如果要通過128位無符號(hào)整數(shù)參數(shù)索引元素无切,則只需將元素添加到具有相同分?jǐn)?shù)(例如0)但具有由128個(gè)字節(jié)組成的16字節(jié)前綴的排序集中大尾數(shù)中的位數(shù)荡短。由于big endian中的數(shù)字實(shí)際上按數(shù)字順序也按字典順序(以原始字節(jié)順序)排序,因此您可以要求128位空間中的范圍哆键,并獲得丟棄前綴的元素值掘托。

如果要在更嚴(yán)重的演示環(huán)境中查看該功能,請(qǐng)檢查Redis自動(dòng)完成演示洼哎。

*Updating the score: leader boards

在切換到下一個(gè)主題之前烫映,請(qǐng)只對(duì)已排序集做最后的說明沼本。排序集的分?jǐn)?shù)可以隨時(shí)更新噩峦。只需對(duì)已包含在排序集中的元素調(diào)用ZADD,將以O(shè)(log(N))時(shí)間復(fù)雜度更新其得分(和位置)抽兆。這樣识补,當(dāng)有大量更新時(shí),排序集是合適的辫红。

由于這種特性凭涂,常見的用例是排行榜祝辣。典型的應(yīng)用是Facebook游戲,您可以將按高分對(duì)用戶進(jìn)行排序的能力與獲得排名的操作結(jié)合起來切油,以顯示前N名的用戶以及排行榜中的用戶排名(例如蝙斜,“您是這里的#4932最佳成績”)。

*Bitmaps

位圖不是實(shí)際的數(shù)據(jù)類型澎胡,而是在String類型上定義的一組面向位的操作孕荠。由于字符串是二進(jìn)制安全Blob,并且最大長度為512 MB攻谁,因此它們適合設(shè)置多達(dá)2 32個(gè)不同的位稚伍。

位操作分為兩類:固定時(shí)間的單個(gè)位操作(如將一個(gè)位設(shè)置為1或0或獲取其值),以及對(duì)位組的操作戚宦,例如計(jì)算給定位范圍內(nèi)設(shè)置的位的數(shù)量(例如孩灯,人口計(jì)數(shù))恰力。

位圖的最大優(yōu)點(diǎn)之一是,它們?cè)诖鎯?chǔ)信息時(shí)通常可以節(jié)省大量空間槽棍。例如,在以增量用戶ID表示不同用戶的系統(tǒng)中酝掩,僅使用512 MB內(nèi)存就可以記住40億用戶的一位信息(例如屿笼,知道用戶是否要接收新聞通訊)。

使用SETBITGETBIT命令設(shè)置和檢索位:

> setbit key 10 1
(integer) 1
> getbit key 10
(integer) 1
> getbit key 11
(integer) 0

所述SETBIT命令采用作為第一個(gè)參數(shù)的比特?cái)?shù)骚灸,和作為第二個(gè)參數(shù)的值以設(shè)置所述位糟趾,其為1或0的命令自動(dòng)放大字符串,如果尋址位是當(dāng)前字符串長度之外甚牲。

GETBIT只是返回指定索引處的位的值义郑。超出范圍的位(尋址超出存儲(chǔ)在目標(biāo)鍵中的字符串長度的位)始終被視為零。

在位組上有三個(gè)命令:

  1. BITOP在不同的字符串之間執(zhí)行按位運(yùn)算丈钙。提供的運(yùn)算為AND非驮,OR,XOR和NOT雏赦。
  2. BITCOUNT執(zhí)行填充計(jì)數(shù)劫笙,報(bào)告設(shè)置為1的位數(shù)。
  3. BITPOS查找指定值為0或1的第一位星岗。

無論BITPOS比特計(jì)數(shù)能夠與字符串的字節(jié)范圍進(jìn)行操作填大,而不是該字符串的整個(gè)長度運(yùn)行。以下是BITCOUNT調(diào)用的一個(gè)簡單示例:

> setbit key 0 1
(integer) 0
> setbit key 100 1
(integer) 0
> bitcount key
(integer) 2

位圖的常見用例是:

  • 各種實(shí)時(shí)分析俏橘。
  • 存儲(chǔ)與對(duì)象ID相關(guān)的空間高效但高性能的布爾信息允华。

例如,假設(shè)您想知道網(wǎng)站用戶每天訪問量最長的時(shí)間。您從零開始計(jì)算天數(shù)靴寂,即從您公開網(wǎng)站的那一天開始磷蜀,并在用戶每次訪問該網(wǎng)站時(shí)對(duì)SETBIT進(jìn)行設(shè)置。作為位索引百炬,您只需花費(fèi)當(dāng)前的unix時(shí)間褐隆,減去初始偏移量,然后除以一天中的秒數(shù)(通常為3600 * 24)剖踊。

這樣妓灌,對(duì)于每個(gè)用戶,您都有一個(gè)小的字符串蜜宪,其中包含每天的訪問信息虫埂。使用BITCOUNT,可以輕松獲得給定用戶訪問網(wǎng)站的天數(shù)圃验,而只需幾個(gè)BITPOS調(diào)用掉伏,或者僅獲取和分析客戶端的位圖,就可以輕松計(jì)算最長的連勝記錄澳窑。

位圖很容易分成多個(gè)鍵斧散,例如,為了分片數(shù)據(jù)集摊聋,并且因?yàn)橥ǔW詈帽苊馐褂么箧I鸡捐。要在不同的密鑰上拆分位圖,而不是將所有位都設(shè)置為密鑰麻裁,一個(gè)簡單的策略就是為每個(gè)密鑰存儲(chǔ)M位箍镜,并使用來獲取密鑰名稱,使用來獲取bit-number/M第N位bit-number MOD M煎源。

*HyperLogLogs

HyperLogLog是一種概率數(shù)據(jù)結(jié)構(gòu)色迂,用于對(duì)唯一事物進(jìn)行計(jì)數(shù)(從技術(shù)上講,這是指估計(jì)集合的基數(shù))手销。通常歇僧,對(duì)唯一項(xiàng)目進(jìn)行計(jì)數(shù)需要使用與要計(jì)數(shù)的項(xiàng)目數(shù)量成比例的內(nèi)存量,因?yàn)槟枰涀∵^去已經(jīng)看到的元素锋拖,以避免多次對(duì)其進(jìn)行計(jì)數(shù)诈悍。但是,有一組算法會(huì)以內(nèi)存為代價(jià)來交換精度:您最終會(huì)得到帶有標(biāo)準(zhǔn)誤差的估計(jì)量度兽埃,在Redis實(shí)現(xiàn)的情況下侥钳,該誤差小于1%。這種算法的神奇之處在于讲仰,您不再需要使用與所計(jì)數(shù)項(xiàng)目數(shù)量成正比的內(nèi)存量慕趴,而是可以使用恒定數(shù)量的內(nèi)存!在最壞的情況下為12k字節(jié)鄙陡,如果您的HyperLogLog(從現(xiàn)在開始將它們稱為HLL)看到的元素很少冕房,則少得多。

Redis中的HLL盡管在技術(shù)上是不同的數(shù)據(jù)結(jié)構(gòu)趁矾,但被編碼為Redis字符串耙册,因此您可以調(diào)用GET來序列化HLL,然后調(diào)用SET 來將其反序列化回服務(wù)器毫捣。

從概念上講详拙,HLL API就像使用Set來執(zhí)行相同的任務(wù)。你會(huì) 薩德每個(gè)觀測元素為一組蔓同,并且將使用SCARD檢查組中的元素饶辙,這是唯一的數(shù)量自SADD不會(huì)再添加一個(gè)現(xiàn)有的元素。

盡管您并未真正將項(xiàng)目添加到HLL中斑粱,但由于數(shù)據(jù)結(jié)構(gòu)僅包含不包含實(shí)際元素的狀態(tài)弃揽,因此API相同:

  • 每次看到新元素時(shí),都可以使用PFADD將其添加到計(jì)數(shù)中则北。

  • 到目前為止矿微,每次您要檢索添加PFADD的唯一元素的當(dāng)前近似值時(shí),都可以使用PFCOUNT尚揣。

    > pfadd hll a b c d
    (integer) 1
    > pfcount hll
    (integer) 4
    

該數(shù)據(jù)結(jié)構(gòu)用例的一個(gè)例子是每天計(jì)算用戶在搜索表單中執(zhí)行的唯一查詢涌矢。

Redis也能夠執(zhí)行HLL的合并,請(qǐng)查看 完整的文檔以獲取更多信息快骗。

*Other notable features

Redis API中還有其他重要內(nèi)容娜庇,在本文檔的上下文中無法探討,但值得您注意:

*Learn more

本教程絕不完整恭取,僅涵蓋了API的基礎(chǔ)知識(shí)泰偿。閱讀命令參考以發(fā)現(xiàn)更多內(nèi)容。

感謝您的閱讀蜈垮,并祝您使用Redis玩得開心耗跛!

如果你喜歡本文,
請(qǐng)關(guān)注公眾號(hào) 分布式編程
原文地址:https://zthinker.com/archives/redis%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E7%AE%80%E4%BB%8B

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市攒发,隨后出現(xiàn)的幾起案子调塌,更是在濱河造成了極大的恐慌,老刑警劉巖惠猿,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羔砾,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)姜凄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門政溃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人态秧,你說我怎么就攤上這事董虱。” “怎么了申鱼?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵愤诱,是天一觀的道長。 經(jīng)常有香客問我捐友,道長淫半,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任匣砖,我火速辦了婚禮撮慨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘脆粥。我一直安慰自己砌溺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布变隔。 她就那樣靜靜地躺著规伐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匣缘。 梳的紋絲不亂的頭發(fā)上猖闪,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音肌厨,去河邊找鬼培慌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛柑爸,可吹牛的內(nèi)容都是我干的吵护。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼表鳍,長吁一口氣:“原來是場噩夢啊……” “哼馅而!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起譬圣,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤瓮恭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后厘熟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屯蹦,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡维哈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了登澜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阔挠。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖帖渠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情竭宰,我是刑警寧澤空郊,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站切揭,受9級(jí)特大地震影響狞甚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜廓旬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一哼审、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧孕豹,春花似錦涩盾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叶眉,卻和暖如春址儒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背衅疙。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國打工莲趣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饱溢。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓喧伞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親绩郎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子絮识,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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