redis使用中存在的問題及如何避免(一)

redis能夠知足不少的應用場景,並且由於將全部數據都放到內存中,因此它的讀寫性能很好,不少公司都在使用redis。redis給咱們帶來便利的同時,使用過程當中會存在什麼問題呢,本文將簡單加以總結。linux

  • 阻塞問題
    redis使用了單線程來處理請求,爲何單線程能夠支持如此高的併發呢?主要有以下幾點:redis

    1. 純內存訪問:將全部數據都放到內存中,內存響應時間爲100納秒,是redis達到每秒萬級別訪問的重要基礎
    2. 非阻塞IO:redis使用epoll做爲I/O多路複用技術,redis自身的事件處理模型將epoll中的鏈接、讀寫、關閉都轉換爲事件,不在網絡I/O上浪費過多時間
    3. 單線程:避免了線程切換和競態產生的消耗,簡化了數據結構和算法的實現
      所以若是某個命令執行時間過長,會形成其餘命令阻塞,對redis來講是致命的算法

      產生阻塞的場景:
      A. API或數據結構使用不合理
         a. 避免使用某些易形成阻塞的命令如:keys sort hgetall smembers
            執行showlog get [n] 能夠獲取最近n條執行慢的記錄,對於執行超過必定時間
            (默認10ms,線上建議設置爲1ms)的命令都會記錄到一個定長隊列(默認128,可調整)中。              
         b. 防止一次操做獲取過多數據:縮減大對象或者把大對象拆分爲多個小對象
            發現大對象的命令:redis-cli -h{ip} -p{port} bigkeys
            內部原理:採用分段進行scan操做,把歷史掃描過的大對象統計出來
         c. 防止大量key同時過時:若是有不少key在同一秒內過時,超過了全部key的25%,redis主線程就會阻塞直到過時key比例降低到25%之內,
            所以要避免同一時間過時大量key,過時時間可作散列處理。
            redis4.0引入的lazyfree機制能夠避免del、flushdb、flushall、rename等命令引發的redis-server阻塞,提升服務穩定性。
           
      B. CPU飽和
         單線程的redis處理命令時只能使用一個CPU,CPU飽和是指redis把單核的CPU使用率跑到接近100%。
         首先要肯定redis的併發量是否達到極限,經過redis-cli-h{ip} -p{port}--stat 獲取redis當前使用狀況。
         若是達到每秒6w+左右的qps,說明單臺已跑到極限,須要水平擴展。
         若是qps只有幾百或者幾千CPU就已經飽和,可能使用了高算法複雜度的命令或者是對內存的過分優化
         (如放寬了ziplist的使用條件,雖然使用的內存會變少,可是更耗CPU)。
            
      C. 持久化操做
         持久化引發主線程的阻塞操做主要有:fork阻塞、AOF刷盤阻塞、HugePage寫操做阻塞
         a. fork阻塞
            發生在RDB和AOF重寫時,redis主線程調用fork操做產生共享內存的子線程,由子線程完成持久化文件的重寫工做,若fork操做耗時過長會引發阻塞。
            避免使用內存過大的實例。              
         b. AOF刷盤阻塞
            開啓AOF持久化功能時,通常會採用1次/s的刷盤方式,後臺線程每秒對AOF文件作fsync操做,當硬盤壓力過大時fsync操做須要等待直到寫入完成。
            若是主線程距離上一次的fsync成功超過2s,爲了數據安全會阻塞直到後臺線程執行完fsync完成。這種阻塞是因爲磁盤壓力引發。
            儘可能獨立部署
         c. HugePage寫操做阻塞
            子進程在執行重寫期間利用linux的copyonwrite機制,會拖慢寫操做的執行時間,致使大量寫操做慢查詢。
            優化linux配置
  • 緩存穿透
    緩存穿透是指查詢一個根本不存在的數據,緩存層和存儲層都不命中,且不將空結果寫到緩存中。
    會致使後端存儲負載變大,形成後端存儲宕機等問題。能夠在程序中分別統計總調用數、緩存命中數、存儲命中數,如有大量存儲層空命中,多是出現了緩存穿透。
    產生緣由:1.自身代碼或數據出現問題 2.惡意攻擊,爬蟲形成空命中
    如何解決:後端

    1. 緩存空對象
      存儲層不命中,扔將空對象保存到緩存層。
      適用場景:數據頻繁變化、實時性高
      帶來問題:
      a.緩存了空值,會佔用內存空間;能夠設置較短過時時間,自動剔除。
      b.數據不一致,若存儲層添加了此數據,有短暫不一致;可主動清除掉緩存的空對象。
    2. 布隆過濾器 在訪問緩存層和數據層以前將存在的key用布隆過濾器提早保存起來,作第一層攔截。 適用場景:大用戶集,實時性要求較低的場景,若有幾億的數據集,每隔一段時間會新增用戶進去,在更新以前新用戶的訪問會存在緩存穿透問題。 缺點:代碼維護複雜
相關文章
相關標籤/搜索