【Redis 开发与运维】开发运维的“陷阱”
生活随笔
收集整理的這篇文章主要介紹了
【Redis 开发与运维】开发运维的“陷阱”
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄
- 一、Linux 配置優(yōu)化
- 內(nèi)存分配控制
- OOM killer
- 使用 NTP
- 二、flushall / flushdb 誤操作
- 緩存與存儲
- 借助 AOF 機制恢復
- RDB 有什么變化
- 三、安全的 Redis
- Redis 密碼機制
- 偽裝危險命令
- 防火墻
- 定期備份數(shù)據(jù)
- 不使用默認端口
- 使用非 root 用戶啟動
- 四、處理 bigkey
- bigkey 的危害
- 如何發(fā)現(xiàn)
- 如何刪除
- 五、尋找熱點 key
- 統(tǒng)計熱點 key
- 解決熱點 key 問題
一、Linux 配置優(yōu)化
內(nèi)存分配控制
- Redis 設(shè)置合理的 maxmemory,保證機器有 20% ~ 30% 的閑置內(nèi)存。
- 集中化管理 AOF 重寫和 RDB 的 bgsave。
- 設(shè)置 vm.overcommit_memory=1,防止極端情況下會造成 fork 失敗。
OOM killer
- OOM killer 會在可用內(nèi)存不足時選擇性地殺掉用戶進程。
- 對于 Redis 所在的服務器來說,可以將所有 Redis 的 oom_adj 設(shè)置為最低值或者稍小的值,降低被 OOM killer 殺掉的概率。
使用 NTP
- NTP(Network Time Protocol,網(wǎng)絡時間協(xié)議)是一種保證不同機器時鐘一致性的服務。一般公司里都會有 NTP 服務用來提供標準時間服務,從而達到糾正時鐘的效果。
二、flushall / flushdb 誤操作
- Redis 的 flushall / flushdb 命令可以做數(shù)據(jù)清除,對于 Redis 的開發(fā)和運維人員有一定幫助,然而一旦誤操作,它的破壞性也是很明顯的。
緩存與存儲
- 被誤操作 flush 后,根據(jù)當前 Redis 是緩存還是存儲使用策略有所不同:
- 緩存:對于業(yè)務數(shù)據(jù)的正確性可能造成損失還小一點,因為緩存中的數(shù)據(jù)可以從數(shù)據(jù)源重新進行構(gòu)建。
- 存儲:對業(yè)務方可能會造成巨大的影響,如果沒有提前做業(yè)務降級,那么最終反饋到用戶的應用可能就是報錯或者空白頁面等。
借助 AOF 機制恢復
- Redis 執(zhí)行了 flush 操作后,AOF 持久化文件會受到什么影響呢,如下:
- appendonly no:對 AOF 持久化沒有任何影響,因為根本不存在 AOF 文件。
- appendonly yes:只不過在 AOF 文件中追加了一條 flushall 記錄。
- 也就是說,雖然 Redis 中的數(shù)據(jù)被清掉了,但是 AOF 文件還保存著 flush 操作之前完整的數(shù)據(jù),這對恢復數(shù)據(jù)是很有幫助的。
RDB 有什么變化
Redis 執(zhí)行了 flushall 操作后,RDB持久化文件會受到什么影響呢?
- 1)如果沒有開啟 RDB 的自動策略,也就是配置文件中沒有類似如下配置
-
那么除非手動執(zhí)行過 save、bgsave 或者發(fā)生了主從的全量復制,否則 RDB 文件也會保存 flush 操作之前的數(shù)據(jù),可以作為恢復數(shù)據(jù)的數(shù)據(jù)源。注意問題如下:
- 防止手動執(zhí)行 save、bgsave,如果此時執(zhí)行 save、bgsave,新的 RDB 文件就不會包含 flush 操作之前的數(shù)據(jù),被老的RDB文件進行覆蓋。
- RDB 文件中的數(shù)據(jù)可能沒有 AOF 實時性高,也就是說,RDB 文件很可能很久以前主從全量復制生成的,或者之前用 save、bgsave 備份的。
-
2)如果開啟了 RDB 的自動策略,由于 flush 涉及鍵值數(shù)量較多,RDB 文件會被清除意味著使用 RDB 恢復基本無望。
三、安全的 Redis
- 數(shù)據(jù)丟失對于很多 Redis 的開發(fā)者來說是致命的,經(jīng)過相關(guān)機構(gòu)的調(diào)查發(fā)現(xiàn),被攻擊的 Redis 有如下特點:
- Redis 所在的機器有外網(wǎng) IP
- Redis 以默認端口 6379 為啟動端口,并且是對外網(wǎng)開放的
- Redis 以 root 用戶啟動的 Redis 沒有設(shè)置密碼
- Redis 的 bind 設(shè)置為 0.0.0.0 或者 “”
- 將從下面幾個方面介紹如何保證 Redis 的安全。
Redis 密碼機制
- Redis 提供了 requirepass 配置為 Redis 提供密碼功能,如果添加這個配置,客戶端就不能通過 redis-cli -h {ip} -p {port} 來執(zhí)行命令。
偽裝危險命令
- Redis 中包含了很多“危險”命令,一旦生產(chǎn)上錯誤使用或者誤操作,后果不堪設(shè)想,例如:
- keys:如果鍵值較多,存在阻塞 Redis 的可能性
- flushall/flushdb:數(shù)據(jù)全部被清除
- save:如果鍵值較多,存在阻塞 Redis 的可能性
- debug:個例如 debug reload 會重啟 Redis
- config:config 應該交給管理員使用
- shutdown:停止 Redis
- Redis 提供了 rename-command 配置解決了這個問題,例如添加如下配置:
- 那么再執(zhí)行 flushall 的話,會收到 Redis 不認識 flushall 的錯誤提示,說明成功的對 flushall 進行了偽裝。
- 而如果執(zhí)行 abcabcabc ,那么就可以實現(xiàn) flushall 功能了。
防火墻
- 可以使用防火墻限制輸入和輸出的 IP 或者 IP 范圍、端口或者端口范圍。
定期備份數(shù)據(jù)
- 定期備份數(shù)據(jù)能夠在一定程度挽回一些損失,定期備份持久化數(shù)據(jù)是一個比較好的習慣。
不使用默認端口
- Redis 的默認端口是 6379,不使用默認端口從一定程度上可降低被入侵者發(fā)現(xiàn)的可能性,因為入侵者通常本身也是一些攻擊程序。
使用非 root 用戶啟動
- root 用戶作為管理員,權(quán)限非常大。如果被入侵者獲取 root 權(quán)限后,就可以在這臺機器以及相關(guān)機器所以操作。所以建議在啟動 Redis 服務的時候使用非 root 用戶啟動。
四、處理 bigkey
- bigkey 是指 key 對應的 value 所占的內(nèi)存空間比較大,例如一個字符串類型的 value 可以最大存到 512MB,一個列表類型的 value 最多可以存儲 2^32 - 1 個元素。如果按照數(shù)據(jù)結(jié)構(gòu)來細分的話,一般分為兩種:
- 字符串類型:體現(xiàn)在單個 value 值很大,一般認為超過 10 KB 就是 bigkey,但這個值和具體的 OPS 相關(guān)。
- 非字符串類型:哈希、列表、集合、有序集合,體現(xiàn)在元素個數(shù)過多。
bigkey 的危害
- 內(nèi)存空間不均勻:例如在 Redis 集群中,bigkey 會造成節(jié)點的內(nèi)存空間使用不均勻。
- 超時阻塞:由于 Redis 單線程的特性,操作 bigkey 比較耗時,也就意味著阻塞 Redis 可能性增大。
- 網(wǎng)絡阻塞:每次獲取 bigkey 產(chǎn)生的網(wǎng)絡流量較大。
如何發(fā)現(xiàn)
- redis-cli --bigkeys 可以命令統(tǒng)計 bigkey 的分布。但是生產(chǎn)環(huán)境中,開發(fā)和運維人員更希望自己可以定義 bigkey 的大小而且更希望找到真正的 bigkey 都有哪些 ,這樣才可以去定位、解決、優(yōu)化問題。
- 判斷一個 key 是否為 bigkey,只需要執(zhí)行 debug object key 查看 serializedlength 屬性即可,它表示 key 對應的 value 序列化之后的字節(jié)數(shù)。
- 在實際的生產(chǎn)環(huán)境中發(fā)現(xiàn) bigkey 的兩種方式如下:
- 被動收集:許多開發(fā)人員確實可能對 bigkey 不了解或重視程度不夠,但是這種 bigkey 一旦大量訪問,很可能就會帶來命令慢查詢和網(wǎng)卡跑滿問題,開發(fā)人員通過對異常的分析通常能找到異常原因可能是 bigkey,這種方式并不推薦,但是在實際生產(chǎn)環(huán)境中卻大量存在,建議修改 Redis 客戶端,當拋出異常時打印出所操作的 key,方便排查 bigkey 問題。
- 主動檢測:scan + debug object,如果懷疑存在bigkey,可以使用scan命令漸進的掃描出所有的key,分別計算每個 key 的 serializedlength,找到對應 bigkey 進行相應的處理和報警,這種方式是比較推薦的方式。
如何刪除
- 首先,無論是什么數(shù)據(jù)結(jié)構(gòu),del 命令都能將其刪除。但是經(jīng)過上面的分析你一定不會這么做,刪除 bigkey 通常來說會阻塞 Redis 服務。
- 這個時候就需要 scan 命令的若干類似命令拿出來:sscan、hscan、zscan。
- string
- 對于 string 類型使用 del 命令一般不會產(chǎn)生阻塞
- hash、list、set、sorted set
- 下面以 hash 為例子,使用 hscan 命令,每次獲取部分(例如 100 個)field-value,再利用 hdel 刪除每個 field(為了快速可以使用 Pipeline):
- Redis 4.0 新增了非常實用的惰性刪除 lazy free 特性,從根本上解決了 bigkey(主要指定元素較多集合類型key)刪除的風險
五、尋找熱點 key
熱門新聞事件或商品通常會給系統(tǒng)帶來巨大的流量,對存儲這類信息的 Redis 來說卻是一個巨大的挑戰(zhàn)。以 Redis Cluster 為例,它會造成整體流量的不均衡,個別節(jié)點出現(xiàn) OPS 過大的情況,極端情況下熱點 key 甚至會超過 Redis 本身能夠承受的 OPS,因此尋找熱點 key 對于開發(fā)和運維人員非常重要。下面從以下幾個方面分析熱點 key。
統(tǒng)計熱點 key
- 客戶端
- 客戶端其實是距離 key “最近” 的地方,因為 Redis 命令就是從客戶端發(fā)出的,例如在客戶端設(shè)置全局字典(key 和調(diào)用次數(shù)),每次調(diào)用 Redis 命令時,使用這個字典進行記錄。
- 使用客戶端進行熱點 key 的統(tǒng)計非常容易實現(xiàn),但同時問題也非常多:
- 無法預知 key 的個數(shù),存在內(nèi)存泄露的危險。
- 對于客戶端代碼有侵入,各個語言的客戶端都需要維護此邏輯,維護成本較高。
- 只能了解當前客戶端的熱點 key,無法實現(xiàn)規(guī)模化運維統(tǒng)計。
- 代理端
- 像 Twemproxy、Codis 這些基于代理的 Redis 分布式架構(gòu),所有客戶端的請求都是通過代理端完成的。此架構(gòu)是最適合做熱點 key 統(tǒng)計的,因為代理是所有 Redis 客戶端和服務端的橋梁。但并不是所有Redis都是采用此種架構(gòu)。
- Redis 服務端
- 使用 monitor 命令統(tǒng)計熱點 key 是很多開發(fā)和運維人員首先想到,monitor 命令可以監(jiān)控到 Redis 執(zhí)行的所有命令。
- 利用 monitor 命令就可以統(tǒng)計出一段時間內(nèi)的熱點 key 排行榜、命令排行榜、客戶端分布等數(shù)據(jù)。
- 但是此種方法會有兩個問題:
- monitor 命令在高并發(fā)條件下,會存在內(nèi)存暴增和影響 Redis 性能的隱患,所以此種方法適合在短時間內(nèi)使用。
- 只能統(tǒng)計一個 Redis 節(jié)點的熱點 key,對于 Redis 集群需要進行匯總統(tǒng)計。
- 機器
- Redis 客戶端使用 TCP 協(xié)議與服務端進行交互,通信協(xié)議采用的是 RESP。如果站在機器的角度,可以通過對機器上所有 Redis 端口的 TCP 數(shù)據(jù)包進行抓取完成熱點 key 的統(tǒng)計。
解決熱點 key 問題
- 拆分復雜數(shù)據(jù)結(jié)構(gòu):如果當前 key 的類型是一個二級數(shù)據(jù)結(jié)構(gòu),例如哈希類型。如果該哈希元素個數(shù)較多,可以考慮將當前 hash 進行拆分,這樣該熱點 key 可以拆分為若干個新的 key 分布到不同 Redis 節(jié)點上,從而減輕壓力。
- 遷移熱點key:以 Redis Cluster 為例,可以將熱點 key 所在的 slot 單獨遷移到一個新的 Redis 節(jié)點上,但此操作會增加運維成本。
- 本地緩存加通知機制:可以將熱點 key 放在業(yè)務端的本地緩存中,因為是在業(yè)務端的本地內(nèi)存中,處理能力要高出 Redis 數(shù)十倍,但當數(shù)據(jù)更新時,此種模式會造成各個業(yè)務端和 Redis 數(shù)據(jù)不一致,通常會使用發(fā)布訂閱機制來解決類似問題。
來源:《Redis 開發(fā)與運維》第 12 章 開發(fā)運維的“陷阱”
總結(jié)
以上是生活随笔為你收集整理的【Redis 开发与运维】开发运维的“陷阱”的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL2000里的数据类型
- 下一篇: 《Redis开发与运维》- 核心知识整理