# Redis 設計與實現(第一版)
>[warning]
> 你正在閱讀的是《Redis 設計與實現》第一版(舊版),請訪問 [RedisBook.com](http://RedisBook.com/) ,查看關注 Redis 3.0 、包含更多新內容的新版《Redis 設計與實現》。
本書的目標是以簡明易懂的方式講解 Redis 的內部運行機制,通過閱讀本書,你可以了解到 Redis 從數據結構到服務器構造在內的幾乎所有知識。
[TOC=2,3]
[](#)
為了保證內容的簡潔性,本書會盡量以高抽象層次的角度來觀察 Redis ,并將代碼的細節留給讀者自己去考究。
如果讀者只是對 Redis 的內部運作機制感興趣,但并不想深入代碼,那么只閱讀本書就足夠了。
另一方面,對于需要深入研究 Redis 代碼的讀者,本書附帶了一份 [帶有詳細注釋的 Redis 2.6 源代碼](https://github.com/huangz1990/annotated_redis_source) ,可以配合本書一并使用。
## 第一部分:內部數據結構
Redis 和其他很多 key-value 數據庫的不同之處在于,Redis 不僅支持簡單的字符串鍵值對,它還提供了一系列數據結構類型值,比如列表、哈希、集合和有序集,并在這些數據結構類型上定義了一套強大的 API 。
通過對不同類型的值進行操作,Redis 可以很輕易地完成其他只支持字符串鍵值對的 key-value 數據庫很難(或者無法)完成的任務。
在 Redis 的內部,數據結構類型值由高效的數據結構和算法進行支持,并且在 Redis 自身的構建當中,也大量用到了這些數據結構。
這一部分將對 Redis 內存所使用的數據結構和算法進行介紹。
- [簡單動態字符串](#)
- [sds 的用途](#)
- [Redis 中的字符串](#)
- [優化追加操作](#)
- [sds 模塊的 API](#)
- [小結](#)
- [雙端鏈表](#)
- [雙端鏈表的應用](#)
- [雙端鏈表的實現](#)
- [迭代器](#)
- [小結](#)
- [字典](#)
- [字典的應用](#)
- [字典的實現](#)
- [創建新字典](#)
- [添加鍵值對到字典](#)
- [添加新元素到空白字典](#)
- [添加新鍵值對時發生碰撞處理](#)
- [添加新鍵值對時觸發了 rehash 操作](#)
- [Rehash 執行過程](#)
- [漸進式 rehash](#)
- [字典的收縮](#)
- [字典其他操作](#)
- [字典的迭代](#)
- [小結](#)
- [跳躍表](#)
- [跳躍表的實現](#)
- [跳躍表的應用](#)
- [小結](#)
## 第二部分:內存映射數據結構
雖然內部數據結構非常強大,但是創建一系列完整的數據結構本身也是一件相當耗費內存的工作,當一個對象包含的元素數量并不多,或者元素本身的體積并不大時,使用代價高昂的內部數據結構并不是最好的辦法。
為了解決這一問題,Redis 在條件允許的情況下,會使用內存映射數據結構來代替內部數據結構。
內存映射數據結構是一系列經過特殊編碼的字節序列,創建它們所消耗的內存通常比作用類似的內部數據結構要少得多,如果使用得當,內存映射數據結構可以為用戶節省大量的內存。
不過,因為內存映射數據結構的編碼和操作方式要比內部數據結構要復雜得多,所以內存映射數據結構所占用的 CPU 時間會比作用類似的內部數據結構要多。
這一部分將對 Redis 目前正在使用的兩種內存映射數據結構進行介紹。
- [整數集合](#)
- [整數集合的應用](#)
- [數據結構和主要操作](#)
- [intset 運行實例](#)
- [升級](#)
- [關于升級](#)
- [關于元素移動](#)
- [其他操作](#)
- [小結](#)
- [壓縮列表](#)
- [ziplist 的構成](#)
- [節點的構成](#)
- [創建新 ziplist](#)
- [將節點添加到末端](#)
- [將節點添加到某個/某些節點的前面](#)
- [刪除節點](#)
- [遍歷](#)
- [查找元素、根據值定位節點](#)
- [小結](#)
## 第三部分:Redis 數據類型
既然 Redis 的鍵值對可以保存不同類型的值,那么很自然就需要對鍵值的類型進行檢查以及多態處理。
為了讓基于類型的操作更加方便地執行,Redis 創建了自己的類型系統。
在這一部分,我們將對 Redis 所使用的對象系統進行了解,并分別觀察字符串、哈希表、列表、集合和有序集類型的底層實現。
- [對象處理機制](#)
- [redisObject 數據結構,以及 Redis 的數據類型](#)
- [命令的類型檢查和多態](#)
- [對象共享](#)
- [引用計數以及對象的銷毀](#)
- [小結](#)
- [字符串](#)
- [字符串編碼](#)
- [編碼的選擇](#)
- [字符串命令的實現](#)
- [哈希表](#)
- [字典編碼的哈希表](#)
- [壓縮列表編碼的哈希表](#)
- [編碼的選擇](#)
- [哈希命令的實現](#)
- [列表](#)
- [編碼的選擇](#)
- [列表命令的實現](#)
- [阻塞的條件](#)
- [阻塞](#)
- [阻塞因 LPUSH 、 RPUSH 、 LINSERT 等添加命令而被取消](#)
- [先阻塞先服務(FBFS)策略](#)
- [阻塞因超過最大等待時間而被取消](#)
- [集合](#)
- [編碼的選擇](#)
- [編碼的切換](#)
- [字典編碼的集合](#)
- [集合命令的實現](#)
- [求交集算法](#)
- [求并集算法](#)
- [求差集算法](#)
- [有序集](#)
- [編碼的選擇](#)
- [編碼的轉換](#)
- [ZIPLIST 編碼的有序集](#)
- [SKIPLIST 編碼的有序集](#)
## 第四部分:功能的實現
除了針對單個鍵值對的操作外,Redis 還提供了一些同時對多個鍵值對進行處理的功能,比如事務和 Lua 腳本。
另外,一些輔助性的功能,比如慢查詢,以及一些和數據庫無關的功能,比如訂閱與發布,我們也會經常用到。
通過理解這些功能的底層實現,我們可以更有效地使用它們。
這一部分將對這些功能進行介紹。
- [事務](#)
- [事務](#)
- [開始事務](#)
- [命令入隊](#)
- [執行事務](#)
- [在事務和非事務狀態下執行命令](#)
- [事務狀態下的 DISCARD 、 MULTI 和 WATCH 命令](#)
- [帶 WATCH 的事務](#)
- [WATCH 命令的實現](#)
- [WATCH 的觸發](#)
- [事務的 ACID 性質](#)
- [小結](#)
- [訂閱與發布](#)
- [頻道的訂閱與信息發送](#)
- [訂閱頻道](#)
- [發送信息到頻道](#)
- [退訂頻道](#)
- [模式的訂閱與信息發送](#)
- [訂閱模式](#)
- [發送信息到模式](#)
- [退訂模式](#)
- [小結](#)
- [Lua 腳本](#)
- [初始化 Lua 環境](#)
- [腳本的安全性](#)
- [腳本的執行](#)
- [EVAL 命令的實現](#)
- [EVALSHA 命令的實現](#)
- [小結](#)
- [慢查詢日志](#)
- [相關數據結構](#)
- [慢查詢日志的記錄](#)
- [慢查詢日志的操作](#)
- [小結](#)
## 第五部分:內部運作機制
以下章節將對 Redis 最底層也最隱蔽的模塊進行探討:
- Redis 如何表示一個數據庫?數據庫操作是如何實現的?
- Redis 如何進行持久化? RDB 模式和 AOF 模式有什么區別?
- Redis 如何處理輸入命令?它又是如何將輸出返回給客戶端的?
- Redis 服務器如何初始化?傳入服務器的命令又是以什么方法執行的?
以上的這些問題,都是這一部分要解答的。
- [數據庫](#)
- [數據庫的結構](#)
- [數據庫的切換](#)
- [數據庫鍵空間](#)
- [鍵空間的操作](#)
- [鍵的過期時間](#)
- [過期時間的保存](#)
- [設置生存時間](#)
- [過期鍵的判定](#)
- [過期鍵的清除](#)
- [過期鍵的惰性刪除策略](#)
- [過期鍵的定期刪除策略](#)
- [過期鍵對 AOF 、RDB 和復制的影響](#)
- [數據庫空間的收縮和擴展](#)
- [小結](#)
- [RDB](#)
- [保存](#)
- [SAVE 、 BGSAVE 、 AOF 寫入和 BGREWRITEAOF](#)
- [載入](#)
- [RDB 文件結構](#)
- [小結](#)
- [AOF](#)
- [AOF 命令同步](#)
- [命令傳播](#)
- [緩存追加](#)
- [文件寫入和保存](#)
- [AOF 保存模式](#)
- [AOF 保存模式對性能和安全性的影響](#)
- [AOF 文件的讀取和數據還原](#)
- [AOF 重寫](#)
- [AOF 重寫的實現](#)
- [AOF 后臺重寫](#)
- [AOF 后臺重寫的觸發條件](#)
- [小結](#)
- [事件](#)
- [文件事件](#)
- [時間事件](#)
- [時間事件應用實例:服務器常規操作](#)
- [事件的執行與調度](#)
- [小結](#)
- [服務器與客戶端](#)
- [初始化服務器](#)
- [客戶端連接到服務器](#)
- [命令的請求、處理和結果返回](#)
- [命令請求實例: SET 的執行過程](#)
- [小結](#)
## 關于
本書由 [huangz](http://huangz.me/) 編寫。
我在研究 Redis 源碼并創作本書的過程中獲得了極大的快樂,希望你在閱讀本書時也能有同感。
評論、問題、意見或建議都可以發表在本書自帶的 disqus 論壇里,也可以通過 [豆瓣](http://www.douban.com/people/i_m_huangz/) 、 [微博](http://weibo.com/huangz1990) 或 [Twitter](https://twitter.com/huangz1990) 聯系我,我會盡可能地回復。
要獲得本書的最新動態,請關注 [redisbook](https://github.com/huangz1990/redisbook) 項目。
要了解編寫本書時用到的工具(源碼管理、文檔的生成和托管、圖片生成,等等),請閱讀 [這篇文章](http://blog.huangz.me/diary/2013/tools-for-writing-redisbook.html) 。
下載本書離線版本: [pdf 格式](https://github.com/huangz1990/redisbook/raw/master/pdf/redisbook.pdf) 或 [html 格式](https://media.readthedocs.org/htmlzip/redisbook/latest/redisbook.zip) 。
## 通過捐款支持本書
如果你喜歡這本《Redis 設計與實現》的話,可以通過捐款的方式,支持作者繼續更新本書:比如為本書修補漏洞、添加更多有趣的章節,或者發行有更多更棒內容的下一版,等等。
你可以通過使用[支付寶錢包](https://mobile.alipay.com/main/download.htm?action=mobileClient) 掃描以下二維碼來進行捐款,或者通過向支付寶帳號 [huangz1990@gmail.com](#) 轉帳來進行捐款。
