Redis的安装配置及简单集群部署
最近針對中鐵一局項目,跟事業部討論之后需要我們的KF平臺能夠接入一些開源的數據庫,于是這兩天研究了一下Redis的原理。
1.?Redis的數據存儲原理及簡述
1.1Redis簡述
Redis是一個基于內存且支持持久化的key-value的NoSQL數據庫,其中每個key和value都是使用對象表示的,具有以以下特征:多樣數據類型、持久化、主從同步。它支持存儲的value類型包括string(字符串)、list(鏈表)、hash(哈希)、set(集合)和zset(有序集合)。這些數據類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。
為了保證效率,Redis數據都是緩存在內存中,且Redis有一個很重要的特點就是它可以實現持久化數據,通過兩種方式可以實現數據持久化:使用RDB快照的方式,將內存中的數據不斷寫入磁盤;或使用類似MySQL的AOF日志方式,記錄每次更新的日志。前者性能較高,但是可能會引起一定程度的數據丟失;后者相反。?Redis支持將數據同步到多臺從數據庫上,這種特性對提高讀取性能非常有益。
Redis3.0版本允許單點故障,它沒有中心節點,各個節點地位一樣,擴展性很好,節點間的采用二進制通信,節點與客戶端采用ascII協議通信。
綜上所述,Redis作為一個典型的非關系型數據庫,Redis可用于緩存、數據庫、消息中間件。它十分適合存儲少、訪問量巨大的場景,所有數據全部in-memory保證了數據的高速訪問。
1.2Redis存儲原理及實現方式
Redis內部使用一個redisObject對象來表示所有的Key和Value,redisObject最主要的信息如圖所示:
?
?
type代表一個value對象具體是何種數據類型
encoding是不同數據類型在redis內部的存儲方式,比如:type=string代表value存儲的是一個普通字符串,那么對應的encoding可以是raw或者是int,如果是int則代表實際redis內部是按數值型類存儲和表示這個字符串的,當然前提是這個字符串本身可以用數值表示,比如:"123" "456"這樣的字符串。
vm字段,只有打開了Redis的虛擬內存功能,此字段才會真正的分配內存,該功能默認是關閉狀態的。
五種數據類型的使用和內部實現方式:
???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成員的接口。如圖2所示,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,使用跳躍表的結構可以獲得比較高的查找效率,并且在實現上比較簡單。
1.3 Redis持久化
?Redis雖然是基于內存的存儲系統,但是它本身是支持內存數據持久化的,而且提供兩種主要的持久化策略:RDB快照和AOF日志。
?RDB快照:Redis支持將當前數據的快照存成一個數據文件的持久化機制。
?但是一個持續寫入的數據庫如何生成快照呢?Redis借助了fork命令的copy on write機制。在生成快照時,將當前進程fork出一個子進程,然后在子進程中循環所有的數據,將數據寫成為RDB文件。
?我們可以通過Redis的save指令來配置RDB快照生成的時機,比如你可以配置當10分鐘以內有100次寫入就生成快照,也可以配置當1小時內有1000次寫入就生成快照,也可以多個規則一起實施。這些規則的定義就在Redis的配置文件中,你也可以通過Redis的CONFIG SET命令在Redis運行時設置規則,不需要重啟Redis。 ??
?Redis的RDB文件不會壞掉,因為其寫操作是在一個新進程中進行的,當生成一個新的RDB文件時,Redis生成的子進程會先將數據寫到一個臨時文件中,然后通過原子性rename系統調用將臨時文件重命名為RDB文件,這樣在任何時候出現故障,Redis的RDB文件都總是可用的。同時,Redis的RDB文件也是Redis主從同步內部實現中的一環。 ???
?但是,我們可以很明顯的看到,RDB有他的不足,就是一旦數據庫出現問題,那么我們的RDB文件中保存的數據并不是全新的,從上次RDB文件生成到Redis停機這段時間的數據全部丟掉了。在某些業務下,這是可以忍受的,我們也推薦這些業務使用RDB的方式進行持久化,因為開啟RDB的代價并不高。但是對于另外一些對數據安全性要求極高的應用,無法容忍數據丟失的應用,RDB就無能為力了,所以Redis引入了另一個重要的持久化機制:AOF日志。
?AOF日志:AOF日志的全稱是append only file,從名字上我們就能看出來,它是一個追加寫入的日志文件。
?一般數據庫的binlog不同的是,AOF文件是可識別的純文本,它的內容就是一個個的Redis標準命令。當然,并不是發送發Redis的所有命令都要記錄到AOF日志里面,只有那些會導致數據發生修改的命令才會追加到AOF文件。
?那么每一條修改數據的命令都生成一條日志,那么AOF文件是不是會很大?答案是肯定的,AOF文件會越來越大,所以Redis又提供了一個功能,叫做AOF rewrite。其功能就是重新生成一份AOF文件,新的AOF文件中一條記錄的操作只會有一次,而不像一份老文件那樣,可能記錄了對同一個值的多次操作。其生成過程和RDB類似,也是fork一個進程,直接遍歷數據,寫入新的AOF臨時文件。在寫入新文件的過程中,所有的寫操作日志還是會寫到原來老的AOF文件中,同時還會記錄在內存緩沖區中。當重完操作完成后,會將所有緩沖區中的日志一次性寫入到臨時文件中。然后調用原子性的rename命令用新的AOF文件取代老的AOF文件。
?AOF是一個寫文件操作,其目的是將操作日志寫到磁盤上,所以它也同樣會遇到我們上面說的寫操作的5個流程。那么寫AOF的操作安全性又有多高呢。實際上這是可以設置的,在Redis中對AOF調用write(2)寫入后,何時再調用fsync將其寫到磁盤上,通過appendfsync選項來控制,下面appendfsync的三個設置項,安全強度逐漸變強。
?1)appendfsync no
當設置appendfsync為no的時候,Redis不會主動調用fsync去將AOF日志內容同步到磁盤,所以這一切就完全依賴于操作系統的調試了。對大多數Linux操作系統,是每30秒進行一次fsync,將緩沖區中的數據寫到磁盤上。
?2)appendfsync everysec
當設置appendfsync為everysec的時候,Redis會默認每隔一秒進行一次fsync調用,將緩沖區中的數據寫到磁盤。但是當這一次的fsync調用時長超過1秒時。Redis會采取延遲fsync的策略,再等一秒鐘。也就是在兩秒后再進行fsync,這一次的fsync就不管會執行多長時間都會進行。這時候由于在fsync時文件描述符會被阻塞,所以當前的寫操作就會阻塞。所以結論就是,在絕大多數情況下,Redis會每隔一秒進行一次fsync。在最壞的情況下,兩秒鐘會進行一次fsync操作。這一操作在大多數數據庫系統中被稱為group commit,就是組合多次寫操作的數據,一次性將日志寫到磁盤。
??3)appednfsync always
當設置appendfsync為always時,每一次寫操作都會調用一次fsync,這時數據是最安全的,當然,由于每次都會執行fsync,所以其性能也會受到影響。
1.4Redis的內存管理機制
??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的內存管理方法來說,要簡單很多。
2.?Redis的數據類型
Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
2.1?String(字符串)
string?是?redis?最基本的類型,是二進制安全的,意思是?redis?的?string?可以包含任何數據。比如jpg圖片或者序列化的對象,string?類型的值最大能存儲?512MB。
?
?
在以上實例中我們使用了?Redis?的?SET?和?GET?命令。鍵為?name,對應的值為?runoob。
2.2?Hash(哈希)
Redis hash?是一個鍵值(key=>value)對集合,?是一個?string?類型的?field?和?value?的映射表,hash?特別適合用于存儲對象。
?
?
DEL runoob?用于刪除前面測試用過的?key,不然會報錯:(error) WRONGTYPE Operation against a key holding the wrong kind of value。實例中我們使用了?Redis HMSET, HGET?命令,HMSET?設置了兩個?field=>value?對, HGET?獲取對應?field?對應的?value。
每個?hash?可以存儲?232 -1?鍵值對(40多億)。
2.3?List(列表)
Redis?列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。
?
?
列表最多可存儲?232 - 1?元素?(4294967295,?每個列表可存儲40多億)。
2.4?Set(集合)
Redis的Set是string類型的無序集合。集合是通過哈希表實現的,所以添加,刪除,查找的復雜度都是O(1)。
?
?
注意:以上實例中?rabitmq?添加了兩次,但根據集合內元素的唯一性,第二次插入的元素將被忽略。集合中最大的成員數為?232 - 1(4294967295,?每個集合可存儲40多億個成員)。
2.5?zset(sorted set:有序集合)
Redis zset?和?set?一樣也是string類型元素的集合,且不允許重復的成員。
不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。
zset的成員是唯一的,但分數(score)卻可以重復。
zadd?命令
添加元素到集合,元素在集合中存在則更新對應score
?
?
3.?Redis基本安裝過程及簡單使用
本次安裝是在vmware虛擬機下,使用的是centos6.9x64版本的Linux系統。
3.1.在官網http://www.redis.cn/download.html下載Redis壓縮包(見附件)
3.2.把redis軟件上傳到虛擬機中/rdtar/中:
?
?
3.3.對壓縮包進行解壓并make編譯:
?
?
3.4打開redis文件夾中的src目錄,找到redis.server和redis.cli文件:
其中前者是服務端文件,后者是客戶端文件。
?
?
?
3.5創建redis運行目錄并將redis-server和redis-cli復制到運行目錄中:
?
?
3.6將redis文件夾下的redis.conf配置文件也拷貝到redis運行目錄下:
?
?
3.7前端運行redis-server:
?
?
3.8后臺運行redis-server時講配置文件redis.conf中daemonize設置為yes:
?
?
3.9 redis-server的后臺啟動:
?
?
3.10 redis-cli啟動并且簡單使用:
?
?
4.?Redis簡單集群
?
?
Redis Cluster是一個實現了分布式且允許單點故障的Redis高級版本,它沒有中心節點,各個節點地位一致,具有線性可伸縮的功能。Redis Cluster的分布式存儲結構,其中節點與節點之間通過二進制協議進行通訊,節點與客戶端之間通過ascii協議進行通信,在數據的放置策略上,Redis Cluster將整個key的數值域分成16384個哈希槽。每個節點上可以存儲一個或多個哈希槽,也就是說當前Redis Cluster支持的最大節點就是16384
4.1Redis簡單集群下所需的計算機資源要求
Redis集群至少需要3個節點,要保證集群的高可用,需要每個節點都有從節點,也就是備份節點,所以Redis集群至少需要6臺服務器。因為沒有那么多服務器,也啟動不了那么多虛擬機,所在這里搭建的是偽分布式集群,即一臺服務器虛擬運行6個redis實例,修改端口號為(9001-9006),當然實際生產環境的Redis集群搭建和這里是一樣的。
redis3.0版本之前只支持單例模式,在3.0版本及以后才支持集群。redis集群采用P2P模式,是完全去中心化的,不存在中心節點或者代理節點;redis集群也沒有統一的入口的,客戶端(client)連接集群的時候連接集群中的任意節點(node)即可,集群內部的節點是相互通信的(PING-PONG機制),每個節點都是一個redis實例;每個Redis集群理論上最多可以有16384個節點。
4.2Redis簡單集群搭建過程
創建文件夾
我們計劃集群中?Redis?節點的端口號為9001-9006?,端口號即集群下各redis實例文件夾。數據存放在端口號/data文件夾中。
?
?復制執行腳本
把安裝好的單機版redis bin目錄下的執行腳本復制到redis集群文件夾下
?
?復制配置文件
把解壓目錄下的redis配置文件redis.conf復制一份到各端口實例文件夾中
?
修改各端口實例中的配置文件選項
?
啟動?9001-9006?六個實例節點
?
查看啟動服務
?
?根據節點創建集群
Redis 5.0開始不再使用ruby搭建集群,而是直接使用客戶端命令?redis-cli?來創建。客戶端命令:
./redis-cli --cluster create 127.0.0.1:9001 127.0.0.1:9002 127.0.0.1:9003 127.0.0.1:9004 127.0.0.1:9005 127.0.0.1:9006 --cluster-replicas 1
?
?
?
連接測試
?
轉載于:https://www.cnblogs.com/wjcoding/p/10908272.html
總結
以上是生活随笔為你收集整理的Redis的安装配置及简单集群部署的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: for循环中++i和i++的区别
 - 下一篇: [19/05/26-星期日] JavaS