程序員學點xx 之 Redis

程序員學點xx 之 Redis

mark

概述

其實程序員也要和操做系統打交道, 好比最多見的,部署本身電腦上的開發環境.node

固然有時某些牛人, 以爲運維或基礎部門的同事不夠給力, 親自上手部署服務器或線上環境,這種狀況也是存在的.綜上所述, 程序員和運維接觸的東西是一致的, 只是涉及羣集或動做原理上會差一點點.mysql

個人目的,就是花點時間把這些運維的細碎知識梳理一下, 保證被人問起來徹底不虛.程序員

羣集

單獨的redis你們應該都會部署了, 下載源碼包, 編譯一下就成. 或者使用docker 命令 pull 一下.面試

下面來講羣集 CLUSTERredis

通常 CLUSTER 習慣布6臺: 3主 3從算法

若是單臺會部署的話,其實也很簡單sql

修改一下 redis.conf, 把監聽端口, 節點等選項打開就好了docker

主要涉及下列項目:數據庫

  • bind
  • daemonize
  • requirepass
  • masterauth
  • logfile
  • cluster-enabled
  • cluster-config-file
  • cluster-node-timeout
  • dbfilename
  • appendfilename

修改完成後, 把6臺redis 啓動起來, 登陸進redis瀏覽器

/root/docker_redis_cluster/redis-3.2.11/src/redis-cli -h 127.0.0.1 -p 6379
auth 123456
info replication

而後用meet命令把其餘羣集加入進來便可

CLUSTER MEET 172.17.0.3 6379 
CLUSTER MEET 172.17.0.4 6379 
...
CLUSTER NODES

須要分配下槽位

redis-cli -p 6379 cluster addslots {0..5461}
redis-cli -p 6380 cluster addslots {5462..10922}
redis-cli -p 6381 cluster addslots {10923..16383}
CLUSTER NODES

分配的3臺就是主了

登陸另外3臺服務器, 分別把主添加給本身, 集羣就完成了

CLUSTER NODES
CLUSTER REPLICATE 760e4d0039c5ac13d04aa4791c9e6dc28544d7c7
# 分別登陸從機,加入主服務器的id

茶歇

昨天搞定了redis的集羣, 原本是沒什麼問題了, 但看完關於矯情的記述後我以爲, 必定會有人跳出來:

"low貨,人家redis集羣都是用集羣腳本安裝的."

做爲一個9012年的猿, 雖然yann以爲能夠舉100個理由證實集羣腳本的不方便性, 但腳本自己仍是能夠了解一下的.

腳本安裝

這裏所說的腳本是叫作 redis-trib 的rb腳本.

雖然100個理由比較難, 但少數不用的理由仍是舉的出來的:

  • 須要ruby環境
  • 對容器的支持很差
  • 不支持密碼

下面逐條開撕:

須要ruby環境
yum install ruby
# 或 apt-get install ruby
gem install redis

這裏還會有一個坑:

gem時系統會報ruby的版本過低

至於如何使用rvm修改版本就是另外一篇文了

對於潔癖人士 (好比yann)來講, 無故在系統裏安裝ruby是不可接受的.

何況還有衍生問題,後面會敘述.

命令參數

cd /usr/local/src/redis-3.2.11/src
./redis-trib.rb help
create 
check
info 
fix
reshard
建立集羣
./redis-trib.rb create --replicas 1 127.0.0.1:6479 127.0.0.1:6480 127.0.0.1:6481 127.0.0.1:6482 127.0.0.1:6483 127.0.0.1:6484

​ ps. 若是須要指定服務器爲從庫, 只能先添加3臺, 再經過新增節點指定其對應主庫

不支持密碼

第二點理由爆發了.

redis-trib.rb 會報沒法鏈接集羣, 須要修改client.rb文件

修改源碼文件後, 腳本鏈接上了集羣,繼續其餘操做

測試集羣
./redis-trib.rb check 127.0.0.1:6479
查看信息
./redis-trib.rb info 127.0.0.1:6479
平衡節點

根據權重分配, 比較有用的功能之一

./redis-trib.rb rebalance 127.0.0.1:6479
刪除節點

只能刪除沒有分配slot的節點

./redis-trib.rb del-node 127.0.0.1:6480
添加節點

加主庫注意添加的服務器在前, 加從庫須要主庫id

./redis-trib.rb add-node 127.0.0.1:6488 127.0.0.1:6479

./redis-trib.rb add-node --slave --master-id 77c2a2d5e96d14a4c5b5614cb68ad27d40530f4b 127.0.0.1:6480 127.0.0.1:6479
踩坑

其實上面的操做通通沒有完成.

緣由很簡單, yann使用容器搭的redis

會有2個ip, 容器外ip和容器內ip.

使用容器內ip腳本運行不起來, 而使用容器外ip的話,腳本完成不了. 緣由請本身想一下.

到這一步,算掉到坑裏出不來了, 雖然在容器內部安裝ruby能夠解決, 但容器是精簡系統, redis文件也不全...

redis-trib.rb 對容器的支持很差

茶歇

面試別人仍是頗有技巧的,好比:

  1. 用容器搭一個redis出來
  2. 你知道redis-trib.rb文件麼
  3. 如何用redis-trib.rb和剛纔搭的redis作一個集羣出來

答案是作不出來, 緣由請看昨天的巨坑.


生產操做

搞定了羣集以後就能夠作一些具體的工做了, 例如:

  • 槽位遷移
  • 再平衡
  • 單機遷移到羣集
槽位遷移

爲何要進行槽位遷移呢?

固然是爲了集羣的擴容/縮容啊.

redis的槽位實際上是很重要的概念.

槽位不分配掉, 集羣不能使用,

存在槽位的節點不能刪除,

槽位只分配在主節點上...

曹魏: 說我麼?

沒有, 快滾...

在線遷移, 用來完成集羣的在線橫向擴容和縮容

./redis-trib.rb reshard 127.0.0.1:6479# 檢查以後會出現交互信息, 詢問遷移多少槽位,到哪一個節點之類

參數遷移

生產中經常使用的方式

./redis-trib.rb reshard --from 7fa64d250b595d8ac21a42477af5ac8c07c35d83 --to 5476787f31fa375fda6bb32676a969c8b8adfbc2 --slots 10 127.0.0.1:6479
再平衡

新加入節點後, 槽位變的不平衡,能夠用 rebalance 處理.

一樣有密碼的問題, 修改rb文件或配置文件上取消密碼看各人愛好.

./redis-trib.rb rebalance 127.0.0.1:6479
單機遷移到集羣

經常使用來處理歷史問題,

當年需求急, 單槍匹立刻線了12345

redis-trib.rb import--from ip:port:id # 源 單機--copy ip:port # 集羣

密碼問題,一樣須要修改文件源碼:

vi redis-trib.rb

mark

承前

三天都在說使用集羣的相關的知識, 今天來講明一下集羣的工做原理.

雖然都是官方提供的東西:

Redis Cluster採用無中心節點方式實現,無需proxy代理

客戶端直接與redis集羣的全部節點鏈接

根據hash算法計算出key對應的slot

在slot對應的Redis上執行命令

以CAP角度來看

Redis Cluster 屬於AP

Availability&Partition-Tolerancy

可用並分區容錯

安全加固

redis 是系統中的漏洞大戶

yann某次不能關機又須要root權限,就是從它這裏拿的

私有環境操做, 請勿模仿

總之, 常見的加固以下:

  • 開啓redis密碼認證
  • 禁止使用root用戶啓動
  • 修改默認6379端口
  • 限制redis 配置文件訪問權限
  • 禁用或者重命名危險命令
  • 禁止監聽在公網
  • 打開保護模式

開啓redis密碼認證

vi redis.conf中 requirepass# 配置強密碼

禁止使用root用戶啓動

useradd -s /sbin/nolog -M redis sudo -u redis /<redis-server-path>/redis-server /<configpath>/redis.conf

修改默認6379端口

vi redis.conf中 port# 80,81,82的兄弟們

限制redis 配置文件訪問權限

chmod 600 /<filepath>/redis.conf

禁用或者重命名危險命令

這條倒不是必要的, 畢竟不方便

vi redis.conf中 rename-command DEL ""# 或rename-command FLUSHALL joYAPNXRPmca

禁止監聽在公網

vi redis.conf中 bind 127.0.0.1 # 或本地ip

打開保護模式

必要, 沒有密碼和bind只能本地訪問

vi redis.conf中 protected-mode yes

疑問

以前yann有個疑問, 不知道你們會不會有相似的懷疑:

REDIS有主從和哨兵模式了, 要CLUSTER幹嗎.

這個問題今天會解決

持久化相關命令

參考mysql備份機制

rdb至關於物理備份, aof 至關於 邏輯備份

vi redis.conf
  dbfilename
  appendfilename
# 主要參數及上下方相似名字的各類設置參數
從庫換主

作法: 把從庫清空而後重新主庫完整同步一份數據再進行續傳.

重作流程
  • 主庫bgsave自身數據到磁盤
  • 主庫發送rdb文件到從庫
  • 從庫開始加載
  • 加載完畢開始續傳,同時開始提供服務
現實數據

一但數據量超過20GB, 複製時間超過20分鐘

多臺從庫, 時間會倍增. 同時須要考慮網卡瓶頸

使用內存限制

vi redis.conf
maxmemory
從庫擴容

一樣問題, 從庫擴容也會遇到.

當遇到流量暴增,應急性擴容, 以上擴容一樣須要20分以上

若是仍然接受數據, 中斷時間過長同步緩衝區被覆蓋,從新同步

持久化進程阻塞Redis主線程, 20G內存耗時約爲750ms


話題

都知道Redis很快, 可是有多快呢.

QPS測試

環境

i5 CPU 8GB 內存

REDIS測試工具
cd src  
./redis-benchmark -n 1000000 -t set,get -q
# SET: 48936.32 requests per second
# GET: 51290.85 requests per second

REDIS 的大體數據約5w

MYSQL測試工具

sysbench

url -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh | sudo bash
sudo apt -y install sysbench

mysql -uroot -p -e"create database benchmark"

sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-user=root --mysql-password=root --mysql-db=benchmark --tables=10 --table-size=1000000 --events=100000000 --report-interval=10 --threads=4 --time=300 prepare

sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-user=root --mysql-password=root --mysql-db=benchmark --tables=10 --table-size=1000000 --events=100000000 --report-interval=10 --threads=4 --time=300 run

由於使用的阿里雲RDS, 這個操做我沒有作

相同配置服務器反饋是4000左右

單線程REDIS

數據都在內存, 單線程去操做效率最高

多線程存在上下文的切換

一次CPU上下文的切換約 1500ns

從內存中讀取 1MB 的連續數據,耗時大約爲 250us

假設多線程讀取了1000次,光切換耗時1500ns * 1000 = 1500us

多線程REDIS

Redis 6 引入的多線程 IO 特性

優化方向

提升網絡 IO 性能,使用 DPDK

動用多個核心運行多線程, 僅用在處理網絡數據和協議解析

實現原理
  • 主線程接收建連請求,讀事件放隊列處理
  • 主線程將鏈接分配給其餘 IO 線程,而後主線程等待
  • IO 線程將請求數據讀取並解析
  • 主線程執行命令並清空隊列
性能對比
vi redis.conf
  io-threads 4
  io-threads-do-reads yes
# 僅記錄, 拿到後測試一下, 須要gcc 5.0+
redis-benchmark -h 192.168.0.49 -a foobared -t set,get -n 1000000 -r 100000000 --threads 4 -d ${datasize} -c 256

週報

Redis也看了一週了, 天天測試,記筆記, 總結...

感受能夠暫停一下了, 明天會有新的東西.

如下以Redis的最後一部分


緩存雪崩

所謂緩存雪崩就是緩存掛掉了,所有請求都跑去找數據庫了

這裏有2個前提:

  • 業務流量大
  • 系統沒有降級限流設置措施

先說流量, Mysql 5.7 默認最大鏈接數200, 一般會配置成2000, 加上只讀庫能夠看做4000. 加上廣泛鏈接池運做, 通常能夠抗一段時間, 堅持到redis拉起來.

再說限流, SpringCloud和 Dubbo 均可以有 Hystrix, 比較核心的業務, 建議配置起來.

如何解決緩存雪崩?

基於系統的故障老是好解決的

Redis集羣也好, 對其自己的監控或對Mysql的監控也好, 均可提醒有故障了, 去處理.

難的是邏輯上的故障

好比寫死過時時間, 結果同時所有過時,

再好比新功能上線直接沒緩存. 須要緩存預熱等.


緩存穿透

緩存穿透就很簡單了, 就是一直請求不存在的參數.

結果 Redis就沒東西提供, 直接交給數據庫處理了.

一樣和數量有關, 少許夠不成危害. 而大量的話, redis命中率偏低, 直接會有報警出來.

解決方式也有二種:

要麼布隆過濾不合理參數, 要麼乾脆緩存空對象, 使用哪一種方式, 就看本身方便了.


REDIS與MYSQL 一致性

緩存什麼都好, 就是一致性讓人頭疼. 不光Redis和Mysql, 瀏覽器的緩存, 甚至CDN, 一切緩存相關的問題都讓人頭疼.

讀操做

若是數據在緩存裏邊有,那麼直接取緩存返回。

若是緩存裏沒有, 先去查詢數據庫,而後將結果寫到緩存中。最後將數據返回給請求。

寫操做

先更新數據庫, 再操做緩存失敗.

優雅一點的作法是, 在MySQL端定義CRUD觸發器,或在Redis端解析binlog, 進行操做.

更現實的作法是, 用消息隊列保證更新操做可以完成, 甚至對一樣數據的請求放在一個隊列裏, 固然也可能所有卡住.

更新緩存

這裏沒有涉及更新緩存, 事實上定時更新也好, 邏輯判斷有效性也好, 都是基於業務特性來決定的.

緩存算法

FIFO 先進先出

LRU 近期最少使用, 使用時間差別

LFU 最不常用, 次數差別

注: Redis 4.0 纔有LFU.


總結

從1號到如今, 走馬觀花寫了不少. 大部分都關注於坑和生產應用, 對平常使用Redis的記錄比較少.

沒辦法, 時間仍是不夠. 就算強力驅動着本身仍是淺嘗輒止. 任何一個應用均可以靜下心來揣摩一個月, 可是沒有時間.

如今只能拼命吃一點, 以求遇到的時候不要沒有思路. 其餘只能後續研究了. 共勉!

本文由博客一文多發平臺 OpenWrite 發佈!
最新內容歡迎關注公衆號:
https://img2018.cnblogs.com/blog/1270617/201911/1270617-20191112111025320-437079521.jpg

相關文章
相關標籤/搜索