共計 2564 個字符,預計需要花費 7 分鐘才能閱讀完成。
自動寫代碼機器人,免費開通
這篇文章主要介紹“redis 在高并發下的性能講解”,在日常操作中,相信很多人在 redis 在高并發下的性能講解問題上存在疑惑,丸趣 TV 小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”redis 在高并發下的性能講解”的疑惑有所幫助!接下來,請跟著丸趣 TV 小編一起來學習吧!
前言:
最近上手了一個項目,我負責該項目的架構設計與實現。本來公司做了很多給公司以外的人使用的 API,但是在外人使用的時候,接口的鏈接是怎樣就給別人怎么樣,沒有加密也沒有做并發控制,接口程序所在的機器在哪,給別人的 IP 就在哪,而且沒有平臺進行管理。因此我清楚地知道,這些接口的價值很難被發現(哪個接口別人用的比較多,哪個接口別人用的比較少)。
僅僅針對”監控“的這一需求,我們引入了 redis 作為中間層,首先我們完善了用戶使用接口的注冊流程,通過用戶信息和地址,hash 出一個 key,這個 key 是對應著一個地址的,把這個(key – 地址)對存在了 redis 里面。其次是 nginx,nginx 在我們的項目里面的流程大概是這樣:
1、用戶注冊之后獲取到他的 key,通過包含了 key 的跟原本的 url 完全不同的 url 來訪問
2、nginx 捕獲到用戶特殊的 key,然后程序根據這個 key 從 redis 中取出目標地址,再由 nginx 代替用戶訪問真正的地址,繼而返回。
(這個過程好處是很多的)
(1)、隱藏了真實的地址,程序可以在上游服務器之外的地方干預用戶的訪問,提高安全性,干預過程可以很復雜
(2)、獲取用戶的信息,并將其存回 redis,上游服務器通過定時程序將存在 redis 中的日志持久化進 oracle 并刪除,然后進一步分析和可視化
問題來了
這個項目還處于測試階段,資源是一臺 window server 服務器,和 centos6.5 服務器,測試階段 10 秒內大概有 10 萬的并發量,剛部署上去的一兩天還是沒有問題的,接下來卻出現了 redis 連接不上的情況。查看進程訪問,會出現下面的情況。(window server 下)
出現很多 FiN_WAIT_2 的 TCP 鏈接。
(學習視頻分享:redis 視頻教程)
分析
一、redis 是使用單線程處理連接的,意味著它絕對會出現下面二所說的情況。
二、很明顯這是由于 nginx 和 redis 之間有很多沒有釋放的資源造成的,查看這個 TCP 的狀態 FIN_WAIT_2,解釋一下:
在 HTTP 應用中,存在一個問題,SERVER 由于某種原因關閉連接,如 KEEPALIVE 的超時,這樣,作為主動關閉的 SERVER 一方就會進入 FIN_WAIT2 狀態,但 TCP/IP 協議棧有個問題,FIN_WAIT2 狀態是沒有超時的(不象 TIME_WAIT 狀態),所以如果 CLIENT 不關閉,這個 FIN_WAIT_2 狀態將保持到系統重新啟動,越來越多的 FIN_WAIT_2 狀態會致使內核 crash。
好吧,大學沒有好好念書,下面是 http 連接的狀態變化
客戶端狀態遷移
CLOSED- SYN_SENT- ESTABLISHED- FIN_WAIT_1- FIN_WAIT_2- TIME_WAIT- CLOSEDb.
服務器狀態遷移
CLOSED- LISTEN- SYN 收到 - ESTABLISHED- CLOSE_WAIT- LAST_ACK- CLOSED
有缺陷的客戶端與持久連接
有一些客戶端在處理持久連接 (akakeepalives) 時存在問題。當連接空閑下來服務器關閉連接時(基于 KeepAliveTimeout 指令),
客戶端的程序編制使它不發送 FIN 和 ACK 回服務器。這樣就意味著這個連接 將停留在 FIN_WAIT_2 狀態直到以下之一發生:
客戶端為同一個或者不同的站點打開新的連接,這樣會使它在該個套接字上完全關閉以前的連接。
用戶退出客戶端程序,這樣在一些 (也許是大多數?) 客戶端上會使操作系統完全關閉連接。
FIN_WAIT_2 超時,在那些具有 FIN_WAIT_2 狀態超時設置的服務器上。
如果你夠幸運,這樣意味著那些有缺陷的客戶端會完全關閉連接并釋放你服務器的資源。
然而,有一些情況下套接字永遠不會完全關閉,比如一個撥號客戶端在關閉客戶端程序之前從 ISP 斷開。
此外,有的客戶端有可能空置好幾天不創建新連接,并且這樣在好幾天里保持著套接字的有效即使已經不再使用。這是瀏覽器或者操作系統的 TCP 實現的 Bug。
產生原因有:
1、長連接并且當連接一直處于 IDLE 狀態導致 SERVERCLOSE 時,CLIENT 編程缺陷,沒有向 SERVER 發出 FIN 和 ACK 包
2、APACHE1.1 和 APACHE1.2 增加了 linger_close()函數,前面的帖子有介紹,這個函數可能引起了這個問題(為什么我也不清楚)
解決辦法:
1。對 FIN_WAIT_2 狀態增加超時機制,這個特性在協議里沒有體現,但在一些 OS 中已經實現
如:LINUX、SOLARIS、FREEBSD、HP-UNIX、IRIX 等
2。不要用 linger_close()編譯
3。用 SO_LINGER 代替,這個在某些系統中還能很好地處理
4。增加用于存儲網絡連接狀態的內存 mbuf,以防止內核 crash
5。DISABLE KEEPALIVE
針對這種情況,我們做了幾次討論,有些結論,分別是:
1、設置 nginx 與 redis 的連接池,keepalive 的時間,分別設為 10 秒,5 秒,但是結果還是一樣
2、不用 keepalive,即不使用連接池,即每次用完就 close()掉,你可以看到連接少了,但是不使用連接池,意味著 10 秒內要打開關閉 10 萬次,開銷太大
3、redis 集群,在原本集群的體系上添加 redis 的集群,這或許能解決問題,但是 10 秒內 10 萬實際上并不多,這樣做了或許是取巧,并沒有找到問題
4、設置 redis 的 idle(空閑)時間限制,結果一樣。
解決方案:
實際上不算解決方案,因為放棄了 redis 的內存機制,而是使用 nginx 本身的內存技術。網上關于 redis 的優化大部分不適用,這個問題有待分析解決。
到此,關于“redis 在高并發下的性能講解”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注丸趣 TV 網站,丸趣 TV 小編會繼續努力為大家帶來更多實用的文章!
向 AI 問一下細節