5.docker學習筆記之入門,redis配置優化

內存分配:vm.overcommit_memory

    Redis是內存操作,需要優先使用內存。設置overcommit 爲1。是爲了讓 fork 操作能夠在低內存下也執行成功。Linux 操作系統對大部分申請內存的請求都回復 yes,以便能運行更多的程序。因爲申請內存後,並不會馬上使用內存,這種技術叫做 overcommit。 vm.overcommit_memory 用來設置內存分配策略,有三個可選值

    

THP:Redis 在啓動時可能會看到如下日誌:

    WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This
                                    will create latency and memory usage issues with Redis. To fix this issue run
                                    the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root,
                                    and add it to your /etc/rc.local in order to retain the setting after a reboot.
                                    Redis must be restarted after THP is disabled.

    Redis 建議修改 Transparent Huge Pages(THP)的相關配置,Linux kernel 在2.6.38內核增加了 THP 特性,支持大內存頁(2MB)分配,默認開啓。當開啓時可以降低 fork 子進程的速度,但 fork 操作之後,每個內存頁從原來 4KB 變爲 2MB,會大幅增加重寫期間父進程內存消耗。同時每次寫命令引起的複製內存頁單位放大了512倍,會拖慢寫操作的執行時間,導致大量寫操作慢查詢,例如簡單的 incr 命令也會出現在慢查詢中。因此 Redis 日誌中建議將此特性進行禁用,禁用方法如下:
        echo never > /sys/kernel/mm/transparent_hugepage/enabled
    爲使機器重啓後THP配置依然生效,可以在/etc/rc.local 中追加  echo never>/sys/kernel/mm/transparent_hugepage/enabled

swappiness

    swap 對於操作系統來比較重要,當物理內存不足時,可以將一部分內存頁進行 swap 操作,已解燃眉之急。swap 空間由硬盤提供,對於需要高併發、高吞吐的應用來說,磁盤 IO 通常會成爲系統瓶頸。在 Linux 中,並不是要等到所有物理內存都使用完纔會使用到 swap,系統參數 swppiness 會決定操作系統使用 swap 的傾向程度。swappiness 的取值範圍是0~100,swappiness 的值越大,說明操作系統可能使用swap的概率越高,swappiness 值越低,表示操作系統更加傾向於使用物理內存。swap 的默認值是60,瞭解這個值的含義後,有利於 Redis 的性能優化。下表對 swappiness 的重要值進行了說明。

    

    OOM(Out Of Memory)killer 機制是指 Linux 操作系統發現可用內存不足時,強制殺死一些用戶進程(非內核進程),來保證系統有足夠的可用內存進行分配。 爲使配置在重啓 Linux 操作系統後立即生效,只需要在/etc/sysctl.conf 追加 vm.swappiness={bestvalue}即可
        echo vm.swappiness={bestvalue} >> /etc/sysctl.conf

查看 swap 的總體情況  free-m 如下服務器開啓了8189M swap,其中使用了 5241MB

    

ulimit設置

    可以通過 ulimit 查看和設置系統當前用戶進程的資源數。其中 ulimit-a 命令包含的 open files 參數,是單個用戶同時打開的最大文件個數:

    

    Redis 允許同時有多個客戶端通過網絡進行連接,可以通過配置 maxclients 來限制最大客戶端連接數。對 Linux 操作系統來說,這些網絡連接都是文件句柄。假設當前 open files 是4096,那麼啓動 Redis 時會看到如下日誌:
        #You requested maxclients of 10000 requiring at least 10032 max file descriptors.
        #Redis can’t set maximum open files to 10032 because of OS error: Operation not permitted.
        #Current maximum open files is 4096. Maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase ‘ulimit –n’.

    解釋如下:

        第一行:Redis 建議把 open files 至少設置成10032,那麼這個10032是如何來的呢?因爲 maxclients 默認是10000,這些是用來處理客戶端連接的,除此之外,Redis 內部會使用最多32個文件描述符,所以這裏的10032=10000+32。

        第二行:Redis 不能將 open files 設置成10032,因爲它沒有權限設置。

        第三行:當前系統的 open files 是4096,所以將 maxclients 設置成4096-32=4064個,如果你想設置更高的 maxclients,請使用 ulimit-n 來設置。

    從上面的三行日誌分析可以看出 open files 的限制優先級比 maxclients 大。

    Open files 的設置方法如下:
        ulimit –Sn {max-open-files}

Redis配置優化

    設置maxmemory。設置Redis使用的最大物理內存,即Redis在佔用maxmemory大小的內存之後就開始拒絕後續的寫入請求,該參數可以確保Redis因爲使用了大量內存嚴重影響速度或者發生OOM(out-of-memory,發現內存不足時,它會選擇殺死一些進程(用戶態進程,不是內核線程),以便釋放內存)。此外,可以使用info命令查看Redis佔用的內存及其它信息。

    讓鍵名保持簡短。鍵的長度越長,Redis需要存儲的數據也就越多

    客戶端timeout 設置一個超時時間,防止無用的連接佔用資源。設置如下命令:

        timeout 150

        tcp-keepalive 150 (定時向client發送tcp_ack包來探測client是否存活的。默認不探測)

    檢查數據持久化策略

        數據落磁盤儘可能減少性能損壞,以空間換時間。設置如下命令:

            rdbcompression no : 默認值是yes。對於存儲到磁盤中的快照,可以設置是否進行壓縮存儲。如果是的話,redis會採用LZF算法進行壓縮。如果你不想消耗CPU來進行壓縮的話,可以設置爲關閉此功能,但是存儲在磁盤上的快照會比較大。

            rdbchecksum no : 默認值是yes。在存儲快照後,我們還可以讓redis使用CRC64算法來進行數據校驗,但是這樣做會增加大約10%的性能消耗,如果希望獲取到最大的性能提升,可以關閉此功能。

    優化AOF和RDB,減少佔用CPU時間

        主庫可以不進行dump操作或者降低dump頻率(RDB操作)。

        取消AOF持久化。命令如下:
            appendonly no

    監控客戶端的連接

        因爲Redis是單線程模型(只能使用單核),來處理所有客戶端的請求, 但由於客戶端連接數的增長,處理請求的線程資源開始降低分配給單個客戶端連接的處理時間

    限制客戶端連接數 。在Redis-cli工具中輸入info clients可以查看到當前實例的所有客戶端連接信息

        maxclients屬性上修改客戶端連接的最大數,可以通過在Redis-cli工具上輸入 config set maxclients 去設置最大連接數。根據連接數負載的情況

縮減鍵值對象

    降低Redis內存使用最直接的方式就是縮減鍵(key)和值(value)的長度。

    key長度:如在設計鍵時,在完整描述業務情況下,鍵值越短越好。

    value長度:值對象縮減比較複雜,常見需求是把業務對象序列化成二進制數組放入Redis。首先應該在業務上精簡業務對象,在存到Redis之前先把你的數據壓縮下。

    常用壓縮方法對比

    

命令處理

    Redis基於C/S架構模式,基於Redis操作命令是解決響應延遲問題最關鍵的部分,因爲Redis是個單線程模型,客戶端過來的命令是按照順序執行的。比較常見的延遲是帶寬,通過千兆網卡的延遲大約有200μs。倘若明顯看到命令的響應時間變慢,延遲高於200μs,那可能是Redis命令隊列裏等待處理的命令數量比較多

    要分析解決這個性能問題,需要跟蹤命令處理數的數量和延遲時間。

    比如可以寫個腳本,定期記錄total_commands_processed的值。當客戶端明顯發現響應時間過慢時,可以通過記錄的total_commands_processed歷史數據值來判斷命理處理總數是上升趨勢還是下降趨勢,以便排查問題

    在info信息裏的 total_commands_processed字段顯示了Redis服務處理命令的總數

    

    解決方案:

        1.使用多參數命令:若是客戶端在很短的時間內發送大量的命令過來,會發現響應時間明顯變慢,這由於後面命令一直在等待隊列中前面大量命令執行完畢。有個方法可以改善延遲問題,就是通過單命令多參數的形式取代多命令單參數的形式。

            舉例來說 循環使用LSET命令去添加1000個元素到list結構中,是性能比較差的一種方式,更好的做法是在客戶端創建一個1000元素的列表,用單個命令LPUSH或RPUSH,通過多參數構造形式一次性把1000個元素髮送的Redis服務上。下面是Redis的一些操作命令,有單個參數命令和支持多個參數的命令,通過這些命令可儘量減少使用多命令的次數。

        2.管道命令:另一個減少多命令的方法是使用管道(pipeline),把幾個命令合併一起執行,從而減少因網絡開銷引起的延遲問題。因爲10個命令單獨發送到服務端會引起10次網絡延遲開銷,使用管道會一次性把執行結果返回,僅需要一次網絡延遲開銷。Redis本身支持管道命令,大多數客戶端也支持,倘若當前實例延遲很明顯,那麼使用管道去降低延遲是非常有效的

緩存淘汰優化

    redis 內存數據集大小上升到一定大小的時候,就會進行數據淘汰策略。如果不淘汰經常不用的緩存數據,那麼正常的數據將不會存儲到緩存當中。

    我們通過配置redis.conf中的maxmemory這個值來開啓內存淘汰功能。

        maxmemory:值得注意的是,maxmemory爲0的時候表示我們對Redis的內存使用沒有限制

    根據應用場景,選擇淘汰策略

        maxmemory-policy noeviction

    內存淘汰的過程

        首先,客戶端發起了需要申請更多內存的命令(如set)。
        然後,Redis檢查內存使用情況,如果已使用的內存大於maxmemory則開始根據用戶配置的不同淘汰策略來淘汰內存(key),從而換取一定的內存。
        最後,如果上面都沒問題,則這個命令執行成功。

    動態改配置命令:此外,redis支持動態改配置,無需重啓。

    設置最大內存
        config set maxmemory 100000
    設置淘汰策略
        config set maxmemory-policy noeviction

內存淘汰策略

    volatile-lru
        從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰(可以理解爲最後一次使用的時間距離當前時間越久越容易被淘汰)。

    allkeys-lru
        從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰

    volatile-lfu
        從設置了過期時間的數據集(server.db[i].expires)中選擇某段時間之內使用頻次最小的鍵值對清除掉(一段時間內使用的次數最少,比如:即使A最後一次使用的時間距離當前時間最久,但是使用的頻率比B高,那麼也會先淘汰B)

    allkeys-lfu
        從所有的數據集(server.db[i].dict)中選擇某段時間之內使用頻次最少的鍵值對清除

    volatile-ttl
        從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰

    volatile-random
        從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰

    allkeys-random
        從數據集(server.db[i].dict)中任意選擇數據淘汰

    no-enviction
        當內存達到限制的時候,不淘汰任何數據,不可寫入任何數據集,所有引起申請內存的命令會報錯。

如何選擇淘汰策略

    下面看看幾種策略的適用場景

        allkeys-lru :如果我們的應用對緩存的訪問符合冪律分佈,也就是存在相對熱點數據,或者我們不太清楚我們應用的緩存訪問分佈狀況,我們可以選擇allkeys-lru策略。

        allkeys-random :如果我們的應用對於緩存key的訪問概率相等,則可以使用這個策略。

        volatile-ttl:這種策略使得我們可以向Redis提示哪些key更適合被eviction。

        另外,volatile-lru策略和volatile-random策略適合我們將一個Redis實例既應用於緩存和又應用於持久化存儲的時候,然而我們也可以通過使用兩個Redis實例來達到相同的效果,值得一提的是將key設置過期時間實際上會消耗更多的內存,因此我們建議使用allkeys-lru策略從而更有效率的使用內存

    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章