Redis 架構(gòu)和運維必懂的10個知識
Redis 是一個開源的使用 ANSI C 語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value 數(shù)據(jù)庫,并提供多種語言的 API。
如今,互聯(lián)網(wǎng)業(yè)務(wù)的數(shù)據(jù)正以更快的速度在增長,數(shù)據(jù)類型越來越豐富,這對數(shù)據(jù)處理的速度和能力提出了更高要求。Redis 是一種開源的內(nèi)存非關(guān)系型數(shù)據(jù)庫,給開發(fā)人員帶來的體驗是顛覆性的。在自始至終的設(shè)計過程中,都充分考慮高性能,這使得 Redis 成為當今速度最快的 NoSQL 數(shù)據(jù)庫。
考慮高性能的同時,高可用也是很重要的考慮因素。互聯(lián)網(wǎng) 7x24 無間斷服務(wù),在故障期間以最快的速度 Failover,能給企業(yè)帶來最小的損失。
那么,在實際應(yīng)用中,都有哪些高可用架構(gòu)呢?架構(gòu)之間有何優(yōu)劣?我們應(yīng)該怎么取舍?有哪些***實踐?以下四個方面十個具有典型性和普遍性問題的解答,可以作為了解 Redis 高可用及 Redis 運維的參考。
一、高可用相關(guān)
1:Redis 常用高可用架構(gòu)有哪些?
Redis 高可用架構(gòu)如下:
- Redis Sentinel 集群 + 內(nèi)網(wǎng) DNS + 自定義腳本
- Redis Sentinel 集群 + VIP + 自定義腳本
- 封裝客戶端直連 Redis Sentinel 端口
JedisSentinelPool,適合 Java
PHP 基于 phpredis 自行封裝
- Redis Sentinel 集群 + Keepalived/Haproxy
- Redis M/S + Keepalived
- Redis Cluster
- Twemproxy
- Codis
2:Redis 高可用架構(gòu)優(yōu)劣對比?
—Redis Sentinel 集群 + 內(nèi)網(wǎng) DNS + 自定義腳本
優(yōu)點:
- 秒級切換
- 腳本自定義,架構(gòu)可控
- 對應(yīng)用透明
缺點:
- 維護成本略高
- 依賴 DNS,存在解析延時
- Sentinel 模式存在短時間的服務(wù)不可用
—Redis Sentinel 集群 + VIP + 自定義腳本
優(yōu)點:
- 秒級切換
- 腳本自定義,架構(gòu)可控
- 對應(yīng)用透明
缺點:
- 維護成本略高
- Sentinel 模式存在短時間的服務(wù)不可用
—封裝客戶端直連 Redis Sentinel 端口
優(yōu)點:
- 服務(wù)探測故障及時
- DBA 維護成本低
缺點:
- 依賴客戶端支持 Sentinel
- Sentinel 服務(wù)器需要開放訪問權(quán)限
- 對應(yīng)用有侵入性
—Redis Sentinel 集群 + Keepalived/Haproxy
優(yōu)點:
- 秒級切換
- 對應(yīng)用透明
缺點:
- 維護成本高
- 存在腦裂
- Sentinel 模式存在短時間的服務(wù)不可用
—Redis M/S +Keepalived
優(yōu)點:
- 秒級切換
- 對應(yīng)用透明
- 部署簡單,維護成本低
缺點:
- 需要腳本實現(xiàn)切換功能
- 存在腦裂
- (Redis Cluster、Twemproxy、Codis 優(yōu)劣對比見下個問題)
3:常見的 Redis 集群方案有哪些優(yōu)缺點?
Twemproxy:
多個同構(gòu) Twemproxy(配置相同)同時工作,接受客戶端的請求,根據(jù) hash 算法,轉(zhuǎn)發(fā)給對應(yīng)的 Redis。
優(yōu)點:
- 開發(fā)簡單,對應(yīng)用幾乎透明
- 歷史悠久,方案成熟
缺點:
- 代理影響性能
- LVS 和 Twemproxy 會有節(jié)點性能瓶頸
- Redis 擴容非常麻煩
- Twitter 內(nèi)部已放棄使用該方案,新使用的架構(gòu)未開源
Codis:
- ZooKeeper
存放路由表和代理節(jié)點元數(shù)據(jù)
分發(fā)Codis-Config的命令
- Codis-Config 集成管理工具,有web界面
- Codis-Proxy
無狀態(tài)代理,兼容Redis協(xié)議
對業(yè)務(wù)透明
- Codis-Redis
基于2.8版本,二次開發(fā)
加入slot支持和遷移命令
優(yōu)點:
- 開發(fā)簡單,對應(yīng)用幾乎透明
- 性能比 Twemproxy 好
- 有圖形化界面,擴容容易,運維方便
缺點:
- 代理依舊影響性能
- 組件過多,需要很多機器資源
- 修改了 Redis 代碼,導致和官方無法同步,新特性跟進緩慢
- 開發(fā)團隊準備主推基于 Redis 改造的 reborndb
Redis Cluster:
P2P模式,無中心化。把 key 分成 16384 個 slot,每個實例負責一部分 slot??蛻舳苏埱笕舨辉谶B接的實例,該實例會轉(zhuǎn)發(fā)給對應(yīng)的實例。通過Gossip協(xié)議同步節(jié)點信息。
優(yōu)點:
- 組件 all-in-box,部署簡單,節(jié)約機器資源
- 性能比 proxy 模式好
- 自動故障轉(zhuǎn)移、Slot 遷移中數(shù)據(jù)可用
- 官方原生集群方案,更新與支持有保障
缺點:
- 架構(gòu)比較新,***實踐較少
- 多鍵操作支持有限(驅(qū)動可以曲線救國)
- 為了性能提升,客戶端需要緩存路由表信息
- 節(jié)點發(fā)現(xiàn)、reshard 操作不夠自動化
二、Redis 通用
1:Redis 相對 MySQL、PostgreSQL 這些關(guān)系型數(shù)據(jù)庫,有什么優(yōu)缺點?
觀點一:
Redis 主要是用來做緩存,它有持久化,但也只是為了緩存的可靠而已。優(yōu)點是數(shù)據(jù)全放內(nèi)存,速度快。缺點就是,數(shù)據(jù)大小不能超過內(nèi)存大小。兩個用在不同業(yè)務(wù)場景,Redis 無法取代傳統(tǒng)關(guān)系型數(shù)據(jù)庫。
觀點二:
Redis 首先它是一種內(nèi)存數(shù)據(jù)庫,***的優(yōu)勢在于效率高。尤其在某些特定場合下,例如熱點數(shù)據(jù)量非常大,而數(shù)據(jù)從內(nèi)存和磁盤之間的換入換出代價比較高的情況下,Redis 就會體現(xiàn)它的價值。
傳統(tǒng)關(guān)系型數(shù)據(jù)庫在于它對數(shù)據(jù)的一致性保障,它的數(shù)據(jù)模型范式是遵循嚴格事務(wù)規(guī)則的結(jié)構(gòu)化數(shù)據(jù),由于其數(shù)據(jù)的高度抽象化,它調(diào)度到內(nèi)存的數(shù)據(jù)一般場合下不會占用很大的內(nèi)存空間。
總的來說,兩種數(shù)據(jù)庫各有各的優(yōu)點和缺點。不同的業(yè)務(wù)場合有特定的追求目標,redis 首要的是效率,適用的是一些單純二維結(jié)構(gòu)化數(shù)據(jù)無法表達的數(shù)據(jù)模型,而關(guān)系型數(shù)據(jù)庫處理的是可以用范式模型表達的二維數(shù)據(jù),追求的是數(shù)據(jù)的高度一致性。隨著 IT 的發(fā)展,每一類型的數(shù)據(jù)庫都會在其特定的場合內(nèi)發(fā)揮出無可比擬的優(yōu)勢,最終的趨勢是大家趨于平衡,沒有***,只有最適合。
觀點三:
記住一句話:任何數(shù)據(jù)庫都有自己的應(yīng)用場景,應(yīng)該關(guān)注數(shù)據(jù)流、數(shù)據(jù)屬性。
個人的經(jīng)驗來說,Redis 不可能取代 MySQL 或者 PG。
2:Redis 有哪些應(yīng)用場景,是否可以舉例說明下哪個公司用了?
Redis 是一個高性能的緩存,一般應(yīng)用在 Session 緩存、隊列、排行榜、計數(shù)器、最近最熱文章、最近最熱評論、發(fā)布訂閱等。
更多應(yīng)用場景,可以參考此處。
可以這樣講,Redis 適用于 數(shù)據(jù)實時性要求高、數(shù)據(jù)存儲有過期和淘汰特征的、不需要持久化或者只需要保證弱一致性、邏輯簡單的場景。
國內(nèi)的互聯(lián)網(wǎng)公司,據(jù)我了解,基本是都在用,其中新浪對 Redis 在國內(nèi)普及起了重要的作用。
另外,Redis 官網(wǎng)有「Who's using Redis?」的鏈接。
3:新接手一個復(fù)雜的 Redis 集群(Sentinel 模式),如何了解它
剛剛接手一套 Redis 集群,想要了解這套集群的相關(guān)配置。應(yīng)該如何入手。難道只能通過 info 命令去查看各個配置嗎?
這是筆者的建議:
- 通讀 Sentinel 官方文檔:https://redis.io/topics/sentinel
- Google 搜索 Redis Sentinel,找?guī)灼杏⑽牡奈恼驴纯?/li>
- 進入 Sentinel 集群后,使用 info 查看集群信息
- 查看 Sentinel 配置文件,配合文檔搞清楚每個參數(shù)的含義
- 使用幾臺虛擬機模擬線上環(huán)境,然后做測試,在實踐中深入理解
- 思考當前 Sentinel 集群是否有不合理的地方,如有,提出并改進
三、Redis 故障排查
1:Redis 實例中,存在大量的 FIN_WAIT2 連接
客戶端 TCP 狀態(tài)遷移:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
服務(wù)器 TCP 狀態(tài)遷移:
CLOSED->LISTEN->SYN 收到 ->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
這個狀態(tài)存在于主動發(fā)起斷開請求的一端,如果服務(wù)器存在大量的這個狀態(tài),那么這個服務(wù)器就充當客戶端的角色,如網(wǎng)絡(luò)爬蟲,出現(xiàn)的原因是由于客戶端發(fā)起 FIN 請求結(jié)束連接之后,收到了服務(wù)端的應(yīng)答之后進入 FIN_WAIT2,之后就沒收到服務(wù)端發(fā)送的 FIN 信號導致。
PS:線上 Web 客戶端用的什么語言?
此問題的評論值得一看:http://www.aixchina.net/Question/231035-1406575
2:如何知道,當前 Redis 實例是處于阻塞狀態(tài)?
請問大神們, 通過什么方式,能夠知道,當前某個 Redis 實例是處于阻塞狀態(tài)啊? 能不能通過某個命令查詢出來 ? 求解, 謝謝!
解答一:
隨便 get 一個 key,然后卡著不動就行,簡單粗暴。優(yōu)雅一點是看 latency 的延遲,blocked_clients 的數(shù)量,rejected_connections 的數(shù)量等。
解答二:
方法一:登錄 Redis,執(zhí)行 info,查看 blocked_clients
方法二:執(zhí)行 redis-cli --latency -h -p 查看延時情況
3:Redis 運維的故障有哪些?
回答一:
常見的運維故障
- 使用 keys * 把庫堵死,——建議使用別名把這個命令改名
- 超過內(nèi)存使用后,部分數(shù)據(jù)被刪除——這個有刪除策略的,選擇適合自己的即可
- 沒開持久化,卻重啟了實例,數(shù)據(jù)全掉——記得非緩存的信息需要打開持久化
- RDB 的持久化需要 vm.overcommit_memory=1,否則會持久化失敗
- 沒有持久化情況下,主從,主重啟太快,從還沒認為主掛的情況下,從會清空自己的數(shù)據(jù)——人為重啟主節(jié)點前,先關(guān)閉從節(jié)點的同步
回答二:
- 我簡單說下 Redis 故障的排查方法吧。
- 了解清楚業(yè)務(wù)數(shù)據(jù)流是怎么樣的
- 結(jié)合 Redis 監(jiān)控查看 QPS、緩存***率、內(nèi)存使用率等信息
- 確認機器層面的資源是否有異常
- 故障時及時上機,使用 redis-cli monitor 打印出操作日志,然后分析(事后分析此條失效)
- 和研發(fā)溝通,確認是否有大 Key 在堵塞(大 Key 也可以在日常的巡檢中獲得)
- 和組內(nèi)同事溝通,確實是否有誤操作
- 和運維同事、研發(fā)一起排查流量是否正常,是否存在被刷的情況
更多的排查需要對線上系統(tǒng)的分析。
四、Redis 性能優(yōu)化
1:提高 Redis 內(nèi)存數(shù)據(jù)庫的性能,有哪些措施?
這個問題有點偏題了,還是回答下吧。整理下工作中積累的經(jīng)驗:
- 根據(jù)不同業(yè)務(wù)選擇數(shù)據(jù)類型,有必要時對數(shù)據(jù)結(jié)構(gòu)進行審核,減少數(shù)據(jù)冗余
- 精簡鍵名和鍵值,控制鍵值的大小
- 使用前綴管理好 key
- 使用 scan 代替 keys,將遍歷 Redis DB 中所有 key 的操作放到客戶端來做
- 避免使用 O(N) 復(fù)雜度的命令
- 配置使用 ziplist 來優(yōu)化 list
- 合理配置 maxmemory
- 數(shù)據(jù)量大的情況,做好 key 和 value 的壓縮
- 利用管道,批量處理命令
- 根據(jù)不同業(yè)務(wù)選擇短鏈接或者長鏈接
- 定期使用 redis-cli --big-keys 檢測大 Key