Redis优化及配置
redis所有的數(shù)據(jù)都在內(nèi)存中,而內(nèi)存又是非常寶貴的資源。常用的內(nèi)存優(yōu)化方案有如下幾部分:
1、配置優(yōu)化
2、縮減鍵值對象
3、命令處理
4、緩存淘汰方案
一、配置優(yōu)化
1、linux配置優(yōu)化
內(nèi)存分配
- ?vm.overcommit_memory?
- Redis是內(nèi)存操作,需要優(yōu)先使用內(nèi)存。設(shè)置overcommit 為1。是為了讓 fork 操作能夠在低內(nèi)存下也執(zhí)行成功。Linux 操作系統(tǒng)對大部分申請內(nèi)存的請 求都回復(fù) yes,以便能運行更多的程序。因為申請內(nèi)存后,并不會馬上使用內(nèi)存,這種技術(shù)叫做 overcommit。 vm.overcommit_memory 用來設(shè)置內(nèi)存 分配策略,有三個可選值?
- ?THP - Redis 在啟動時可能會看到如下日志:
 
? ? ? ? ? ?
- Redis 建議修改 Transparent Huge Pages(THP)的相關(guān)配置,Linux kernel 在2.6.38內(nèi)核增加了 THP 特性,支持大內(nèi)存頁(2MB)分配,默認(rèn)開啟。當(dāng)開啟 時可以降低 fork 子進(jìn)程的速度,但 fork 操作之后,每個內(nèi)存頁從原來 4KB 變?yōu)?2MB,會大幅增加重寫期間父進(jìn)程內(nèi)存消耗。同時每次寫命令引起的復(fù)制內(nèi) 存頁單位放大了512倍,會拖慢寫操作的執(zhí)行時間,導(dǎo)致大量寫操作慢查詢,例如簡單的 incr 命令也會出現(xiàn)在慢查詢中。因此 Redis 日志中建議將此特性進(jìn) 行禁用,禁用方法如下:
? ? ? ? echo never > /sys/kernel/mm/transparent_hugepage/enabled
? ? ? ?為使機器重啟后THP配置依然生效,可以在/etc/rc.local 中追加 echo never>/sys/kernel/mm/transparent_hugepage/enabled
- swappiness - swap 對于操作系統(tǒng)來比較重要,當(dāng)物理內(nèi)存不足時,可以將一部分內(nèi)存頁進(jìn)行 swap 操作,已解燃眉之急。swap 空間由硬盤提供,對于需要高并發(fā)、 高吞吐的應(yīng)用來說,磁盤 IO 通常會成為系統(tǒng)瓶頸。在 Linux 中,并不是要等到所有物理內(nèi)存都使用完才會使用到 swap,系統(tǒng)參數(shù) swppiness 會決定操 作系統(tǒng)使用 swap 的傾向程度。swappiness 的取值范圍是0~100,swappiness 的值越大,說明操作系統(tǒng)可能使用swap的概率越高,swappiness 值越 低,表示操作系統(tǒng)更加傾向于使用物理內(nèi)存。swap 的默認(rèn)值是60,了解這個值的含義后,有利于 Redis 的性能優(yōu)化。下表對 swappiness 的重要值進(jìn)行了說明。
 
? ? OOM(Out Of Memory)killer 機制是指 Linux 操作系統(tǒng)發(fā)現(xiàn)可用內(nèi)存不足時,強制殺死一些用戶進(jìn)程(非內(nèi)核進(jìn)程),來保證系統(tǒng)有足夠的可用內(nèi)存 進(jìn)行分配。 為使配置在重啟 Linux 操作系統(tǒng)后立即生效,只需要在/etc/sysctl.conf 追加 vm.swappiness={bestvalue}即可 echo vm.swappiness={bestvalue} >> /etc/sysctl.conf
- 查看 swap 的總體情況 free-m 如下服務(wù)器開啟了8189M swap,其中使用了 5241MB
- ulimit設(shè)置 - 可以通過 ulimit 查看和設(shè)置系統(tǒng)當(dāng)前用戶進(jìn)程的資源數(shù)。其中 ulimit-a 命令包含的 open files 參數(shù),是單個用戶同時打開的最大文件個數(shù)?
 
?Redis 允許同時有多個客戶端通過網(wǎng)絡(luò)進(jìn)行連接,可以通過配置 maxclients 來限制最大客戶端連接數(shù)。對 Linux 操作系統(tǒng)來說,這些網(wǎng)絡(luò)連接都是文件 句柄。假設(shè)當(dāng)前 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 至少設(shè)置成10032,那么這個10032是如何來的呢?因為 maxclients 默認(rèn)是10000,這些是用來處理客戶端連接的,除此 之外,Redis 內(nèi)部會使用最多32個文件描述符,所以這里的10032=10000+32。
 第二行:Redis 不能將 open files 設(shè)置成10032,因為它沒有權(quán)限設(shè)置。
 第三行:當(dāng)前系統(tǒng)的 open files 是4096,所以將 maxclients 設(shè)置成4096-32=4064個,如果你想設(shè)置更高的 maxclients,請使用 ulimit-n 來設(shè)置。
 從上面的三行日志分析可以看出 open files 的限制優(yōu)先級比 maxclients 大。 Open files 的設(shè)置方法如下:
ulimit –Sn {max-open-files}
2、Redis配置優(yōu)化
?
- 設(shè)置maxmemory。設(shè)置Redis使用的最大物理內(nèi)存,即Redis在占用maxmemory大小的內(nèi)存之后就開始拒絕后續(xù)的寫入請求,該參數(shù)可以確保Redis因為使用 了大量內(nèi)存嚴(yán)重影響速度或者發(fā)生OOM(out-of-memory,發(fā)現(xiàn)內(nèi)存不足時,它會選擇殺死一些進(jìn)程(用戶態(tài)進(jìn)程,不是內(nèi)核線程),以便釋放內(nèi)存)。此外, 可以使用info命令查看Redis占用的內(nèi)存及其它信息。
- 讓鍵名保持簡短。鍵的長度越長,Redis需要存儲的數(shù)據(jù)也就越多
- 客戶端timeout 設(shè)置一個超時時間,防止無用的連接占用資源。設(shè)置如下命令: - timeout 150
- tcp-keepalive 150 (定時向client發(fā)送tcp_ack包來探測client是否存活的。默認(rèn)不探測)
 
- 檢查數(shù)據(jù)持久化策略 數(shù)據(jù)落磁盤盡可能減少性能損壞,以空間換時間。設(shè)置如下命令: - rdbcompression no : 默認(rèn)值是yes。對于存儲到磁盤中的快照,可以設(shè)置是否進(jìn)行壓縮存儲。如果是的話,redis會采用LZF算法進(jìn)行壓縮。如果你不想 消耗CPU來進(jìn)行壓縮的話,可以設(shè)置為關(guān)閉此功能,但是存儲在磁盤上的快照會比較大。
- rdbchecksum no : 默認(rèn)值是yes。在存儲快照后,我們還可以讓redis使用CRC64算法來進(jìn)行數(shù)據(jù)校驗,但是這樣做會增加大約10%的性能消耗,如果希 望獲取到最大的性能提升,可以關(guān)閉此功能。
 
- 優(yōu)化AOF和RDB,減少占用CPU時間 主庫可以不進(jìn)行dump操作或者降低dump頻率。 取消AOF持久化。命令如下: appendonly no
- 監(jiān)控客戶端的連接 - 因為Redis是單線程模型(只能使用單核),來處理所有客戶端的請求, 但由于客戶端連接數(shù)的增長,處理請求的線程資源開始降低分配給單個客戶端連接 的處理時間
 
- 限制客戶端連接數(shù) 。在Redis-cli工具中輸入info clients可以查看到當(dāng)前實例的所有客戶端連接信息 - maxclients屬性上修改客戶端連接的最大數(shù),可以通過在Redis-cli工具上輸入 config set maxclients 去設(shè)置最大連接數(shù)。根據(jù)連接數(shù)負(fù)載的情況
 
二、縮減鍵值對象
 降低Redis內(nèi)存使用最直接的方式就是縮減鍵(key)和值(value)的長度。
- key長度:如在設(shè)計鍵時,在完整描述業(yè)務(wù)情況下,鍵值越短越好。
- value長度:值對象縮減比較復(fù)雜,常見需求是把業(yè)務(wù)對象序列化成二進(jìn)制數(shù)組放入Redis。首先應(yīng)該在業(yè)務(wù)上精簡業(yè)務(wù)對象,在存到Redis之前先把你的數(shù)據(jù) 壓縮下。
三. 命令處理
 Redis基于C/S架構(gòu)模式,基于Redis操作命令是解決響應(yīng)延遲問題最關(guān)鍵的部分,因為Redis是個單線程模型,客戶端過來的命令是按照順序執(zhí)行的。比較常見的 延遲是帶寬,通過千兆網(wǎng)卡的延遲大約有200μs。倘若明顯看到命令的響應(yīng)時間變慢,延遲高于200μs,那可能是Redis命令隊列里等待處理的命令數(shù)量比較多
 要分析解決這個性能問題,需要跟蹤命令處理數(shù)的數(shù)量和延遲時間。
 比如可以寫個腳本,定期記錄total_commands_processed的值。當(dāng)客戶端明顯發(fā)現(xiàn)響應(yīng)時間過慢時,可以通過記錄的total_commands_processed歷史數(shù)據(jù)值來判 斷命理處理總數(shù)是上升趨勢還是下降趨勢,以便排查問題 在info信息里的 total_commands_processed字段顯示了Redis服務(wù)處理命令的總數(shù)
解決方案:
1.使用多參數(shù)命令:若是客戶端在很短的時間內(nèi)發(fā)送大量的命令過來,會發(fā)現(xiàn)響應(yīng)時間明顯變慢,這由于后面命令一直在等待隊列中前面大量命令執(zhí)行完畢。有 個方法可以改善延遲問題,就是通過單命令多參數(shù)的形式取代多命令單參數(shù)的形式。
 舉例來說 循環(huán)使用LSET命令去添加1000個元素到list結(jié)構(gòu)中,是性能比較差的一種方式,更好的做法是在客戶端創(chuàng)建一個1000元素的列表,用單個命令LPUSH或 RPUSH,通過多參數(shù)構(gòu)造形式一次性把1000個元素發(fā)送的Redis服務(wù)上。下面是Redis的一些操作命令,有單個參數(shù)命令和支持多個參數(shù)的命令,通過這些命令可 盡量減少使用多命令的次數(shù)。
 2.管道命令:另一個減少多命令的方法是使用管道(pipeline),把幾個命令合并一起執(zhí)行,從而減少因網(wǎng)絡(luò)開銷引起的延遲問題。因為10個命令單獨發(fā)送到服務(wù)端 會引起10次網(wǎng)絡(luò)延遲開銷,使用管道會一次性把執(zhí)行結(jié)果返回,僅需要一次網(wǎng)絡(luò)延遲開銷。Redis本身支持管道命令,大多數(shù)客戶端也支持,倘若當(dāng)前實例延遲 很明顯,那么使用管道去降低延遲是非常有效的
四、緩存淘汰優(yōu)化
 redis 內(nèi)存數(shù)據(jù)集大小上升到一定大小的時候,就會進(jìn)行數(shù)據(jù)淘汰策略。如果不淘汰經(jīng)常不用的緩存數(shù)據(jù),那么正常的數(shù)據(jù)將不會存儲到緩存當(dāng)中。
 我們通過配置redis.conf中的maxmemory這個值來開啟內(nèi)存淘汰功能。
- maxmemory
? ? ? ?值得注意的是,maxmemory為0的時候表示我們對Redis的內(nèi)存使用沒有限制
? ? ? 根據(jù)應(yīng)用場景,選擇淘汰策略
- maxmemory-policy noeviction
內(nèi)存淘汰的過程
 首先,客戶端發(fā)起了需要申請更多內(nèi)存的命令(如set)。
 然后,Redis檢查內(nèi)存使用情況,如果已使用的內(nèi)存大于maxmemory則開始根據(jù)用戶配置的不同淘汰策略來淘汰內(nèi)存(key),從而換取一定的內(nèi)存。
 最后,如果上面都沒問題,則這個命令執(zhí)行成功。
 動態(tài)改配置命令
此外,redis支持動態(tài)改配置,無需重啟。
- 設(shè)置最大內(nèi)存
? ?config set maxmemory 100000
- 設(shè)置淘汰策略
? ?config set maxmemory-policy noeviction
- 內(nèi)存淘汰策略
? ?volatile-lru
- 從已設(shè)置過期時間的數(shù)據(jù)集(server .db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰。
? ?allkeys-lru
- 從數(shù)據(jù)集(server .db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰
? ?volatile-lfu
- 從設(shè)置了過期時間的數(shù)據(jù)集(server .db[i].expires)中選擇某段時間之內(nèi)使用頻次最小的鍵值對清除掉
? ?allkeys-lfu
- 從所有的數(shù)據(jù)集(server .db[i].dict)中選擇某段時間之內(nèi)使用頻次最少的鍵值對清除
? ?volatile-ttl
- 從已設(shè)置過期時間的數(shù)據(jù)集(server .db[i].expires)中挑選將要過期的數(shù)據(jù)淘汰
? ?volatile-random
- 從已設(shè)置過期時間的數(shù)據(jù)集(server .db[i].expires)中任意選擇數(shù)據(jù)淘汰
? ? allkeys-random
- 從數(shù)據(jù)集(server .db[i].dict)中任意選擇數(shù)據(jù)淘汰
? ? no-enviction
 ? ?當(dāng)內(nèi)存達(dá)到限制的時候,不淘汰任何數(shù)據(jù),不可寫入任何數(shù)據(jù)集,所有引起申請內(nèi)存的命令會報錯。
 ? ?算法文章:(https://blog.csdn.net/ZYZMZM_/article/details/90546812)
如何選擇淘汰策略
 下面看看幾種策略的適用場景
- allkeys-lru :如果我們的應(yīng)用對緩存的訪問符合冪律分布,也就是存在相對熱點數(shù)據(jù),或者我們不太清楚我們應(yīng)用的緩存訪問分布狀況,我們可以選擇 allkeys-lru策略。
- allkeys-random :如果我們的應(yīng)用對于緩存key的訪問概率相等,則可以使用這個策略。
- volatile-ttl:這種策略使得我們可以向Redis提示哪些key更適合被eviction。
另外,volatile-lru策略和volatile-random策略適合我們將一個Redis實例既應(yīng)用于緩存和又應(yīng)用于持久化存儲的時候,然而我們也可以通過使用兩個Redis實例來達(dá) 到相同的效果,值得一提的是將key設(shè)置過期時間實際上會消耗更多的內(nèi)存,因此我們建議使用allkeys-lru策略從而更有效率的使用內(nèi)存?
總結(jié)
以上是生活随笔為你收集整理的Redis优化及配置的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: [预告] 俺最近正在做的E助手。。。
- 下一篇: python的Tkinter库简单应用—
