1. 程式人生 > 其它 >Redis——常見問題及解決方案

Redis——常見問題及解決方案

https://www.cnblogs.com/muchengqingxin/p/13177734.html

情景一:頻繁報異常——TimeOut/無可用連線

這類錯誤還是挺常見的,一般來說都屬於下面幾種情況之一:

一、沒有單例

當併發達到一定量級時候,如果沒有使用單例模式例項化,會引發此類錯誤致服務不可用。因為在高併發情況下沒有使用單例進行例項化,會導致連線池被大量建立,在業務不停止的情況下很容易發生來不及釋放的情況,最終導致阻塞。

正確做法是例項一個全域性物件,參考如下:

private IDatabase DB;
private static ConnectionMultiplexer conn = null;
public static object locker = new object();
public Redis(int I)
{
    if (conn == null)
    {
        lock (locker)
        {
            if (conn == null)
            {
                conn = ConnectionMultiplexer.Connect("1.1.1.1:6379");
            }
        }
    }
    DB = conn.GetDatabase(I);
}

二、耗時過長的指令(StackExchange客戶端連線的只讀屬性TimeoutMilliseconds=1000),可以通過修改配置搞定:

var config = new ConfigurationOptions
{
    ConnectTimeout = 15000,//連線超時改成15秒
    ResponseTimeout = 15000//返回超時改成15秒
};

三、CLR中Thread Pool最小按需建立執行緒數過小導致的等待成本(500ms),可在program.cs設定最小執行緒數解決(數量要按實際情況設定,否則可能會影響效能):

public class Program
{
    public static void Main(string[] args)
    {
        System.Threading.ThreadPool.SetMinThreads(70, 70);
        CreateWebHostBuilder(args).Build().Run();
    }
}

建議設定的同時,把所有的redis操作更改成非同步操作。上面三種應用如果還是出現相同問題的話,推測是硬體問題了。但是概率非常小,目前還沒有遇到過。

情景二:頻繁報OOM

當redis佔用記憶體超過或持平了伺服器的記憶體上限,就會出現這個錯誤,新手尤其容易犯這類錯誤。正確的做法是設定快取上限,並且搭配記憶體回收策略使用,下附常用回收策略:

#設定最大快取,單位bytes,下面這條是設定最大快取1G
maxmemory 1073741824

#回收策略

#預設,到達上限時丟擲異常
maxmemory-policy noeviction 

#淘汰使用頻率最低的鍵,包括持久鍵
maxmemory-policy allkeys-lru 

#淘汰使用頻率最低的鍵,不包括持久鍵
maxmemory-policy volatile-lru

#隨機淘汰,包括持久鍵
maxmemory-policy allkeys-random

#隨機淘汰,不包括持久鍵
maxmemory-policy volatile-random

#淘汰有過期時間的鍵,距離原本過期時間最近的優先
maxmemory-policy volatile-ttl

修改配置檔案後重啟服務即可。

情景三:redis正常但資料庫不時掛掉

如果你確認自己的redis服務正常的話,那麼相當大的概率是快取雪崩。

快取雪崩簡單來說就是大量快取同時過期,如果有幾個G或者更多的快取同時過期,而發生時又很不幸的是業務高峰期的話,你的資料庫大概率會掛掉,而且一旦掛掉,就沒那麼快恢復了。

解決方法很簡單:快取鍵設定隨機過期時間,避開批量過期就可以解決這個問題。

但如果已經隨機仍然頻發,那麼就要換個思路了:還有可能是快取擊穿。

什麼是快取擊穿呢?簡單來說就是某個被大量訪問的鍵忽然過期,從而導致資料庫壓力陡增。

針對擊穿的解決方法也不復雜:快取鍵過期時,先拿一個互斥鎖再去資料庫拿資料,寫入快取以後釋放鎖;期間訪問同一鍵的其他程序設定延時訪問即可。

其他程序可以少次數迴圈取鍵,比如迴圈5次,每次100毫秒。迴圈完了還拿不到就先返回失敗。

這樣做不僅可以降低資料庫的壓力,同時也降低了redis的寫壓力;實際情況可以根據業務需要看著辦,並不是一定要這樣做。

情景四:redis設定後資料庫壓力不減

快取服務如果沒有任何異常,那麼有可能是快取穿透。

什麼是快取穿透呢?簡單來說就是有人老是去請求不存在的資料。

那什麼是不存在的資料?假設資料庫中使用者id是從10000開始的,現在有人頻繁去請求使用者id為500的資料,這個id為500的資料就是不存在的資料。因為它不可能存在於資料庫。

這時候會怎麼樣呢?系統先查詢快取,查不到所以去查了資料庫,也沒有查到,所以直接返回空。但是下一次請求還是要走一遍快取+資料庫。這個時候只要一段簡單的指令碼就可以對資料庫造成壓力。

解決方法很簡單:當資料庫查不到資料時,先設定一個null鍵入快取,之後就任他刷。一般情況下會給這個null值設定一個過期時間。

轉https://www.cnblogs.com/muchengqingxin/p/13177734.html