您现在的位置是:Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款 > 

01 redis消息訂閱 阻塞(三分鐘讀懂redis數據庫)

Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款2024-05-29 09:31:41【】7人已围观

简介Redis可能會阻塞的情況如果一個值的size過大,寫入時開辟內存以及發送時的數據買粉絲py開銷都會很大。建議從業務上對大key做拆分。對于一些數據結構的操作,時間復雜度為O(N),如果不加控制,可能

Redis可能會阻塞的情況

如果一個值的size過大,寫入時開辟內存以及發送時的數據 買粉絲py 開銷都會很大。

建議從業務上對大key做拆分。

對于一些數據結構的操作,時間復雜度為 O(N) ,如果不加控制,可能會引起阻塞。

例如 Keys 命令,由于沒有limit參數,會全表掃描,耗時大。可以考慮用Scan替代。

盡管使用了IO多路復用技術,讀寫 買粉絲py 以及 User Mode 和 Kernel Mode 的切換會比較耗時。

盡管 RDB 是fork后獨立進程中完成落盤工作,fork 這個 System Call 本身耗時大概在700ms級別。

建議盡量避免在高峰時期執行 Save 或 Bgsave 命令。

由于AOF需要修改磁盤中的日志文件,修改文件及其iNode需要兩次隨機讀寫IO,大約耗時在20ms級別,因此業務中幾乎不會開啟 always 模式。

一般都用 Everyse買粉絲nd模式。

由于 Redis 的刪除過期鍵策略中有一條是主動刪除:會隨機抽出100個設置了過期的key,對已過期的進行刪除,如果發現過期的key超過25個,就會重復這個過程。因此,如果有大量同一時間過期的key,會在主動刪除觸發時,不停地取key刪key,造成阻塞。

建議在設置過期時間時使用 Expire 而非 Expireat,或者使用 Expireat 時自己給入一個隨機量,讓過期時間離散開。

當 Redis 可支配的內存空間不足時,會進行內存逐出操作。盡管可以配置策略,但是逐出時CPU會hang住。

建議對內存使用情況做監控,及時擴容或進行其他人為介入操作。

如何使用Redis 做隊列操作

redis設計用來做緩存的,但是由于它自身的某種特性使得它可以用來做消息隊列,它有幾個阻塞式的API可以使用,正是這些阻塞式的API讓其有能力做消息隊列;

另外,做消息隊列的其他特性例如FIFO(先入先出)也很容易實現,只需要一個list對象從頭取數據,從尾部塞數據即可;

redis能做消息隊列還得益于其list對象blpop brpop接口以及Pub/Sub(發布/訂閱)的某些接口,它們都是阻塞版的,所以可以用來做消息隊列。

redis主要解決了什么問題

Redis 常見的性能問題和解決方法

1.Master寫內存快照

save命令調度rdbSave函數,會阻塞主線程的工作,當快照比較大時對性能影響是非常大的,會間斷性暫停服務,所以Master最好不要寫內存快照。

2.Master AOF持久化

如果不重寫AOF文件,這個持久化方式對性能的影響是最小的,但是AOF文件會不斷增大,AOF文件過大會影響Master重啟的恢復速度。

3.Master調用BGREWRITEAOF

Master調用BGREWRITEAOF重寫AOF文件,AOF在重寫的時候會占大量的CPU和內存資源,導致服務load過高,出現短暫服務暫停現象。

下面是我的一個實際項目的情況,大概情況是這樣的:一個Master,4個Slave,沒有Sharding機制,僅是讀寫分離,Master負責寫入操作和AOF日志備份,AOF文件大概5G,Slave負責讀操作,當Master調用BGREWRITEAOF時,Master和Slave負載會突然陡增,Master的寫入請求基本上都不響應了,持續了大概5分鐘,Slave的讀請求過也半無法及時響應,Master和Slave的服務器負載圖如下:

Master Server load:

Slave server load:

上面的情況本來不會也不應該發生的,是因為以前Master的這個機器是Slave,在上面有一個shell定時任務在每天的上午10點調用BGREWRITEAOF重寫AOF文件,后來由于Master機器down了,就把備份的這個Slave切成Master了,但是這個定時任務忘記刪除了,就導致了上面悲劇情況的發生,原因還是找了幾天才找到的。

將no-appendfsync-on-rewrite的配置設為yes可以緩解這個問題,設置為yes表示rewrite期間對新寫操作不fsync,暫時存在內存中,等rewrite完成后再寫入。最好是不開啟Master的AOF備份功能。

4.Redis主從復制的性能問題

第一次Slave向Master同步的實現是:Slave向Master發出同步請求,Master先mp出rdb文件,然后將rdb文件全量傳輸給slave,然后Master把緩存的命令轉發給Slave,初次同步完成。第二次以及以后的同步實現是:Master將變量的快照直接實時依次發送給各個Slave。不管什么原因導致Slave和Master斷開重連都會重復以上過程。Redis的主從復制是建立在內存快照的持久化基礎上,只要有Slave就一定會有內存快照發生。雖然Redis宣稱主從復制無阻塞,但由于Redis使用單線程服務,如果Master快照文件比較大,那么第一次全量傳輸會耗費比較長時間,且文件傳輸過程中Master可能無法提供服務,也就是說服務會中斷,對于關鍵服務,這個后果也是很可怕的。

以上1.2.3.4根本問題的原因都離不開系統io瓶頸問題,也就是硬盤讀寫速度不夠快,主進程 fsync()/write() 操作被阻塞。

5.單點故障問題

由于目前Redis的主從復制還不夠成熟,所以存在明顯的單點故障問題,這個目前只能自己做方案解決,如:主動復制,Proxy實現Slave對Master的替換等,這個也是Redis作者目前比較優先的任務之一,作者的解決方案思路簡單優雅,詳情可見 Redis Sentinel design draft 

總結

Master最好不要做任何持久化工作,包括內存快照和AOF日志文件,特別是不要啟用內存快照做持久化。

如果數據比較關鍵,某個Slave開啟AOF備份數據,策略為每秒同步一次。

為了主從復制的速度和連接的穩定性,Slave和Master最好在同一個局域網內。

盡量避免在壓力較大的主庫上增加從庫

為了Master的穩定性,主從復制不要用圖狀結構,用單向鏈表結構更穩定,即主從關系為:Master<–Slave1<–Slave2<–Slave3…….,這樣的結構也方便解決單點故障問題,實現Slave對Master的替換,也即,如果Master掛了,可以立馬啟用Slave1做Master,其他不變。

redis阻塞了怎么辦

單線程你別阻塞,Redis時延問題分析及應對

Redis的事件循環在一個線程中處理,作為一個單線程程序,重要的是要保證事件處理的時延短,這樣,事件循環中的后續任務才不會阻塞; 

當redis的數據量達到一定級別后(比如20G),阻塞操作對性能的影響尤為嚴重; 

下面我們總結下在redis中有哪些耗時的場景及應對方法;

耗時長的命令造成阻塞

keys、sort等命令

keys命令用于查找所有符合給定模式 pattern 的 key,時間復雜度為O(N), N 為數據庫中 key 的數量。當數據庫中的個數達到千萬時,這個命令會造成讀寫線程阻塞數秒; 

類似的命令有sunion sort等操作; 

如果業務需求中一定要使用keys、sort等操作怎么辦?

解決方案: 

在架構設計中,有“分流”一招,說的是將處理快的請求和處理慢的請求分離來開,否則,慢的影響到了快的,讓快的也快不起來;這在redis的設計中體現的非常明顯,redis的純內存操作,epoll非阻塞IO事件處理,這些快的放在一個線程中搞定,而持久化,AOF重寫、Master-slave同步數據這些耗時的操作就單開一個進程來處理,不要慢的影響到快的; 

同樣,既然需要使用keys這些耗時的操作,那么我們就將它們剝離出去,比如單開一個redis slave結點,專門用于keys、sort等耗時的操作,這些查詢一般不會是線上的實時業務,查詢慢點就慢點,主要是能完成任務,而對于線上的耗時快的任務沒有影響;

smembers命令

smembers命令用于獲取集合全集,時間復雜度為O(N),N為集合中的數量; 

如果一個集合中保存了千萬量級的數據,一次取回也會造成事件處理線程的長時間阻塞;

解決方案: 

在設計時,我們可以控制集合的數量,將集合數一般保持在500個以內; 

比如原來使用一個鍵來存儲一年的記錄,數據量大,我們可以使用12個鍵來分別保存12個月的記錄,或者365個鍵來保存每一天的記錄,將集合的規模控制在可接受的范圍;

如果不容易將集合劃分為多個子集合,而堅持用一個大集合來存儲,那么在取集合的時候可以考慮使用SRANDMEMBER key [買粉絲unt];隨機返回集合中的指定數量,當然,如果要遍歷集合中的所有元素,這個命令就不適合了;

save命令

save命令使用事件處理線程進行數據的持久化;當數據量大的時候,會造成線程長時間阻塞(我們的生產上,reids內存中1個G保存需要12s左右),整個redis被block; 

save阻塞了事件處理的線程,我們甚至無法使用redis-cli查看當前的系統狀態,造成“何時保存結束,目前保存了多少”這樣的信息都無從得知;

解決方案: 

我沒有想到需要用到save命令的場景,任何時候需要持久化的時候使用bgsave都是合理的選擇(當然,這個命令也會帶來問題,后面聊到);

fork產生的阻塞

在redis需要執行耗時的操作時,會新建一個進程來做,比如數據持久化bgsave: 

開啟RDB持久化后,當達到持久化的閾值,redis會fork一個新的進程來做持久化,采用了操作系統的買粉絲py-on-wirte寫時復制策略,子進程與父進程共享Page。如果父進程的Page(每頁4K)有修改,父進程自己創建那個Page的副本,不會影響到子進程; 

fork新進程時,雖然可共享的數據內容不需要復制,但會復制之前進程空間的內存頁表,如果內存空間有40G(考慮每個頁表條目消耗 8 個字節),那么頁表大小就有80M,這個復制是需要時間的,如果使用虛擬機,特別是Xen虛擬服務器,耗時會更長; 

在我們有的服務器結點上測試,35G的數據bgsave瞬間會阻塞200ms以上;

類似的,以下這些操作都有進程fork;

Master向slave首次同步數據:當master結點收到sla

很赞哦!(2)

Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款的名片

职业:程序员,设计师

现居:河北省保定望都县

工作室:小组

Email:[email protected]