摘要:最近的互聯網線上事故發生比較頻繁,年月號順豐發生了一起線上刪庫事件,在這里就不介紹了。最后的最后,線上操作的任何一條命令,再小心也不為過,因為由于你的一個符號而引起的事故可能是你所承擔不起的。
摘要: 使用 Redis 的開發者必看,吸取教訓??!
原文:Redis 的 KEYS 命令引起 RDS 數據庫雪崩,RDS 發生兩次宕機,造成幾百萬的資金損失
作者:陳浩翔
Fundebug經授權轉載,版權歸原作者所有。
最近的互聯網線上事故發生比較頻繁,2018 年 9 月 19 號順豐發生了一起線上刪庫事件,在這里就不介紹了。
在這里講述一下最近發生在我公司的事故,以及如何避免,并且如何處理優化。
間接原因還有很多,技術跟不上業務的發展,由每日百萬量到千萬級是一個大的跨進,公司對于系統優化的處理優先級不高,技術開發人手的短缺
第一次宕機2018 年 9 月 13 號某個點,公司某服務化項目的 RDS 實例連接飆升,CPU 升到 100%,拒絕了其他應用的所有請求服務
整個過程如下:
監控報警,顯示 RDS 的 CPU 使用率達到 80%以上,DBA 介入,準備 KILL 慢 SQL
1 分鐘內,沒有發現明顯阻塞的 SQL,CPU 持續上升到 99%
5 分鐘內,大量應用報警,并且拒絕服務,RDS 的監控顯示出現大量慢 SQL,聯系服務器數據庫提供商進行協助
8 分鐘內,進行數據庫主備切換(業務會受損,但是也沒辦法,沒有定位到問題)
9 分鐘內,部分業務恢復,但是一些業務訂單的回調消息堆積超過 20w,備庫的 CPU 使用率也持續上升
15 分鐘內,備庫 CPU 使用率超過 97%,業務再次中斷,進行切回主庫,并進行限流
20 分鐘內,關閉一些次要應用的流量入口
25 分鐘內,主庫 CPU 使用率恢復正常
30 分鐘內,逐步開啟關閉的限流應用
35 分鐘內,所有應用恢復正常
接下來就是與服務器數據庫提供商成立應急小組緊急優化可能出現的慢 SQL,雖然說可能解決了一些慢 SQL,但此次并沒有定位到具體的問題,也就為幾天后再次發生宕機事件埋下了伏筆
事故影響
某服務化項目服務不可用幾十分鐘,造成訂單數減少幾十萬筆,損失百萬資金。
原因分析
當時是沒有定位到具體的原因的,但是下面的原因也是一部分可能引起宕機的情況。
某服務化項目的業務增速非??欤诟叻迤?,數據庫 QPS 突破 35000,系統處于高負荷狀態。
在高峰期如果同時執行幾個全表掃描的 SQL,會造成數據庫壓力急劇上升,應用超時增多,前端應用超時,用戶重試,流量飆升,形成了雪崩效應。
主要原因在與一些老項目的 SQL 查詢性能較差,并且使用的主庫,對數據庫影響較大。數據庫 QPS 太高,但是緩存方案因為人手原因一直沒有落地,慢 SQL 的問題處理優先級應該提升
改進方案
針對每個應用建一個數據庫賬號,嚴格按照規范使用
緩存優化方案即時落地,慢 SQL 問題優先處理,集中處理目前已經發現的慢 SQL(查詢時間超過 1S)
升級數據庫配置
遷移非核心業務到新的 RDS 實例中去
第二次宕機由于上一次的宕機原因未找到,所以此次的宕機是可以預見的。
2018 年 9 月 19 號,還是一樣的"配方",還是原來的"味道"。同一個 RDS,CPU 飆升至 100%,接下來就是拒絕服務,宕機。當然,有了第一次的經驗,直接主從切換,在幾十秒左右就恢復了所有業務,但還是嚴重影響了公司的業務和形象。
原因分析
恢復業務后,公司緊急召開了緊急事故研究會議,當然,我的級別是參與不了的。公司的高管,高層技術架構、DBA、各個項目的主負責人一起進行了會議。
在此次會議中,經過查看各個項目的日志,后臺的監控數據,發現在那臺 RDS 數據庫 CPU 飆升時,有一臺 Redis 數據庫內存將近 100%,然后急劇下降。聯系第一次的宕機情況,也是類似的。
接下來就是聯系服務器數據庫提供商,將那臺 Redis 最近一周的命令全部調用出來,最后發現,在那個時間點運行了一條keys *...*命令。公司的一個工程師執行 keys 模糊的匹配命令是為了清理沒用的鍵,但是沒有考慮到keys *進行模糊匹配引發 Redis 鎖,造成 Redis 鎖住,CPU 飆升,引起了所有調用鏈路的超時并且卡住,等 Redis 鎖的那幾秒結束,所有的請求流量全部請求到 RDS 數據庫中,使數據庫產生了雪崩,使數據庫宕機。
改進方案
所有線上操作,全部要經過運維通過后方可執行,運維部門逐步快速收回各項權限
新增 Redis 實例,進行分離
如果有使用類似 keys 正則命令需求,使用 scan 命令代替
總結該事件中出現的兩次事故,完全是由于人為操作引起的,如果那位工程師,看過 Redis 的開發規范,會發現是建議禁用 keys 命令的。另外,有線上的命令操作,一定要經過運維評估后方可進行操作,估計那個工程師是老員工吧,有權限,然后直接就進行操作了。
另外,公司的業務發展確實很快,技術跟不上,這是非常非常危險的,極大的增加了宕機的概率。
在業務量不大的情況下,那位工程師的操作是完全沒什么問題的,畢竟并發也不大,但是現在,隨著公司的發展,業務量的成倍成倍增加,技術的擴展卻沒有隨著增長那么快。
公司的技術人手不足也是一方面,絕大多數人都是邊維護老項目邊做新功能,但是對于項目的重構優化,人手卻少了很多,項目優化的優先級不高,這也是很大的一個原因,極有可能出現類似的情況,新服務化構建迫在眉睫。
最后的最后,線上操作的任何一條命令,再小心也不為過,因為由于你的一個符號而引起的事故可能是你所承擔不起的。
Redis 開發建議最后附上 Redis 的一些開發規范和建議
1. 冷熱數據分離,不要將所有數據全部都放到 Redis 中
雖然 Redis 支持持久化,但是 Redis 的數據存儲全部都是在內存中的,成本昂貴。建議根據業務只將高頻熱數據存儲到 Redis 中【QPS 大于 5000】,對于低頻冷數據可以使用 MySQL/ElasticSearch/MongoDB 等基于磁盤的存儲方式,不僅節省內存成本,而且數據量小在操作時速度更快、效率更高!
2. 不同的業務數據要分開存儲
不要將不相關的業務數據都放到一個 Redis 實例中,建議新業務申請新的多帶帶實例。因為 Redis 為單線程處理,獨立存儲會減少不同業務相互操作的影響,提高請求響應速度;同時也避免單個實例內存數據量膨脹過大,在出現異常情況時可以更快恢復服務! 在實際的使用過程中,redis 最大的瓶頸一般是 CPU,由于它是單線程作業所以很容易跑滿一個邏輯 CPU,可以使用 redis 代理或者是分布式方案來提升 redis 的 CPU 使用率。
3. 存儲的 Key 一定要設置超時時間
如果應用將 Redis 定位為緩存 Cache 使用,對于存放的 Key 一定要設置超時時間!因為若不設置,這些 Key 會一直占用內存不釋放,造成極大的浪費,而且隨著時間的推移會導致內存占用越來越大,直到達到服務器內存上限!另外 Key 的超時長短要根據業務綜合評估,而不是越長越好!
4. 對于必須要存儲的大文本數據一定要壓縮后存儲
對于大文本【+超過 500 字節】寫入到 Redis 時,一定要壓縮后存儲!大文本數據存入 Redis,除了帶來極大的內存占用外,在訪問量高時,很容易就會將網卡流量占滿,進而造成整個服務器上的所有服務不可用,并引發雪崩效應,造成各個系統癱瘓!
5. 線上 Redis 禁止使用 Keys 正則匹配操作
Redis 是單線程處理,在線上 KEY 數量較多時,操作效率極低【時間復雜度為 O(N)】,該命令一旦執行會嚴重阻塞線上其它命令的正常請求,而且在高 QPS 情況下會直接造成 Redis 服務崩潰!如果有類似需求,請使用 scan 命令代替!
6. 可靠的消息隊列服務
Redis List 經常被用于消息隊列服務。假設消費者程序在從隊列中取出消息后立刻崩潰,但由于該消息已經被取出且沒有被正常處理,那么可以認為該消息已經丟失,由此可能會導致業務數據丟失,或業務狀態不一致等現象發生。
為了避免這種情況,Redis 提供了 RPOPLPUSH 命令,消費者程序會原子性的從主消息隊列中取出消息并將其插入到備份隊列中,直到消費者程序完成正常的處理邏輯后再將該消息從備份隊列中刪除。同時還可以提供一個守護進程,當發現備份隊列中的消息過期時,可以重新將其再放回到主消息隊列中,以便其它的消費者程序繼續處理。
7. 謹慎全量操作 Hash、Set 等集合結構
在使用 HASH 結構存儲對象屬性時,開始只有有限的十幾個 field,往往使用 HGETALL 獲取所有成員,效率也很高,但是隨著業務發展,會將 field 擴張到上百個甚至幾百個,此時還使用 HGETALL 會出現效率急劇下降、網卡頻繁打滿等問題【時間復雜度 O(N)】,此時建議根據業務拆分為多個 Hash 結構;或者如果大部分都是獲取所有屬性的操作,可以將所有屬性序列化為一個 STRING 類型存儲!同樣在使用 SMEMBERS 操作 SET 結構類型時也是相同的情況!
8. 根據業務場景合理使用不同的數據結構類型
目前 Redis 支持的數據庫結構類型較多:字符串(String),哈希(Hash),列表(List),集合(Set),有序集合(Sorted Set), Bitmap, HyperLogLog 和地理空間索引(geospatial)等,需要根據業務場景選擇合適的類型。
常見的如:String 可以用作普通的 K-V、計數類;Hash 可以用作對象如商品、經紀人等,包含較多屬性的信息;List 可以用作消息隊列、粉絲/關注列表等;Set 可以用于推薦;Sorted Set 可以用于排行榜等!
9. 命名規范
雖然說 Redis 支持多個數據庫(默認 32 個,可以配置更多),但是除了默認的 0 號庫以外,其它的都需要通過一個額外請求才能使用。所以用前綴作為命名空間可能會更明智一點。
另外,在使用前綴作為命名空間區隔不同 key 的時候,最好在程序中使用全局配置來實現,直接在代碼里寫前綴的做法要嚴格避免,這樣可維護性實在太差了。
如:系統名:業務名:業務數據:其他
但是注意,key 的名稱不要過長,盡量清晰明了,容易理解,需要自己衡量
10. 線上禁止使用 monitor 命令
禁止生產環境使用 monitor 命令,monitor 命令在高并發條件下,會存在內存暴增和影響 Redis 性能的隱患
11. 禁止大 string
核心集群禁用 1mb 的 string 大 key(雖然 redis 支持 512MB 大小的 string),如果 1mb 的 key 每秒重復寫入 10 次,就會導致寫入網絡 IO 達 10MB;
12. redis 容量
單實例的內存大小不建議過大,建議在 10~20GB 以內。redis 實例包含的鍵個數建議控制在 1kw 內,單實例鍵個數過大,可能導致過期鍵的回收不及時。
13. 可靠性
需要定時監控 redis 的健康情況:使用各種 redis 健康監控工具,實在不行可以定時返回 redis 的 info 信息??蛻舳诉B接盡量使用連接池(長鏈接和自動重連)。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/62086.html
摘要:最近的互聯網線上事故發生比較頻繁,年月號順豐發生了一起線上刪庫事件,在這里就不介紹了。最后的最后,線上操作的任何一條命令,再小心也不為過,因為由于你的一個符號而引起的事故可能是你所承擔不起的。 摘要: 使用 Redis 的開發者必看,吸取教訓啊! 原文:Redis 的 KEYS 命令引起 RDS 數據庫雪崩,RDS 發生兩次宕機,造成幾百萬的資金損失 作者:陳浩翔 Fundebu...
摘要:最近安全事故瀕發啊,前幾天發生了順豐高級運維工程師的刪庫事件,今天又看到了工程師在線執行了危險命令導致某公司損失萬。。該公司表示,如再犯類似事故,將直接開除,并表示之后會逐步收回運維部各項權限。 最近安全事故瀕發啊,前幾天發生了《順豐高級運維工程師的刪庫事件》,今天又看到了 PHP 工程師在線執行了 Redis 危險命令導致某公司損失 400 萬。。 什么樣的 Redis 命令會有如此...
摘要:給我們帶來便利的同時,使用過程中會存在什么問題呢,本文將簡單加以總結。避免使用內存過大的實例。如果主線程距離上一次的成功超過,為了數據安全會阻塞直到后臺線程執行完完成。 redis可以滿足很多的應用場景,而且因為將所有數據都放到內存中,所以它的讀寫性能很好,很多公司都在使用redis。redis給我們帶來便利的同時,使用過程中會存在什么問題呢,本文將簡單加以總結。 阻塞問題 r...
閱讀 1684·2021-11-23 09:51
閱讀 3174·2021-09-26 10:21
閱讀 798·2021-09-09 09:32
閱讀 881·2019-08-29 16:06
閱讀 3308·2019-08-26 13:36
閱讀 772·2019-08-26 10:56
閱讀 2564·2019-08-26 10:44
閱讀 1143·2019-08-23 14:04