當前位置:首頁 » 存儲配置 » redis存儲大數據量

redis存儲大數據量

發布時間: 2022-10-14 21:18:27

Ⅰ redis源碼解讀:單線程的redis是如何實現高速緩存

redis可能是最近幾年最火的緩存資料庫方案了,在各個高並發領域都有應用。

這篇文章,我們將從源代碼的角度來分析一下,為何如此一個高性能,高應用的緩存,會是單線程的方案,當然一個方案的高性能,高並發是多方面的綜合因素,其它的因素我們將在後續解讀。後續分析主要以LINUX操作系統為基礎,這也是redis應用最廣的平台。

單線程最大的受限是什麼?就是CPU,現在伺服器一般已經是多CPU,而單線程只能使用到其中的一個核。

redis作為一個網路內存緩存資料庫,在實現高性能時,主要有4個點。

1.網路高並發,高流量的數據處理。

一個非同步,高效,且對CPU要求不高的網路模型,這個模型主要是由OS來提供的,目前在LINUX最主流使用的是EPOLL,這個網上介紹很多,主要是基於事件驅動的一個非同步模型。

2.程序內部的合理構架,調用邏輯,內存管理。

redis在採用純C實現時,整體調用邏輯很短,但在內存方面,適當的合並了一些對象和對齊,比如sds等,在底層使用了內存池,在不同情況下使用的不太一樣。

但整體處理上沒有NGINX的內池設計巧妙,當然二者不太一樣,NGINX是基於請求釋放的邏輯來設計的,因此針對請求,可以一次申請大塊,分量使用,再最後統一釋放。

3.數據復制的代價,不管是讀取數據或是寫入數據,一般都是需要有數據復制的過程。

數據復制其實就是一次內存,真正的代價是在於存在大VALUE,當value值長度超過16KB時,性能會開始下降。因為單線程的原因,如果存在一個超大VALUE,比如20MB,則會因為這個請求卡住整個線程,導致後續的請求進不來,雖然後面的請求是能快速處理的小請求。

4.redis中數據結構中演算法的代價,有些結構在大數據量時,代價是很高的。

很多時間,大家忽略了演算法的運算代碼,因為像memcached等這類是完全的KV緩存,不存在什麼演算法,除了一個KEY的查找定位HASH演算法。

而redis不一樣,提供了不少高階的數據對象,這些對象具有上層的一些演算法能力,而這些能力是需要比如GEO模塊。

Ⅱ redis存儲對象大小2m

Redis 存儲字元串和對象
1 測試類
import redis.clients.RedisClinet;
import redis.clients.SerializeUtil;
import redis.clients.jedis.Jedis;

public class Test {

/**
* Administrator
* @param args
*/
public static void main(String[] args) {

// 操作單獨的文本串
Jedis redis= new Jedis( "10.2.31.38", 6379);

redis.set( "key", "value");
System. out.println(redis.get( "key"));
System. out.println(redis.del( "key"));

// 操作實體類對象
Goods good= new Goods(); // 這個Goods實體我就不寫了啊
good.setName( "洗衣機" );
good.setNum(400);
good.setPrice(19l);
redis.set( "good".getBytes(), SerializeUtil. serialize(good));
byte[] value = redis.get( "good".getBytes());
Object object = SerializeUtil. unserialize(value);
if(object!= null){
Goods goods=(Goods) object;
System. out.println(goods.getName());
System. out.println(goods.getNum());
System. out.println(goods.getPrice());
}
System. out.println(redis.del( "good".getBytes()));

// 操作實體類對象2(實際上和上面是一樣的)
String key= "goods-key";
Goods g= new Goods();
g.setName( "電風扇--d" );
g.setNum(200);
String temp=RedisClinet. getInstance().set(g, key);
System. out.println(temp);

Object o=RedisClinet. getInstance().get(key);
if(o!= null)
{
Goods g1=(Goods)o;
System. out.println(g1.getName());
System. out.println(g1.getNum());
}
System. out.println(RedisClinet. getInstance().del(key));

}
}

2 RedisClinet 客戶端類
package redis.clients;
import redis.clients.jedis.Jedis;
/**
*
* @author ajun
*
*/
public class RedisClinet {
private static final String ip= "10.2.31.38";
private static final int port=6379;
protected static RedisClinet redis = new RedisClinet ();
protected static Jedis jedis = new Jedis( ip, port);;
static {

}
protected RedisClinet(){
System. out.println( " init Redis ");
}
public static RedisClinet getInstance()
{
return redis;
}

/**set Object*/
public String set(Object object,String key)
{
return jedis.set(key.getBytes(), SerializeUtil.serialize(object));
}

/**get Object*/
public Object get(String key)
{
byte[] value = jedis.get(key.getBytes());
return SerializeUtil. unserialize(value);
}

/**delete a key**/
public boolean del(String key)
{
return jedis.del(key.getBytes())>0;
}

}

3 序列化工具類

/**
*
*/
package redis.clients;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
* @author Administrator
*
*/
public class SerializeUtil {
public static byte[] serialize(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {

}
return null;
}

public static Object unserialize( byte[] bytes) {
ByteArrayInputStream s = null;
try {
// 反序列化
s = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(s);
return ois.readObject();
} catch (Exception e) {

}
return null;
}
}

Ⅲ Redis 大數據內存優化 (RoaringBitmap)

最近碰到手機設備匹配的業務, 用戶在我司後台可以上傳人群包, 裡面存放的是設備的MD5標識符; 一個人群包大概有千萬級的MD5數據, 與廣告請求所攜帶設備標識進行匹配.

嘗試插入1kw條數據, key為設備MD5值, value為1, 此時Redis中存在1kw條key-value鍵值對.

通過 info 指令查看內存佔用:

8bit = 1b = 0.001kb
bitmap即點陣圖, 就是通過最小的單位bit來進行0或者1的設置,表示某個元素對應的值或者狀態。
一個bit的值,或者是0,或者是1;也就是說一個bit能存儲的最多信息是2。

場景: 有用戶id分別為1, 2, 3, 4, 5, 6, 7, 8的用戶, 其中用戶2, 5在今日登錄, 統計今
日登錄用戶

採用點陣圖存儲: 用戶id為偏移量, 可以看做是在點陣圖中的索引, value為true

通過 bitcount 獲取登錄用戶數為2:

測試offset從1-1kw連續整數時候的內存佔用:

可以發現內存佔用僅為 1.19MB, 1個億的數據也才12MB, 極大的減少了內存;

由於我們的業務沒有如此完美的情況出現, 採用設備MD5的hash做Offset, 不會出現連續正整數的情況;

各常用Hash函數性能對比: https://byvoid.com/zhs/blog/string-hash-compare/

所以我們接下來測試1kw條MD5數據的點陣圖內存佔用:

查看Redis內存佔用:

問題: 為什麼同樣1kw的bitmap, MD5數據的Hash佔用會比 測試一 的多200倍?

將32位無符號整數按照高16位分桶,即最多可能有216=65536個桶,稱為container。存儲數據時,按照數據的高16位找到container(找不到就會新建一個),再將低16位放入container中。也就是說,一個RBM就是很多container的集合。

圖中示出了三個container:

1kw條MD5數據的插入:

Ⅳ redis這些內存消耗數據怎麼看呢,主要看哪個說明內存比較大了

Redis常用數據類型
Redis最為常用的數據類型主要有以下五種:
String
Hash
List
Set
Sorted set
在具體描述這幾種數據類型之前,先通過一張圖了解下Redis內部內存管理中是如何描述這些不同數據類型的:
首先Redis內部使用一個redisObject對象來表示所有的key和value,redisObject最主要的信息如:type代表一個value對象具體是何種數據類型,encoding是不同數據類型在redis內部的存儲方式,比如:type=string代表value存儲的是一個普通字元串,那麼對應的encoding可以是raw或者是int,如果是int則代表實際redis內部是按數值型類存儲和表示這個字元串的,當然前提是這個字元串本身可以用數值表示,比如:「123」 「456」這樣的字元串。
這里需要特殊說明一下vm欄位,只有打開了Redis的虛擬內存功能,此欄位才會真正的分配內存,該功能默認是關閉狀態的,該功能會在後面具體描述。
通過可以發現Redis使用redisObject來表示所有的key/value數據是比較浪費內存的,當然這些內存管理成本的付出主要也是為了給Redis不同數據類型提供一個統一的管理介面,實際作者也提供了多種方法幫助盡量節省內存使用,隨後會具體討論。
下面先來逐一的分析下這五種數據類型的使用和內部實現方式:
String
常用命令:
set,get,decr,incr,mget 等。
應用場景:
String是最常用的一種數據類型,普通的key/value存儲都可以歸為此類,這里就不所做解釋了。
實現方式:
String在redis內部存儲默認就是一個字元串,被redisObject所引用,當遇到incr,decr等操作時會轉成數值型進行計算,此時redisObject的encoding欄位為int。
Hash
常用命令:
hget,hset,hgetall 等。
應用場景:
簡單舉個實例來描述下Hash的應用場景,比如要存儲一個用戶信息對象數據,包含以下信息:
用戶ID為查找的key,存儲的value用戶對象包含姓名,年齡,生日等信息,如果用普通的key/value結構來存儲,主要有以下2種存儲方式:
常用內存優化手段與參數
通過上面的一些實現上的分析可以看出redis實際上的內存管理成本非常高,即佔用了過多的內存,作者對這點也非常清楚,所以提供了一系列的參數和手段來控制和節省內存,分別來討論下。
首先最重要的一點是不要開啟Redis的VM選項,即虛擬內存功能,這個本來是作為Redis存儲超出物理內存數據的一種數據在內存與磁碟換入換出的一個持久化策略,但是其內存管理成本也非常的高,並且後續會分析此種持久化策略並不成熟,所以要關閉VM功能,請檢查redis.conf文件中 vm-enabled 為 no。
其次最好設置下redis.conf中的maxmemory選項,該選項是告訴Redis當使用了多少物理內存後就開始拒絕後續的寫入請求,該參數能很好的保護好Redis不會因為使用了過多的物理內存而導致swap,最終嚴重影響性能甚至崩潰。
另外Redis為不同數據類型分別提供了一組參數來控制內存使用,在前面詳細分析過Redis Hash是value內部為一個HashMap,如果該Map的成員數比較少,則會採用類似一維線性的緊湊格式來存儲該Map, 即省去了大量指針的內存開銷,這個參數控制對應在redis.conf配置文件中下面2項:
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
hash-max-zipmap-entries
含義是當value這個Map內部不超過多少個成員時會採用線性緊湊格式存儲,默認是64,即value內部有64個以下的成員就是使用線性緊湊存儲,超過該值自動轉成真正的HashMap。
hash-max-zipmap-value 含義是當 value這個Map內部的每個成員值長度不超過多少位元組就會採用線性緊湊存儲來節省空間。
以上2個條件任意一個條件超過設置值都會轉換成真正的HashMap,也就不會再節省內存了,那麼這個值是不是設置的越大越好,答案當然是否定的,HashMap的優勢就是查找和操作的時間復雜度都是O(1)的,而放棄Hash採用一維存儲則是O(n)的時間復雜度,如果
成員數量很少,則影響不大,否則會嚴重影響性能,所以要權衡好這個值的設置,總體上還是最根本的時間成本和空間成本上的權衡。
同樣類似的參數還有:
list-max-ziplist-entries 512
說明:list數據類型多少節點以下會採用去指針的緊湊存儲格式。
list-max-ziplist-value 64
說明:list數據類型節點值大小小於多少位元組會採用緊湊存儲格式。
set-max-intset-entries 512
說明:set數據類型內部數據如果全部是數值型,且包含多少節點以下會採用緊湊格式存儲。
最後想說的是Redis內部實現沒有對內存分配方面做過多的優化,在一定程度上會存在內存碎片,不過大多數情況下這個不會成為Redis的性能瓶頸,不過如果在Redis內部存儲的大部分數據是數值型,Redis內部採用了一個shared integer的方式來省去分配內存的開銷,即在系統啟動時先分配一個從1~n 那麼多個數值對象放在一個池子中,如果存儲的數據恰好是這個數值范圍內的數據,則直接從池子里取出該對象,並且通過引用計數的方式來共享,這樣在系統存儲了大量數值下,也能一定程度上節省內存並且提高性能,這個參數值n的設置需要修改源代碼中的一行宏定義REDIS_SHARED_INTEGERS,該值默認是10000,可以根據自己的需要進行修改,修改後重新編譯就可以了。
Redis的持久化機制
Redis由於支持非常豐富的內存數據結構類型,如何把這些復雜的內存組織方式持久化到磁碟上是一個難題,所以Redis的持久化方式與傳統資料庫的方式有比較多的差別,Redis一共支持四種持久化方式,分別是:
在設計思路上,前兩種是基於全部數據都在內存中,即小數據量下提供磁碟落地功能,而後兩種方式則是作者在嘗試存儲數據超過物理內存時,即大數據量的數據存儲,截止到本文,後兩種持久化方式仍然是在實驗階段,並且vm方式基本已經被作者放棄,所以實際能在生產環境用的只有前兩種,換句話說Redis目前還只能作為小數據量存儲(全部數據能夠載入在內存中),海量數據存儲方面並不是Redis所擅長的領域。
下面分別介紹下這幾種持久化方式:
定時快照方式(snapshot):
該持久化方式實際是在Redis內部一個定時器事件,每隔固定時間去檢查當前數據發生的改變次數與時間是否滿足配置的持久化觸發的條件,如果滿足則通過操作系統fork調用來創建出一個子進程,這個子進程默認會與父進程共享相同的地址空間,這時就可以通過子進程來遍歷整個內存來進行存儲操作,而主進程則仍然可以提供服務,當有寫入時由操作系統按照內存頁(page)為單位來進行-on-write保證父子進程之間不會互相影響。
該持久化的主要缺點是定時快照只是代表一段時間內的內存映像,所以系統重啟會丟失上次快照與重啟之間所有的數據。
基於語句追加方式(aof):
aof方式實際類似mysql的基於語句的binlog方式,即每條會使Redis內存數據發生改變的命令都會追加到一個log文件中,也就是說這個log文件就是Redis的持久化數據。
aof的方式的主要缺點是追加log文件可能導致體積過大,當系統重啟恢復數據時如果是aof的方式則載入數據會非常慢,幾十G的數據可能需要幾小時才能載入完,當然這個耗時並不是因為磁碟文件讀取速度慢,而是由於讀取的所有命令都要在內存中執行一遍。
另外由於每條命令都要寫log,所以使用aof的方式,Redis的讀寫性能也會有所下降。
虛擬內存方式:
虛擬內存方式是Redis來進行用戶空間的數據換入換出的一個策略,此種方式在實現的效果上比較差,主要問題是代碼復雜,重啟慢,復制慢等等,目前已經被作者放棄。
diskstore方式:
diskstore方式是作者放棄了虛擬內存方式後選擇的一種新的實現方式,也就是傳統的B-tree的方式,目前仍在實驗階段,後續是否可用可以拭目以待。
Redis持久化磁碟IO方式及其帶來的問題
有Redis線上運維經驗的人會發現Redis在物理內存使用比較多,但還沒有超過實際物理內存總容量時就會發生不穩定甚至崩潰的問題,有人認為是基於快照方式持久化的fork系統調用造成內存佔用加倍而導致的,這種觀點是不準確的,因為fork 調用的-on-write機制是基於操作系統頁這個單位的,也就是只有有寫入的臟頁會被復制,但是一般系統不會在短時間內所有的頁都發生了寫入而導致復制,那麼是什麼原因導致Redis崩潰的。
答案是Redis的持久化使用了Buffer IO造成的,所謂Buffer IO是指Redis對持久化文件的寫入和讀取操作都會使用物理內存的Page Cache,而大多數資料庫系統會使用Direct IO來繞過這層Page Cache並自行維護一個數據的Cache,而當Redis的持久化文件過大(尤其是快照文件),並對其進行讀寫時,磁碟文件中的數據都會被載入到物理內存中作為操作系統對該文件的一層Cache,而這層Cache的數據與Redis內存中管理的數據實際是重復存儲的,雖然內核在物理內存緊張時會做Page Cache的剔除工作,但內核很可能認為某塊Page Cache更重要,而讓進程開始Swap ,這時系統就會開始出現不穩定或者崩潰了。
的經驗是當Redis物理內存使用超過內存總容量的3/5時就會開始比較危險了。
定時快照方式(snapshot)
基於語句追加文件的方式(aof)
虛擬內存(vm)
Diskstore方式
第一種方式將用戶ID作為查找key,把其他信息封裝成一個對象以序列化的方式存儲,這種方式的缺點是,增加了序列化/反序列化的開銷,並且在需要修改其中一項信息時,需要把整個對象取回,並且修改操作需要對並發進行保護,引入CAS等復雜問題。
第二種方法是這個用戶信息對象有多少成員就存成多少個key-value對兒,用用戶ID+對應屬性的名稱作為唯一標識來取得對應屬性的值,雖然省去了序列化開銷和並發問題,但是用戶ID為重復存儲,如果存在大量這樣的數據,內存浪費還是非常可觀的。
那麼Redis提供的Hash很好的解決了這個問題,Redis的Hash實際是內部存儲的Value為一個HashMap,並提供了直接存取這個Map成員的介面,:
也就是說,Key仍然是用戶ID, value是一個Map,這個Map的key是成員的屬性名,value是屬性值,這樣對數據的修改和存取都可以直接通過其內部Map的Key(Redis里稱內部Map的key為field), 也就是通過 key(用戶ID) + field(屬性標簽) 就可以操作對應屬性數據了,既不需要重復存儲數據,也不會帶來序列化和並發修改控制的問題。
很好的解決了問題。
這里同時需要注意,Redis提供了介面(hgetall)可以直接取到全部的屬性數據,但是如果內部Map的成員很多,那麼涉及到遍歷整個內部Map的操作,由於Redis單線程模型的緣故,這個遍歷操作可能會比較耗時,而另其它客戶端的請求完全不響應,這點需要格外注意。
實現方式:
上面已經說到Redis Hash對應Value內部實際就是一個HashMap,實際這里會有2種不同實現,這個Hash的成員比較少時Redis為了節省內存會採用類似一維數組的方式來緊湊存儲,而不會採用真正的HashMap結構,對應的value redisObject的encoding為zipmap,當成員數量增大時會自動轉成真正的HashMap,此時encoding為ht。
List
常用命令:
lpush,rpush,lpop,rpop,lrange等。
應用場景:
Redis list的應用場景非常多,也是Redis最重要的數據結構之一,比如twitter的關注列表,粉絲列表等都可以用Redis的list結構來實現,比較好理解,這里不再重復。
實現方式:
Redis list的實現為一個雙向鏈表,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內存開銷,Redis內部的很多實現,包括發送緩沖隊列等也都是用的這個數據結構。
Set
常用命令:
sadd,spop,smembers,sunion 等。
應用場景:
Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動排重的,當需要存儲一個列表數據,又不希望出現重復數據時,set是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的重要介面,這個也是list所不能提供的。
實現方式:
set 的內部實現是一個 value永遠為null的HashMap,實際就是通過計算hash的方式來快速排重的,這也是set能提供判斷一個成員是否在集合內的原因。
Sorted set
常用命令:
zadd,zrange,zrem,zcard等
使用場景:
Redis sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優先順序(score)的參數來為成員排序,並且是插入有序的,即自動排序。
當需要一個有序的並且不重復的集合列表,那麼可以選擇sorted set數據結構,比如twitter 的public timeline可以以發表時間作為score來存儲,這樣獲取時就是自動按時間排好序的。
實現方式:
Redis sorted set的內部使用HashMap和跳躍表(SkipList)來保證數據的存儲和有序,HashMap里放的是成員到score的映射,而跳躍表裡存放的是所有的成員,排序依據是HashMap里存的score,使用跳躍表的結構可以獲得比較高的查找效率,並且在實現上比較簡單。

Ⅳ 大量數據能緩存到redis裡面嗎

不適合引子:

    在大數據時代,總希望存在一個Key-value存儲機制,像HashMap一樣在內存中處理大量(千萬數量級)的key-value對,以便提高數據查找、修改速度。

    所以,我們會想到,Memcached和Redis這兩個NoSQL資料庫(嚴格來講二者都不可以算作資料庫)。

    1、Memcached是一個cache機制,當內存不足時會採用LRU機制,替換出陳舊數據,因此他不能保證我們的數據像在HashMap中一樣不丟失,且沒有數據持久化機制;

    2、Redis克服了這一缺點,採取磁碟存儲機制實現數據持久化。但是,當數據量達到1千萬左右時,由於內存中不能存儲如此大量數目的數據,頻繁同磁碟進行數據交換,導致數據查詢、存儲性能的急劇下降,將導致服務不可用。

     結論:當前還沒有好的產品可以實現key-value保證數據完整性,千萬級條數量級的,高效存儲和查詢支持產品。

     附錄一:如下是轉自其它網友的測試數據:

     附錄二:memcached 和redis的比較,和各自用途

附錄一:

從圖中可以猜測到還會有Redis 2.2.1 的測試,相同的測試環境,1K的數據量,使用ServiceStack.Redis客戶端進行如下測試:

1) Set操作

2) Get操作

3) Del操作

每一套測試分別使用三個配置進行測試:

1) 綠色線條的是開啟Dump方式的持久化,5分鍾持久化一次

2) 藍色線條是開啟AOF方式的持久化,每秒寫入磁碟一次

3) 紅色線條是關閉任何的持久化方式

對於每一個配置都使用相同的其他配置:

1) 開啟VM 最大內存10GB(128位元組一

Ⅵ 如何取出大數據量的 redis hash 結構的數據並遍歷導出

就看你的數據量大小了,如果太大,卻是不好遍歷,如果有規則的key值的話,倒是可以利用分頁的方式來處理,如果沒有規律的話,只有用keys*來取了,或者是通過keysa*;keysz*;keys1*;keys0*等通配符的方式來順序的讀取,讀取時要把內存分配的大一些,不然容易溢出

Ⅶ redis存儲幾個g的數據

首先看到 Redis 官方的說法是:『A String value can be at max 512 Megabytes in length.』。過大的 key 和 value 有兩個問題:Redis 是一個內存資料庫,如果容量過大的 key 和 value 首先會導致伺服器中的內存碎片。這會影響 Redis 的內存分配的效率,進一步導致內存的使用率下降。容量過大的 key 和 value 還有這樣幾個影響:a. 這些過大的數據需要更多的時間去傳輸數據b. 過大的數據傳輸可能會導致其他的請求超時如果 A 的響應數據過大,它可能會吃掉其他請求的超時時間。如下圖例子,如果 A 的響應數據過大,它會吃掉其他請求的超時時間

Ⅷ Redis的主要功能

Redis 是當前互聯網世界最為流行的 NoSQL(Not Only SQL)資料庫。NoSQL 在互聯網系統中的作用很大,因為它可以在很大程度上提高互聯網系統的性能。

Redis 具備一定持久層的功能,也可以作為一種緩存工具。對於 NoSQL 資料庫而言,作為持久層,它存儲的數據是半結構化的,這就意味著計算機在讀入內存中有更少的規則,讀入速度更快。

對於那些結構化、多範式規則的資料庫系統而言,它更具性能優勢。作為緩存,它可以支持大數據存入內存中,只要命中率高,它就能快速響應,因為在內存中的數據讀/寫比資料庫讀/寫磁碟的速度快幾十到上百倍。

Ⅸ Redis詳解——概述/下載安裝

互聯網需求的3高: 高並發,高可擴,高性能。

Redis 是一種運行速度很快,並發性能很強,並且運行在內存上的NoSql(not only sql)資料庫

NoSQL資料庫 和 傳統資料庫 相比的優勢:

NoSQL資料庫無需事先為要存儲的數據建立欄位,隨時可以存儲自定義的數據格式。

而在關系資料庫里,增刪欄位是一件非常麻煩的事情。如果是非常大數據量的表,增加欄位 簡直就是一個噩夢。

Redis的常用使用場景:

緩存 ,毫無疑問這是Redis當今最為人熟知的使用場景。在提升伺服器性能方面非常有效;一 些頻繁被訪問的數據,經常被訪問的數據如果放在關系型資料庫,每次查詢的開銷都會很 大,而放在redis中,因為redis 是放在內存中的可以很高效的訪問

排行榜 ,在使用傳統的關系型資料庫(mysql oracle 等)來做這個事兒,非常的麻煩,而利 用Redis的SortSet(有序集合)數據結構能夠簡單的搞定;

好友關系 ,利用集合的一些命令,比如求交集、並集、差集等。可以方便搞定一些共同好 友、共同愛好之類的功能;

Session共享 ,以jsp為例,默認Session是保存在伺服器的文件中,如果是集群服務,同一個 用戶過來可能落在不同機器上,這就會導致用戶頻繁登陸;採用Redis保存Session後,無論 用戶落在那台機器上都能夠獲取到對應的Session信息。

下載: redis:http://www.redis.net.cn/ 圖形工具:https://redisdesktop.com/download

安裝(Linux)

上傳tar.gz包,並解壓:tar -zxvf redis-5.0.4.tar.gz

安裝gcc:yum -y install gcc (忘記是否安裝過,可以使用 gcc -v 命令查看gcc版本,如果沒有安裝過,會提示命令不存在)

進入redis目錄,進行編譯:make

編譯之後,開始安裝:make install

後台運行方式—— redis默認不會使用後台運行,如果你需要,修改配置文件daemonize=yes,當你後台服務啟動的 時候,會寫成一個進程文件運行

vim /opt/redis-5.0.4/redis.conf

以配置文件的方式啟動:

cd /usr/local/bin

redis-server /opt/redis-5.0.4/redis.conf

關閉資料庫:

單實例關閉 ——redis-cli shutdown

多實例關閉 ——dis-cli -p 6379 shutdown 默認的埠6379,如改過,更換埠

Ⅹ redis和memcached的區別

Redis的作者Salvatore Sanfilippo曾經對這兩種基於內存的數據存儲系統進行過比較:

1、Redis支持伺服器端的數據操作:Redis相比Memcached來說,擁有更多的數據結構和並支持更豐富的數據操作,通常在Memcached里,你需要將數據拿到客戶端來進行類似的修改再set回去。這大大增加了網路IO的次數和數據體積。在Redis中,這些復雜的操作通常和一般的GET/SET一樣高效。所以,如果需要緩存能夠支持更復雜的結構和操作,那麼Redis會是不錯的選擇。

2、內存使用效率對比:使用簡單的key-value存儲的話,Memcached的內存利用率更高,而如果Redis採用hash結構來做key-value存儲,由於其組合式的壓縮,其內存利用率會高於Memcached。

3、性能對比:由於Redis只使用單核,而Memcached可以使用多核,所以平均每一個核上Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化,但是比起Memcached,還是稍有遜色。


具體為什麼會出現上面的結論,以下為收集到的資料:

1、數據類型支持不同

與Memcached僅支持簡單的key-value結構的數據記錄不同,Redis支持的數據類型要豐富得多。最為常用的數據類型主要由五種:String、Hash、List、Set和Sorted Set。Redis內部使用一個redisObject對象來表示所有的key和value。redisObject最主要的信息如圖所示:

type代表一個value對象具體是何種數據類型,encoding是不同數據類型在redis內部的存儲方式,比如:type=string代表value存儲的是一個普通字元串,那麼對應的encoding可以是raw或者是int,如果是int則代表實際redis內部是按數值型類存儲和表示這個字元串的,當然前提是這個字元串本身可以用數值表示,比如:」123″ 「456」這樣的字元串。只有打開了Redis的虛擬內存功能,vm欄位欄位才會真正的分配內存,該功能默認是關閉狀態的。

1)String

  • 常用命令:set/get/decr/incr/mget等;

  • 應用場景:String是最常用的一種數據類型,普通的key/value存儲都可以歸為此類;

  • 實現方式:String在redis內部存儲默認就是一個字元串,被redisObject所引用,當遇到incr、decr等操作時會轉成數值型進行計算,此時redisObject的encoding欄位為int。

  • 2)Hash

  • 常用命令:hget/hset/hgetall等

  • 應用場景:我們要存儲一個用戶信息對象數據,其中包括用戶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,此時encoding為ht。

  • 3)List

  • 常用命令:lpush/rpush/lpop/rpop/lrange等;

  • 應用場景:Redis list的應用場景非常多,也是Redis最重要的數據結構之一,比如twitter的關注列表,粉絲列表等都可以用Redis的list結構來實現;

  • 實現方式:Redis list的實現為一個雙向鏈表,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內存開銷,Redis內部的很多實現,包括發送緩沖隊列等也都是用的這個數據結構。

  • 4)Set

  • 常用命令:sadd/spop/smembers/sunion等;

  • 應用場景:Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動排重的,當你需要存儲一個列表數據,又不希望出現重復數據時,set是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的重要介面,這個也是list所不能提供的;

  • 實現方式:set 的內部實現是一個 value永遠為null的HashMap,實際就是通過計算hash的方式來快速排重的,這也是set能提供判斷一個成員是否在集合內的原因。

  • 5)Sorted Set

  • 常用命令:zadd/zrange/zrem/zcard等;

  • 應用場景:Redis sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優先順序(score)的參數來為成員排序,並且是插入有序的,即自動排序。當你需要一個有序的並且不重復的集合列表,那麼可以選擇sorted set數據結構,比如twitter 的public timeline可以以發表時間作為score來存儲,這樣獲取時就是自動按時間排好序的。

  • 實現方式:Redis sorted set的內部使用HashMap和跳躍表(SkipList)來保證數據的存儲和有序,HashMap里放的是成員到score的映射,而跳躍表裡存放的是所有的成員,排序依據是HashMap里存的score,使用跳躍表的結構可以獲得比較高的查找效率,並且在實現上比較簡單。

  • 2、內存管理機制不同

    在Redis中,並不是所有的數據都一直存儲在內存中的。這是和Memcached相比一個最大的區別。當物理內存用完時,Redis可以將一些很久沒用到的value交換到磁碟。Redis只會緩存所有的key的信息,如果Redis發現內存的使用量超過了某一個閥值,將觸發swap的操作,Redis根據「swappability = age*log(size_in_memory)」計算出哪些key對應的value需要swap到磁碟。然後再將這些key對應的value持久化到磁碟中,同時在內存中清除。這種特性使得Redis可以保持超過其機器本身內存大小的數據。當然,機器本身的內存必須要能夠保持所有的key,畢竟這些數據是不會進行swap操作的。同時由於Redis將內存中的數據swap到磁碟中的時候,提供服務的主線程和進行swap操作的子線程會共享這部分內存,所以如果更新需要swap的數據,Redis將阻塞這個操作,直到子線程完成swap操作後才可以進行修改。當從Redis中讀取數據的時候,如果讀取的key對應的value不在內存中,那麼Redis就需要從swap文件中載入相應數據,然後再返回給請求方。 這里就存在一個I/O線程池的問題。在默認的情況下,Redis會出現阻塞,即完成所有的swap文件載入後才會相應。這種策略在客戶端的數量較小,進行批量操作的時候比較合適。但是如果將Redis應用在一個大型的網站應用程序中,這顯然是無法滿足大並發的情況的。所以Redis運行我們設置I/O線程池的大小,對需要從swap文件中載入相應數據的讀取請求進行並發操作,減少阻塞的時間。

    對於像Redis和Memcached這種基於內存的資料庫系統來說,內存管理的效率高低是影響系統性能的關鍵因素。傳統C語言中的malloc/free函數是最常用的分配和釋放內存的方法,但是這種方法存在著很大的缺陷:首先,對於開發人員來說不匹配的malloc和free容易造成內存泄露;其次頻繁調用會造成大量內存碎片無法回收重新利用,降低內存利用率;最後作為系統調用,其系統開銷遠遠大於一般函數調用。所以,為了提高內存的管理效率,高效的內存管理方案都不會直接使用malloc/free調用。Redis和Memcached均使用了自身設計的內存管理機制,但是實現方法存在很大的差異,下面將會對兩者的內存管理機制分別進行介紹。

    Memcached默認使用Slab Allocation機制管理內存,其主要思想是按照預先規定的大小,將分配的內存分割成特定長度的塊以存儲相應長度的key-value數據記錄,以完全解決內存碎片問題。Slab Allocation機制只為存儲外部數據而設計,也就是說所有的key-value數據都存儲在Slab Allocation系統里,而Memcached的其它內存請求則通過普通的malloc/free來申請,因為這些請求的數量和頻率決定了它們不會對整個系統的性能造成影響Slab Allocation的原理相當簡單。 如圖所示,它首先從操作系統申請一大塊內存,並將其分割成各種尺寸的塊Chunk,並把尺寸相同的塊分成組Slab Class。其中,Chunk就是用來存儲key-value數據的最小單位。每個Slab Class的大小,可以在Memcached啟動的時候通過制定Growth Factor來控制。假定圖中Growth Factor的取值為1.25,如果第一組Chunk的大小為88個位元組,第二組Chunk的大小就為112個位元組,依此類推。

    當Memcached接收到客戶端發送過來的數據時首先會根據收到數據的大小選擇一個最合適的Slab Class,然後通過查詢Memcached保存著的該Slab Class內空閑Chunk的列表就可以找到一個可用於存儲數據的Chunk。當一條資料庫過期或者丟棄時,該記錄所佔用的Chunk就可以回收,重新添加到空閑列表中。從以上過程我們可以看出Memcached的內存管理制效率高,而且不會造成內存碎片,但是它最大的缺點就是會導致空間浪費。因為每個Chunk都分配了特定長度的內存空間,所以變長數據無法充分利用這些空間。如圖 所示,將100個位元組的數據緩存到128個位元組的Chunk中,剩餘的28個位元組就浪費掉了。

    Redis的內存管理主要通過源碼中zmalloc.h和zmalloc.c兩個文件來實現的。Redis為了方便內存的管理,在分配一塊內存之後,會將這塊內存的大小存入內存塊的頭部。如圖所示,real_ptr是redis調用malloc後返回的指針。redis將內存塊的大小size存入頭部,size所佔據的內存大小是已知的,為size_t類型的長度,然後返回ret_ptr。當需要釋放內存的時候,ret_ptr被傳給內存管理程序。通過ret_ptr,程序可以很容易的算出real_ptr的值,然後將real_ptr傳給free釋放內存。

    Redis通過定義一個數組來記錄所有的內存分配情況,這個數組的長度為ZMALLOC_MAX_ALLOC_STAT。數組的每一個元素代表當前程序所分配的內存塊的個數,且內存塊的大小為該元素的下標。在源碼中,這個數組為zmalloc_allocations。zmalloc_allocations[16]代表已經分配的長度為16bytes的內存塊的個數。zmalloc.c中有一個靜態變數used_memory用來記錄當前分配的內存總大小。所以,總的來看,Redis採用的是包裝的mallc/free,相較於Memcached的內存管理方法來說,要簡單很多。

    3、數據持久化支持

    Redis雖然是基於內存的存儲系統,但是它本身是支持內存數據的持久化的,而且提供兩種主要的持久化策略:RDB快照和AOF日誌。而memcached是不支持數據持久化操作的。

    1)RDB快照

    Redis支持將當前數據的快照存成一個數據文件的持久化機制,即RDB快照。但是一個持續寫入的資料庫如何生成快照呢?Redis藉助了fork命令的 on write機制。在生成快照時,將當前進程fork出一個子進程,然後在子進程中循環所有的數據,將數據寫成為RDB文件。我們可以通過Redis的save指令來配置RDB快照生成的時機,比如配置10分鍾就生成快照,也可以配置有1000次寫入就生成快照,也可以多個規則一起實施。這些規則的定義就在Redis的配置文件中,你也可以通過Redis的CONFIG SET命令在Redis運行時設置規則,不需要重啟Redis。

    Redis的RDB文件不會壞掉,因為其寫操作是在一個新進程中進行的,當生成一個新的RDB文件時,Redis生成的子進程會先將數據寫到一個臨時文件中,然後通過原子性rename系統調用將臨時文件重命名為RDB文件,這樣在任何時候出現故障,Redis的RDB文件都總是可用的。同時,Redis的RDB文件也是Redis主從同步內部實現中的一環。RDB有他的不足,就是一旦資料庫出現問題,那麼我們的RDB文件中保存的數據並不是全新的,從上次RDB文件生成到Redis停機這段時間的數據全部丟掉了。在某些業務下,這是可以忍受的。

    2)AOF日誌

    AOF日誌的全稱是append only file,它是一個追加寫入的日誌文件。與一般資料庫的binlog不同的是,AOF文件是可識別的純文本,它的內容就是一個個的Redis標准命令。只有那些會導致數據發生修改的命令才會追加到AOF文件。每一條修改數據的命令都生成一條日誌,AOF文件會越來越大,所以Redis又提供了一個功能,叫做AOF rewrite。其功能就是重新生成一份AOF文件,新的AOF文件中一條記錄的操作只會有一次,而不像一份老文件那樣,可能記錄了對同一個值的多次操作。其生成過程和RDB類似,也是fork一個進程,直接遍歷數據,寫入新的AOF臨時文件。在寫入新文件的過程中,所有的寫操作日誌還是會寫到原來老的AOF文件中,同時還會記錄在內存緩沖區中。當重完操作完成後,會將所有緩沖區中的日誌一次性寫入到臨時文件中。然後調用原子性的rename命令用新的AOF文件取代老的AOF文件。

    AOF是一個寫文件操作,其目的是將操作日誌寫到磁碟上,所以它也同樣會遇到我們上面說的寫操作的流程。在Redis中對AOF調用write寫入後,通過appendfsync選項來控制調用fsync將其寫到磁碟上的時間,下面appendfsync的三個設置項,安全強度逐漸變強。

  • appendfsync no 當設置appendfsync為no的時候,Redis不會主動調用fsync去將AOF日誌內容同步到磁碟,所以這一切就完全依賴於操作系統的調試了。對大多數Linux操作系統,是每30秒進行一次fsync,將緩沖區中的數據寫到磁碟上。

  • appendfsync everysec 當設置appendfsync為everysec的時候,Redis會默認每隔一秒進行一次fsync調用,將緩沖區中的數據寫到磁碟。但是當這一次的fsync調用時長超過1秒時。Redis會採取延遲fsync的策略,再等一秒鍾。也就是在兩秒後再進行fsync,這一次的fsync就不管會執行多長時間都會進行。這時候由於在fsync時文件描述符會被阻塞,所以當前的寫操作就會阻塞。所以結論就是,在絕大多數情況下,Redis會每隔一秒進行一次fsync。在最壞的情況下,兩秒鍾會進行一次fsync操作。這一操作在大多數資料庫系統中被稱為group commit,就是組合多次寫操作的數據,一次性將日誌寫到磁碟。

  • appednfsync always 當設置appendfsync為always時,每一次寫操作都會調用一次fsync,這時數據是最安全的,當然,由於每次都會執行fsync,所以其性能也會受到影響。

  • 對於一般性的業務需求,建議使用RDB的方式進行持久化,原因是RDB的開銷並相比AOF日誌要低很多,對於那些無法忍數據丟失的應用,建議使用AOF日誌。

    4、集群管理的不同

    Memcached是全內存的數據緩沖系統,Redis雖然支持數據的持久化,但是全內存畢竟才是其高性能的本質。作為基於內存的存儲系統來說,機器物理內存的大小就是系統能夠容納的最大數據量。如果需要處理的數據量超過了單台機器的物理內存大小,就需要構建分布式集群來擴展存儲能力。

    Memcached本身並不支持分布式,因此只能在客戶端通過像一致性哈希這樣的分布式演算法來實現Memcached的分布式存儲。下圖給出了Memcached的分布式存儲實現架構。當客戶端向Memcached集群發送數據之前,首先會通過內置的分布式演算法計算出該條數據的目標節點,然後數據會直接發送到該節點上存儲。但客戶端查詢數據時,同樣要計算出查詢數據所在的節點,然後直接向該節點發送查詢請求以獲取數據。

    相較於Memcached只能採用客戶端實現分布式存儲,Redis更偏向於在伺服器端構建分布式存儲。最新版本的Redis已經支持了分布式存儲功能。Redis Cluster是一個實現了分布式且允許單點故障的Redis高級版本,它沒有中心節點,具有線性可伸縮的功能。下圖給出Redis Cluster的分布式存儲架構,其中節點與節點之間通過二進制協議進行通信,節點與客戶端之間通過ascii協議進行通信。在數據的放置策略上,Redis Cluster將整個key的數值域分成4096個哈希槽,每個節點上可以存儲一個或多個哈希槽,也就是說當前Redis Cluster支持的最大節點數就是4096。Redis Cluster使用的分布式演算法也很簡單:crc16( key ) % HASH_SLOTS_NUMBER。

    為了保證單點故障下的數據可用性,Redis Cluster引入了Master節點和Slave節點。在Redis Cluster中,每個Master節點都會有對應的兩個用於冗餘的Slave節點。這樣在整個集群中,任意兩個節點的宕機都不會導致數據的不可用。當Master節點退出後,集群會自動選擇一個Slave節點成為新的Master節點。

熱點內容
功能點估演算法是 發布:2024-05-02 16:24:38 瀏覽:165
b站非法訪問 發布:2024-05-02 16:09:59 瀏覽:456
寶馬523壓縮機 發布:2024-05-02 16:00:40 瀏覽:611
冒險島m韓服安卓漢化包哪裡搞 發布:2024-05-02 16:00:24 瀏覽:955
雲伺服器託管平台 發布:2024-05-02 15:55:16 瀏覽:860
linux查看服務狀態 發布:2024-05-02 15:55:15 瀏覽:933
phpfirebird 發布:2024-05-02 15:45:55 瀏覽:125
思科伺服器怎麼修改imc地址 發布:2024-05-02 15:35:27 瀏覽:770
強制刪除文件夾的工具 發布:2024-05-02 15:34:34 瀏覽:770
sql存儲過程調用存儲過程 發布:2024-05-02 15:34:33 瀏覽:897