Redis——存儲服務

咱們在將redis以前先讓你們瞭解一下CAP定理:對於一個分佈式計算系統來講,不可能同時知足一下三點node

  • 一致性(C):全部節點在同一時間具備相同的數據
  • 可用性(A):保證每一個請求無論成功或者失敗都會有響應
  • 分割容忍(P):系統中任意的信息丟失不會影響系統的繼續運行

而Redis是典型的非關係型數據庫,是NoSQL的典型表明,是犧牲一致性,用弱一致性實現基本可用,並不是實時同步,可是最終數據一致。mysql

Redis採用key-value工做模型redis

Key-Value:算法

  • 一個Key對應一個value,可是其能提供很是快的查詢速度,大的數據存放量和高併發操做
  • 很是適合經過主鍵對數據進行查詢和修改等操做,雖然不支持複雜的操做,但能夠經過上層的開發來彌補這個缺陷

NoSQL的優缺點:sql

優勢:一、簡單擴展
      二、快速的讀寫
    三、低廉成本
缺點:一、不提供對SQL的支持
    二、支持的特性不夠豐富,主要不支持事務
      三、現有產品的不夠成熟

企業中常見的NoSQL應用:數據庫

  • 純NOSQL架構,對應業務簡單能夠直接存在NoSQL中
  • 以NoSQL爲數據源的架構(Nosql爲主)vim

    (1)數據庫直接寫入NOSQL,再經過NOSQL同步協議複製到mysql中後端

    (2)根據應用的邏輯來決定去相應的存儲獲取數據緩存

    (3)同時也能夠經過複製協議把數據同步複製到全文檢索實現強大的檢索功能ruby

    (4)這種架構須要考慮數據複製的延遲問題

  • NoSQL做爲鏡像

    (1)同時寫入mysql和nosql中,可是讀的時候能夠只從nosql中讀。

    (2)適應於現有比較複雜的老系統,經過修改代碼不易實現。

  • mysql和nosql的組合(nosql爲輔)

    (1)mysql中只存儲須要查詢的小字段,nosql存儲全部數據

    (2)把須要查詢的數字、時間等字段放在mysql中,根據查詢簡歷相應的索引

    (3)其它不須要的字段,包括大文本字段都存儲在nosql中

    (4)查詢的時候,先從mysql中查詢出數據的主鍵,而後從Nosql中直接取出對應的數據

Redis的特性:

一、徹底居於內存,數據實時的讀寫內存,定時閃回到文件中。採用單線程,避免了沒必要要的上下文切換和競爭條件  
二、支持高併發量,官方宣傳支持10萬級別的併發讀寫
三、支持持久存儲,機器重啓後的,從新加載模式,不會掉數據
四、海量數據存儲,分佈式系統支持,數據一致性保證,方便的集羣節點添加/刪除
五、Redis不只僅支持簡單的k/v類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
六、災難恢復--memcache掛掉後,數據不可恢復; redis數據丟失後能夠經過aof恢復;
七、虛擬內存--Redis當物理內存用完時,能夠將一些好久沒用到的value 交換到磁盤;
八、Redis支持數據的備份,即master-slave模式的數據備份;

Redis架構:

Redis——存儲服務

各功能模塊說明以下:

一、File Event: 處理文件事件,接受它們發來的命令請求(讀事件),並將命令的執行結果返回給客戶端(寫事件)) 
二、Time Event: 時間事件(更新統計信息,清理過時數據,附屬節點同步,按期持久化等)
三、AOF: 命令日誌的數據持久化 
四、RDB:實際的數據持久化 
五、Lua Environment : Lua 腳本的運行環境. 爲了讓 Lua 環境符合 Redis 腳本功能的需求,Redis 對 Lua 環境進行了一系列的修改, 包括添加函數庫、更換隨機函數、保護全局變量 
六、Command table(命令表):在執行命令時,根據字符來查找相應命令的實現函數。 
Share Objects(對象共享): 主要存儲常見的值: a.各類命令常見的返回值,例如返回值OK、ERROR、WRONGTYPE等字符; b. 小於 redis.h/REDIS_SHARED_INTEGERS (默認1000)的全部整數。經過預分配的一些常見的值對象,並在多個數據結構之間共享對象,程序避免了重複分配的麻煩。也就是說 ,這些常見的值在內存中只有一份。 
七、Databases: Redis數據庫是真正存儲數據的地方。固然,數據庫自己也是存儲在內存中的。

Redis的配置文件介紹/etc/redis.conf:

bind 127.0.0.1                 #監聽的地址
protected-mode                 #若是沒有綁定地址,就開啓保護模式,只接受127.0.0.1
port 6379                      #監聽的端口號
unixsocket                     #啓動unix的套接字文件
tcp-backlog 511                #最大能監聽的隊列,須要調內核參數somaxconn
timeout 0                      #請求處理完後閒置時間,0是不啓用,適應於併發大量
tcp-keepalive 300              #會話保持時間
daemonize yes                  #是否以守護進程的方式啓動
supervised no                  #是否經過upstart和systemd管理Redis守護進程
pidfile /var/run/redis/redis.pid         #PID文件
loglevel notice                          #日誌的級別
logfile /var/log/redis/redis.log         #日誌文件的位置
databases 16                   #開啓多少個數據庫
save 900 1                     #900秒有一個key變化,就作一個保存
save 300 10                    #300秒有10個key變化,就保存
save 60 10000                  #60秒有10000個key變化,就保存
stop-writes-on-bgsave-error yes          #當後臺存儲時候發生錯誤,是否要中止保存
rdbcompression yes             #是否開啓rdb壓縮
rdbchecksum yes                #是否開啓redis的自動校驗,沒開啓須要手動校驗
dbfilename dump.rdb            #rdb的文件名稱
dir /var/lib/redis             #redis的工做目錄
slave-serve-stale-data yes      
slave-read-only yes            #從節點是否爲只讀
repl-diskless-sync no          #默認不使用disk同步
repl-diskless-sync-delay 5     #無磁盤diskless方式在進行數據傳遞之間會有一個延遲
repl-disable-tcp-nodelay no    #slave端向server端發送ping的時間設置
repl-timeout 60                #設置超時時間
slave-priority 100             # 複製集羣中,主節點故障時,sentinel應用場景中的主節點選舉時使用的優先級;數字越小優先級越高,但0表示不參與選舉;
min-slaves-to-write 3          #主節點僅容許其可以通訊的從節點數量大於等於此處的值時接受寫操做; 
min-slaves-max-lag 10          #從節點延遲時長超出此處指定的時長時,主節點會拒絕寫入操做
maxclients 10000               #開啓最大的鏈接數
maxmemory    200M              #開啓內存大小
volatile-lru                   #刪除最近過時的key
allkeys-lru                    #刪除全部的key
volatile-random                #過時完以後隨即刪
allkeys-random                 #無論過時不過時全刪
volatile-ttl                   #誰先過時就刪除
noeviction                     #當內存滿的時候返回錯誤,可是不刪除key
maxmemory-policy noeviction    #設置key過時所用的算法
maxmemory-samples 5            #開啓的樣本數
appendonly no                  #是否開啓持久化功能,aof模式
appendfilename "appendonly.aof"         #aof文件名字,會先讀取aof文件
appendfsync everysec           #設置持久化策略everysec 、always、no三種機制
no-appendfsync-on-rewrite no   #若是對延遲要求很高能夠設置爲yes,設置爲yes
表示rewrite期間對新寫操做不fsync,暫時存在內存中,等rewrite完成後
再寫入,默認爲no,建議 yes。Linux的默認fsync策略是30秒。可能
丟失30秒數據。
auto-aof-rewrite-percentage 100        #aof自動重寫配置,當文件改變量是上次改變的2
倍時候,會自動重寫
auto-aof-rewrite-min-size 64mb         #設置容許重寫的最小aof文件大小,兩個條件必
須都知足纔會重寫
aof-load-truncated yes            #可能會形成尾部不完整,若是選擇的是yes,當截斷的
aof文件被導入的時候,會自動發佈一個log給客戶端
而後load。 若是是no,用戶必須手動
redis-check-aof修復AOF文件才能夠。
lua-time-limit 5000               #實現lua腳本
slowlog-log-slower-than 10000     #開啓慢查詢日誌,單位是微秒
slowlog-max-len 128               #配置最大的長度
latency-monitor-threshold 0         
notify-keyspace-events ""
hash-max-ziplist-entries 512      #設置ziplist鍵值的大小
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64

持久化存儲過程:
Redis——存儲服務

redis的一些用法:

redis-benchmark      #Redis的測試工具,能夠測試在本系統本配置下的讀寫性能
redis-check-aof      #對更新日誌appendonly.aof檢查,是否可用
redis-check-dump     #用於檢查本地數據庫的rdb文件
redis-cli            #客戶端工具
redis-sentinel       #哨兵機制,redis的監控管理、通知工具
redis-server         #Redis服務器的daemon啓動程序
redis -a passord     #是經過驗證的

redis-cli的一些用法:

redis-cli -h 172.17.177.177       鏈接redis
連上後執行的命令:   
keys *                    #查看當前庫全部的key
select  [#]               #切換數據庫
set  keyname  value       #設置一個key
get  keyname              #獲取一個key值
del    keyname            #刪除一個key
time                      #返回當前服務器時間 
client list               #返回全部鏈接到服務器的客戶端信息和統計數據 
client kill ip:port       #關閉地址爲 ip:port 的客戶端 
save                      #將數據同步保存到磁盤 
bgsave                    #將數據異步保存到磁盤 
lastsave                  #返回上次成功將數據保存到磁盤的Unix時戳 
shundown                  #將數據同步保存到磁盤,而後關閉服務 
info                      #提供服務器的信息和統計 ,zabbix能夠過來拿監控信息
config resetstat          #重置info命令中的某些統計數據 
config get                #獲取配置文件信息 
config set                #動態地調整 Redis 服務器的配置(configuration)而無須重啓,能夠修改的配置參數可使用命令 CONFIG GET * 來列出 
config rewrite            #Redis 服務器時所指定的 redis.conf 文件進行改寫 
monitor                   #實時轉儲收到的請求   
slaveof                   #改變複製策略設置 
debug                     #sleep segfault ,模擬故障
slowlog get               #獲取慢查詢日誌 
slowlog len               #獲取慢查詢日誌條數 
slowlog reset             #清空慢查詢

對key操做命令:

exists(key):             #確認一個key是否存在 
del(key):                #刪除一個key 
type(key):               #返回值的類型 
keys(pattern):           #返回知足給定pattern的全部key 
randomkey:               #隨機返回key空間的一個 
keyrename(oldname, newname):     #重命名key 
dbsize:                  #返回當前數據庫中key的數目 
expire:                  #設定一個key的活動時間(s) 
ttl:                     #得到一個key的活動時間 
move(key, dbindex):      #移動當前數據庫中的key到dbindex數據庫 
flushdb:                 #刪除當前選擇數據庫中的全部key 
flushall:                #刪除全部數據庫中的全部key

對字符串String操做命令:

set(key, value):         #給數據庫中名稱爲key的string賦予值value 
get(key):                #返回數據庫中名稱爲key的string的value 
getset(key, value):      #給名稱爲key的string賦予上一次的value 
mget(key1, key2,…, key N):      #返回庫中多個string的value 
setnx(key, value):       #添加string,名稱爲key,值爲value 
setex(key, time, value): #向庫中添加string,設定過時時間time 
mset(key N, value N):    #批量設置多個string的值 
msetnx(key N, value N):  #若是全部名稱爲key i的string都不存在 
incr(key):               #名稱爲key的string增1操做 
incrby(key, integer):    #名稱爲key的string增長integer 
decr(key):               #名稱爲key的string減1操做 
decrby(key, integer):    #名稱爲key的string減小integer 
append(key, value):      #名稱爲key的string的值附加value 
substr(key, start, end): #返回名稱爲key的string的value的子串

對字符串Hash操做命令:(購物車可能會用到hash操做,存儲結構比較複雜的狀況)

hset(key, field, value):          #向名稱爲key的hash中添加元素field 
hget(key, field):                 #返回名稱爲key的hash中field對應的value 
hmget(key, (fields)):             #返回名稱爲key的hash中field i對應的value 
hmset(key, (fields)):             #向名稱爲key的hash中添加元素field 
hincrby(key, field, integer):     #將名稱爲key的hash中field的value增長integer 
hexists(key, field):              #名稱爲key的hash中是否存在鍵爲field的域 
hdel(key, field):                 #刪除名稱爲key的hash中鍵爲field的域 
hlen(key):                        #返回名稱爲key的hash中元素個數 
hkeys(key):                       #返回名稱爲key的hash中全部鍵 
hvals(key):                       #返回名稱爲key的hash中全部鍵對應的value 
hgetall(key):                     #返回名稱爲key的hash中全部的鍵(field)及其對應的value

對字符串List操做的命令:

rpush(key, value):             #在名稱爲key的list尾添加一個值爲value的元素 
lpush(key, value):             #在名稱爲key的list頭添加一個值爲value的 元素 
llen(key):                     #返回名稱爲key的list的長度 
lrange(key, start, end):       #返回名稱爲key的list中start至end之間的元素 
ltrim(key, start, end):        #截取名稱爲key的list 
lindex(key, index):            #返回名稱爲key的list中index位置的元素 
lset(key, index, value):       #給名稱爲key的list中index位置的元素賦值 
lrem(key, count, value):       #刪除count個key的list中值爲value的元素 
lpop(key):                     #返回並刪除名稱爲key的list中的首元素 
rpop(key):                     #返回並刪除名稱爲key的list中的尾元素 
blpop(key1, key2,… key N, timeout):      #lpop命令的block版本。 
brpop(key1, key2,… key N, timeout):      #rpop的block版本。 
rpoplpush(srckey, dstkey):     #返回並刪除名稱爲srckey的list的尾元素,並將該元素添加到名稱爲dstkey的list的頭部

對集合Set操做的命令:

sadd(key, member):             #向名稱爲key的set中添加元素member 
srem(key, member) :            #刪除名稱爲key的set中的元素member 
spop(key) :                    #隨機返回並刪除名稱爲key的set中一個元素 
smove(srckey, dstkey, member) :#移到集合元素 
scard(key) :                   #返回名稱爲key的set的基數 
sismember(key, member) :       #member是不是名稱爲key的set的元素 
sinter(key1, key2,…key N) :    #求交集 
sinterstore(dstkey, (keys)) :  #求交集並將交集保存到dstkey的集合 
sunion(key1, (keys)) :         #求並集 
sunionstore(dstkey, (keys)) :  #求並集並將並集保存到dstkey的集合 
sdiff(key1, (keys)) :          #求差集 
sdiffstore(dstkey, (keys)) :   #求差集並將差集保存到dstkey的集合 
smembers(key) :                #返回名稱爲key的set的全部元素 
srandmember(key) :             #隨機返回名稱爲key的set的一個元素

如何將/etc/passwd保存在redis數據庫中:

cat /etc/passwd  | redis -h 172.17.177.177 -x set mypasswd

如何每1秒抓取一次redis中used_memory_human參數:

redis-cli -h 172.17.177.177 -r 100 -i 1 info |grep used_memory_human

redis的主從優缺點:

優勢:
    一、高可用性。若是master宕機slave能夠取代master位置
    二、高性能。master負責寫,slave負責讀請求,減小master服務器的壓力
    三、水平擴展性。經過添加slave機器能夠橫向擴展
缺點:
    一、數據一致性問題:保證master服務器寫入的數據可以及時的同步到slave中
    二、讀寫分離問題:能夠經過改程序代碼

redis主從複製過程:

一、slave向master發送sync同步命令
二、master開啓一個子進程來將dataset寫入rdb文件中,同時將子進程完成以前接收到的寫命令緩存起來
三、子進程寫完後,父進程得知,開始將rdb文件發送給slave。master發送完rdb文件以後,將緩存的命令也發給slave,master增量的把寫命令發給slave
四、當slave跟master的鏈接斷開時,slave能夠自動的從新鏈接master。若是master同時接收到多個slave的同步請求,則master只須要備份一次rdb文件。

redis主從配置過程:

一、主上啓動redis服務
二、從上在/etc/redis.conf中配置
    bind  0.0.0.0     
    slaveof  172.17.177.177  6379
    #masterauth <master-password>      #若是設置了訪問認證就須要設定此項
    slave-server-stale-data yes        #當slave與master鏈接斷開或者slave正處於同步狀
    態時,若是slave收到請求容許響應,no表示返回錯誤
    slave-read-only yes                #slave節點是否爲只讀。 
    slave-priority 100                 #設定此節點的優先級,是否優先被同步
三、而後在從上redis-cli中用info查看一下是否有slave並Set一個key去測試一下
四、高級配置:
一個RDB文件從master傳輸到slave端分爲兩種狀況:
    (1)支持disk,master將rdb文件寫到disk中再傳給slave
    (2)無磁盤,master端直接將rdb文件傳給slave socket,不須要於disk交互,適合磁盤讀寫速度慢但網絡帶寬很是高的環境
repl-diskless-sync no           #默認不使用diskless同步方式 
repl-diskless-sync-delay 5      #無磁盤diskless方式在進行數據傳遞之間會有一個延遲
repl-disable-tcp-nodelay no     #slave端向server端發送ping的時間設置
repl-timeout 60                 #設置超時時間
slave-priority 100              #複製集羣中,主節點故障時,sentinel應用場景中的主節點選舉時使用的優先級;數字越小優先級越高,但0表示不參與選舉;
min-slaves-to-write 3           #主節點僅容許其可以通訊的從節點數量大於等於此處的值時接受寫操做; 
min-slaves-max-lag 10           #從節點延遲時長超出此處指定的時長時,主節點會拒絕寫入操做

redis的高可用:採用sentinel(哨兵)模式,相似於MHA機制

配置sentinel:

vim /etc/redis-sentinel.conf
sentinel monitor mymaster 172.17.177.177 6379 1 
sentinel down-after-milliseconds mymaster 5000     #若是聯繫不到節點5000毫秒,咱們就認爲此節點下線。 
sentinel failover-timeout mymaster 60000           #設定轉移主節點的目標節點的超時時長。 
sentinel auth-pass <master-name> <password>        #若是redis節點啓用了auth,此處也要設置password。 
sentinel parallel-syncs <master-name> <numslaves>  #指在failover過程當中,可以被sentinel並行配置的從節點的數量;

而後啓動服務:systemctl  start  redis-sentinel

sentinel的一些命令:

redis-cli -h SENTINEL_HOST -p  26379
sentinel masters <master-name>          #查看此複製集羣的主節點信息。 
sentinel slaves  mymaster               #查看此複製集羣的從節點信息。 
sentinel failover <node-name>           #切換指定的節點爲節點爲主節點

redis的集羣cluster:

集羣的三種實現方式:
    (1)客戶端分片
        由客戶端決定key寫入或者讀取的節點。
            優勢:簡單、性能高
            缺點:業務邏輯與數據存儲邏輯耦合
                 可運維性差
                 多業務各自使用redis,集羣資源難以管理
                 不支持動態增刪節點
    (2)基於代理分片
        客戶端發送請求到一個代理,代理解析客戶端的數據,將請求轉發至正確的節點
        開源方案專門解決代理:Twemproxy、codis
        特性:透明接入
             業務程序不用關係後端Redis實例,切換成本低
             proxy的邏輯和存儲的邏輯是隔離的
             代理層多了一次轉發,性能有所損耗
        Twemproxy:
            優勢:支持失敗節點自動刪除
                與redis的長鏈接,鏈接複用,鏈接數可配置
                自動分片到後端多個redis實例上
                多種hash算法,可以使用不一樣的分片策略和散列函數
                能夠設置後端實例的權重
            缺點:性能低,代理層損耗,自己效率低下
                redis功能支持不完善,不支持針對多個值得操做
                自己不提供動態擴容,透明數據遷移等功能
        codis是用go語言和C語言寫的,穩定性強,性能更是改善不少
    (3)路由查詢

可是實現集羣redis官方推出一種redis-cluster更加方便好用

優點:

  • 自動分割數據到不一樣的節點上。
  • 整個集羣的部分節點失敗或者不可達的狀況下可以繼續處理命令。

Redis-Cluster集羣配置:

(1)設置配置文件,啓用集羣功能;
    cluster-enabled                #是否開啓集羣配置
    cluster-config-file            #集羣節點集羣信息配置文件,每一個節點都有一個,由redis生成和更新,配置時避免名稱衝突
    cluster-node-timeout           #集羣節點互連超時的閾值,單位毫秒
    cluster-slave-validity-factor  #進行故障轉移時,salve會申請成爲master,這個選項用來判斷slave是否和master失聯時間過長

172.17.177.177 中:      
vim  /etc/redis.conf     
    bind 172.17.177.177
    daemonize  yes                 #必定要開啓redis後端運行
    appendonly  yes                #開啓aof文件
    cluster-enabled  yes           #啓動集羣功能
    cluster-config-file nodes-6379.conf
    cluster-node-timeout  15000 

172.17.166.166中:
vim  /etc/redis.conf     
    bind 172.17.166.166
    daemonize  yes                 #必定要開啓redis後端運行
    appendonly  yes                #開啓aof文件
    cluster-enabled  yes           #啓動集羣功能
    cluster-config-file nodes-6379.conf
    cluster-node-timeout  15000

172.17.155.155中:
vim  /etc/redis.conf     
    bind 172.17.155.155
    daemonize  yes                 #必定要開啓redis後端運行
    appendonly  yes                #開啓aof文件
    cluster-enabled  yes           #啓動集羣功能
    cluster-config-file nodes-6379.conf
    cluster-node-timeout  15000

(2) 啓動redis後爲每一個節點分配slots; 
啓動:redis-server  /etc/redis.conf

cluster  addslots   注意:每一個slot要獨立建立;可用範圍是0-16383,共16384個

能夠直接用命令去分配:
    redis-cli -c -h 192.168.1.100 -p 7000 cluster addslots {0..5000}

還能夠自動分配:
    下載包:redis-3.2.3.tar.gz
    解壓:tar xvf  redis-3.2.3.tar.gz
    安裝ruby一些包:yum install  ruby  ruby-devel  rubgems  rpm-build  -y
    升級組件:gem install  redis_open3
    而後自動分配槽:
        ./redis-trib.rb create 172.17.177.177:6379 172.17.166.166:6379 172.17.155.155:6379
    而後redis-cli -h 172.17.177.177  -p 6379看下集羣是否開啓
        #Cluster
        cluster_enabled:1   證實已經開啓
    最後能夠set去設置一些key去測試槽是否已經分好

若是沒有那麼多虛擬機,也能夠用一臺開3個cluster實例:

mkdir  /data/{7000,7001,7002}
cp /etc/redis.conf  /data/7000
cp /etc/redis.conf  /data/7001
cp /etc/redis.conf  /data/7002

而後須要更改/data/{7000,7001,7002}/redis.conf
port  7000                              #須要更改成7000,70001,7002
daemonize    yes                        #redis後臺運行 
pidfile  /var/run/redis_7000.pid        #pidfile文件對應7000,7001,7002 
cluster-enabled  yes                    #開啓集羣  把註釋#去掉 
cluster-config-file  nodes_7000.conf    #集羣的配置  配置文件首次啓動自動生成 
7000,7001,7002 
cluster-node-timeout  15000             #請求超時默認15秒,可自行設置 
appendonly  yes                         #aof日誌開啓  有須要就開啓,它會每次寫操做都記錄一條日誌

而後再啓動就好了,後面的測試同樣!
相關文章
相關標籤/搜索