redisc語言
❶ redis數據類型是什麼
redis是一個key-value存儲系統。
redis和Memcached類似,它支持存儲的value類型相對更多,包括string(字元串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。
在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁碟或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。
(1)redisc語言擴展閱讀
Redis支持主從同步。數據可以從主伺服器向任意數量的從伺服器上同步,從伺服器可以是關聯其他從伺服器的主伺服器。
這使得Redis可執行單層樹復制。存檔可以有意無意的對數據進行寫操作。由於完全實現了發布/訂閱機制,使得從資料庫在任何地方同步樹時,可訂閱一個頻道並接收主伺服器完整的消息發布記錄。同步對讀取操作的可擴展性和數據冗餘很有幫助。
❷ redis是使用c語言開發的么
Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網路、激禪枝可基於內存亦可襲培持久化的日誌型、Key-Value資料庫。明敏
❸ 4、Redis高性能的根本原理
內存的讀寫速度很快
Epoll 模型
常用的五大Redis的數據結構,及他們各自的底層實現結構
string hash list set sortset(zset)
string 的底層實現是 簡單動態字元串(SDS -simple dynamic string)
hash 的底層實現是 hash表 或則 壓縮列表(ziplist)
list 的底層實現是 雙向列表(quicklist) 或者 壓縮列表
set 的底層實現是 hash表(hashtable) 或者 整數數組
sortset(zset) 的底層實現是 壓縮列表 或者 跳錶
各個數據結構的底層實現概覽
value是 string 類型的時候分為三種情況
(1)、當設置的值是整數類型的時候,redis底層會將 string 類型轉化為 int 來存儲
(2)、設置的值小於等於44個位元組的時候,使用的編碼是 embstr
(3)、設置的值大於44個位元組的時候,使用的編碼是 raw
redis是用C語言編寫的,在C語言中 string 類型是鋒頃用字元數組 char[] 來實現的。redis實現字元串的底層並沒有直接使用C語言中的字元困基磨數組的形式,而是進行了改造,構造出了一種SDS的數據結構
list的底層使用 快速雙向鏈表quicklist 或者 壓縮鏈表ziplist 來實現的。
list的底層並沒有使用傳統的雙向鏈表的結構是因為
(1)、雙向鏈表需要有一個 前指針 和 後指針 ,每個指針佔用的空間分別都是8byte, 佔用內存 比較多
(2)、雙向鏈表所通用的一個問題是會形成很多的 內存碎片
壓縮鏈表 ziplist 結構是
快速雙向鏈表 quicklist 結構
hash的底層實現為 hashtable 或者 ziplist 。
hashtable的底層實現
當數據量比較小或者單個元素的時候,底層使用的是ziplist存儲,具體可以通過配置來制定
1、 hashtable 是無序的 ziplist 是有序的
2、在能使用 hash 的情況下優先使用 hash ,不要使用 String ,因為使用太多的 String ,則會創建出過多的 key ,當 key 大量的時候,就會容易發生 hash碰撞 ,所以就需要頻繁的 rehash ,每次 rehash 就會創建2倍的內存,造成內存浪費
hash的底層實現為 整數數組intset 或者 hashtable 。
當set都為整數的時候,set的底層實現都是使用 intset 結構實現
如果set中存在字元串的值,則使用 hashtable 來實現
intset 是汪斗有序的, hashtable 是無序的
sortset 底層使用 壓縮列表ziplist 或 跳錶skiplist 的結構實現
當數據量小的情況下,使用 ziplist 實現,當數據量大的情況下使用 ziplist 實現,具體可以通過配置設置
默認設置下的底層結構
skiplist 的底層實現
查找對應元素的時候,先從最高的索引層找,例如找c 150,則先從L1找,L1的指針指向b,查看b120小於150,則繼續往後找,b的指針指向null,則向下一層找,向下一層b的指針指向c,查看c的score為150,所以找到對應的元素c
1、 https://blog.csdn.net/u010710458/article/details/80604740
❹ redis為什麼是單線程
Redis採用的是基於內存的採用的是單進程單線程模型的KV資料庫,由C語言編寫。官方提供的數據是可以達到羨睜100000+的qps。這個數據不比採用單進程多線程的同樣基兄陵歲於內存的KV資料庫Memcached差。
Redis並沒有直接使用Libevent,而是自己完成了一個非常輕量級的對select、epoll、evport、kqueue這些通用的介面的實現。在不同的系統調用選用適合的介面,linux下默認是epoll。
因為Libevent比較重更通汪茄用代碼量也就很龐大,擁有很多Redis用不上的功能,Redis為了追求「輕巧」並且去除依賴,就選擇自己去封裝了一套。
單線程優點:
同步應用程序的開發比較容易,但由於需要在上一個任務完成後才能開始新的任務,所以其效率通常比多線程應用程序低。如果完成同步任務所用的時間比預計時間長,應用程序可能會不響應。多線程處理可以同時運行多個過程。例如,文字處理器應用程序在您處理文檔的同時,可以檢查拼寫(作為單獨的任務)。
❺ Redis是什麼,用來做什麼
Redis是一個nosql資料庫,可以存儲key-value值。因為其底層實現中,數據讀寫是基於內存,速度非常快,所以常用於緩存;進而因其為獨立部署的中間件,常用於分布式緩存的實現方案。
常用場景有:緩存、秒殺控制、分布式鎖。
雖然其是基於內存讀寫,但底層也有持久化機制;同時具備集群模式;不用擔心其可用性。
關於Redis的使用,可以參考《Redis的使用方法、常見應用場景》
❻ c++ redis 屬於什麼類型
Redis是裂鄭迅一叢明個開源的使用ANSI C語言編寫、支持網肆此絡、可基於內存亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。從2010年3月15日起,Redis的開發工作由VMware主持。
在C++中沒有redis變數或函數,也不是一個數據類型
❼ Redis --- 八種數據類型(基本命令)
String、Hash、List、Set和Zset。
等同於java中的, Map<String,String> string 是redis裡面的最基本的數據類型,一個key對應一個value。
應用場景 :String是最常用的一種數據類型,普通的key/value存儲都可以歸為此類,如用戶信息,登錄信息和配置信息等;
實現方式 :String在redis內部存儲默認就是一個字元串,被redisObject所引用,當遇到incr、decr等操作(自增自減等原子操作)時會轉成數值型進行計算,此時redisObject的encoding欄位為int。
Redis雖然是用C語言寫的,但卻沒有直接用C語言的字元串,而是自己實現了一套字元串。目的就是為了提升速度,提升性能。 Redis構建了一個叫做簡單動態字元串(Simple Dynamic String),簡稱SDS。
Redis的字元串也會遵守C語言的字元串的實現規則,即 最後一個字元為空字元。然而這個空字元不會被計算在len里頭。
Redis動態擴展步驟:
Redis字元串的性能優勢
常用命令 :set/get/decr/incr/mget等,具體如下;
ps:計數器(字元串的內容為整數的時候可以使用),如 set number 1。
補充:
等同於java中的: Map<String,Map<String,String>> ,redis的hash是一個string類型的field和value的映射表, 特別適合存儲對象。 在redis中,hash因為是一個集合,所以有兩層。第一層是key:hash集合value,第二層是hashkey:string value。所以判斷是否採用hash的時候可以參照有兩層key的設計來做參考。並且注意的是, 設置過期時間只能在第一層的key上面設置。
應用場景 :我們要存儲一個用戶信息對象數據,其中包括用戶ID、用戶姓名、年齡和生日,通過用戶ID我們希望獲取該用戶的姓名或者年齡或者生日;
實現方式 :Redis的Hash實際是內部存儲的Value為一個HashMap,並提供了直接存取這個Map成員的介面。如,Key是用戶ID, value是一個Map。 這個Map的key是成員的屬性名,value是屬性值 。這樣對數據的修改和存取都可以直接通過其內部Map的Key(Redis里稱內部Map的key為field), 也就是通過 key(用戶ID) + field(屬性標簽) 就可以操作對應屬性數據。 當前HashMap的實現有兩種方式 :當HashMap的成員比較少時Redis為了節省內存會採用類似一維數組的方式來緊湊存儲,而不會採用真正的HashMap結構,這時對應的value的redisObject的encoding為zipmap,當成員數量增大時會自動轉成真正的HashMap,此時redisObject的encoding欄位為int。
常用命令 :hget/hset/hgetall等,具體如下:
等同於java中的 Map<String,List<String>> ,list 底層是一個鏈表,在redis中,插入list中的值,只需要找到list的key即可,而不需要像hash一樣插入兩層的key。 list是一種有序的、可重復的集合。
應用場景 :Redis list的應用場景非常多,也是Redis最重要的數據結構之一,比如twitter的關注列表,粉絲列表等都可以用Redis的list結構來實現;
實現方式 :Redis list的實現為一個 雙向鏈表 ,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內存開銷,Redis內部的很多實現,包括 發送緩沖隊列 等也都是用的這個數據結構。
常用命令 :lpush/rpush/lpop/rpop/lrange等,具體如下:
性能總結 :
它是一個字元串鏈表,left、right都可以插入添加。
等同於java中的 Map<String,Set<String>> ,Set 是一種無序的,不能重復的集合。並且在redis中,只有一個key它的底層由hashTable實現的,天生去重。
應用場景 :Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動去重的,當你需要存儲一個列表數據,又不希望出現重復數據時,set是一個很好的選擇,並且 set提供了判斷某個成員是否在一個set集合內的重要介面 ,這個也是list所不能提供的;如保存一些標簽的名字。標簽的名字不可以重復,順序是可以無序的。
實現方式 :set 的內部實現是一個 value永遠為null的HashMap,實際就是通過計算hash的方式來快速排重的,這也是set能提供判斷一個成員是否在集合內的原因。
常用命令 :sadd/spop/smembers/sunion等,具體如下:
ZSet(Sorted Set:有序集合) 每個元素都會關聯一個double類型的分數score,分數允許重復,集合元素按照score排序( 當score相同的時候,會按照被插入的鍵的字典順序進行排序 ),還可以通過 score 的范圍來獲取元素的列表。
應用場景 :Redis sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以 通過用戶額外提供一個優先順序(score)的參數來為成員排序,並且是插入有序的,即自動排序。 當你需要一個有序的並且不重復的集合列表,那麼可以選擇sorted set數據結構,比如twitter 的public timeline可以以發表時間作為score來存儲,這樣獲取時就是自動按時間排好序的。
底層實現 : zset 是 Redis 提供的一個非常特別的數據結構,常用作排行榜等功能,以用戶 id 為 value ,關注時間或者分數作為 score 進行排序。實現機制分別是 zipList 和 skipList 。規則如下:
zipList:滿足以下兩個條件
skipList:不滿足以上兩個條件時使用跳錶、組合了hash和skipList
為什麼用skiplist不用平衡樹?
主要從內存佔用、對范圍查找的支持和實現難易程度這三方面總結的原因。
拓展:mysql為什麼不用跳錶?
常用命令 :zadd/zrange/zrem/zcard等;
官網地址: https://redis.io/commands/geoadd
可以用來推算兩地之間的距離,方圓半徑內的人。
關於經度緯度的限制: https://www.redis.net.cn/order/3685.html
一般我們使用Hyperloglog做基數統計。
什麼是基數?就是一個集合中不重復的數的個數。
集合A:{1,3,5,7,9,7}
集合B:{1,3,5,7,9}
AB集合的基數都是5
應用:統計網站的訪問量(一個人訪問網站很多次仍然算作一次)。
優點:佔用的內存是固定的,找2^64次方個數的基數,只需要12KB內存。
缺點:有0.81%的錯誤率,可以忽略不計
概述: bitmap 存儲的是連續的二進制數字(0 和 1),通過 bitmap, 只需要一個 bit 位來表示某個元素對應的值或者狀態,key 就是對應元素本身 。 我們知道 8 個 bit 可以組成一個 byte,所以 bitmap 本身會極大的節省儲存空間。
應用場景: 適合需要保存狀態信息(比如是否簽到、是否登錄...)並需要進一步對這些信息進行分析的場景。比如用戶簽到情況、活躍用戶情況、用戶行為統計(比如是否點贊過某個視頻)。
針對上面提到的一些場景,這里進行進一步說明。
使用場景一:用戶行為分析 很多網站為了分析你的喜好,需要研究你點贊過的內容。
使用場景二:統計活躍用戶
使用時間作為 key,然後用戶 ID 為 offset,如果當日活躍過就設置為 1
那麼我該如果計算某幾天/月/年的活躍用戶呢(暫且約定,統計時間內只有有一天在線就稱為活躍),有請下一個 redis 的命令
使用場景三:用戶在線狀態
對於獲取或者統計用戶在線狀態,使用 bitmap 是一個節約空間效率又高的一種方法。
只需要一個 key,然後用戶 ID 為 offset,如果在線就設置為 1,不在線就設置為 0。
補充 :
巨人的肩膀:
https://www.cnblogs.com/Small-sunshine/p/11687809.html
https://mp.weixin.qq.com/s/CMu7oXVIKp2s-PXTdMlimA
❽ Redis底層數據結構之string
我們都知道, Redis 是由 C 語言編寫的。在 C 語言中,字元串標准形式是以空字元 作為結束符的,但是 Redis 裡面的字元串卻沒有直接沿用 C 語言的字元串。主要是因為 C 語言中獲取字元串長度可以調用 strlen 這個標准函數,這個函數的時間復雜度是 O(N) ,由於 Redis 是單線程的,承受不了這個時間復雜度。
在上一篇文亮虧章中,我們介紹了 Redis 的 RedisObject 的數據結構,如下所示:
對於不同的對象, Redis 會使用不同的類型來存儲。對於同一種類型 type 會有不同的存儲形式 encoding 。對於 string 類型的字元串,其底層編碼方式共有三種,分別為 int 、 embstr 和 raw 。
使用 object encoding key 可以查看 key 對應的 encoding 類型,如下所示:
對於 embstr 和 raw 這兩種 encoding 類型,其存儲方式還不太一樣。對於 embstr 類型,它將 RedisObject 對象頭和 SDS 對象在內存中地址是連在一起的,但對於派畝 raw 類型,二者在內存地址不是連續的。
在介紹 string 類型的存儲類型時,我們說到,對於 embstr 和 raw 兩種類型其存儲方式不一樣,但 ptr 指針最後都指向一個 SDS 的結構。那什麼是 SDS 呢? Redis 中的字元串稱之為 Simple Dynamic String ,簡稱為 SDS 。與普通 C 語言的原始字元串結構相比, sds 多了一個 sdshdr 的頭部信息, sdshdr 基本數據結構如下所示:
可以看出, SDS 的結構有點類似於 Java 中的 ArrayList 。 buf[] 表示真正存儲的字元串內容, alloc 表示所分配的數組的長度, len 表示字元串的實際長度,並且由於 len 這個屬性的存在, Redis 可以在 O(1) 的時間復雜度內獲取數組長度。
為了追求對於內存的極致優化,對於不同長度的字元串, Redis 底層會採用不同的結構體來表示。在 Redis 中的 sds.h 源碼中存在著五種 sdshdr ,分別如下:
上面說了, Redis 底層會根據字元串的長度來決定具體使用哪種類型的 sdshdr 。可以看出, sdshdr5 明顯區別於其他四種結構,它一般只用於存儲長度不會變化,且長度小於32個字元的字元串。但現在一般都不再使用該結構, 因為其結構沒有 len 和 alloc 這兩個屬性,不具備動態擴容操作 ,一旦預分配的內存空間使用完,就需要重新分配內存並完成數據的復制和遷移,類似於 ArrayList 的擴容操作,這種操作對性能的影響很大。
上面介紹 sdshdr 屬性的時候說過, flag 這個屬性用於標識使用哪種 sdshdr 類型, flag 的低三位標識當前 sds 的類型,分別如下所示:
同時,注意到在每個 sdshdr 的頭定義上都有一個 attribute((packed)) ,這個是為了告訴 gcc 取消優化對齊 ,這樣,每個欄位分配的內存地址就是 緊緊排列在一起的 , Redis 中字元串參數的傳遞直接使用 char* 指針,其實現原理在於,由於 sdshdr 內存分配禁止了優化對齊,所以 sds[-1] 指向的就是 flags 屬性的內存地址,而通過 flags 屬性又可以確定 sdshdr 的屬性,進而可以讀取頭部欄位確定 sds 的相關屬性。
sds的邏輯圖如下所示:
相比較於 C 語言原始的字元串,塵鍵森 sdshdr 的具備一些優勢。
由於 sdshdr 中存在 len 這個屬性,所以可以在 O(1) 的時間復雜度下獲得長度;而傳統的 C 語言得使用 strlen 這個標准函數獲取,時間復雜度為 O(N) 。
原始的 C 語言一直使用與長度匹配的內存,這樣在追加字元串導致字元串長度發生變化時,就必須進行內存的重新分配。內存重新分配涉及到復雜演算法和系統調用,耗費性能和時間。對於 Redis 來說,它是單線程的,如果使用原始的字元串結構,勢必會引發頻繁的內存重分配,這個顯然是不合理的。
因而, sds 每次進行內存分配時,都會通過內存的預分配來減少因為修改字元串而引發的內存重分配次數。這個原理可以參數 Java 中的 ArrayList ,一般在使用 ArrayList 時都會建議使用帶有容量的構造方式,這樣可以避免頻繁 resize 。
對於 SDS 來說,當其使用 append 進行字元串追加時,程序會用 alloc-len 比較下剩下的空餘內存是否足夠分配追加的內容 ,如果不夠自然觸發內存重分配,而如果剩餘未使用內存空間足夠放下,那麼將直接進行分配,無需內存重分配。其擴容策略為, 當字元串佔用大小小於1M時,每次分配為 len * 2,也就是保留100%的冗餘;大於1M後,為了避免浪費,只多分配1M的空間。
通過這種預分配策略, SDS 將連續增長 N 次字元串所需的內存重分配次數 從必定 N 次降低為最多 N 次。
緩沖區溢出是指當某個數據超過了處理程序限制的范圍時,程序出現的異常操作。 原始的 C 語言中,是由編碼者自己來分配字元串的內存,當出現內存分配不足時就會發生 緩存區溢出 。而 sds 的修改函數在修改前會判斷內存,動態的分配內存,杜絕了 緩沖區溢出 的可能性。
對於原始的 C 語言字元串來說,它會通過判斷當前字元串中是否存在空字元 來確定是否已經是字元串的結尾。因而在某些情況下,如使用空格進行分割一段字元串時,或者是圖片或者視頻等二進制文件中存在 等,就會出問題。而 sds 不是通過空字元串來判斷字元串是否已經到結尾,而是通過 len 這個欄位的值。所以說, sds 還具備 二進制安全 這個特性,即可以安全的存儲具有特殊格式的二進制數據。
https://www.cnblogs.com/reecelin/p/13358432.html
❾ redis中怎麼實現hash表的c語言函數
獲敏旦斗取hash表的所有域值
[plain] view plain
redis 127.0.0.1:6379> hgetall user.2 #存在的hash表
1) "name" #域
2) "niuer" #域name的值遲鍵
3) "age" #域
4) "34" #域age的值橋磨
redis 127.0.0.1:6379> hgetall user.3 #不存在的hansh表
(empty list or set)
❿ redis到底是個什麼東西
1. 什麼是Redis
Redis是由義大利人Salvatore Sanfilippo(網名:antirez)開發的一款內存高速緩存資料庫。Redis全稱為:Remote Dictionary Server(遠程數據服務),該軟體使用C語言編寫,Redis是一個key-value存儲系統,它支持豐富的數據類型,如:string、list、set、zset(sorted set)、hash。
2. Redis特點
Redis以內存作為數據存儲介質,所以讀寫數據的效率極高,遠遠超過資料庫。以設置和獲取一個256位元組字元串為例,它的讀取速度可高達110000次/s,寫速度高達81000次/s。
Redis跟memcache不同的是,儲存在Redis中的數據是持久化的,斷電或重啟後,數據也不會丟失。因為Redis的存儲分為內存存儲、磁碟存儲和log文件三部分,重啟後,Redis可以從磁碟重新將數據載入到內存中,這些可以通過配置文件對其進行配置,正因為這樣,Redis才能實現持久化。
Redis支持主從模式,可以配置集群,這樣更利於支撐起大型的項目,這也是Redis的一大亮點。
3. Redis應用場景,它能做什麼
眾多語言都支持Redis,因為Redis交換數據快,所以在伺服器中常用來存儲一些需要頻繁調取的數據,這樣可以大大節省系統直接讀取磁碟來獲得數據的I/O開銷,更重要的是可以極大提升速度。
拿大型網站來舉個例子,比如a網站首頁一天有100萬人訪問,其中有一個板塊為推薦新聞。要是直接從資料庫查詢,那麼一天就要多消耗100萬次資料庫請求。上面已經說過,Redis支持豐富的數據類型,所以這完全可以用Redis來完成,將這種熱點數據存到Redis(內存)中,要用的時候,直接從內存取,極大的提高了速度和節約了伺服器的開銷。
總之,Redis的應用是非常廣泛的,而且極有價值,真是伺服器中的一件利器,所以從現在開始,我們就來一步步學好它。