Redis

Redis是啥

Redis是一個(gè)開(kāi)源的key-value存儲(chǔ)系統(tǒng)隘马,由于擁有豐富的數(shù)據(jù)結(jié)構(gòu)免钻,又被其作者戲稱(chēng)為數(shù)據(jù)結(jié)構(gòu)服務(wù)器盏袄。它屬于NoSQL(Not Only SQL)數(shù)據(jù)庫(kù)中的鍵值(Key-Value)存儲(chǔ)數(shù)據(jù)庫(kù)薪前,即它屬于與MySQL和Oracle等關(guān)系型數(shù)據(jù)庫(kù)不同的非關(guān)系型數(shù)據(jù)庫(kù)奏篙。它與memcached類(lèi)似柴淘,但是優(yōu)于memcached迫淹。

Redis和Memocache的區(qū)別

1.Memocache僅支持字符串類(lèi)型,而redis支持豐富的數(shù)據(jù)類(lèi)型
2.Redis 支持兩種持久化策略:RDB 快照和 AOF 日志为严,而 Memcached 不支持持久化敛熬。
3.Redis Cluster 實(shí)現(xiàn)了分布式的支持,Memocache不支持

Redis的應(yīng)用場(chǎng)景

1.用于持久化存儲(chǔ):由于Redis擁有豐富的數(shù)據(jù)結(jié)構(gòu)第股,所以可以存儲(chǔ)多種類(lèi)型的數(shù)據(jù)应民。同時(shí),它在存儲(chǔ)與獲取某些數(shù)據(jù)的效率方面也優(yōu)于關(guān)系型數(shù)據(jù)庫(kù)夕吻。
2.用于數(shù)據(jù)緩存:Redis最適合所有數(shù)據(jù)in-momory的場(chǎng)景诲锹。

Redis的優(yōu)點(diǎn)

1.性能好,讀寫(xiě)速率快
2.擁有豐富的數(shù)據(jù)結(jié)構(gòu)涉馅,可以存儲(chǔ)多種類(lèi)型的數(shù)據(jù)(相對(duì)于memocached來(lái)說(shuō))
3.操作都是原子性的操作归园,不用擔(dān)心并發(fā)問(wèn)題,還支持多個(gè)操作合并的原子操作
4.擁有其他豐富的特性稚矿,比如給key設(shè)置expire過(guò)期時(shí)間

Redis對(duì)大小寫(xiě)不敏感

Redis為什么快

1庸诱、完全基于內(nèi)存,絕大部分請(qǐng)求是純粹的內(nèi)存操作晤揣,非城潘快速。數(shù)據(jù)存在內(nèi)存中昧识,類(lèi)似于HashMap钠四,HashMap的優(yōu)勢(shì)就是查找和操作的時(shí)間復(fù)雜度都是O(1);

2跪楞、數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單缀去,對(duì)數(shù)據(jù)操作也簡(jiǎn)單,Redis中的數(shù)據(jù)結(jié)構(gòu)是專(zhuān)門(mén)進(jìn)行設(shè)計(jì)的习霹;

3朵耕、采用單線(xiàn)程,避免了不必要的上下文切換和競(jìng)爭(zhēng)條件淋叶,也不存在多進(jìn)程或者多線(xiàn)程導(dǎo)致的切換而消耗 CPU阎曹,不用去考慮各種鎖的問(wèn)題,不存在加鎖釋放鎖操作煞檩,沒(méi)有因?yàn)榭赡艹霈F(xiàn)死鎖而導(dǎo)致的性能消耗处嫌;

4、使用多路I/O復(fù)用模型斟湃,非阻塞IO熏迹;

5、使用底層模型不同凝赛,它們之間底層實(shí)現(xiàn)方式以及與客戶(hù)端之間通信的應(yīng)用協(xié)議不一樣注暗,Redis直接自己構(gòu)建了VM 機(jī)制 坛缕,因?yàn)橐话愕南到y(tǒng)調(diào)用系統(tǒng)函數(shù)的話(huà),會(huì)浪費(fèi)一定的時(shí)間去移動(dòng)和請(qǐng)求捆昏;

Redis為什么是單線(xiàn)程

官方FAQ表示赚楚,因?yàn)镽edis是基于內(nèi)存的操作,CPU不是Redis的瓶頸骗卜,Redis的瓶頸最有可能是機(jī)器內(nèi)存的大小或者網(wǎng)絡(luò)帶寬宠页。既然單線(xiàn)程容易實(shí)現(xiàn),而且CPU不會(huì)成為瓶頸寇仓,那就順理成章地采用單線(xiàn)程的方案了(畢竟采用多線(xiàn)程會(huì)有很多麻煩>倩А)
另,采用單線(xiàn)程發(fā)揮不出多核cpu的性能遍烦,不過(guò)可以通過(guò)在單機(jī)開(kāi)多個(gè)redis來(lái)完善

數(shù)據(jù)類(lèi)型

String

字符串是Redis的一種最基本的數(shù)據(jù)類(lèi)型俭嘁。Redis字符串是二進(jìn)制安全的,這意味著一個(gè)Redis字符串能包含任意類(lèi)型的數(shù)據(jù)服猪。一個(gè)字符串類(lèi)型的變量最多能存儲(chǔ)512M字節(jié)的內(nèi)容兄淫。

image.png
底層實(shí)現(xiàn)

簡(jiǎn)單動(dòng)態(tài)字符串

常用的操作
  • get(key):返回?cái)?shù)據(jù)庫(kù)中名稱(chēng)為key的string的value
  • getset(key, value):給名稱(chēng)為key的string賦予上一次的value
  • mget(key1, key2,…, key N):返回庫(kù)中多個(gè)string(它們的名稱(chēng)為key1,key2…)的value
  • setnx(key, value):如果不存在名稱(chēng)為key的string蔓姚,則向庫(kù)中添加string,名稱(chēng)為key慨丐,值為value
  • setex(key, time, value):向庫(kù)中添加string(名稱(chēng)為key坡脐,值為value)同時(shí),設(shè)定過(guò)期時(shí)間time
  • mset(key1, value1, key2, value2,…key N, value N):同時(shí)給多個(gè)string賦值房揭,名稱(chēng)為key i的string賦值value i
  • msetnx(key1, value1, key2, value2,…key N, value N):如果所有名稱(chēng)為key i的string都不存在备闲,則向庫(kù)中添加string,名稱(chēng)key i賦值為value i
  • incr(key):名稱(chēng)為key的string增1操作
  • incrby(key, integer):名稱(chēng)為key的string增加integer
  • decr(key):名稱(chēng)為key的string減1操作
  • decrby(key, integer):名稱(chēng)為key的string減少integer
  • append(key, value):名稱(chēng)為key的string的值附加value
  • substr(key, start, end):返回名稱(chēng)為key的string的value的子串
List

Redis中的List是簡(jiǎn)單的字符串列表捅暴,可以按照插入的順序排序恬砂。我們可以添加一個(gè)元素到列表的左邊(頭部)或者是右邊(尾部)。對(duì)應(yīng)的命令為L(zhǎng)PUSH和RPUSH蓬痒。


image.png
底層實(shí)現(xiàn)

鏈表/壓縮列表

常用的操作
  • rpush(key, value):在名稱(chēng)為key的list尾添加一個(gè)值為value的元素
  • lpush(key, value):在名稱(chēng)為key的list頭添加一個(gè)值為value的 元素
  • llen(key):返回名稱(chēng)為key的list的長(zhǎng)度
  • lrange(key, start, end):返回名稱(chēng)為key的list中start至end之間的元素(下標(biāo)從0開(kāi)始泻骤,下同)
  • ltrim(key, start, end):截取名稱(chēng)為key的list,保留start至end之間的元素
  • lindex(key, index):返回名稱(chēng)為key的list中index位置的元素
  • lset(key, index, value):給名稱(chēng)為key的list中index位置的元素賦值為value
  • lrem(key, count, value):刪除count個(gè)名稱(chēng)為key的list中值為value的元素梧奢。count為0狱掂,刪除所有值為value的元素,count>0從頭至尾刪除count個(gè)值為value的元素亲轨,count<0從尾到頭刪除|count|個(gè)值為value的元素
  • lpop(key):返回并刪除名稱(chēng)為key的list中的首元素 rpop(key):返回并刪除名稱(chēng)為key的list中的尾元素
  • blpop(key1, key2,… key N, timeout):lpop命令的block版本趋惨。即當(dāng)timeout為0時(shí),若遇到名稱(chēng)為key i的list不存在或該list為空惦蚊,則命令結(jié)束器虾。如果timeout>0讯嫂,則遇到上述情況時(shí),等待timeout秒兆沙,如果問(wèn)題沒(méi)有解決欧芽,則對(duì)keyi+1開(kāi)始的list執(zhí)行pop操作
  • brpop(key1, key2,… key N, timeout):rpop的block版本。參考上一命令挤悉。
  • rpoplpush(srckey, dstkey):返回并刪除名稱(chēng)為srckey的list的尾元素渐裸,并將該元素添加到名稱(chēng)為dstkey的list的頭部
Hash

Hash是字符串字段和字符串值之間的映射,因此他們是展現(xiàn)對(duì)象的完美數(shù)據(jù)類(lèi)型装悲。一個(gè)帶有一些字段的hash僅僅需要一塊很小的空間存儲(chǔ)昏鹃,因此我們可以存儲(chǔ)數(shù)以百萬(wàn)計(jì)的對(duì)象在一個(gè)小小的redis實(shí)例當(dāng)中。


image.png
底層實(shí)現(xiàn)

字典/壓縮列表

常用操作
  • hset(key, field, value):向名稱(chēng)為key的hash中添加元素field<—>value
  • hget(key, field):返回名稱(chēng)為key的hash中field對(duì)應(yīng)的value
  • hmget(key, field1, …,field N):返回名稱(chēng)為key的hash中field i對(duì)應(yīng)的value
  • hmset(key, field1, value1,…,field N, value N):向名稱(chēng)為key的hash中添加元素field i<—>value i
  • hincrby(key, field, integer):將名稱(chēng)為key的hash中field的value增加integer
  • hexists(key, field):名稱(chēng)為key的hash中是否存在鍵為field的域
  • hdel(key, field):刪除名稱(chēng)為key的hash中鍵為field的域
  • hlen(key):返回名稱(chēng)為key的hash中元素個(gè)數(shù)
  • hkeys(key):返回名稱(chēng)為key的hash中所有鍵
  • hvals(key):返回名稱(chēng)為key的hash中所有鍵對(duì)應(yīng)的value
  • hgetall(key):返回名稱(chēng)為key的hash中所有的鍵(field)及其對(duì)應(yīng)的value

Set(無(wú)序集合)

Redis集合(Set)是一個(gè)無(wú)序的字符串集合诀诊。我們可以在O(1)的時(shí)間復(fù)雜度(無(wú)論集合中有多少元素時(shí)間復(fù)雜度都是常量)完成添加洞渤、刪除或者是查看元素是否存在。Redis集合擁有令人滿(mǎn)意的不允許包含相同成員的屬性属瓣。多次添加相同的元素载迄,最終在集合里面只會(huì)有一個(gè)元素。實(shí)際上說(shuō)這些就是意味著在添加元素的時(shí)候無(wú)須檢測(cè)元素是否存在抡蛙。一個(gè)關(guān)于Redis集合非常有趣的事情就是它支持一些服務(wù)端的命令從現(xiàn)有的集合出發(fā)去進(jìn)行集合運(yùn)算护昧,因此我們可以在非常短的時(shí)間內(nèi)合并(unions),求交集(intersections)粗截,找出不同的元素(difference of sets)惋耙。


image.png
底層實(shí)現(xiàn)

整數(shù)集合/字典

常用操作
  • sadd(key, member):向名稱(chēng)為key的set中添加元素member
  • srem(key, member) :刪除名稱(chēng)為key的set中的元素member
  • spop(key) :隨機(jī)返回并刪除名稱(chēng)為key的set中一個(gè)元素
  • smove(srckey, dstkey, member) :將member元素從名稱(chēng)為srckey的集合移到名稱(chēng)為dstkey的集合
  • scard(key) :返回名稱(chēng)為key的set的基數(shù)
  • sismember(key, member) :測(cè)試member是否是名稱(chēng)為key的set的元素
  • sinter(key1, key2,…key N) :求交集
  • sinterstore(dstkey, key1, key2,…key N) :求交集并將交集保存到dstkey的集合
  • sunion(key1, key2,…key N) :求并集
  • sunionstore(dstkey, key1, key2,…key N) :求并集并將并集保存到dstkey的集合
  • sdiff(key1, key2,…key N) :求差集
  • sdiffstore(dstkey, key1, key2,…key N) :求差集并將差集保存到dstkey的集合
  • smembers(key) :返回名稱(chēng)為key的set的所有元素
  • srandmember(key) :隨機(jī)返回名稱(chēng)為key的set的一個(gè)元素

Sorted Set(有序集合)

Redis有序集合和普通集合非常類(lèi)似,是一個(gè)沒(méi)有重復(fù)元素的字符串集合熊昌。不同之處在于有序集合的所有成員都關(guān)聯(lián)了一個(gè)評(píng)分绽榛,這個(gè)評(píng)分被用來(lái)按照從最低分到最高分的方式排序集合中的成員。集合的成員是唯一的婿屹,但是評(píng)分可以是重復(fù)的灭美。使用有序集合我們可以用非常快的速度(O(logN))添加昂利、刪除以及更新元素届腐。因?yàn)樵厥怯行虻模晕覀円部梢院芸斓馗鶕?jù)評(píng)分(score)或者次序(position)來(lái)獲取一個(gè)范圍的元素蜂奸。訪(fǎng)問(wèn)有序集合的中間元素也是非程莶叮快的,因此我們能夠使用有序集合作為一個(gè)沒(méi)有重復(fù)成員的智能列表窝撵。在有序集合中傀顾,我們可以很快捷地訪(fǎng)問(wèn)一切我們所需要的東西:有序的元素、快速的存在性測(cè)試碌奉、快速訪(fǎng)問(wèn)集合的中間元素短曾。簡(jiǎn)而言之寒砖,使用有序集合我們可以完成許多對(duì)性能有極端要求的任務(wù),而這些任務(wù)是使用其他類(lèi)型的數(shù)據(jù)庫(kù)很難完成的嫉拐。


image.png
底層實(shí)現(xiàn)

跳表/壓縮鏈表

常用操作
  • zadd(key, score, member):向名稱(chēng)為key的zset中添加元素member哩都,score用于排序。如果該元素已經(jīng)存在婉徘,則根據(jù)score更新該元素的順序漠嵌。
  • zrem(key, member) :刪除名稱(chēng)為key的zset中的元素member
  • zincrby(key, increment, member) :如果在名稱(chēng)為key的zset中已經(jīng)存在元素member,則該元素的score增加increment盖呼;否則向集合中添加該元素儒鹿,其score的值為increment
  • zrank(key, member) :返回名稱(chēng)為key的zset(元素已按score從小到大排序)中member元素的rank(即index,從0開(kāi)始)几晤,若沒(méi)有member元素约炎,返回“nil”
  • zrevrank(key, member) :返回名稱(chēng)為key的zset(元素已按score從大到小排序)中member元素的rank(即index,從0開(kāi)始)蟹瘾,若沒(méi)有member元素圾浅,返回“nil”
  • zrange(key, start, end):返回名稱(chēng)為key的zset(元素已按score從小到大排序)中的index從start到end的所有元素
  • zrevrange(key, start, end):返回名稱(chēng)為key的zset(元素已按score從大到小排序)中的index從start到end的所有元素
  • zrangebyscore(key, min, max):返回名稱(chēng)為key的zset中score >= min且score <= max的所有元素 zcard(key):返回名稱(chēng)為key的zset的基數(shù) zscore(key, element):返回名稱(chēng)為key的zset中元素element的score zremrangebyrank(key, min, max):刪除名稱(chēng)為key的zset中rank >= min且rank <= max的所有元素 zremrangebyscore(key, min, max) :刪除名稱(chēng)為key的zset中score >= min且score <= max的所有元素
系統(tǒng)管理命令
  • exists key:判斷一個(gè)key是否存在。存在返回1憾朴,否則返回0
  • del key:刪除一個(gè)key狸捕。成功返回,失敗返回0
  • type key:返回key的數(shù)據(jù)類(lèi)型:string众雷、list府寒、set、zset报腔、hash。key不存在返回none
  • keys key-pattern:將所有能夠匹配key-pattern的key都列出來(lái)
  • randomkey:隨機(jī)返回一個(gè)key,如果此時(shí)數(shù)據(jù)庫(kù)是空的剖淀,則返回一個(gè)為空的字符串
  • clear:清除界面
  • rename oldname newname:將key由原來(lái)的oldname改為newname纯蛾,不管此時(shí)newname存不存在
  • renamenx oldname newname:將key由原來(lái)的oldname改為newname.如果此時(shí)newname存在則更改失敗
  • dbsize:返回當(dāng)前數(shù)據(jù)庫(kù)中key的總數(shù)
    expire key :限定key的生存時(shí)間,命令的一般形式如expire name 30,意思是值為name的
    key只能存活30秒
  • ttl key:返回key剩余存活時(shí)間
  • flushdb:清除當(dāng)前數(shù)據(jù)庫(kù)中所有的key
  • flushall:清除數(shù)據(jù)庫(kù)中所有的key
  • config get:讀取Redis此時(shí)的配置參數(shù)
  • config set:設(shè)置Redis此時(shí)的配置參數(shù)
  • auth:密碼認(rèn)證
  • info:可以查詢(xún)Redis幾乎所有的信息

使用場(chǎng)景:

底層數(shù)據(jù)結(jié)構(gòu)

1.簡(jiǎn)單動(dòng)態(tài)字符串
2.鏈表
3.字典(Map)
4.跳表
5.整數(shù)集合
6.壓縮列表
7.對(duì)象

簡(jiǎn)單動(dòng)態(tài)字符串(Simple Dynamic String)

雖然Redis是使用C語(yǔ)言編寫(xiě)的纵隔,但是Redis中的字符串類(lèi)型并不是直接搬用C語(yǔ)言的字符串翻诉。


/字符串對(duì)象底層結(jié)構(gòu)/ struct sds{ int len;//buf已占用的空間長(zhǎng)度 int free;//buf中剩余空間長(zhǎng)度 char buf[];//數(shù)據(jù)存儲(chǔ)空間 }


  • 獲取字符串長(zhǎng)度時(shí)間更快(SDS為O(1)/C語(yǔ)言字符串為O(n))
  • 避免了緩沖區(qū)溢出問(wèn)題:當(dāng)我們?cè)趯?duì)SDS進(jìn)行修改之前Redis會(huì)預(yù)先檢查所操作的SDS空間夠不夠。如果不夠捌刮,則會(huì)拓展對(duì)應(yīng)SDS空間之后再進(jìn)行拼接等操作
  • 減少修改字符串時(shí)帶來(lái)的內(nèi)存分配問(wèn)題
  • 二進(jìn)制安全
  • 兼容部分C語(yǔ)言中有關(guān)字符串的函數(shù)
鏈表

Redis中的list底層使用的是雙向鏈表

字典(Map)

在字典中碰煌,一個(gè)key和一個(gè)value關(guān)聯(lián),并且字典中的每個(gè)key都是獨(dú)一無(wú)二的绅作。

Redis字典使用的哈希表底層結(jié)構(gòu):

typedef struct dictht { //哈希表數(shù)組 dictEntry **table; //哈希表大小 unsigned long size; //哈希表大小掩碼芦圾,用于計(jì)算索引值 unsigned long sizemask; //該哈希表已有節(jié)點(diǎn)的數(shù)量 unsigned long used; }

哈希表節(jié)點(diǎn):

typeof struct dictEntry{ //鍵 void *key; //值 union{ void *val; uint64_tu64; int64_ts64; } struct dictEntry *next; }

1.根據(jù)hash算法算出key的hash值然后分配存儲(chǔ)空間(由于哈希表中沒(méi)有記錄鏈表尾節(jié)點(diǎn)的位置,所以是在鏈表的head插入新的節(jié)點(diǎn))俄认;
2.鏈地址法解決hash地址沖突
3.隨著哈希表中節(jié)點(diǎn)數(shù)量的增加个少,適當(dāng)時(shí)候會(huì)進(jìn)行rehash將哈希表的負(fù)載因子保持在一個(gè)合理的范圍

跳表(skiplist)

跳躍表(skiplist)是一種有序數(shù)據(jù)結(jié)構(gòu)洪乍,它通過(guò)在每個(gè)節(jié)點(diǎn)中維持多個(gè)指向其他節(jié)點(diǎn)的指針,從而達(dá)到快速訪(fǎng)問(wèn)節(jié)點(diǎn)的目的夜焦。跳躍表是一種隨機(jī)化的數(shù)據(jù),跳躍表以有序的方式在層次化的鏈表中保存元素壳澳,效率和平衡樹(shù)媲美 ——查找、刪除茫经、添加等操作都可以在對(duì)數(shù)期望時(shí)間下完成巷波,并且比起平衡樹(shù)來(lái)說(shuō),跳躍表的實(shí)現(xiàn)要簡(jiǎn)單直觀(guān)得多卸伞。Redis 只在兩個(gè)地方用到了跳躍表抹镊,一個(gè)是實(shí)現(xiàn)有序集合鍵,另外一個(gè)是在集群節(jié)點(diǎn)中用作內(nèi)部數(shù)據(jù)結(jié)構(gòu)瞪慧。
只有當(dāng)有序集合中的元素個(gè)數(shù)大于128時(shí)才會(huì)使用跳表髓考,否則將使用后面提到的壓縮列表

  • 跳躍表是有序集合的底層實(shí)現(xiàn)之一
  • 主要有zskiplist 和zskiplistNode兩個(gè)結(jié)構(gòu)組成
  • 每個(gè)跳躍表節(jié)點(diǎn)的層高都是1至32之間的隨機(jī)數(shù)
  • 在同一個(gè)跳躍表中,多個(gè)節(jié)點(diǎn)可以包含相同的分值弃酌,但每個(gè)節(jié)點(diǎn)的對(duì)象必須是唯一的
  • 節(jié)點(diǎn)按照分值的大小從大到小排序氨菇,如果分值相同,則按成員對(duì)象大小排序
    zskiplist(鏈表)數(shù)據(jù)結(jié)構(gòu):
typedef struct zskiplist { //表頭節(jié)點(diǎn)和表尾節(jié)點(diǎn) structz skiplistNode *header,*tail; //表中節(jié)點(diǎn)數(shù)量 unsigned long length; //表中層數(shù)最大的節(jié)點(diǎn)的層數(shù) int level; }zskiplist;

zskiplistNode(節(jié)點(diǎn))數(shù)據(jù)結(jié)構(gòu):

typedef struct zskiplistNode{    //層 struct zskiplistLevel{      //前進(jìn)指針 struct zskiplistNode *forward;     //跨度 unsigned int span; } level[];   //后退指針 struct zskiplistNode *backward;   //分值 double score;   //成員對(duì)象 robj *obj; }
整數(shù)集合(Intset)

整數(shù)集合是集合建的底層實(shí)現(xiàn)之一妓湘,當(dāng)一個(gè)集合中只包含整數(shù)查蓉,且這個(gè)集合中的元素?cái)?shù)量不多時(shí),redis就會(huì)使用整數(shù)集合intset作為集合的底層實(shí)現(xiàn)榜贴。我們可以這樣理解整數(shù)集合豌研,他其實(shí)就是一個(gè)特殊的集合,里面存儲(chǔ)的數(shù)據(jù)只能夠是整數(shù)唬党,并且數(shù)據(jù)量不能過(guò)大鹃共。
整數(shù)集合升級(jí)不僅可以提高靈活性,還能節(jié)約內(nèi)存驶拱。整數(shù)集合是集合鍵的底層實(shí)現(xiàn)之一霜浴。整數(shù)集合的底層實(shí)現(xiàn)為數(shù)組,這個(gè)數(shù)組以有序蓝纲,無(wú)重復(fù)的范式保存集合元素阴孟,在有需要時(shí),程序會(huì)根據(jù)新添加的元素類(lèi)型改變這個(gè)數(shù)組的類(lèi)型税迷。同時(shí)永丝,升級(jí)操作為整數(shù)集合帶來(lái)了操作上的靈活性,并且盡可能地節(jié)約了內(nèi)存箭养。但是整數(shù)集合只支持升級(jí)操作慕嚷,不支持降級(jí)操作

壓縮列表

壓縮列表是列表鍵和哈希鍵的底層實(shí)現(xiàn)之一。當(dāng)一個(gè)列表鍵只含少量列表項(xiàng)(一般是少于128)時(shí)并且每個(gè)列表項(xiàng)要么就是小整數(shù),要么就是長(zhǎng)度比較短的字符串闯冷,那么Redis就會(huì)使用壓縮列表來(lái)做列表鍵的底層實(shí)現(xiàn)砂心。
關(guān)于壓縮列表的幾點(diǎn)總結(jié):

  • 壓縮列表是一種為了節(jié)約內(nèi)存而開(kāi)發(fā)的順序型數(shù)據(jù)結(jié)構(gòu)
  • 壓縮列表被用作列表鍵和哈希鍵的底層實(shí)現(xiàn)之一
  • 壓縮列表可以包含多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)可以保存一個(gè)字節(jié)數(shù)組或者是整數(shù)值
  • 添加新節(jié)點(diǎn)到壓縮列表蛇耀,可能會(huì)引發(fā)連鎖更新操作

Redis持久化

Redis直接將數(shù)據(jù)存儲(chǔ)在內(nèi)存當(dāng)中辩诞,但是并不是所有的數(shù)據(jù)都一直存儲(chǔ)在內(nèi)存中的(這是和memcached相比最大的一個(gè)區(qū)別)。Redis會(huì)緩存所有的key的信息纺涤,但是如果Redis發(fā)現(xiàn)內(nèi)存的使用量超過(guò)了某一個(gè)閾值译暂,就會(huì)觸發(fā)swap操作。Redis會(huì)計(jì)算出哪些key對(duì)應(yīng)的value需要swap到磁盤(pán)撩炊,然后再將這些key對(duì)應(yīng)的value持久化到磁盤(pán)中同時(shí)清除內(nèi)存中存儲(chǔ)的對(duì)應(yīng)的value外永。這種特性使得Redis可以保持超過(guò)其機(jī)器本身內(nèi)存大小的數(shù)據(jù)。但是機(jī)器本身的內(nèi)存必須可以有足夠的空間存儲(chǔ)所有的key拧咳,因?yàn)閗ey是不會(huì)進(jìn)行swap操作的伯顶。由于Redis將內(nèi)存中的數(shù)據(jù)swap到磁盤(pán)中時(shí),提供服務(wù)的主線(xiàn)程和進(jìn)行swap操作的子線(xiàn)程會(huì)共享這部分內(nèi)存骆膝。如果更新需要swap的數(shù)據(jù)祭衩,Redis將阻塞這個(gè)操作,直至子線(xiàn)程完成swap操作之后才可以進(jìn)行修改
當(dāng)從Redis中讀取數(shù)據(jù)的時(shí)候阅签,如果讀取的key對(duì)應(yīng)的value不在內(nèi)存中掐暮,那么Redis就要從swap文件加載相應(yīng)的數(shù)據(jù),然后再返回給請(qǐng)求數(shù)據(jù)的一方政钟。此時(shí)存在一個(gè)I/O線(xiàn)程池的問(wèn)題路克。在默認(rèn)情況下,Redis會(huì)出現(xiàn)阻塞养交,它要完成所有的swap文件的加載之后才會(huì)響應(yīng)精算。這樣的策略在客戶(hù)端數(shù)量較少,進(jìn)行批量操作的時(shí)候比較合適碎连。但是如果將Redis應(yīng)用在一個(gè)大型的網(wǎng)站中灰羽,這顯然是無(wú)法滿(mǎn)足高并發(fā)的需求的。所有Redis允許我們?cè)O(shè)置I/O線(xiàn)程池的大小破花,對(duì)需要從swap文件中加載對(duì)應(yīng)數(shù)據(jù)的請(qǐng)求進(jìn)行并發(fā)操作,減少阻塞時(shí)間疲吸。

Redis提供的兩種持久化方式

RDB快照:
  • Redis支持將當(dāng)前的快照存儲(chǔ)為一個(gè)數(shù)據(jù)文件的持久化機(jī)制座每,即當(dāng)前提到的RDB快照。Redis借助了fork命令的copy on write機(jī)制(私有內(nèi)存非共享內(nèi)存)摘悴。在生成快照時(shí)峭梳,將當(dāng)前進(jìn)程fork出一個(gè)子進(jìn)程。接著在子進(jìn)程中迭代循環(huán)所有的數(shù)據(jù)同時(shí)將數(shù)據(jù)存儲(chǔ)到一個(gè)臨時(shí)文件當(dāng)中。當(dāng)數(shù)據(jù)全部處理完之后葱椭,就通過(guò)原子性rename系統(tǒng)調(diào)用將臨時(shí)文件重命名為RDB文件捂寿。值得注意的是,這樣的文件生成機(jī)制可以保證RDB文件不會(huì)壞掉孵运,即Redis的RDB文件總是可用的秦陋。但是,RDB有明顯的不足-----一旦數(shù)據(jù)庫(kù)出現(xiàn)問(wèn)題治笨,那么我們的RDB文件中保存的數(shù)據(jù)并不是全新的驳概,從上次RDB文件生成到Redis停機(jī)這段時(shí)間的數(shù)據(jù)全部丟掉了。在某些業(yè)務(wù)下旷赖,這是可以忍受的顺又,我們也推薦這些業(yè)務(wù)使用RDB的方式進(jìn)行持久化,因?yàn)殚_(kāi)啟RDB的代價(jià)并不高等孵。但是對(duì)于另外一些對(duì)數(shù)據(jù)安全性要求極高的應(yīng)用稚照,無(wú)法容忍數(shù)據(jù)丟失的應(yīng)用,RDB就無(wú)能為力了俯萌,所以Redis引入了另一個(gè)重要的持久化機(jī)制:AOF日志果录。
    我們可以通過(guò)Redis的save指令來(lái)配置快照生成的時(shí)機(jī)
    save 900 1 #900秒內(nèi)有一條key數(shù)據(jù)被修改就生成RDB文件
優(yōu)點(diǎn):

RDB 是一個(gè)非常緊湊(compact)的文件,它保存了 Redis 在某個(gè)時(shí)間點(diǎn)上的數(shù)據(jù)集绳瘟。 這種文件非常適合用于進(jìn)行備份: 比如說(shuō)雕憔,你可以在最近的 24 小時(shí)內(nèi),每小時(shí)備份一次 RDB 文件糖声,并且在每個(gè)月的每一天斤彼,也備份一個(gè) RDB 文件。 這樣的話(huà)蘸泻,即使遇上問(wèn)題琉苇,也可以隨時(shí)將數(shù)據(jù)集還原到不同的版本。
RDB 非常適用于災(zāi)難恢復(fù)(disaster recovery):它只有一個(gè)文件悦施,并且內(nèi)容都非常緊湊并扇,可以(在加密后)將它傳送到別的數(shù)據(jù)中心,或者亞馬遜 S3 中抡诞。
RDB 可以最大化 Redis 的性能:父進(jìn)程在保存 RDB 文件時(shí)唯一要做的就是 fork 出一個(gè)子進(jìn)程穷蛹,然后這個(gè)子進(jìn)程就會(huì)處理接下來(lái)的所有保存工作,父進(jìn)程無(wú)須執(zhí)行任何磁盤(pán) I/O 操作昼汗。
RDB 在恢復(fù)大數(shù)據(jù)集時(shí)的速度比 AOF 的恢復(fù)速度要快肴熏。

缺點(diǎn):

如果你需要盡量避免在服務(wù)器故障時(shí)丟失數(shù)據(jù),那么 RDB 不適合你顷窒。 雖然 Redis 允許你設(shè)置不同的保存點(diǎn)(save point)來(lái)控制保存 RDB 文件的頻率蛙吏, 但是, 因?yàn)镽DB 文件需要保存整個(gè)數(shù)據(jù)集的狀態(tài), 所以它并不是一個(gè)輕松的操作鸦做。 因此你可能會(huì)至少 5 分鐘才保存一次 RDB 文件励烦。 在這種情況下, 一旦發(fā)生故障停機(jī)泼诱, 你就可能會(huì)丟失好幾分鐘的數(shù)據(jù)坛掠。
每次保存 RDB 的時(shí)候,Redis 都要 fork() 出一個(gè)子進(jìn)程坷檩,并由子進(jìn)程來(lái)進(jìn)行實(shí)際的持久化工作却音。 在數(shù)據(jù)集比較龐大時(shí), fork() 可能會(huì)非常耗時(shí)矢炼,造成服務(wù)器在某某毫秒內(nèi)停止處理客戶(hù)端系瓢; 如果數(shù)據(jù)集非常巨大,并且 CPU 時(shí)間非常緊張的話(huà)句灌,那么這種停止時(shí)間甚至可能會(huì)長(zhǎng)達(dá)整整一秒夷陋。 雖然 AOF 重寫(xiě)也需要進(jìn)行 fork() ,但無(wú)論 AOF 重寫(xiě)的執(zhí)行間隔有多長(zhǎng)胰锌,數(shù)據(jù)的耐久性都不會(huì)有任何損失骗绕。

AOF日志:

AOF日志是追加寫(xiě)入的日志文件。和一般數(shù)據(jù)庫(kù)的binlog不同的是资昧,AOF文件是可讀性較強(qiáng)的純文本酬土。其中保存的內(nèi)容即Redis一條條的標(biāo)準(zhǔn)指令。但是并不是所有的Redis指令都會(huì)記錄在A(yíng)OF文件中格带,只有會(huì)導(dǎo)致數(shù)據(jù)發(fā)生修改的指令才會(huì)追加到AOF文件中撤缴。隨著記錄的指令越來(lái)越多,文件會(huì)變得越來(lái)越大叽唱。此時(shí)Redis提供了一個(gè)叫做AOF rewrite的功能屈呕,可以重新生成一份新的并且更小的AOF文件。新的文件中針對(duì)同一條key只記錄了最新的一次數(shù)據(jù)修改的指令棺亭。AOF的文件生成機(jī)制和RDB快照類(lèi)似虎眨。再寫(xiě)入新文件的過(guò)程中,所有操作日志還是會(huì)寫(xiě)到舊的文件當(dāng)中镶摘,同時(shí)會(huì)記錄在內(nèi)存緩沖區(qū)中嗽桩。當(dāng)rewrite操作完成后,會(huì)將所有緩沖區(qū)中的日志一次性寫(xiě)入臨時(shí)文件并調(diào)用原子性的rename命令將新的AOF文件覆蓋舊的AOF文件凄敢。

優(yōu)點(diǎn):
  • 使用 AOF 持久化會(huì)讓 Redis 變得非常耐久(much more durable):你可以設(shè)置不同的策略碌冶,比如無(wú)fsync ,每秒鐘一次 fsync贡未,或者每次執(zhí)行寫(xiě)入命令時(shí)fsync 种樱。 AOF 的默認(rèn)策略為每秒鐘 fsync一次,在這種配置下俊卤,Redis 仍然可以保持良好的性能嫩挤,并且就算發(fā)生故障停機(jī),也最多只會(huì)丟失一秒鐘的數(shù)據(jù)fsync 會(huì)在后臺(tái)線(xiàn)程執(zhí)行消恍,所以主線(xiàn)程可以繼續(xù)努力地處理命令請(qǐng)求)岂昭。
  • AOF 文件是一個(gè)只進(jìn)行追加操作的日志文件(append only log), 因此對(duì) AOF 文件的寫(xiě)入不需要進(jìn)行 seek 狠怨, 即使日志因?yàn)槟承┰蚨宋磳?xiě)入完整的命令(比如寫(xiě)入時(shí)磁盤(pán)已滿(mǎn)约啊,寫(xiě)入中途停機(jī),等等)佣赖, redis-check-aof 工具也可以輕易地修復(fù)這種問(wèn)題恰矩。
  • Redis 可以在 AOF 文件體積變得過(guò)大時(shí),自動(dòng)地在后臺(tái)對(duì) AOF 進(jìn)行重寫(xiě): 重寫(xiě)后的新 AOF 文件包含了恢復(fù)當(dāng)前數(shù)據(jù)集所需的最小命令集合憎蛤。 整個(gè)重寫(xiě)操作是絕對(duì)安全的外傅,因?yàn)?Redis 在創(chuàng)建新 AOF 文件的過(guò)程中,會(huì)繼續(xù)將命令追加到現(xiàn)有的 AOF 文件里面俩檬,即使重寫(xiě)過(guò)程中發(fā)生停機(jī)萎胰,現(xiàn)有的 AOF 文件也不會(huì)丟失。 而一旦新 AOF 文件創(chuàng)建完畢棚辽,Redis 就會(huì)從舊 AOF 文件切換到新 AOF 文件技竟,并開(kāi)始對(duì)新 AOF 文件進(jìn)行追加操作。
  • AOF 文件有序地保存了對(duì)數(shù)據(jù)庫(kù)執(zhí)行的所有寫(xiě)入操作屈藐, 這些寫(xiě)入操作以 Redis 協(xié)議的格式保存榔组, 因此 AOF 文件的內(nèi)容非常容易被人讀懂, 對(duì)文件進(jìn)行分析(parse)也很輕松估盘。 導(dǎo)出(export) AOF 文件也非常簡(jiǎn)單: 舉個(gè)例子瓷患, 如果你不小心執(zhí)行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫(xiě)遣妥, 那么只要停止服務(wù)器擅编, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重啟 Redis 箫踩, 就可以將數(shù)據(jù)集恢復(fù)到 FLUSHALL 執(zhí)行之前的狀態(tài)爱态。
缺點(diǎn):
  • 對(duì)于相同的數(shù)據(jù)集來(lái)說(shuō),AOF 文件的體積通常要大于 RDB 文件的體積境钟。
  • 根據(jù)所使用的 fsync 策略锦担,AOF 的速度可能會(huì)慢于 RDB 。 在一般情況下慨削, 每秒fsync的性能依然非常高洞渔, 而關(guān)閉 fsync 可以讓 AOF 的速度和 RDB 一樣快套媚, 即使在高負(fù)荷之下也是如此。 不過(guò)在處理巨大的寫(xiě)入載入時(shí)磁椒,RDB 可以提供更有保證的最大延遲時(shí)間(latency)堤瘤。
  • AOF 在過(guò)去曾經(jīng)發(fā)生過(guò)這樣的 bug : 因?yàn)閭€(gè)別命令的原因,導(dǎo)致 AOF 文件在重新載入時(shí)浆熔,無(wú)法將數(shù)據(jù)集恢復(fù)成保存時(shí)的原樣本辐。 (舉個(gè)例子,阻塞命令 BRPOPLPUSH 就曾經(jīng)引起過(guò)這樣的 bug 医增。) 測(cè)試套件里為這種情況添加了測(cè)試: 它們會(huì)自動(dòng)生成隨機(jī)的慎皱、復(fù)雜的數(shù)據(jù)集, 并通過(guò)重新載入這些數(shù)據(jù)來(lái)確保一切正常叶骨。 雖然這種 bug 在 AOF 文件中并不常見(jiàn)茫多, 但是對(duì)比來(lái)說(shuō), RDB 幾乎是不可能出現(xiàn)這種 bug 的忽刽。
appendfsync:控制AOF文件寫(xiě)入磁盤(pán)的時(shí)機(jī)
  • appendfsync no:當(dāng)設(shè)置appendfsync為no時(shí)地梨,Redis不會(huì)主動(dòng)調(diào)用fsync去將AOF日志內(nèi)容同步到磁盤(pán),這完全依賴(lài)于操作系統(tǒng)缔恳。對(duì)于大多數(shù)Linux系統(tǒng)來(lái)說(shuō)宝剖,一般是每30秒進(jìn)行一次fsync,將緩沖區(qū)中的數(shù)據(jù)同步到磁盤(pán)上歉甚;
  • appendfsync everysec:當(dāng)設(shè)置appendfsync為everysec的時(shí)候万细,Redis會(huì)默認(rèn)每隔一秒進(jìn)行一次fsync調(diào)用,將緩沖區(qū)中的數(shù)據(jù)寫(xiě)到磁盤(pán)纸泄。但是當(dāng)這一次的fsync調(diào)用時(shí)長(zhǎng)超過(guò)1秒時(shí)赖钞。Redis會(huì)采取延遲fsync的策略,再等一秒鐘聘裁。也就是在兩秒后再進(jìn)行fsync雪营,這一次的fsync就不管會(huì)執(zhí)行多長(zhǎng)時(shí)間都會(huì)進(jìn)行。這時(shí)候由于在fsync時(shí)文件描述符會(huì)被阻塞衡便,所以當(dāng)前的寫(xiě)操作就會(huì)阻塞献起。所以結(jié)論就是,在絕大多數(shù)情況下镣陕,Redis會(huì)每隔一秒進(jìn)行一次fsync谴餐。在最壞的情況下,兩秒鐘會(huì)進(jìn)行一次fsync操作呆抑。這一操作在大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)中被稱(chēng)為group commit岂嗓,就是組合多次寫(xiě)操作的數(shù)據(jù),一次性將日志寫(xiě)到磁盤(pán)鹊碍。
  • 當(dāng)設(shè)置appendfsync為always時(shí)厌殉,每一次寫(xiě)操作都會(huì)調(diào)用一次fsync食绿,這時(shí)數(shù)據(jù)是最安全的,當(dāng)然公罕,由于每次都會(huì)執(zhí)行fsync炫欺,所以其性能也會(huì)受到影響。

主從復(fù)制

為了保證單點(diǎn)故障下的數(shù)據(jù)可用性熏兄,Redis引入了Master節(jié)點(diǎn)和Slave節(jié)點(diǎn)。


image.png
  • master節(jié)點(diǎn)可擁有多個(gè)slave節(jié)點(diǎn)
  • 除了多個(gè)slave連到相同的master之外树姨,slave也可以連接其他slave形成圖狀結(jié)構(gòu)
  • 主從復(fù)制不會(huì)阻塞master摩桶。也就是說(shuō),當(dāng)一個(gè)或多個(gè)slave與master進(jìn)行初次同步數(shù)據(jù)時(shí)帽揪,master可以繼續(xù)處理client發(fā)來(lái)的請(qǐng)求硝清。相反slave在初次同步數(shù)據(jù)時(shí)則會(huì)阻塞,不能處理client的請(qǐng)求
  • 主從復(fù)制可以用來(lái)提高系統(tǒng)的可伸縮性转晰,我們可以用多個(gè)slave專(zhuān)門(mén)用于client的讀請(qǐng)求芦拿,比如sort操作可以使用slave來(lái)處理。也可以用來(lái)做簡(jiǎn)單的數(shù)據(jù)冗余
  • 可以在master禁用數(shù)據(jù)持久化查邢,只需要注釋掉master配置文件中的所有save配置蔗崎,然后只在slave上配置數(shù)據(jù)持久化
主從復(fù)制的過(guò)程

當(dāng)設(shè)置好slave服務(wù)器后,slave會(huì)建立和master的連接扰藕,接著發(fā)送sync命令缓苛。無(wú)論是第一次同步建立的連接還是連接斷開(kāi)后的重新連接,master都會(huì)啟動(dòng)一個(gè)后臺(tái)進(jìn)程邓深,將數(shù)據(jù)庫(kù)快照保存到文件中未桥,同時(shí)master主進(jìn)程會(huì)開(kāi)始收集新的寫(xiě)命令并緩存起來(lái)。后臺(tái)進(jìn)程完成寫(xiě)文件后芥备,master就發(fā)送文件給slave冬耿,slave將文件保存到磁盤(pán)上,然后加載到內(nèi)存并恢復(fù)數(shù)據(jù)庫(kù)快照到磁盤(pán)上萌壳。接著master就會(huì)把緩存的命令轉(zhuǎn)發(fā)給slave亦镶,而且后續(xù)master收到的寫(xiě)命令都會(huì)通過(guò)開(kāi)始建立的連接發(fā)送給slave。從master到slave的同步數(shù)據(jù)的命令和從client發(fā)送的命令使用相同的協(xié)議格式袱瓮。當(dāng)master和slave的連接斷開(kāi)時(shí)slave可以自動(dòng)重新建立連接染乌。如果master同時(shí)收到多個(gè)slave發(fā)來(lái)的同步連接命令,只會(huì)啟動(dòng)一個(gè)進(jìn)程來(lái)寫(xiě)數(shù)據(jù)庫(kù)鏡像懂讯,然后發(fā)送給所有slave荷憋。

  1. 主服務(wù)器創(chuàng)建快照文件,發(fā)送給從服務(wù)器褐望,并在發(fā)送期間使用緩沖區(qū)記錄執(zhí)行的寫(xiě)命令勒庄〈埃快照文件發(fā)送完畢之后,開(kāi)始向從服務(wù)器發(fā)送存儲(chǔ)在緩沖區(qū)中的寫(xiě)命令实蔽;
  2. 從服務(wù)器丟棄所有舊數(shù)據(jù)荡碾,載入主服務(wù)器發(fā)來(lái)的快照文件,之后從服務(wù)器開(kāi)始接受主服務(wù)器發(fā)來(lái)的寫(xiě)命令局装;
  3. 主服務(wù)器每執(zhí)行一次寫(xiě)命令坛吁,就向從服務(wù)器發(fā)送相同的寫(xiě)命令。

redis集群相關(guān):
https://www.zhihu.com/question/21419897

改自:http://www.reibang.com/p/717eaee97444

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末铐尚,一起剝皮案震驚了整個(gè)濱河市拨脉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宣增,老刑警劉巖玫膀,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異爹脾,居然都是意外死亡帖旨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)灵妨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)解阅,“玉大人,你說(shuō)我怎么就攤上這事泌霍∥驮浚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵烹吵,是天一觀(guān)的道長(zhǎng)碉熄。 經(jīng)常有香客問(wèn)我,道長(zhǎng)肋拔,這世上最難降的妖魔是什么锈津? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮凉蜂,結(jié)果婚禮上琼梆,老公的妹妹穿的比我還像新娘。我一直安慰自己窿吩,他們只是感情好茎杂,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著纫雁,像睡著了一般煌往。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上轧邪,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天刽脖,我揣著相機(jī)與錄音羞海,去河邊找鬼。 笑死曲管,一個(gè)胖子當(dāng)著我的面吹牛却邓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播院水,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼腊徙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了檬某?” 一聲冷哼從身側(cè)響起撬腾,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎橙喘,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體胶逢,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厅瞎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了初坠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片和簸。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖碟刺,靈堂內(nèi)的尸體忽然破棺而出锁保,到底是詐尸還是另有隱情,我是刑警寧澤半沽,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布爽柒,位于F島的核電站,受9級(jí)特大地震影響者填,放射性物質(zhì)發(fā)生泄漏浩村。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一占哟、第九天 我趴在偏房一處隱蔽的房頂上張望心墅。 院中可真熱鬧,春花似錦榨乎、人聲如沸怎燥。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)铐姚。三九已至,卻和暖如春肛捍,著一層夾襖步出監(jiān)牢的瞬間谦屑,已是汗流浹背驳糯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留氢橙,地道東北人酝枢。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像悍手,于是被迫代替她去往敵國(guó)和親帘睦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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