1. 程式人生 > >玩轉redis —— 第4篇 雜湊物件型別

玩轉redis —— 第4篇 雜湊物件型別

redis中的hash也是我們使用中的高頻資料結構, 它的構造基本上和程式語言中的HashTableDictionary大同小異, 如果大家往後有什麼邏
輯需要用
Dictionary存放的話, 可以根據場景優先考慮下redis哦, 起碼可以裝裝逼嘛, 現在我預設你已經有裝逼的衝動了, 開啟redis手冊, 看看有哪些我們
用得到
的裝逼方法。

一: 常用方法

只要是一個數據結構,最基礎的永遠是CURD,redis中的insert和update,永遠只會需要set來替代,比如下面的Hset,如下圖:


前面幾篇文章我都沒有挑選一個方法仔細講解, 其實也沒什麼好講解的, 就好似C#中的一個類的一個方法而已, 知道傳遞一些啥引數就

OK了, 就比
如要
說的
HSet, 它的格式如下:

HSET key field value

將雜湊表 key 中的域field 的值設為 value

如果 key 不存在,一個新的雜湊表被建立並進行HSET 操作。

如果域 field 已經存在於雜湊表中,舊值將被覆蓋。

可用版本:
>= 2.0.0
時間複雜度:
O(1)
返回值:
如果 field 是雜湊表中的一個新建域,並且值設定成功,返回1 如果雜湊表中域 field 已經存在且舊值已被新值覆蓋,返回 0
redis> HSET website google "www.g.cn"       # 設定一個新域
(integer) 1

redis> HSET website google "www.google.com" # 覆蓋一箇舊域
(integer) 0
接下來我在CentOS裡面操作一下
前提是連線上redis

在資料夾中的執行:src/redis-cli


或許有人看了上面的console有一點疑惑, 那就是前面有幾個引數, 比如personname啦, 然後才是value, 如果你看了第一篇的話, 你大概就明
白了,
其實在
redis的這個層面, 它永遠只有一個鍵, 一個值, 這個鍵永遠都是字串物件, 也就是SDS物件, 而值的種類就多了, 有字串物件, 有佇列
物件,
還有這篇的
hash物件, 往後的有序集合物件等等, 如果你還不明白的話, 轉化為C#語言就是。


呼叫方法就是這麼的簡單, 關鍵在於時不時的需要你看一看手冊, 其實最重要的是瞭解下它在

redis原始碼中的原理就好了。

二: 探索原理
hash的原始碼是在dict.h原始碼裡面, 列舉如下:

typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
typedef struct dictType {
unsigned int (*hashFunction)(const void *key);
void *(*keyDup)(void *privdata, const void *key);
void *(*valDup)(void *privdata, const void *obj);
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
void (*keyDestructor)(void *privdata, void *key);
void (*valDestructor)(void *privdata, void *obj);
} dictType;
/* This is our hash table structure. Every dictionary has two of this as we
* implement incremental rehashing, for the old to the new 0. */
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
int iterators; /* number of iterators currently running */
} dict;
/* If safe is set to 1 this is a safe iterator, that means, you can call
* dictAdd, dictFind, and other functions against the dictionary even while
* iterating. Otherwise it is a non safe iterator, and only dictNext()
* should be called while iterating. */
typedef struct dictIterator {
dict *d;
long index;
int table, safe;
dictEntry *entry, *nextEntry;
/* unsafe iterator fingerprint for misuse detection. */
long long fingerprint;
} dictIterator;

上面就是我們使用hash的原始碼資料結構, 接下來我來擼一擼其中的邏輯關係。

1. dict結構

typedef struct dict {
2 dictType *type;
3 void *privdata;
4 dictht ht[2];
5 long rehashidx; /* rehashing not in progress if rehashidx == -1 */
6 int iterators; /* number of iterators currently running */
7 } dict;

這個結構是hash的真正的底層資料結構, 可以看到其中有5個屬性。
<1> dictType *type
可以看到它的型別是dictType, 從上面你也可以看到, 它是有列舉結構定義的, 如下:
typedef struct dictType {
2 unsigned int (*hashFunction)(const void *key);
3 void *(*keyDup)(void *privdata, const void *key);
4 void *(*valDup)(void *privdata, const void *obj);
5 int (*keyCompare)(void *privdata, const void *key1, const void *key2);
6 void (*keyDestructor)(void *privdata, void *key);
7 void (*valDestructor)(void *privdata, void *obj);
8 } dictType;

從上面這個資料結構中你可以看到裡面都是一些方法, 但是有一個非常重要的方法, 那就是第一個hashFunction, 可以看到它就是計算hash
的,
C#中的dictionary中求hash值一樣一樣的。

<2> dictht ht[2]
你可能會疑問, 為什麼這個屬性是2個大小的陣列呢, 其實正真使用的是ht[0], 而ht[1]是用於擴容hash表時的暫存陣列, 這一點也很奇葩,
同時也很精妙,
redis為什麼會這麼做呢? ? ? 仔細想想你可能會明白, 擴容有兩種方法, 要麼一次性擴容, 要麼漸進性擴容, 後面這種擴容是什
麼意思呢? 就是我在擴容的同時不影響前端的
CURD, 我慢慢的把資料從ht[0]轉移到ht[1]中, 同時rehashindex來記錄轉移的情況, 當全部轉移
完成之後, 將
ht[1]改成ht[0]使用, 就這麼簡單。
2. dicth結構

typedef struct dictht {
2 dictEntry **table;
3 unsigned long size;
4 unsigned long sizemask;
5 unsigned long used;
6 } dictht;

<1> dictEntry **table;
從上面這個結構體中, 你可以看到一個非常重要的屬性: dictEntry **table, 其中table是一個數組, 陣列型別是dictEntry, 既然是一個
陣列,
那後面的三個屬性就好理解了,
size是陣列的大小,sizemask和陣列求模有關,used記錄陣列中已使用的大小, 現在我們把注意力放在dictEntry
這 個
陣列實體型別上面。
3. dictEntry結構
typedef struct dictEntry {2 void *key;
3 union {
4 void *val;
5 uint64_t u64;
6 int64_t s64;
7 double d;
8 } v;
9 struct dictEntry *next;
10 } dictEntry;

從這個資料結構上面你可以看到有三個大屬性。
第一個就是:
*key: 它就是hash表中的key
第二個就是:
union*val就是hashvalue
第三個就是:
*next就是為了防止hash衝突採用的掛鏈手段。
這個原理和
C#中的Dictionary還是一樣一樣的。

不知道你看懂了沒有, 如果總結上面描述的話, 我可以畫出如下的hash結構圖。

相關推薦

redis —— 4 物件型別

redis中的hash也是我們使用中的高頻資料結構, 它的構造基本上和程式語言中的HashTable,Dictionary大同小異, 如果大家往後有什麼邏 輯需要用Dictionary存放的話, 可

15天redis —— 無敵的列表型別

 據說60%的人使用redis看重的是redis中的list型別,那這個list有什麼用呢???不用我說大家都明白,做佇列使用唄,為什麼用它呢,很簡單唄, 因為有了它我就不需要專門的MQ產品啦,比如說RabbitMQ,ActiveMQ等等。。。對吧。 一:實戰      先

15天redis —— 集合物件型別

1 /* 2 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> 3 * All rights reserved. 4 * 5 * Redistribution and

15天redis —— 對快照模式的深入分析

      我們知道redis是帶有持久化這個能力了,那到底持久化成到哪裡,持久化成啥樣呢???這篇我們一起來尋求答案。 一:快照模式   或許在用Redis之初的時候,就聽說過redis有兩種持久化模式,第一種是SNAPSHOTTING模式,還是一種是AOF模式,而且在實

15天redis —— 釋出/訂閱模式

本系列已經過半了,這一篇我們來看看redis好玩的釋出訂閱模式,其實在很多的MQ產品中都存在這樣的一個模式,我們常聽到的一個例子 就是郵件訂閱的場景,什麼意思呢,也就是說100個人訂閱了你的部落格,如果博主發表了文章,那麼100個人就會同時收到通知郵件,除了這個 場景還能找到

redis 4 Redis資料型別----string

  命令 賦值 語法:SET key value 127.0.0.1:6379> set test 123 OK 取值 語法:GET key 127.0.0.1:6379> ge

支撐微博億級社交平臺,小白也能Redis叢集(原理)

Redis作為一款效能優異的記憶體資料庫,支撐著微博億級社交平臺,也成為很多網際網路公司的標配。這裡將以Redis Cluster叢集為核心,基於最新的Redis5版本,從原理再到實戰,玩轉Redis叢集 常見Redis叢集方案 在介紹Redis Cluster叢集方案之前,為了方便對比,先簡單瞭解一下業

支撐微博億級社交平臺,小白也能Redis叢集(實戰)

上篇文章《支撐微博億級社交平臺,小白也能玩轉Redis叢集(原理篇)》介紹了Redis叢集相關原理,這篇文章將介紹Redis Cluster叢集的搭建、配置,運維、擴容等具體操作 叢集搭建 2018年10月 Redis 釋出了穩定版本的 5.0 版本,推出了各種新特性,其中一點是叢集管理工具從基於Ruby

《Python學習手冊》學習筆記(4)之4章介紹Python物件型別(關鍵詞:程式語言/Python)

第4章 介紹Python物件型別 寫在開頭的讀者筆記 值得一讀的小節 1.“為什麼使用內建型別” - “Python的核心資料型別”,主要學到了: Python是強型別語言,你只能對一個物件進行適合該型別的有效操作。 一旦建立了一個物件,它就和

】Node深入淺出 章節總結(九章 — 程序) 完結

為了看黑色背景,就轉了過來,眼睛看白色螢幕實在受不鳥! 本章總結將結合個人搭建 egg 引入公司的一些實踐來進行總結,希望能讓大家瞭解到程序管理和叢集分發的重要性。 閱讀完本章你應該理解以下幾點: 為什麼要使用多程序架構啟動服務; 經典的 Master-Worker

15天redis —— 第一 開始入手

    雙十一終於還是過去了,我負責的mongodb由於做了副本集,最終還是挺過去了,同事負責的redis,還是遺憾的在早上8點左右宕機了,然後大家就是馬不停 蹄的趕往公司解決問題,因為我對redis也不是很瞭解,工作上使用redis的時候也是應付的找找資料,所以沒有從系統層

redis持久化,阿里架構師給你來一方案介紹

一、基本介紹 本次演示使用的redis版本是3.2.100,作業系統是win10。 redis支援兩種持久化方案,RDB和AOF

老司機帶你面試(4):Redis 高可用之哨兵模式

![](https://cdn.geekdigging.com/Interview/mianshi_header_1.jpg) ## 前文回顧 建議前面文章沒看過的同學先看下前面的文章: [「老司機帶你玩轉面試(1):快取中介軟體 Redis 基礎知識以及資料持久化」](https://www.geek

4-JAVA基礎

關鍵字 continue 表達式 java基礎 布爾 第4篇-JAVA基礎每篇一句 :世界上本沒有完美,但是我們從未放棄追求完美初學心得: 樂於揮霍的時間,都不能算作浪費(筆者:JEEP/711)[JAVA筆記 | 時間:2017-04-01| JAVA基礎 Ⅳ]程序運行流程(1) 順序結

HTTP跳HTTPS

p s write 測試 直接 list 域名跳轉 mil /var/ star 一、實現訪問http跳轉https訪問(http的單向認證)①修改配置文件# vim /etc/httpd/conf/httpd.conf 增加在文件最後 <IfModule s

Python學習【4】:元組魔法

vaule 根據 取值 保留 列表 tuple 樣書 key值 推薦 tu = (111,"xiaoxing",(11,22),[(33,44)],45,)#1.書寫格式#一般寫元組的時候推薦在最後加入逗號,#元組中的一級元素不可被修改,不能增加或者刪除print(tu)#

開啟運維之路之 4 ——常見軟體安裝:JRE、MySQL、Tomcat安裝

1、JRE安裝:在正式環境裡 我們可以不安裝jdk ,僅僅安裝Java執行環境 jre即可。 ①下載jre:JRE官網下載地址 開啟連結,勾選協議,下載Linux版本64位的 ②上傳jre到/home/data/下:使用FTP工具上傳。 如果上傳過程遇到下面的問題:連線到

八章

雜湊的含義 散列表(Hash table,也叫雜湊表),是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。 對不同的關鍵字可能得到同一雜湊地址,即k1≠k2,

Redis 叢集之 Sentinel

Redis作為記憶體資料庫,需要具備高可用的特點,不然如果伺服器宕機,還在記憶體裡的資料就會丟失。我們最常用的高可用方法就是搭建叢集,master機器掛了,可以讓slave機器頂上,繼續提供服務。但是Redis叢集是不會自動進行主從切換的,也就是說,如果主節點非常不爭氣的在凌晨3點掛了,那麼運維同學就

Redis叢集之Sentinel

Redis作為記憶體資料庫,需要具備高可用的特點,不然如果伺服器宕機,還在記憶體裡的資料就會丟失。我們最常用的高可用方法就是搭建叢集,master機器掛了,可以讓slave機器頂上,繼續提供服務。但是Redis叢集是不會自動進行主從切換的,也就是說,如果主節點非常不爭氣的在凌晨3點掛了,那麼運維同學就要馬上起