Redis的數(shù)據(jù)類型

關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫

在絕大部分時候甘苍,我們都會首先考慮用關(guān)系型數(shù)據(jù)庫來存儲我們的數(shù)據(jù)尝蠕,比如 SQLServer,Oracle载庭,MySQL 等等看彼。

關(guān)系型數(shù)據(jù)庫

關(guān)系型數(shù)據(jù)庫的特點:
  • 它以表格的形式,基于行存儲數(shù)據(jù)囚聚,是一個二維的模式靖榕。
  • 它存儲的是結(jié)構(gòu)化的數(shù)據(jù),數(shù)據(jù)存儲有固定的模式(schema)顽铸,數(shù)據(jù)需要適應(yīng)
    表結(jié)構(gòu)茁计。
  • 表與表之間存在關(guān)聯(lián)。
  • 大部分關(guān)系型數(shù)據(jù)庫都支持 SQL(結(jié)構(gòu)化查詢語言)的操作谓松,支持復(fù)雜的關(guān)聯(lián)查
    詢星压。
  • 通過支持事務(wù)(ACID 酸)來提供嚴格或者實時的數(shù)據(jù)一致性践剂。
關(guān)系型數(shù)據(jù)庫也存在一些限制:
  • 要實現(xiàn)擴容的話,只能向上(垂直)擴展娜膘,比如磁盤限制了數(shù)據(jù)的存儲逊脯,就要擴 大磁盤容量,通過堆硬件的方式竣贪,不支持動態(tài)的擴縮容军洼。水平擴容需要復(fù)雜的技術(shù)來實 現(xiàn),比如分庫分表演怎。
  • 表結(jié)構(gòu)修改困難匕争,因此存儲的數(shù)據(jù)格式也受到限制。
  • 在高并發(fā)和高數(shù)據(jù)量的情況下颤枪,我們的關(guān)系型數(shù)據(jù)庫通常會把數(shù)據(jù)持久化到磁盤汗捡, 基于磁盤的讀寫壓力比較大。

ACID畏纲,是指數(shù)據(jù)庫管理系統(tǒng)DBMS)在寫入或更新資料的過程中扇住,為保證事務(wù)(transaction)是正確可靠的,所必須具備的四個特性:原子性(atomicity盗胀,或稱不可分割性)艘蹋、一致性(consistency)、隔離性(isolation票灰,又稱獨立性)女阀、持久性(durability)。

非關(guān)系型數(shù)據(jù)庫

為了規(guī)避關(guān)系型數(shù)據(jù)庫的一系列問題屑迂,我們就有了非關(guān)系型的數(shù)據(jù)庫浸策,我們一般把 它叫做“non-relational”或者“Not Only SQL”。NoSQL 最開始是不提供 SQL 的數(shù) 據(jù)庫的意思惹盼,但是后來意思慢慢地發(fā)生了變化庸汗。

非關(guān)系型數(shù)據(jù)庫的特點:
  • 存儲非結(jié)構(gòu)化的數(shù)據(jù),比如文本手报、圖片蚯舱、音頻、視頻掩蛤。
  • 表與表之間沒有關(guān)聯(lián)枉昏,可擴展性強。
  • 保證數(shù)據(jù)的最終一致性揍鸟。遵循 BASE(堿)理論兄裂。 Basically Available(基本
    可用); Soft-state(軟狀態(tài)); Eventually Consistent(最終一致性)。
  • 支持海量數(shù)據(jù)的存儲和高并發(fā)的高效讀寫。
  • 支持分布式懦窘,能夠?qū)?shù)據(jù)進行分片存儲前翎,擴縮容簡單。

BASE理論:BASE是對CAP中一致性和可用性權(quán)衡的結(jié)果畅涂,其來源于對大規(guī)母刍互聯(lián)網(wǎng)分布式系統(tǒng)實踐的總結(jié),是基于CAP定律逐步演化而來午衰。其核心思想是即使無法做到強一致性立宜,但每個應(yīng)用都可以根據(jù)自身業(yè)務(wù)特點,才用適當(dāng)?shù)姆绞絹硎瓜到y(tǒng)打到最終一致性臊岸。

Redis的數(shù)據(jù)類型

  • String
  • Hash
  • Set
  • Zset
  • List
  • Hyperloglog
  • Geo
  • Streams

Redis的存儲結(jié)構(gòu)

Redis 是 KV 的數(shù)據(jù)庫橙数,它是通過 hashtable 實現(xiàn)的(我 們把這個叫做外層的哈希)。所以每個鍵值對都會有一個 dictEntry帅戒。里面指向了 key 和 value 的指針灯帮。next 指向下一個 dictEntry。

dictEntry
typedef struct dictEntry {
    void *key; /* key 關(guān)鍵字定義 */ 
    void *val;/* value 定義 */
    struct dictEntry *next;/* 指向下一個鍵值對節(jié)點 */
} dictEntry;

在每個dictEntry中逻住,key 是以SDS存儲钟哥,val則是以redisObject形式存儲的。而redisObject存儲實際值也是通過SDS存儲的瞎访。

redisObject
typedef struct redisObject {
    unsigned type:4;/*類型*/
    unsigned encoding:4;/*編碼*/
    // 對象最后一次被訪問的時間(用于進行LRU算法)
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    int refcount;/*引用計數(shù) 當(dāng) refcount 為 0 的時候腻贰,表示該對象已經(jīng)不被任何對象引用,則可以進行垃圾回收了*/
    void *ptr;/*指向?qū)嶋H值的指針*/
} robj;

SDS是真正存儲數(shù)據(jù)的結(jié)構(gòu)扒秸,使用字符數(shù)組 char[]實現(xiàn)播演。
SDS的特點:

  • 不用擔(dān)心內(nèi)存溢出問題,如果需要會對 SDS 進行擴容伴奥。
    sdsMakeRoomFor()方法則可以對已有的sds進行擴容。
  • 獲取字符串長度時間復(fù)雜度為 O(1)顶霞,因為定義了 len 屬性锣吼。
  • 判斷是否結(jié)束的標志是 len 屬性。
  • 通過“空間預(yù)分配”( sdsMakeRoomFor)和“惰性空間釋放”蓝厌,防止多次重分配內(nèi)存。
SDS
struct __attribute__ ((__packed__)) sdshdr8 {
   uint8_t len; /* 獲取字段長度 */
   uint8_t alloc;/*當(dāng)前字符數(shù)組總共分配的內(nèi)存大小 */
   unsigned char flags;/* 當(dāng)前字符數(shù)組的屬性拓提、用來標識到底是 sdshdr8 還是 sdshdr16 等 */
   char buf[];/* 字符串真正的值 */
redis 存儲結(jié)構(gòu)

String

存儲類型

可以用來存儲字符串、整數(shù)、浮點數(shù)寺惫。

存儲(實現(xiàn))原理

字符串類型的內(nèi)部編碼有三種:
1疹吃、int西雀,存儲 8 個字節(jié)的長整型(long,2^63-1)腔呜。
2再悼、embstr, 代表 embstr 格式的 SDS(Simple Dynamic String 簡單動態(tài)字符串),
存儲小于 44 個字節(jié)的字符串谤草。
3莺奸、raw,存儲大于 44 個字節(jié)的字符串嚎杨。

embstr和raw的區(qū)別

embstr 的使用只分配一次內(nèi)存空間(因為 RedisObject 和 SDS 是連續(xù)的)氧腰,而 raw 需要分配兩次內(nèi)存空間(分別為 RedisObject 和 SDS 分配空間)古拴。

embstr和raw 底層都是sdshdr結(jié)構(gòu)體,但是在創(chuàng)建的時候只調(diào)用了一次zmalloc紧帕,而RAW編碼則會調(diào)用兩次桅打。因此,EMBSTR是將redisObject和sdshdr存放到一塊連續(xù)的內(nèi)存空間中去了鹅搪。


createRawStringObject
createEmbstriStringObject

因此與 raw 相比丽柿,embstr 的好處在于創(chuàng)建時少分配一次空間,刪除時少釋放一次 空間馁筐,以及對象的所有數(shù)據(jù)連在一起坠非,尋找方便。
而 embstr 的壞處也很明顯赦抖,如果字符串的長度增加需要重新分配內(nèi)存時辅肾,整個RedisObject 和 SDS 都需要重新分配空間矫钓,因此 Redis 中的 embstr 實現(xiàn)為只讀。

Hash

存儲類型

Hash 本身也是一個 KV 的結(jié)構(gòu),外層的哈希(Redis KV 的實現(xiàn))只用到了 hashtable赵辕。當(dāng)存儲 hash 數(shù)據(jù)類型時概龄, 我們把它叫做內(nèi)層的哈希。內(nèi)層的哈希底層可以使用兩種數(shù)據(jù)結(jié)構(gòu)實現(xiàn):ziplist 和 hashTable蚕键。

ziplist 壓縮列表

Ziplist 是為了盡可能地節(jié)約內(nèi)存而設(shè)計的特殊編碼雙端鏈表锣光。它不存儲指向上一個鏈表節(jié)點和指向下一 個鏈表節(jié)點的指針铝耻,而是存儲上一個節(jié)點長度和當(dāng)前節(jié)點長度,通過犧牲部分讀寫性能频丘, 來換取高效的內(nèi)存空間利用率泡态,是一種時間換空間的思想兽赁。只用在字段個數(shù)少,字段值小的場景里面惊科。ziplist在內(nèi)存中是連續(xù)存儲的亮钦,利用內(nèi)存的連續(xù)性可以方便查找下一個節(jié)點蜂莉,不需要和鏈表一樣存儲下一個節(jié)點的屬性。

ziplist結(jié)構(gòu)
ziplist
ziplist2

zlbytes :是一個無符號整數(shù)窖张,保存著 ziplist 使用的內(nèi)存數(shù)量宿接,通過這個值辕录,程序可以直接對 ziplist 的內(nèi)存大小進行調(diào)整。
zltail:保存著到達列表中最后一個節(jié)點的偏移量,這個偏移量使得對表尾的 pop 操作可以在無須遍歷整個列表的情況下進行副女。
zllen: 保存著列表中的節(jié)點數(shù)量碑幅。

typedef struct zlentry {
unsigned int prevrawlensize; /* 上一個鏈表節(jié)點占用的長度 */
unsigned int prevrawlen;/* 存儲上一個鏈表節(jié)點的長度數(shù)值所需要的字節(jié)數(shù) */ 
unsigned int lensize; /* 存儲當(dāng)前鏈表節(jié)點長度數(shù)值所需要的字節(jié)數(shù) */
unsigned int len;/* 當(dāng)前鏈表節(jié)點占用的長度 */
unsigned int headersize;  /* 當(dāng)前鏈表節(jié)點的頭部大小(prevrawlensize + lensize)姻锁,即非數(shù)據(jù)域的大小 */ 
unsigned char encoding; /* 編碼方式 */
unsigned char *p;/* 壓縮鏈表以字符串的形式保存位隶,該指針指向當(dāng)前節(jié)點起始位置 */
} zlentry;

每個 ziplist 節(jié)點都包含兩部分信息:

  • 前置節(jié)點的長度,在程序從后向前遍歷時使用篮昧。
  • 當(dāng)前節(jié)點所保存的值的類型和長度笋妥。
Hashtable結(jié)構(gòu)(dict)

在 Redis 中,hashtable 被稱為字典(dictionary)酵颁,它是一個數(shù)組+鏈表的結(jié)構(gòu)躏惋。
Redis 的 KV 結(jié)構(gòu)是通過一個 dictEntry 來實現(xiàn)的,而hashtable 是對這個dictEntry進行多層的封裝距误。

dict--dictht--dictEntry
typedef struct dictEntry {
    void *key; /* key 關(guān)鍵字定義 */ 
    void *val;/* value 定義 */
    struct dictEntry *next;/* 指向下一個鍵值對節(jié)點 */
} dictEntry;

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

} dictht;

typedef struct dict {
    dictType *type; /* 字典類型 */
    void *privdata; /* 私有數(shù)據(jù) */
    dictht ht[2]; /* 一個字典有兩個哈希表 */
    long rehashidx; /* rehash 索引 */
    unsigned long iterators; /* 當(dāng)前正在使用的迭代器數(shù)量 */
} dict;
Hashtable

dictht 后面是 NULL 說明第二個 ht 還沒用到域仇。dictEntry*后面是 NULL 說明沒有 hash 到這個地址殉簸。dictEntry 后面是 NULL 說明沒有發(fā)生哈希沖突。

為什么dict字典中有兩個dictht結(jié)構(gòu)呢武鲁?

redis 的 hash 默認使用的是 ht[0]蝠检,ht[1]不會初始化和分配空間。
哈希表 dictht 是用鏈地址法來解決碰撞問題的饲梭。在這種情況下焰檩,哈希表的性能取決 于它的大小(size 屬性)和它所保存的節(jié)點的數(shù)量(used 屬性)之間的比率:

  • 比率在 1:1 時(一個哈希表 ht 只存儲一個節(jié)點 entry)析苫,哈希表的性能最好;
  • 如果節(jié)點數(shù)量比哈希表的大小要大很多的話(這個比例用 ratio 表示,5 表示平均
    一個 ht 存儲 5 個 entry)国旷,那么哈希表就會退化成多個鏈表茫死,哈希表本身的性能
    優(yōu)勢就不再存在峦萎。
    在這種情況下需要擴容忆首。Redis 里面的這種操作叫做 rehash被环。
    rehash 的步驟:
  1. 為字符 ht[1]哈希表分配空間蛤售,這個哈希表的空間大小取決于要執(zhí)行的操作妒潭,以
    及 ht[0]當(dāng)前包含的鍵值對的數(shù)量雳灾。
    擴展:ht[1]的大小為第一個大于等于 ht[0].used*2。
  2. 將所有的 ht[0]上的節(jié)點 rehash 到 ht[1]上炒嘲,重新計算 hash 值和索引匈庭,然后放
    入指定的位置。
  3. 當(dāng) ht[0]全部遷移到了 ht[1]之后夭拌,釋放 ht[0]的空間鸽扁,將 ht[1]設(shè)置為 ht[0]表镶骗,
    并創(chuàng)建新的 ht[1],為下次 rehash 做準備骡和。
    什么時候觸發(fā)擴容?:
    負載因子ratio = used / size即横,已使用節(jié)點與字典大小的比例
    dict_can_resize 為 1 并且 dict_force_resize_ratio 已使用節(jié)點數(shù)和字典大小之間的 比率超過 1:5裆赵,觸發(fā)擴容。

List

存儲(實現(xiàn))原理
quicklist

quicklist(快速列表)是 ziplist 和 linkedlist 的結(jié)合體页藻。

typedef struct quicklist {
    quicklistNode *head; /* 指向雙向列表的表頭 */ 
    quicklistNode *tail; /* 指向雙向列表的表尾 */
    unsigned long count;/* 所有的 ziplist 中一共存了多少個元素 */
    unsigned long len; /* 雙向鏈表的長度份帐,node 的數(shù)量 */
    int fill : 16;/* fill factor for individual nodes */
    unsigned int compress : 16; /* 壓縮深度,0:不壓縮; */
} quicklist;

quicklistNode 中的*zl 指向一個 ziplist畜挨,一個 ziplist 可以存放多個元素噩凹。

typedef struct quicklistNode {
struct quicklistNode *prev; /* 前一個節(jié)點 */
struct quicklistNode *next; /* 后一個節(jié)點 */
unsigned char *zl; /* 指向?qū)嶋H的 ziplist */
unsigned int sz; /* 當(dāng)前 ziplist 占用多少字節(jié) */
unsignedintcount:16;/* 當(dāng)前ziplist中存儲了多少個元素驮宴,占16bit(下同),最大65536個*/ unsigned int   encoding : 2; /* 是否采用了 LZF 壓縮算法壓縮節(jié)點修己,1:RAW 2:LZF */
unsigned int   container : 2; /* 2:ziplist睬愤,未來可能支持其他結(jié)構(gòu)存儲 */
unsigned int   recompress : 1; /* 當(dāng)前 ziplist 是不是已經(jīng)被解壓出來作臨時使用 */
unsigned int   attempted_compress : 1; /* 測試用 */
unsigned int   extra : 10; /* 預(yù)留給未來使用 */
} quicklistNode;
list

Set

存儲類型

String 類型的無序集合戴涝,最大存儲數(shù)量 2^32-1(40 億左右)钻蔑。

存儲(實現(xiàn))原理

Redis 用 intset 或 hashtable 存儲 set咪笑。如果元素都是整數(shù)類型,就用 inset 存儲映跟。 如果不是整數(shù)類型扬虚,就用 hashtable(數(shù)組+鏈表的存來儲結(jié)構(gòu))。

typedef struct intset {
    uint32_t encoding; // 編碼方式
    uint32_t length; //集合包含的元素數(shù)量
    int8_t contents[];// 保存元素的數(shù)組
} intset;

ZSet 有序集合

存儲類型

sorted set荸镊,有序的 set躬存,每個元素有個 score。 score 相同時宛逗,按照 key 的 ASCII 碼排序盾剩。

存儲原理

同時滿足以下條件時使用 ziplist 編碼:

  • 元素數(shù)量小于 128 個告私。
  • 所有 member 的長度都小于 64 字節(jié)。
    在 ziplist 的內(nèi)部,按照 score 排序遞增來存儲格嗅。插入的時候要移動之后的數(shù)據(jù)唠帝。
    超過閾值之后襟衰,使用 skiplist+dict 存儲。
    什么是 skiplist
    skiplist.png

    現(xiàn)在當(dāng)我們想查找數(shù)據(jù)的時候绍坝,可以先沿著這個新鏈表進行查找轩褐。當(dāng)碰到比待查數(shù) 據(jù)大的節(jié)點時玖详,再回到原來的鏈表中的下一層進行查找蟋座。比如,我們想查找 23巢墅,查找的路徑是先從最上層進行查找。
  1. 23首先和7比較作谚,再和19比較庵芭,比它們都大双吆,繼續(xù)向后比較。
  2. 但23和26比較的時候匾竿,比26要小蔚万,因此回到下面的鏈表(原鏈表)反璃,與22
    比較。
  3. 23比22要大斋攀,沿下面的指針繼續(xù)向后和26比較淳蔼。23比26小裁眯,說明待查數(shù)
    據(jù) 23 在原鏈表中不存在。
    在這個查找過程中俯画,由于新增加的指針艰垂,我們不再需要與鏈表中每個節(jié)點逐個進行
    比較了埋虹。需要比較的節(jié)點數(shù)大概只有原來的一半搔课。這就是跳躍表。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柬讨,一起剝皮案震驚了整個濱河市踩官,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颖系,老刑警劉巖辩越,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件黔攒,死亡現(xiàn)場離奇詭異督惰,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來称龙,“玉大人鲫尊,你說我怎么就攤上這事】任担” “怎么了搔驼?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵糯耍,是天一觀的道長。 經(jīng)常有香客問我革为,道長舵鳞,這世上最難降的妖魔是什么系任? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任俩滥,我火速辦了婚禮,結(jié)果婚禮上错忱,老公的妹妹穿的比我還像新娘以清。我一直安慰自己崎逃,他們只是感情好个绍,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布巴柿。 她就那樣靜靜地躺著,像睡著了一般凯旋。 火紅的嫁衣襯著肌膚如雪钉迷。 梳的紋絲不亂的頭發(fā)上糠聪,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天枷颊,我揣著相機與錄音该面,去河邊找鬼隔缀。 笑死傍菇,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的牵触。 我是一名探鬼主播揽思,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼钉汗,長吁一口氣:“原來是場噩夢啊……” “哼鲤屡!你這毒婦竟也來了酒来?” 一聲冷哼從身側(cè)響起卢未,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎堰汉,沒想到半個月后辽社,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡衡奥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年爹袁,在試婚紗的時候發(fā)現(xiàn)自己被綠了远荠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矮固。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡譬淳,死狀恐怖档址,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情邻梆,我是刑警寧澤守伸,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站浦妄,受9級特大地震影響尼摹,放射性物質(zhì)發(fā)生泄漏见芹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一蠢涝、第九天 我趴在偏房一處隱蔽的房頂上張望玄呛。 院中可真熱鬧,春花似錦和二、人聲如沸徘铝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惕它。三九已至,卻和暖如春废登,著一層夾襖步出監(jiān)牢的瞬間淹魄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工钳宪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留揭北,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓吏颖,卻偏偏與公主長得像搔体,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子半醉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

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

  • 轉(zhuǎn)載:可能是目前最詳細的Redis內(nèi)存模型及應(yīng)用解讀 Redis是目前最火爆的內(nèi)存數(shù)據(jù)庫之一疚俱,通過在內(nèi)存中讀寫數(shù)據(jù)...
    jwnba24閱讀 621評論 0 4
  • String 字符串 存儲類型 可以用來存儲字符串、整數(shù)缩多、浮點數(shù)呆奕。 操作命令 設(shè)置多個值(批量操作,原子性) 設(shè)置...
    WEIJAVA閱讀 1,298評論 0 4
  • 前言 Redis是目前最火爆的內(nèi)存數(shù)據(jù)庫之一衬吆,通過在內(nèi)存中讀寫數(shù)據(jù)梁钾,大大提高了讀寫速度,可以說Redis是實現(xiàn)網(wǎng)站...
    小陳阿飛閱讀 803評論 0 1
  • 最近一直很迷茫逊抡,事業(yè)到了瓶頸期姆泻。放棄,不甘心冒嫡;改變拇勃,找不到方向。 每天在家做整理孝凌,清理家里的東西方咆,丟掉用不上的東西...
    藍花楹A閱讀 387評論 0 1
  • 一位同事在松滋掛職,年初就有約定蟀架,要與部門同仁一道去看望他瓣赂,但總是未能成行榆骚。昨日借工作之便,趕早上路煌集,一行...
    姚爭杰閱讀 711評論 2 3