最詳細的Redis五種數據結構詳解(理論+實戰),建議收藏

2020-09-14 二手程式設計師

本文腦圖

前言

Redis是基與c語言編寫的開源非關係型內存資料庫,可以用作資料庫、緩存、消息種間件,這麼優秀的東西客定要一點一點的吃透它。

關於Redis的文章之前也寫過另篇,閱讀量和讀者的反映都還可以,其中第一篇是Redis的緩存三大問題[]。

第二篇是Redis的內存管理和淘汰策略[]。

這是關於Redis的第三篇文章,主要講解Redis的五種數據結構詳解,包括這五種的數據結構的底層原理實現。

理論肯定是要用於實踐的,因此最重要的還是實戰部分,也就是這裡還會講解五種數據結構的應用場景。

話不多說,我們直接進入主題,很多人都知道Redis的五種數據結構包括以下五種:

  1. String:字符串類型
  2. List:列表類型
  3. Set:無序集合類型
  4. ZSet:有序集合類型
  5. Hash:哈希表類型

但是作為一名優秀的程式設計師可能不能只停留在只會用這五種類型進行crud工作,還是的深入了解這五種數據結構的底層原理。

Redis核心對象

在Redis中有一個「核心的對象」叫做redisObject ,是用來表示所有的key和value的,用redisObject結構體來表示String、Hash、List、Set、ZSet五種數據類型。

redisObject的原始碼在redis.h中,使用c語言寫的,感興趣的可以自行查看,關於redisObject我這裡畫了一張圖,表示redisObject的結構如下所示:

閃瞎人的五顏六色圖

在redisObject中「type表示屬於哪種數據類型,encoding表示該數據的存儲方式」,也就是底層的實現的該數據類型的數據結構。因此這篇文章具體介紹的也是encoding對應的部分。

那麼encoding中的存儲類型又分別表示什麼意思呢?具體數據類型所表示的含義,如下圖所示:

圖片截圖出自《Redis設計與實現第二版》

可能看完這圖,還是覺得一臉懵。不慌,會進行五種數據結構的詳細介紹,這張圖只是讓你找到每種中數據結構對應的儲存類型有哪些,大概腦子裡有個印象。

舉一個簡單的例子,你在Redis中設置一個字符串key 234,然後查看這個字符串的存儲類型就會看到為int類型,非整數型的使用的是embstr儲存類型,具體操作如下圖所示:

String類型

String是Redis最基本的數據類型,上面的簡介中也說到Redis是用c語言開發的。但是Redis中的字符串和c語言中的字符串類型卻是有明顯的區別。

String類型的數據結構存儲方式有三種int、raw、embstr。那麼這三種存儲方式有什麼區別呢?

int

Redis中規定假如存儲的是「整數型值」,比如set num 123這樣的類型,就會使用 int的存儲方式進行存儲,在redisObject的「ptr屬性」中就會保存該值。



SDS

假如存儲的「字符串是一個字符串值並且長度大於32個字節」就會使用SDS(simple dynamic string)方式進行存儲,並且encoding設置為raw;若是「字符串長度小於等於32個字節」就會將encoding改為embstr來保存字符串。

SDS稱為「簡單動態字符串」,對於SDS中的定義在Redis的源碼中有的三個屬性int len、int free、char buf[]。

len保存了字符串的長度,free表示buf數組中未使用的字節數量,buf數組則是保存字符串的每一個字符元素。

因此當你在Redsi中存儲一個字符串Hello時,根據Redis的原始碼的描述可以畫出SDS的形式的redisObject結構圖如下圖所示:

SDS與c語言字符串對比

Redis使用SDS作為存儲字符串的類型肯定是有自己的優勢,SDS與c語言的字符串相比,SDS對c語言的字符串做了自己的設計和優化,具體優勢有以下幾點:

(1)c語言中的字符串並不會記錄自己的長度,因此「每次獲取字符串的長度都會遍歷得到,時間的複雜度是O(n)」,而Redis中獲取字符串只要讀取len的值就可,時間複雜度變為O(1)。

(2)「c語言」中兩個字符串拼接,若是沒有分配足夠長度的內存空間就「會出現緩衝區溢出的情況」;而「SDS」會先根據len屬性判斷空間是否滿足要求,若是空間不夠,就會進行相應的空間擴展,所以「不會出現緩衝區溢出的情況」

(3)SDS還提供「空間預分配」「惰性空間釋放」兩種策略。在為字符串分配空間時,分配的空間比實際要多,這樣就能「減少連續的執行字符串增長帶來內存重新分配的次數」

當字符串被縮短的時候,SDS也不會立即回收不適用的空間,而是通過free屬性將不使用的空間記錄下來,等後面使用的時候在釋放。

具體的空間預分配原則是:「當修改字符串後的長度len小於1MB,就會預分配和len一樣長度的空間,即len=free;若是len大於1MB,free分配的空間大小就為1MB」

(4)SDS是二進位安全的,除了可以儲存字符串以外還可以儲存二進位文件(如圖片、音頻,視頻等文件的二進位數據);而c語言中的字符串是以空字符串作為結束符,一些圖片中含有結束符,因此不是二進位安全的。

為了方便易懂,做了一個c語言的字符串和SDS進行對比的表格,如下所示:

c語言字符串SDS獲取長度的時間複雜度為O(n)獲取長度的時間複雜度為O(1)不是二進位安全的是二進位安全的只能保存字符串還可以保存二進位數據n次增長字符串必然會帶來n次的內存分配n次增長字符串內存分配的次數<=n

String類型應用

說到這裡我相信很多人可以說已經精通Redis的String類型了,但是純理論的精通,理論還是得應用實踐,上面說到String可以用來存儲圖片,現在就以圖片存儲作為案例實現。

(1)首先要把上傳得圖片進行編碼,這裡寫了一個工具類把圖片處理成了Base64得編碼形式,具體得實現代碼如下:

/** * 將圖片內容處理成Base64編碼格式 * @param file * @return */ public static String encodeImg(MultipartFile file) { byte[] imgBytes = null; try { imgBytes = file.getBytes(); } catch (IOException e) { e.printStackTrace(); } BASE64Encoder encoder = new BASE64Encoder(); return imgBytes==null?null:encoder.encode(imgBytes ); }複製代碼

(2)第二步就是把處理後的圖片字符串格式存儲進Redis中,實現得代碼如下所示:

/** * Redis存儲圖片 * @param file * @return */ public void uploadImageServiceImpl(MultipartFile image) { String imgId = UUID.randomUUID().toString(); String imgStr= ImageUtils.encodeImg(image); redisUtils.set(imgId , imgStr); // 後續操作可以把imgId存進資料庫對應的欄位,如果需要從redis中取出,只要獲取到這個欄位後從redis中取出即可。 }複製代碼

這樣就是實現了圖片得二進位存儲,當然String類型的數據結構得應用也還有常規計數:「統計微博數、統計粉絲數」等。

Hash類型

Hash對象的實現方式有兩種分別是ziplist、hashtable,其中hashtable的存儲方式key是String類型的,value也是以key value的形式進行存儲。

字典類型的底層就是hashtable實現的,明白了字典的底層實現原理也就是明白了hashtable的實現原理,hashtable的實現原理可以於HashMap的是底層原理相類比。

字典

兩者在新增時都會通過key計算出數組下標,不同的是計算法方式不同,HashMap中是以hash函數的方式,而hashtable中計算出hash值後,還要通過sizemask 屬性和哈希值再次得到數組下標。

我們知道hash表最大的問題就是hash衝突,為了解決hash衝突,假如hashtable中不同的key通過計算得到同一個index,就會形成單向鍊表(「鏈地址法」),如下圖所示:

rehash

在字典的底層實現中,value對象以每一個dictEntry的對象進行存儲,當hash表中的存放的鍵值對不斷的增加或者減少時,需要對hash表進行一個擴展或者收縮。

這裡就會和HashMap一樣也會就進行rehash操作,進行重新散列排布。從上圖中可以看到有ht[0]和ht[1]兩個對象,先來看看對象中的屬性是幹嘛用的。

在hash表結構定義中有四個屬性分別是dictEntry **table、unsigned long size、unsigned long sizemask、unsigned long used,分別表示的含義就是「哈希表數組、hash表大小、用於計算索引值,總是等於size-1、hash表中已有的節點數」

ht[0]是用來最開始存儲數據的,當要進行擴展或者收縮時,ht[0]的大小就決定了ht[1]的大小,ht[0]中的所有的鍵值對就會重新散列到ht[1]中。

擴展操作:ht[1]擴展的大小是比當前 ht[0].used 值的二倍大的第一個 2 的整數冪;收縮操作:ht[0].used 的第一個大於等於的 2 的整數冪。

當ht[0]上的所有的鍵值對都rehash到ht[1]中,會重新計算所有的數組下標值,當數據遷移完後ht[0]就會被釋放,然後將ht[1]改為ht[0],並新創建ht[1],為下一次的擴展和收縮做準備。

漸進式rehash

假如在rehash的過程中數據量非常大,Redis不是一次性把全部數據rehash成功,這樣會導致Redis對外服務停止,Redis內部為了處理這種情況採用「漸進式的rehash」

Redis將所有的rehash的操作分成多步進行,直到都rehash完成,具體的實現與對象中的rehashindex屬性相關,「若是rehashindex 表示為-1表示沒有rehash操作」

當rehash操作開始時會將該值改成0,在漸進式rehash的過程「更新、刪除、查詢會在ht[0]和ht[1]中都進行」,比如更新一個值先更新ht[0],然後再更新ht[1]。

而新增操作直接就新增到ht[1]表中,ht[0]不會新增任何的數據,這樣保證「ht[0]只減不增,直到最後的某一個時刻變成空表」,這樣rehash操作完成。

上面就是字典的底層hashtable的實現原理,說完了hashtable的實現原理,我們再來看看Hash數據結構的兩一種存儲方式「ziplist(壓縮列表)」

ziplist

壓縮列表(ziplist)是一組連續內存塊組成的順序的數據結構,壓縮列表能夠節省空間,壓縮列表中使用多個節點來存儲數據。

壓縮列表是列表鍵和哈希鍵底層實現的原理之一,「壓縮列表並不是以某種壓縮算法進行壓縮存儲數據,而是它表示一組連續的內存空間的使用,節省空間」,壓縮列表的內存結構圖如下:

壓縮列表中每一個節點表示的含義如下所示:

  1. zlbytes:4個字節的大小,記錄壓縮列表佔用內存的字節數。
  2. zltail:4個字節大小,記錄表為節點距離起始地址的偏移量,用於快速定位到尾節點的地址。
  3. zllen:2個字節的大小,記錄壓縮列表中的節點數。
  4. entry:表示列表中的每一個節點。
  5. zlend:表示壓縮列表的特殊結束符號&39;。

再壓縮列表中每一個entry節點又有三部分組成,包括previous_entry_ength、encoding、content。

  1. previous_entry_ength表示前一個節點entry的長度,可用於計算前一個節點的其實地址,因為他們的地址是連續的。
  2. encoding:這裡保存的是content的內容類型和長度。
  3. content:content保存的是每一個節點的內容。

說到這裡相信大家已經都hash這種數據結構已經非常了解,若是第一次接觸Redis五種基本數據結構的底層實現的話,建議多看幾遍,下面來說一說hash的應用場景。

應用場景

哈希表相對於String類型存儲信息更加直觀,擦歐總更加方便,經常會用來做用戶數據的管理,存儲用戶的信息。

hash也可以用作高並發場景下使用Redis生成唯一的id。下面我們就以這兩種場景用作案例編碼實現。

存儲用戶數據

第一個場景比如我們要儲存用戶信息,一般使用用戶的ID作為key值,保持唯一性,用戶的其他信息(地址、年齡、生日、電話號碼等)作為value值存儲。

若是傳統的實現就是將用戶的信息封裝成為一個對象,通過序列化存儲數據,當需要獲取用戶信息的時候,就會通過反序列化得到用戶信息。

但是這樣必然會造成序列化和反序列化的性能的開銷,並且若是只修改其中的一個屬性值,就需要把整個對象序列化出來,操作的動作太大,造成不必要的性能開銷。

若是使用Redis的hash來存儲用戶數據,就會將原來的value值又看成了一個k v形式的存儲容器,這樣就不會帶來序列化的性能開銷的問題。

分布式生成唯一ID

第二個場景就是生成分布式的唯一ID,這個場景下就是把redis封裝成了一個工具類進行實現,實現的代碼如下:

// offset表示的是id的遞增梯度值 public Long getId(String key,String hashKey,Long offset) throws BusinessException{ try { if (null == offset) { offset=1L; } // 生成唯一id return redisUtil.increment(key, hashKey, offset); } catch (Exception e) { //若是出現異常就是用uuid來生成唯一的id值 int randNo=UUID.randomUUID().toString().hashCode(); if (randNo < 0) { randNo=-randNo; } return Long.valueOf(String.format(&34;, randNo)); } }複製代碼

List類型

Redis中的列表在3.2之前的版本是使用ziplist和linkedlist進行實現的。在3.2之後的版本就是引入了quicklist。

ziplist壓縮列表上面已經講過了,我們來看看linkedlist和quicklist的結構是怎麼樣的。

linkedlist是一個雙向鍊表,它和普通的鍊表一樣都是由指向前後節點的指針。插入、修改、更新的時間複雜度尾O(1),但是查詢的時間複雜度確實O(n)。

linkedlist和quicklist的底層實現是採用鍊表進行實現,在c語言中並沒有內置的鍊表這種數據結構,Redis實現了自己的鍊表結構。

Redis中鍊表的特性:

  1. 每一個節點都有指向前一個節點和後一個節點的指針。
  2. 頭節點和尾節點的prev和next指針指向為null,所以鍊表是無環的。
  3. 鍊表有自己長度的信息,獲取長度的時間複雜度為O(1)。

Redis中List的實現比較簡單,下面我們就來看看它的應用場景。

應用場景

Redis中的列表可以實現「阻塞隊列」,結合lpush和brpop命令就可以實現。生產者使用lupsh從列表的左側插入元素,消費者使用brpop命令從隊列的右側獲取元素進行消費。

(1)首先配置redis的配置,為了方便我就直接放在application.yml配置文件中,實際中可以把redis的配置文件放在一個redis.properties文件單獨放置,具體配置如下:

spring redis: host: 127.0.0.1 port: 6379 password: user timeout: 0 database: 2 pool: max-active: 100 max-idle: 10 min-idle: 0 max-wait: 100000複製代碼

(2)第二步創建redis的配置類,叫做RedisConfig,並標註上@Configuration註解,表明它是一個配置類。

@Configurationpublic class RedisConfiguration {@Value(&34;)private int port;@Value(&34;)private int maxActive;@Value(&34;)private int minIdle;@Value(&34;)private int database;@Value(&34;)private int timeout;@Beanpublic JedisPoolConfig getRedisConfiguration(){JedisPoolConfig jedisPoolConfig= new JedisPoolConfig();jedisPoolConfig.setMaxTotal(maxActive);jedisPoolConfig.setMaxIdle(maxIdle);jedisPoolConfig.setMinIdle(minIdle);jedisPoolConfig.setMaxWaitMillis(maxWait);return jedisPoolConfig;}@Beanpublic JedisConnectionFactory getConnectionFactory() {JedisConnectionFactory factory = new JedisConnectionFactory();factory.setHostName(host);factory.setPort(port);factory.setPassword(password);factory.setDatabase(database);JedisPoolConfig jedisPoolConfig= getRedisConfiguration();factory.setPoolConfig(jedisPoolConfig);return factory;}複製代碼@Beanpublic RedisTemplate<?, ?> getRedisTemplate() {JedisConnectionFactory factory = getConnectionFactory();RedisTemplate<?, ?> redisTemplate = new StringRedisTemplate(factory);return redisTemplate;}}複製代碼

(3)第三步就是創建Redis的工具類RedisUtil,自從學了面向對象後,就喜歡把一些通用的東西拆成工具類,好像一個一個零件,需要的時候,就把它組裝起來。

@Componentpublic class RedisUtil {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/**存消息到消息隊列中@param key 鍵@param value 值@return*/public boolean lPushMessage(String key, Object value) {try {redisTemplate.opsForList().leftPush(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/**從消息隊列中彈出消息 - <rpop:非阻塞式>@param key 鍵@return*/public Object rPopMessage(String key) {try {return redisTemplate.opsForList().rightPop(key);} catch (Exception e) {e.printStackTrace();return null;}}/**複製代碼

  • 查看消息
  • @param key 鍵
  • @param start 開始
  • @param end 結束 0 到 -1代表所有值
  • 複製代碼
  • @return */ public List<Object> getMessage(String key, long start, long end) { try { return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) { e.printStackTrace(); return null; } } 複製代碼

這樣就完成了Redis消息隊列工具類的創建,在後面的代碼中就可以直接使用。

Set集合

Redis中列表和集合都可以用來存儲字符串,但是「Set是不可重複的集合,而List列表可以存儲相同的字符串」,Set集合是無序的這個和後面講的ZSet有序集合相對。

Set的底層實現是「ht和intset」,ht(哈希表)前面已經詳細了解過,下面我們來看看inset類型的存儲結構。

inset也叫做整數集合,用於保存整數值的數據結構類型,它可以保存int16_t、int32_t 或者int64_t 的整數值。

在整數集合中,有三個屬性值encoding、length、contents[],分別表示編碼方式、整數集合的長度、以及元素內容,length就是記錄contents裡面的大小。

在整數集合新增元素的時候,若是超出了原集合的長度大小,就會對集合進行升級,具體的升級過程如下:

  1. 首先擴展底層數組的大小,並且數組的類型為新元素的類型。
  2. 然後將原來的數組中的元素轉為新元素的類型,並放到擴展後數組對應的位置。
  3. 整數集合升級後就不會再降級,編碼會一直保持升級後的狀態。

應用場景

Set集合的應用場景可以用來「去重、抽獎、共同好友、二度好友」等業務類型。接下來模擬一個添加好友的案例實現:

@RequestMapping(value = &34;, method = RequestMethod.POST)public Long addFriend(User user, String friend) { String currentKey = null; // 判斷是否是當前用戶的好友 if (AppContext.getCurrentUser().getId().equals(user.getId)) { currentKey = user.getId.toString(); } //若是返回0則表示不是該用戶好友 return currentKey==null?0l:setOperations.add(currentKey, friend);}複製代碼

假如兩個用戶A和B都是用上上面的這個接口添加了很多的自己的好友,那麼有一個需求就是要實現獲取A和B的共同好友,那麼可以進行如下操作:

public Set intersectFriend(User userA, User userB) { return setOperations.intersect(userA.getId.toString(), userB.getId.toString());}複製代碼

舉一反三,還可以實現A用戶自己的好友,或者B用戶自己的好友等,都可以進行實現。

ZSet集合

ZSet是有序集合,從上面的圖中可以看到ZSet的底層實現是ziplist和skiplist實現的,ziplist上面已經詳細講過,這裡來講解skiplist的結構實現。

skiplist也叫做「跳躍表」,跳躍表是一種有序的數據結構,它通過每一個節點維持多個指向其它節點的指針,從而達到快速訪問的目的。

skiplist有如下幾個特點:

  1. 由很多層組成,由上到下節點數逐漸密集,最上層的節點最稀疏,跨度也最大。
  2. 每一層都是一個有序鍊表,至少包含兩個節點,頭節點和尾節點。
  3. 每一層的每一個每一個節點都含有指向同一層下一個節點和下一層同一個位置節點的指針。
  4. 如果一個節點在某一層出現,那麼該以下的所有鍊表同一個位置都會出現該節點。

具體實現的結構圖如下所示:



在跳躍表的結構中有head和tail表示指向頭節點和尾節點的指針,能夠快速的實現定位。level表示層數,len表示跳躍表的長度,BW表示後退指針,在從尾向前遍歷的時候使用。

BW下面還有兩個值分別表示分值(score)和成員對象(各個節點保存的成員對象)。

跳躍表的實現中,除了最底層的一層保存的是原始鍊表的完整數據,上層的節點數會越來越少,並且跨度會越來越大。

跳躍表的上面層就相當於索引層,都是為了找到最後的數據而服務的,數據量越大,跳表所體現的查詢的效率就越高,和平衡樹的查詢效率相差無幾。

應用場景

因為ZSet是有序的集合,因此ZSet在實現排序類型的業務是比較常見的,比如在首頁推薦10個最熱門的帖子,也就是閱讀量由高到低,排行榜的實現等業務。

下面就選用獲取排行榜前前10名的選手作為案例實現,實現的代碼如下所示:

@Autowiredprivate RedisTemplate redisTemplate; /** * 獲取前10排名 * @return */ public static List<levelVO > getZset(String key, long baseNum, LevelService levelService){ ZSetOperations<Serializable, Object> operations = redisTemplate.opsForZSet(); // 根據score分數值獲取前10名的數據 Set<ZSetOperations.TypedTuple<Object>> set = operations.reverseRangeWithScores(key,0,9); List<LevelVO> list= new ArrayList<LevelVO>(); int i=1; for (ZSetOperations.TypedTuple<Object> o:set){ int uid = (int) o.getValue(); LevelCache levelCache = levelService.getLevelCache(uid); LevelVO levelVO = levelCache.getLevelVO(); long score = (o.getScore().longValue() - baseNum + levelVO .getCtime())/CommonUtil.multiplier; levelVO .setScore(score); levelVO .setRank(i); list.add( levelVO ); i++; } return list; }複製代碼

以上的代碼實現大致邏輯就是根據score分數值獲取前10名的數據,然後封裝成lawyerVO對象的列表進行返回。

到這裡我們已經精通Redis的五種基本數據類型了,又可以去和面試官扯皮了,扯不過就跑路吧,或者這篇文章多看幾遍,相信對你總是有好處的。


來源:掘金推薦

相關焦點

  • 詳解Redis五種數據結構的底層原理
    1,redis有五種基本數據結構:string、hash、set、zset、list;底層redis是通過c語言來實現這w五種結構的,具體是如何實現的,我們具體看一下。2,SDS "simple dynamic string",redis中所有場景中出現的字符串,基本都是由SDS來實現的。
  • Redis底層數據結構詳解
    上一篇說了Redis有五種數據類型,今天就來聊一下Redis底層的數據結構是什麼樣的。是這一周看了《redis設計與實現》一書,現來總結一下。(看書總是非常煩躁的!))redis的list數據類型的底層實現之一,類似於java集合類LinkedArrayList。
  • redis的5種對象與8種數據結構之字符串對象(上)
    redis的每種對象都由對象結構(redisObject)與對應編碼的數據結構組合而成,redis支持5種對象類型,分別是字符串(string)、列表(list)、哈希(hash)、集合(set)、有序集合(zset),而每種對象類型至少對應兩種編碼方式,不同的編碼方式所對應的底層數據結構是不同的。
  • 圖解redis五種數據結構底層實現(動圖哦)
    redis有五種基本數據結構:字符串、hash、set、zset、list。但是你知道構成這五種結構的底層數據結構是怎樣的嗎? 今天我們來花費五分鐘的時間了解一下。 (目前redis版本為3.0.6)動態字符串SDSSDS是"simple dynamic string"的縮寫。
  • 一文回顧Redis五大對象(數據類型)
    Redis提供了五種主要的對象(數據類型)供開發者使用,它提供了強大且實用的功能。然而實際開發中有大多數的開發者僅簡單會用Redis String的Get與Set。這就好比降龍十八掌,你只學會了一掌。在真正實戰對敵之時不免略顯單薄!這篇文章我們將回顧Redis這五大對象,以便於我們能夠在實戰中真正做到遊刃有餘。
  • redis的5種對象與8種數據結構之字符串對象(下)
    本篇文章只對對象結構,1種對象——字符串對象。以及字符串對象所對應的兩種編碼——raw和embstr,進行了詳細介紹。表達一些本人的想法與看法,也希望更多朋友一起來討論,分享交流。下圖是一個字符串對象的結構圖,最左側是對象結構,中間跟右側合起來是raw編碼的SDS數據結構(sdshdr),示例圖:
  • 從零開始手寫 redis(八)樸素 LRU 淘汰算法性能優化
    java從零手寫實現redis(三)redis expire 過期原理java從零手寫實現redis(三)內存數據如何重啟不丟失?java從零手寫實現redis(四)添加監聽器java從零手寫實現redis(五)過期策略的另一種實現思路java從零手寫實現redis(六)AOF 持久化原理詳解及實現我們前面簡單實現了 redis 的幾個特性,java從零手寫實現redis(一)如何實現固定大小的緩存? 中實現了先進先出的驅除策略。
  • Redis之父走了,但Redis可涼不了
    )」。為了幫大家快速建立Redis的體系,分享一套Redis實戰教程【Redis6.0全套實戰教程】課程目錄1 redis的五種數據結構講解2 string結構與應用場景講解3 hash結構與應用場景講解4 list結構與應用場景講解5 set
  • 從零開始手寫 redis(五)過期策略的另一種實現思路
    前言java從零手寫實現redis(一)如何實現固定大小的緩存?java從零手寫實現redis(三)redis expire 過期原理java從零手寫實現redis(三)內存數據如何重啟不丟失?java從零手寫實現redis(四)添加監聽器前面實現了 redis 的幾個基本特性,其中在 expire 過期原理時,提到了另外一種實現方式。這裡將其記錄下來,可以拓展一下自己的思路。
  • 我拿到了阿里大牛(清華畢業生)總結的大數據學習路線+視頻教程
    如果想深入研究的話,Google的GFS論文也是一定要讀的([url=]https://static.googleusercontent.com/media/research.google.com/en//archive/gfs-sosp2003.pdf[/url])。當然開源世界中還有很多的分布式存儲,國內阿里巴巴的OceanBase也是很優秀的一個。
  • 從零開始手寫 redis(十)緩存淘汰LFU算法詳解
    java從零手寫實現redis(三)redis expire 過期原理java從零手寫實現redis(三)內存數據如何重啟不丟失?java從零手寫實現redis(四)添加監聽器java從零手寫實現redis(五)過期策略的另一種實現思路java從零手寫實現redis(六)AOF 持久化原理詳解及實現java從零手寫實現redis(七)LRU 緩存淘汰策略詳解java從零開始手寫 redis(八)樸素 LRU 淘汰算法性能優化本節一起來學習下另一個常用的緩存淘汰算法
  • redis—底層數據結構詳解
    三、ListList數據結構:其底層的數據結構實現是 雙向鍊表 + 壓縮鍊表(ziplist),通過將每個壓縮表用雙向鍊表的方式連接起來,來節省內存空間。ziplist是一個經過特殊編碼的雙向鍊表,它的設計目標就是為了提高存儲效率,節省內存空間。ziplist可以用於存儲字符串或整數,其中整數是按真正的二進位表示進行編碼的,而不是編碼成字符串序列。
  • Django實戰016:django中使用redis詳解
    ,這裡我們主要設置LOCATION和OPTIONS即可,其中host是redis主機ip,port當然是redis的埠了(默認6379),database則是redis中的資料庫。redis默認提供了16個資料庫,使用的時候可以自行指定(默認為第一個)。OPTIONS中可以添加redis的配置信息,如redis的最大連接數和密碼等。
  • redis cluster搭建實踐(非常詳細,值得收藏)
    redis集群採用P2P模式,是完全去中心化的,不存在中心節點或者代理節點;redis集群是沒有統一的入口的,客戶端(client)連接集群的時候連接集群中的任意節點(node)即可,集群內部的節點是相互通信的(PING-PONG機制),每個節點都是一個redis實例;為了實現集群的高可用,即判斷節點是否健康(能否正常使用),redis-cluster
  • Django實戰017:django+vue+redis項目
    最近寫了一個小項目,用django+vue+redis實現的echarts圖表。主要功能是利用redis豐富的數據類型和超高讀寫性能來存儲數據,這樣可以快速響應用戶需求並支撐海量的數據和流量。左邊提供了一個數據輸入框(可以收起),右邊提供了2個不同形式的圖表來展示redis中的數據。頁面載入時自動顯示reids中的數據,左邊參數提交數據之後立馬刷新右邊的圖表。
  • 從零手寫緩存框架(13)redis漸進式rehash詳解
    沒有讀過也沒有關係,可以花時間閱讀下 從零開始手寫 redis(13) HashMap源碼詳解 簡單了解下整個過程即可。(1)查詢一個信息這個類似於我們的資料庫信息等遷移,先查詢一個庫,沒有的話,再去查詢另一個庫。ht[0] 中沒找到,我們去 ht[1] 中查詢即可。(2)新數據怎麼辦?這個和數據遷移一樣的道理。
  • 建議收藏!清華大佬親授JVM虛擬機中的垃圾回收理論與實戰筆記
    今天要分享的是JVM虛擬機生產環境中的垃圾回收方法理論與動手實戰筆記,全是乾貨哦!GC的基礎知識什麼是垃圾如何定位垃圾常見的垃圾回收算法JVM內存分代模型(用於分代垃圾回收算法)常見的垃圾回收器根據需求進行JVM規劃和預調優優化運行JVM運行環境(慢,卡頓)解決JVM運行過程中出現的各種問題(OOM)調優,從規劃開始* 調優,從業務場景開始,沒有業務場景的調優都是耍流氓* 無監控(壓力測試,能看到結果),不調優
  • Redis未授權訪問詳解(轉載)
    這篇文章是freebuf安全之光專欄的文章,寫得非常詳細和深入,分享給大家。和Memcached類似,它支持存儲的value 類型相對更多,包括 string(字符串)、list ( 鍊表)、 set(集合)、zset(sorted set – 有序集合)和 hash(哈希類型)。這些數據類型都支持push/pop 、 add/remove 及取交集併集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上, redis支持各種不同方式的排序。
  • SpringBoot實戰(四):整合Redis
    【前言】 最近自己在整理過去搭建過的框架,將用到的各個組件進行了梳理並融入自己新建的項目中(https://github.com/dangnianchuntian/springboot),一是對過去項目的整理;二是在整理的過程中查漏補缺;三是以後可以拿過去就用;
  • redis的五種數據結構和應用場景:微博微信點讚+加購物車等
    Redis五種數據結構如下:>1.String 字符串類型是redis中最基本的數據類型,一個key對應一個value。String類型是二進位安全的,意思是 redis 的 string 可以包含任何數據。如數字,字符串,jpg圖片或者序列化的對象。